Support sampling depth and stencil of combined d/s formats
This CL adds sampling of depth-only and stencil-only texture views on all backends. However, Metal on macOS <= 10.11 will need a workaround to use separate depth/stencil textures for each aspect since it is impossible to sample the stencil aspect of a combined depth/stencil texture. Also fixes sampling of depth24plus on D3D12 which had an incomplete check for determining if a TYPELESS format is necessary. Bug: dawn:439, dawn:553 Change-Id: Id4991c565f822add200054296714e2dcd330119a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30725 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
parent
9d6265bc07
commit
a0f1725c4f
|
@ -90,4 +90,12 @@ bool IsFloat16NaN(uint16_t fp16);
|
||||||
|
|
||||||
float SRGBToLinear(float srgb);
|
float SRGBToLinear(float srgb);
|
||||||
|
|
||||||
|
template <typename T1,
|
||||||
|
typename T2,
|
||||||
|
typename Enable = typename std::enable_if<sizeof(T1) == sizeof(T2)>::type>
|
||||||
|
constexpr bool IsSubset(T1 subset, T2 set) {
|
||||||
|
T2 bitsAlsoInSet = subset & set;
|
||||||
|
return bitsAlsoInSet == subset;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // COMMON_MATH_H_
|
#endif // COMMON_MATH_H_
|
||||||
|
|
|
@ -150,7 +150,7 @@ namespace dawn_native {
|
||||||
};
|
};
|
||||||
|
|
||||||
auto AddDepthStencilFormat = [&AddFormat](wgpu::TextureFormat format, Aspect aspects,
|
auto AddDepthStencilFormat = [&AddFormat](wgpu::TextureFormat format, Aspect aspects,
|
||||||
uint32_t byteSize, bool isDepthSampleable) {
|
uint32_t byteSize) {
|
||||||
Format internalFormat;
|
Format internalFormat;
|
||||||
internalFormat.format = format;
|
internalFormat.format = format;
|
||||||
internalFormat.isRenderable = true;
|
internalFormat.isRenderable = true;
|
||||||
|
@ -162,12 +162,8 @@ namespace dawn_native {
|
||||||
internalFormat.firstAspect.block.width = 1;
|
internalFormat.firstAspect.block.width = 1;
|
||||||
internalFormat.firstAspect.block.height = 1;
|
internalFormat.firstAspect.block.height = 1;
|
||||||
internalFormat.firstAspect.baseType = wgpu::TextureComponentType::Float;
|
internalFormat.firstAspect.baseType = wgpu::TextureComponentType::Float;
|
||||||
if (isDepthSampleable) {
|
internalFormat.firstAspect.supportedComponentTypes =
|
||||||
internalFormat.firstAspect.supportedComponentTypes =
|
ComponentTypeBit::Float | ComponentTypeBit::DepthComparison;
|
||||||
ComponentTypeBit::Float | ComponentTypeBit::DepthComparison;
|
|
||||||
} else {
|
|
||||||
internalFormat.firstAspect.supportedComponentTypes = ComponentTypeBit::None;
|
|
||||||
}
|
|
||||||
AddFormat(internalFormat);
|
AddFormat(internalFormat);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -238,12 +234,12 @@ namespace dawn_native {
|
||||||
AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, 16, Type::Float);
|
AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, 16, Type::Float);
|
||||||
|
|
||||||
// Depth-stencil formats
|
// Depth-stencil formats
|
||||||
AddDepthStencilFormat(wgpu::TextureFormat::Depth32Float, Aspect::Depth, 4, true);
|
AddDepthStencilFormat(wgpu::TextureFormat::Depth32Float, Aspect::Depth, 4);
|
||||||
AddDepthStencilFormat(wgpu::TextureFormat::Depth24Plus, Aspect::Depth, 4, false);
|
AddDepthStencilFormat(wgpu::TextureFormat::Depth24Plus, Aspect::Depth, 4);
|
||||||
// TODO(cwallez@chromium.org): It isn't clear if this format should be copyable
|
// TODO(cwallez@chromium.org): It isn't clear if this format should be copyable
|
||||||
// because its size isn't well defined, is it 4, 5 or 8?
|
// because its size isn't well defined, is it 4, 5 or 8?
|
||||||
AddDepthStencilFormat(wgpu::TextureFormat::Depth24PlusStencil8,
|
AddDepthStencilFormat(wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
Aspect::Depth | Aspect::Stencil, 4, false);
|
Aspect::Depth | Aspect::Stencil, 4);
|
||||||
|
|
||||||
// BC compressed formats
|
// BC compressed formats
|
||||||
bool isBCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionBC);
|
bool isBCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionBC);
|
||||||
|
|
|
@ -171,7 +171,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
return DXGI_FORMAT_R32_TYPELESS;
|
return DXGI_FORMAT_R32_TYPELESS;
|
||||||
|
|
||||||
case wgpu::TextureFormat::Depth24PlusStencil8:
|
case wgpu::TextureFormat::Depth24PlusStencil8:
|
||||||
return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
|
return DXGI_FORMAT_R32G8X24_TYPELESS;
|
||||||
|
|
||||||
case wgpu::TextureFormat::BC1RGBAUnorm:
|
case wgpu::TextureFormat::BC1RGBAUnorm:
|
||||||
case wgpu::TextureFormat::BC1RGBAUnormSrgb:
|
case wgpu::TextureFormat::BC1RGBAUnormSrgb:
|
||||||
|
@ -451,8 +451,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
// This will need to be much more nuanced when WebGPU has
|
// This will need to be much more nuanced when WebGPU has
|
||||||
// texture view compatibility rules.
|
// texture view compatibility rules.
|
||||||
bool needsTypelessFormat = GetFormat().format == wgpu::TextureFormat::Depth32Float &&
|
const bool needsTypelessFormat =
|
||||||
(GetUsage() & wgpu::TextureUsage::Sampled) != 0;
|
GetFormat().HasDepthOrStencil() && (GetUsage() & wgpu::TextureUsage::Sampled) != 0;
|
||||||
|
|
||||||
DXGI_FORMAT dxgiFormat = needsTypelessFormat
|
DXGI_FORMAT dxgiFormat = needsTypelessFormat
|
||||||
? D3D12TypelessTextureFormat(GetFormat().format)
|
? D3D12TypelessTextureFormat(GetFormat().format)
|
||||||
|
@ -1027,13 +1027,50 @@ namespace dawn_native { namespace d3d12 {
|
||||||
TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor)
|
TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor)
|
||||||
: TextureViewBase(texture, descriptor) {
|
: TextureViewBase(texture, descriptor) {
|
||||||
mSrvDesc.Format = D3D12TextureFormat(descriptor->format);
|
mSrvDesc.Format = D3D12TextureFormat(descriptor->format);
|
||||||
if (descriptor->format == wgpu::TextureFormat::Depth32Float) {
|
|
||||||
// TODO(enga): This will need to be much more nuanced when WebGPU has
|
|
||||||
// texture view compatibility rules.
|
|
||||||
mSrvDesc.Format = DXGI_FORMAT_R32_FLOAT;
|
|
||||||
}
|
|
||||||
mSrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
mSrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||||
|
|
||||||
|
// TODO(enga): This will need to be much more nuanced when WebGPU has
|
||||||
|
// texture view compatibility rules.
|
||||||
|
UINT planeSlice = 0;
|
||||||
|
if (GetFormat().HasDepthOrStencil()) {
|
||||||
|
// Configure the SRV descriptor to reinterpret the texture allocated as
|
||||||
|
// TYPELESS as a single-plane shader-accessible view.
|
||||||
|
switch (descriptor->format) {
|
||||||
|
case wgpu::TextureFormat::Depth32Float:
|
||||||
|
case wgpu::TextureFormat::Depth24Plus:
|
||||||
|
mSrvDesc.Format = DXGI_FORMAT_R32_FLOAT;
|
||||||
|
break;
|
||||||
|
case wgpu::TextureFormat::Depth24PlusStencil8:
|
||||||
|
switch (descriptor->aspect) {
|
||||||
|
case wgpu::TextureAspect::DepthOnly:
|
||||||
|
planeSlice = 0;
|
||||||
|
mSrvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
|
||||||
|
break;
|
||||||
|
case wgpu::TextureAspect::StencilOnly:
|
||||||
|
planeSlice = 1;
|
||||||
|
mSrvDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
|
||||||
|
// Stencil is accessed using the .g component in the shader.
|
||||||
|
// Map it to the zeroth component to match other APIs.
|
||||||
|
mSrvDesc.Shader4ComponentMapping =
|
||||||
|
D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||||
|
D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
|
||||||
|
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||||
|
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||||
|
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1);
|
||||||
|
break;
|
||||||
|
case wgpu::TextureAspect::All:
|
||||||
|
// A single aspect is not selected. The texture view must not be
|
||||||
|
// sampled.
|
||||||
|
mSrvDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Currently we always use D3D12_TEX2D_ARRAY_SRV because we cannot specify base array layer
|
// Currently we always use D3D12_TEX2D_ARRAY_SRV because we cannot specify base array layer
|
||||||
// and layer count in D3D12_TEX2D_SRV. For 2D texture views, we treat them as 1-layer 2D
|
// and layer count in D3D12_TEX2D_SRV. For 2D texture views, we treat them as 1-layer 2D
|
||||||
// array textures.
|
// array textures.
|
||||||
|
@ -1065,7 +1102,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
mSrvDesc.Texture2DArray.FirstArraySlice = descriptor->baseArrayLayer;
|
mSrvDesc.Texture2DArray.FirstArraySlice = descriptor->baseArrayLayer;
|
||||||
mSrvDesc.Texture2DArray.MipLevels = descriptor->mipLevelCount;
|
mSrvDesc.Texture2DArray.MipLevels = descriptor->mipLevelCount;
|
||||||
mSrvDesc.Texture2DArray.MostDetailedMip = descriptor->baseMipLevel;
|
mSrvDesc.Texture2DArray.MostDetailedMip = descriptor->baseMipLevel;
|
||||||
mSrvDesc.Texture2DArray.PlaneSlice = 0;
|
mSrvDesc.Texture2DArray.PlaneSlice = planeSlice;
|
||||||
mSrvDesc.Texture2DArray.ResourceMinLODClamp = 0;
|
mSrvDesc.Texture2DArray.ResourceMinLODClamp = 0;
|
||||||
break;
|
break;
|
||||||
case wgpu::TextureViewDimension::Cube:
|
case wgpu::TextureViewDimension::Cube:
|
||||||
|
@ -1093,6 +1130,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
const D3D12_SHADER_RESOURCE_VIEW_DESC& TextureView::GetSRVDescriptor() const {
|
const D3D12_SHADER_RESOURCE_VIEW_DESC& TextureView::GetSRVDescriptor() const {
|
||||||
|
ASSERT(mSrvDesc.Format != DXGI_FORMAT_UNKNOWN);
|
||||||
return mSrvDesc;
|
return mSrvDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace dawn_native { namespace metal {
|
||||||
return usage & kUsageNeedsTextureView;
|
return usage & kUsageNeedsTextureView;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTLTextureUsage MetalTextureUsage(wgpu::TextureUsage usage) {
|
MTLTextureUsage MetalTextureUsage(const Format& format, wgpu::TextureUsage usage) {
|
||||||
MTLTextureUsage result = MTLTextureUsageUnknown; // This is 0
|
MTLTextureUsage result = MTLTextureUsageUnknown; // This is 0
|
||||||
|
|
||||||
if (usage & (wgpu::TextureUsage::Storage)) {
|
if (usage & (wgpu::TextureUsage::Storage)) {
|
||||||
|
@ -43,6 +43,14 @@ namespace dawn_native { namespace metal {
|
||||||
|
|
||||||
if (usage & (wgpu::TextureUsage::Sampled)) {
|
if (usage & (wgpu::TextureUsage::Sampled)) {
|
||||||
result |= MTLTextureUsageShaderRead;
|
result |= MTLTextureUsageShaderRead;
|
||||||
|
|
||||||
|
// For sampling stencil aspect of combined depth/stencil. See TextureView
|
||||||
|
// constructor.
|
||||||
|
if (@available(macOS 10.12, iOS 10.0, *)) {
|
||||||
|
if (IsSubset(Aspect::Depth | Aspect::Stencil, format.aspects)) {
|
||||||
|
result |= MTLTextureUsagePixelFormatView;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usage & (wgpu::TextureUsage::RenderAttachment)) {
|
if (usage & (wgpu::TextureUsage::RenderAttachment)) {
|
||||||
|
@ -85,6 +93,11 @@ namespace dawn_native { namespace metal {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsSubset(Aspect::Depth | Aspect::Stencil, texture->GetFormat().aspects) &&
|
||||||
|
textureViewDescriptor->aspect == wgpu::TextureAspect::StencilOnly) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (textureViewDescriptor->dimension) {
|
switch (textureViewDescriptor->dimension) {
|
||||||
case wgpu::TextureViewDimension::Cube:
|
case wgpu::TextureViewDimension::Cube:
|
||||||
case wgpu::TextureViewDimension::CubeArray:
|
case wgpu::TextureViewDimension::CubeArray:
|
||||||
|
@ -285,7 +298,8 @@ namespace dawn_native { namespace metal {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MTLTextureDescriptor* CreateMetalTextureDescriptor(const TextureDescriptor* descriptor) {
|
MTLTextureDescriptor* CreateMetalTextureDescriptor(DeviceBase* device,
|
||||||
|
const TextureDescriptor* descriptor) {
|
||||||
MTLTextureDescriptor* mtlDesc = [MTLTextureDescriptor new];
|
MTLTextureDescriptor* mtlDesc = [MTLTextureDescriptor new];
|
||||||
|
|
||||||
mtlDesc.width = descriptor->size.width;
|
mtlDesc.width = descriptor->size.width;
|
||||||
|
@ -293,7 +307,8 @@ namespace dawn_native { namespace metal {
|
||||||
mtlDesc.sampleCount = descriptor->sampleCount;
|
mtlDesc.sampleCount = descriptor->sampleCount;
|
||||||
// TODO: add MTLTextureUsagePixelFormatView when needed when we support format
|
// TODO: add MTLTextureUsagePixelFormatView when needed when we support format
|
||||||
// reinterpretation.
|
// reinterpretation.
|
||||||
mtlDesc.usage = MetalTextureUsage(descriptor->usage);
|
mtlDesc.usage = MetalTextureUsage(device->GetValidInternalFormat(descriptor->format),
|
||||||
|
descriptor->usage);
|
||||||
mtlDesc.pixelFormat = MetalPixelFormat(descriptor->format);
|
mtlDesc.pixelFormat = MetalPixelFormat(descriptor->format);
|
||||||
mtlDesc.mipmapLevelCount = descriptor->mipLevelCount;
|
mtlDesc.mipmapLevelCount = descriptor->mipLevelCount;
|
||||||
mtlDesc.storageMode = MTLStorageModePrivate;
|
mtlDesc.storageMode = MTLStorageModePrivate;
|
||||||
|
@ -328,7 +343,7 @@ namespace dawn_native { namespace metal {
|
||||||
|
|
||||||
Texture::Texture(Device* device, const TextureDescriptor* descriptor)
|
Texture::Texture(Device* device, const TextureDescriptor* descriptor)
|
||||||
: TextureBase(device, descriptor, TextureState::OwnedInternal) {
|
: TextureBase(device, descriptor, TextureState::OwnedInternal) {
|
||||||
MTLTextureDescriptor* mtlDesc = CreateMetalTextureDescriptor(descriptor);
|
MTLTextureDescriptor* mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
|
||||||
mMtlTexture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc];
|
mMtlTexture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc];
|
||||||
[mtlDesc release];
|
[mtlDesc release];
|
||||||
|
|
||||||
|
@ -351,7 +366,7 @@ namespace dawn_native { namespace metal {
|
||||||
reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor),
|
reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor),
|
||||||
TextureState::OwnedInternal) {
|
TextureState::OwnedInternal) {
|
||||||
MTLTextureDescriptor* mtlDesc = CreateMetalTextureDescriptor(
|
MTLTextureDescriptor* mtlDesc = CreateMetalTextureDescriptor(
|
||||||
reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor));
|
device, reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor));
|
||||||
mtlDesc.storageMode = kIOSurfaceStorageMode;
|
mtlDesc.storageMode = kIOSurfaceStorageMode;
|
||||||
mMtlTexture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc
|
mMtlTexture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc
|
||||||
iosurface:ioSurface
|
iosurface:ioSurface
|
||||||
|
@ -581,6 +596,20 @@ namespace dawn_native { namespace metal {
|
||||||
mMtlTextureView = [mtlTexture retain];
|
mMtlTextureView = [mtlTexture retain];
|
||||||
} else {
|
} else {
|
||||||
MTLPixelFormat format = MetalPixelFormat(descriptor->format);
|
MTLPixelFormat format = MetalPixelFormat(descriptor->format);
|
||||||
|
if (descriptor->aspect == wgpu::TextureAspect::StencilOnly) {
|
||||||
|
if (@available(macOS 10.12, iOS 10.0, *)) {
|
||||||
|
ASSERT(format == MTLPixelFormatDepth32Float_Stencil8);
|
||||||
|
format = MTLPixelFormatX32_Stencil8;
|
||||||
|
} else {
|
||||||
|
// TODO(enga): Add a workaround to back combined depth/stencil textures
|
||||||
|
// with Sampled usage using two separate textures.
|
||||||
|
// Or, consider always using the workaround for D32S8.
|
||||||
|
GetDevice()->ConsumedError(
|
||||||
|
DAWN_DEVICE_LOST_ERROR("Cannot create stencil-only texture view of "
|
||||||
|
"combined depth/stencil format."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MTLTextureType textureViewType =
|
MTLTextureType textureViewType =
|
||||||
MetalTextureViewType(descriptor->dimension, texture->GetSampleCount());
|
MetalTextureViewType(descriptor->dimension, texture->GetSampleCount());
|
||||||
auto mipLevelRange = NSMakeRange(descriptor->baseMipLevel, descriptor->mipLevelCount);
|
auto mipLevelRange = NSMakeRange(descriptor->baseMipLevel, descriptor->mipLevelCount);
|
||||||
|
|
|
@ -306,6 +306,24 @@ namespace dawn_native { namespace opengl {
|
||||||
for (auto unit : mPipeline->GetTextureUnitsForTextureView(viewIndex)) {
|
for (auto unit : mPipeline->GetTextureUnitsForTextureView(viewIndex)) {
|
||||||
gl.ActiveTexture(GL_TEXTURE0 + unit);
|
gl.ActiveTexture(GL_TEXTURE0 + unit);
|
||||||
gl.BindTexture(target, handle);
|
gl.BindTexture(target, handle);
|
||||||
|
if (ToBackend(view->GetTexture())->GetGLFormat().format ==
|
||||||
|
GL_DEPTH_STENCIL) {
|
||||||
|
Aspect aspect = view->GetAspects();
|
||||||
|
ASSERT(HasOneBit(aspect));
|
||||||
|
switch (aspect) {
|
||||||
|
case Aspect::None:
|
||||||
|
case Aspect::Color:
|
||||||
|
UNREACHABLE();
|
||||||
|
case Aspect::Depth:
|
||||||
|
gl.TexParameteri(target, GL_DEPTH_STENCIL_TEXTURE_MODE,
|
||||||
|
GL_DEPTH_COMPONENT);
|
||||||
|
break;
|
||||||
|
case Aspect::Stencil:
|
||||||
|
gl.TexParameteri(target, GL_DEPTH_STENCIL_TEXTURE_MODE,
|
||||||
|
GL_STENCIL_INDEX);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,16 @@ namespace dawn_native { namespace opengl {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ToBackend(texture)->GetGLFormat().format == GL_DEPTH_STENCIL &&
|
||||||
|
(texture->GetUsage() & wgpu::TextureUsage::Sampled) != 0 &&
|
||||||
|
textureViewDescriptor->aspect == wgpu::TextureAspect::StencilOnly) {
|
||||||
|
// We need a separate view for one of the depth or stencil planes
|
||||||
|
// because each glTextureView needs it's own handle to set
|
||||||
|
// GL_DEPTH_STENCIL_TEXTURE_MODE. Choose the stencil aspect for the
|
||||||
|
// extra handle since it is likely sampled less often.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (textureViewDescriptor->dimension) {
|
switch (textureViewDescriptor->dimension) {
|
||||||
case wgpu::TextureViewDimension::Cube:
|
case wgpu::TextureViewDimension::Cube:
|
||||||
case wgpu::TextureViewDimension::CubeArray:
|
case wgpu::TextureViewDimension::CubeArray:
|
||||||
|
|
|
@ -19,6 +19,16 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr wgpu::TextureFormat kDepthFormats[] = {
|
||||||
|
wgpu::TextureFormat::Depth32Float,
|
||||||
|
wgpu::TextureFormat::Depth24Plus,
|
||||||
|
wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr wgpu::TextureFormat kStencilFormats[] = {
|
||||||
|
wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
|
};
|
||||||
|
|
||||||
constexpr wgpu::CompareFunction kCompareFunctions[] = {
|
constexpr wgpu::CompareFunction kCompareFunctions[] = {
|
||||||
wgpu::CompareFunction::Never, wgpu::CompareFunction::Less,
|
wgpu::CompareFunction::Never, wgpu::CompareFunction::Less,
|
||||||
wgpu::CompareFunction::LessEqual, wgpu::CompareFunction::Greater,
|
wgpu::CompareFunction::LessEqual, wgpu::CompareFunction::Greater,
|
||||||
|
@ -32,10 +42,19 @@ namespace {
|
||||||
// Test 0, below the ref, equal to, above the ref, and 1.
|
// Test 0, below the ref, equal to, above the ref, and 1.
|
||||||
const std::vector<float> kNormalizedTextureValues = {0.0, 0.3, 0.4, 0.5, 1.0};
|
const std::vector<float> kNormalizedTextureValues = {0.0, 0.3, 0.4, 0.5, 1.0};
|
||||||
|
|
||||||
|
// Test the limits, and some values in between.
|
||||||
|
const std::vector<uint8_t> kStencilValues = {uint8_t(0), uint8_t(1), uint8_t(38), uint8_t(255),
|
||||||
|
uint8_t(256)};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
class DepthSamplingTest : public DawnTest {
|
class DepthStencilSamplingTest : public DawnTest {
|
||||||
protected:
|
protected:
|
||||||
|
enum class TestAspect {
|
||||||
|
Depth,
|
||||||
|
Stencil,
|
||||||
|
};
|
||||||
|
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
DawnTest::SetUp();
|
DawnTest::SetUp();
|
||||||
|
|
||||||
|
@ -43,32 +62,10 @@ class DepthSamplingTest : public DawnTest {
|
||||||
uniformBufferDesc.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst;
|
uniformBufferDesc.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst;
|
||||||
uniformBufferDesc.size = sizeof(float);
|
uniformBufferDesc.size = sizeof(float);
|
||||||
mUniformBuffer = device.CreateBuffer(&uniformBufferDesc);
|
mUniformBuffer = device.CreateBuffer(&uniformBufferDesc);
|
||||||
|
|
||||||
wgpu::BufferDescriptor textureUploadDesc;
|
|
||||||
textureUploadDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
|
|
||||||
textureUploadDesc.size = sizeof(float);
|
|
||||||
mTextureUploadBuffer = device.CreateBuffer(&textureUploadDesc);
|
|
||||||
|
|
||||||
wgpu::TextureDescriptor inputTextureDesc;
|
|
||||||
inputTextureDesc.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::RenderAttachment;
|
|
||||||
inputTextureDesc.size = {1, 1, 1};
|
|
||||||
inputTextureDesc.format = wgpu::TextureFormat::Depth32Float;
|
|
||||||
mInputTexture = device.CreateTexture(&inputTextureDesc);
|
|
||||||
|
|
||||||
wgpu::TextureDescriptor outputTextureDesc;
|
|
||||||
outputTextureDesc.usage =
|
|
||||||
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
|
|
||||||
outputTextureDesc.size = {1, 1, 1};
|
|
||||||
outputTextureDesc.format = wgpu::TextureFormat::R32Float;
|
|
||||||
mOutputTexture = device.CreateTexture(&outputTextureDesc);
|
|
||||||
|
|
||||||
wgpu::BufferDescriptor outputBufferDesc;
|
|
||||||
outputBufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
|
|
||||||
outputBufferDesc.size = sizeof(float);
|
|
||||||
mOutputBuffer = device.CreateBuffer(&outputBufferDesc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::RenderPipeline CreateSamplingRenderPipeline() {
|
wgpu::RenderPipeline CreateSamplingRenderPipeline(std::vector<TestAspect> aspects,
|
||||||
|
uint32_t componentIndex) {
|
||||||
wgpu::ShaderModule vsModule =
|
wgpu::ShaderModule vsModule =
|
||||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
||||||
#version 450
|
#version 450
|
||||||
|
@ -78,42 +75,102 @@ class DepthSamplingTest : public DawnTest {
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
|
|
||||||
wgpu::ShaderModule fsModule =
|
|
||||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
|
|
||||||
#version 450
|
|
||||||
layout(set = 0, binding = 0) uniform sampler samp;
|
|
||||||
layout(set = 0, binding = 1) uniform texture2D tex;
|
|
||||||
|
|
||||||
layout(location = 0) out float samplerResult;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
samplerResult = texture(sampler2D(tex, samp), vec2(0.5, 0.5)).r;
|
|
||||||
}
|
|
||||||
)");
|
|
||||||
|
|
||||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
|
||||||
|
|
||||||
|
std::ostringstream shaderSource;
|
||||||
|
std::ostringstream shaderBody;
|
||||||
|
shaderSource << R"(
|
||||||
|
#version 450
|
||||||
|
layout(set = 0, binding = 0) uniform sampler samp;
|
||||||
|
)";
|
||||||
|
|
||||||
|
uint32_t index = 0;
|
||||||
|
for (TestAspect aspect : aspects) {
|
||||||
|
switch (aspect) {
|
||||||
|
case TestAspect::Depth:
|
||||||
|
shaderSource << "layout(set = 0, binding = " << 1 + index
|
||||||
|
<< ") uniform texture2D tex" << index << ";\n";
|
||||||
|
|
||||||
|
shaderSource << "layout(location = " << index << ") out float result" << index
|
||||||
|
<< ";\n";
|
||||||
|
|
||||||
|
shaderBody << "result" << index << " = texture(sampler2D(tex" << index
|
||||||
|
<< ", samp), vec2(0.5, 0.5))[" << componentIndex << "];\n";
|
||||||
|
pipelineDescriptor.cColorStates[index].format = wgpu::TextureFormat::R32Float;
|
||||||
|
break;
|
||||||
|
case TestAspect::Stencil:
|
||||||
|
shaderSource << "layout(set = 0, binding = " << 1 + index
|
||||||
|
<< ") uniform utexture2D tex" << index << ";\n";
|
||||||
|
|
||||||
|
shaderSource << "layout(location = " << index << ") out uint result" << index
|
||||||
|
<< ";\n";
|
||||||
|
|
||||||
|
shaderBody << "result" << index << " = texelFetch(usampler2D(tex" << index
|
||||||
|
<< ", samp), ivec2(0, 0), 0)[" << componentIndex << "];\n";
|
||||||
|
pipelineDescriptor.cColorStates[index].format = wgpu::TextureFormat::R8Uint;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderSource << "void main() { " << shaderBody.str() << " }";
|
||||||
|
|
||||||
|
wgpu::ShaderModule fsModule = utils::CreateShaderModule(
|
||||||
|
device, utils::SingleShaderStage::Fragment, shaderSource.str().c_str());
|
||||||
pipelineDescriptor.vertexStage.module = vsModule;
|
pipelineDescriptor.vertexStage.module = vsModule;
|
||||||
pipelineDescriptor.cFragmentStage.module = fsModule;
|
pipelineDescriptor.cFragmentStage.module = fsModule;
|
||||||
pipelineDescriptor.primitiveTopology = wgpu::PrimitiveTopology::PointList;
|
pipelineDescriptor.primitiveTopology = wgpu::PrimitiveTopology::PointList;
|
||||||
pipelineDescriptor.cColorStates[0].format = wgpu::TextureFormat::R32Float;
|
pipelineDescriptor.colorStateCount = static_cast<uint32_t>(aspects.size());
|
||||||
|
|
||||||
return device.CreateRenderPipeline(&pipelineDescriptor);
|
return device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::ComputePipeline CreateSamplingComputePipeline() {
|
wgpu::ComputePipeline CreateSamplingComputePipeline(std::vector<TestAspect> aspects,
|
||||||
wgpu::ShaderModule csModule =
|
uint32_t componentIndex) {
|
||||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
|
std::ostringstream shaderSource;
|
||||||
#version 450
|
std::ostringstream shaderBody;
|
||||||
layout(set = 0, binding = 0) uniform sampler samp;
|
shaderSource << R"(
|
||||||
layout(set = 0, binding = 1) uniform texture2D tex;
|
#version 450
|
||||||
layout(set = 0, binding = 2) writeonly buffer SamplerResult {
|
layout(set = 0, binding = 0) uniform sampler samp;
|
||||||
float samplerResult;
|
)";
|
||||||
};
|
|
||||||
|
|
||||||
void main() {
|
uint32_t index = 0;
|
||||||
samplerResult = texture(sampler2D(tex, samp), vec2(0.5, 0.5)).r;
|
for (TestAspect aspect : aspects) {
|
||||||
}
|
switch (aspect) {
|
||||||
)");
|
case TestAspect::Depth:
|
||||||
|
shaderSource << "layout(set = 0, binding = " << 1 + 2 * index
|
||||||
|
<< ") uniform texture2D tex" << index << ";\n";
|
||||||
|
|
||||||
|
shaderSource << "layout(set = 0, binding = " << 1 + 2 * index + 1
|
||||||
|
<< ") writeonly buffer Result" << index << " {\n"
|
||||||
|
<< " float result" << index << ";\n"
|
||||||
|
<< "};\n";
|
||||||
|
|
||||||
|
shaderBody << "result" << index << " = texture(sampler2D(tex" << index
|
||||||
|
<< ", samp), vec2(0.5, 0.5))[" << componentIndex << "];\n";
|
||||||
|
break;
|
||||||
|
case TestAspect::Stencil:
|
||||||
|
shaderSource << "layout(set = 0, binding = " << 1 + 2 * index
|
||||||
|
<< ") uniform utexture2D tex" << index << ";\n";
|
||||||
|
|
||||||
|
shaderSource << "layout(set = 0, binding = " << 1 + 2 * index + 1
|
||||||
|
<< ") writeonly buffer Result" << index << " {\n"
|
||||||
|
<< " uint result" << index << ";\n"
|
||||||
|
<< "};\n";
|
||||||
|
|
||||||
|
shaderBody << "result" << index << " = texelFetch(usampler2D(tex" << index
|
||||||
|
<< ", samp), ivec2(0, 0), 0)[" << componentIndex << "];\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderSource << "void main() { " << shaderBody.str() << " }";
|
||||||
|
|
||||||
|
wgpu::ShaderModule csModule = utils::CreateShaderModule(
|
||||||
|
device, utils::SingleShaderStage::Compute, shaderSource.str().c_str());
|
||||||
|
|
||||||
wgpu::ComputePipelineDescriptor pipelineDescriptor;
|
wgpu::ComputePipelineDescriptor pipelineDescriptor;
|
||||||
pipelineDescriptor.computeStage.module = csModule;
|
pipelineDescriptor.computeStage.module = csModule;
|
||||||
|
@ -202,32 +259,97 @@ class DepthSamplingTest : public DawnTest {
|
||||||
return device.CreateComputePipeline(&pipelineDescriptor);
|
return device.CreateComputePipeline(&pipelineDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInputTexture(wgpu::CommandEncoder commandEncoder, float textureValue) {
|
wgpu::Texture CreateInputTexture(wgpu::TextureFormat format) {
|
||||||
utils::ComboRenderPassDescriptor passDescriptor({}, mInputTexture.CreateView());
|
wgpu::TextureDescriptor inputTextureDesc;
|
||||||
passDescriptor.cDepthStencilAttachmentInfo.clearDepth = textureValue;
|
inputTextureDesc.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment;
|
||||||
|
inputTextureDesc.size = {1, 1, 1};
|
||||||
|
inputTextureDesc.format = format;
|
||||||
|
return device.CreateTexture(&inputTextureDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::Texture CreateOutputTexture(wgpu::TextureFormat format) {
|
||||||
|
wgpu::TextureDescriptor outputTextureDesc;
|
||||||
|
outputTextureDesc.usage =
|
||||||
|
wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc;
|
||||||
|
outputTextureDesc.size = {1, 1, 1};
|
||||||
|
outputTextureDesc.format = format;
|
||||||
|
return device.CreateTexture(&outputTextureDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::Buffer CreateOutputBuffer() {
|
||||||
|
wgpu::BufferDescriptor outputBufferDesc;
|
||||||
|
outputBufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
|
||||||
|
outputBufferDesc.size = sizeof(float); // Large enough for both float and uint8_t
|
||||||
|
return device.CreateBuffer(&outputBufferDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateInputDepth(wgpu::CommandEncoder commandEncoder,
|
||||||
|
wgpu::Texture texture,
|
||||||
|
float depthValue) {
|
||||||
|
utils::ComboRenderPassDescriptor passDescriptor({}, texture.CreateView());
|
||||||
|
passDescriptor.cDepthStencilAttachmentInfo.clearDepth = depthValue;
|
||||||
|
|
||||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||||
pass.EndPass();
|
pass.EndPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoSamplingTest(wgpu::RenderPipeline pipeline, std::vector<float> textureValues) {
|
void UpdateInputStencil(wgpu::CommandEncoder commandEncoder,
|
||||||
|
wgpu::Texture texture,
|
||||||
|
uint8_t stencilValue) {
|
||||||
|
utils::ComboRenderPassDescriptor passDescriptor({}, texture.CreateView());
|
||||||
|
passDescriptor.cDepthStencilAttachmentInfo.clearStencil = stencilValue;
|
||||||
|
|
||||||
|
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||||
|
pass.EndPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void DoSamplingTest(TestAspect aspect,
|
||||||
|
wgpu::RenderPipeline pipeline,
|
||||||
|
wgpu::TextureFormat format,
|
||||||
|
std::vector<T> textureValues,
|
||||||
|
std::vector<T> expectedValues) {
|
||||||
|
ASSERT(textureValues.size() == expectedValues.size());
|
||||||
|
|
||||||
wgpu::SamplerDescriptor samplerDesc;
|
wgpu::SamplerDescriptor samplerDesc;
|
||||||
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
|
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
|
||||||
|
|
||||||
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
wgpu::Texture outputTexture;
|
||||||
{
|
wgpu::Texture inputTexture = CreateInputTexture(format);
|
||||||
{0, sampler},
|
wgpu::TextureViewDescriptor inputViewDesc = {};
|
||||||
{1, mInputTexture.CreateView()},
|
switch (aspect) {
|
||||||
});
|
case TestAspect::Depth:
|
||||||
|
inputViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
|
||||||
|
outputTexture = CreateOutputTexture(wgpu::TextureFormat::R32Float);
|
||||||
|
break;
|
||||||
|
case TestAspect::Stencil:
|
||||||
|
inputViewDesc.aspect = wgpu::TextureAspect::StencilOnly;
|
||||||
|
outputTexture = CreateOutputTexture(wgpu::TextureFormat::R8Uint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (float textureValue : textureValues) {
|
wgpu::BindGroup bindGroup =
|
||||||
|
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
||||||
|
{
|
||||||
|
{0, sampler},
|
||||||
|
{1, inputTexture.CreateView(&inputViewDesc)},
|
||||||
|
});
|
||||||
|
|
||||||
|
for (size_t i = 0; i < textureValues.size(); ++i) {
|
||||||
// Set the input depth texture to the provided texture value
|
// Set the input depth texture to the provided texture value
|
||||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||||
UpdateInputTexture(commandEncoder, textureValue);
|
switch (aspect) {
|
||||||
|
case TestAspect::Depth:
|
||||||
|
UpdateInputDepth(commandEncoder, inputTexture, textureValues[i]);
|
||||||
|
break;
|
||||||
|
case TestAspect::Stencil:
|
||||||
|
UpdateInputStencil(commandEncoder, inputTexture, textureValues[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Render into the output texture
|
// Render into the output texture
|
||||||
{
|
{
|
||||||
utils::ComboRenderPassDescriptor passDescriptor({mOutputTexture.CreateView()});
|
utils::ComboRenderPassDescriptor passDescriptor({outputTexture.CreateView()});
|
||||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||||
pass.SetPipeline(pipeline);
|
pass.SetPipeline(pipeline);
|
||||||
pass.SetBindGroup(0, bindGroup);
|
pass.SetBindGroup(0, bindGroup);
|
||||||
|
@ -238,22 +360,49 @@ class DepthSamplingTest : public DawnTest {
|
||||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
EXPECT_PIXEL_FLOAT_EQ(textureValue, mOutputTexture, 0, 0);
|
EXPECT_TEXTURE_EQ(expectedValues[i], outputTexture, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoSamplingTest(wgpu::ComputePipeline pipeline, std::vector<float> textureValues) {
|
template <typename T>
|
||||||
|
void DoSamplingTest(TestAspect aspect,
|
||||||
|
wgpu::ComputePipeline pipeline,
|
||||||
|
wgpu::TextureFormat format,
|
||||||
|
std::vector<T> textureValues,
|
||||||
|
std::vector<T> expectedValues) {
|
||||||
|
ASSERT(textureValues.size() == expectedValues.size());
|
||||||
|
|
||||||
wgpu::SamplerDescriptor samplerDesc;
|
wgpu::SamplerDescriptor samplerDesc;
|
||||||
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
|
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
|
||||||
|
|
||||||
|
wgpu::Texture inputTexture = CreateInputTexture(format);
|
||||||
|
wgpu::TextureViewDescriptor inputViewDesc = {};
|
||||||
|
switch (aspect) {
|
||||||
|
case TestAspect::Depth:
|
||||||
|
inputViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
|
||||||
|
break;
|
||||||
|
case TestAspect::Stencil:
|
||||||
|
inputViewDesc.aspect = wgpu::TextureAspect::StencilOnly;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::Buffer outputBuffer = CreateOutputBuffer();
|
||||||
|
|
||||||
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
|
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
|
||||||
device, pipeline.GetBindGroupLayout(0),
|
device, pipeline.GetBindGroupLayout(0),
|
||||||
{{0, sampler}, {1, mInputTexture.CreateView()}, {2, mOutputBuffer}});
|
{{0, sampler}, {1, inputTexture.CreateView(&inputViewDesc)}, {2, outputBuffer}});
|
||||||
|
|
||||||
for (float textureValue : textureValues) {
|
for (size_t i = 0; i < textureValues.size(); ++i) {
|
||||||
// Set the input depth texture to the provided texture value
|
// Set the input depth texture to the provided texture value
|
||||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||||
UpdateInputTexture(commandEncoder, textureValue);
|
switch (aspect) {
|
||||||
|
case TestAspect::Depth:
|
||||||
|
UpdateInputDepth(commandEncoder, inputTexture, textureValues[i]);
|
||||||
|
break;
|
||||||
|
case TestAspect::Stencil:
|
||||||
|
UpdateInputStencil(commandEncoder, inputTexture, textureValues[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Sample into the output buffer
|
// Sample into the output buffer
|
||||||
{
|
{
|
||||||
|
@ -267,10 +416,28 @@ class DepthSamplingTest : public DawnTest {
|
||||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
EXPECT_BUFFER_U32_EQ(*reinterpret_cast<uint32_t*>(&textureValue), mOutputBuffer, 0);
|
uint32_t expectedValueU32 = 0;
|
||||||
|
memcpy(&expectedValueU32, &expectedValues[i], std::min(sizeof(T), sizeof(uint32_t)));
|
||||||
|
EXPECT_BUFFER_U32_EQ(expectedValueU32, outputBuffer, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void DoSamplingTest(TestAspect aspect,
|
||||||
|
wgpu::RenderPipeline pipeline,
|
||||||
|
wgpu::TextureFormat format,
|
||||||
|
std::vector<T> textureValues) {
|
||||||
|
DoSamplingTest(aspect, pipeline, format, textureValues, textureValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void DoSamplingTest(TestAspect aspect,
|
||||||
|
wgpu::ComputePipeline pipeline,
|
||||||
|
wgpu::TextureFormat format,
|
||||||
|
std::vector<T> textureValues) {
|
||||||
|
DoSamplingTest(aspect, pipeline, format, textureValues, textureValues);
|
||||||
|
}
|
||||||
|
|
||||||
static bool CompareFunctionPasses(float compareRef,
|
static bool CompareFunctionPasses(float compareRef,
|
||||||
wgpu::CompareFunction compare,
|
wgpu::CompareFunction compare,
|
||||||
float textureValue) {
|
float textureValue) {
|
||||||
|
@ -296,31 +463,38 @@ class DepthSamplingTest : public DawnTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoCompareRefTest(wgpu::RenderPipeline pipeline,
|
void DoDepthCompareRefTest(wgpu::RenderPipeline pipeline,
|
||||||
float compareRef,
|
wgpu::TextureFormat format,
|
||||||
wgpu::CompareFunction compare,
|
float compareRef,
|
||||||
std::vector<float> textureValues) {
|
wgpu::CompareFunction compare,
|
||||||
|
std::vector<float> textureValues) {
|
||||||
queue.WriteBuffer(mUniformBuffer, 0, &compareRef, sizeof(float));
|
queue.WriteBuffer(mUniformBuffer, 0, &compareRef, sizeof(float));
|
||||||
|
|
||||||
wgpu::SamplerDescriptor samplerDesc;
|
wgpu::SamplerDescriptor samplerDesc;
|
||||||
samplerDesc.compare = compare;
|
samplerDesc.compare = compare;
|
||||||
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
|
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
|
||||||
|
|
||||||
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
wgpu::Texture inputTexture = CreateInputTexture(format);
|
||||||
{
|
wgpu::TextureViewDescriptor inputViewDesc = {};
|
||||||
{0, sampler},
|
inputViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
|
||||||
{1, mInputTexture.CreateView()},
|
|
||||||
{2, mUniformBuffer},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
wgpu::BindGroup bindGroup =
|
||||||
|
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
||||||
|
{
|
||||||
|
{0, sampler},
|
||||||
|
{1, inputTexture.CreateView(&inputViewDesc)},
|
||||||
|
{2, mUniformBuffer},
|
||||||
|
});
|
||||||
|
|
||||||
|
wgpu::Texture outputTexture = CreateOutputTexture(wgpu::TextureFormat::R32Float);
|
||||||
for (float textureValue : textureValues) {
|
for (float textureValue : textureValues) {
|
||||||
// Set the input depth texture to the provided texture value
|
// Set the input depth texture to the provided texture value
|
||||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||||
UpdateInputTexture(commandEncoder, textureValue);
|
UpdateInputDepth(commandEncoder, inputTexture, textureValue);
|
||||||
|
|
||||||
// Render into the output texture
|
// Render into the output texture
|
||||||
{
|
{
|
||||||
utils::ComboRenderPassDescriptor passDescriptor({mOutputTexture.CreateView()});
|
utils::ComboRenderPassDescriptor passDescriptor({outputTexture.CreateView()});
|
||||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||||
pass.SetPipeline(pipeline);
|
pass.SetPipeline(pipeline);
|
||||||
pass.SetBindGroup(0, bindGroup);
|
pass.SetBindGroup(0, bindGroup);
|
||||||
|
@ -331,32 +505,39 @@ class DepthSamplingTest : public DawnTest {
|
||||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||||
queue.Submit(1, &commands);
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
EXPECT_PIXEL_FLOAT_EQ(
|
EXPECT_TEXTURE_EQ(CompareFunctionPasses(compareRef, compare, textureValue) ? 1.f : 0.f,
|
||||||
CompareFunctionPasses(compareRef, compare, textureValue) ? 1.f : 0.f,
|
outputTexture, 0, 0);
|
||||||
mOutputTexture, 0, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoCompareRefTest(wgpu::ComputePipeline pipeline,
|
void DoDepthCompareRefTest(wgpu::ComputePipeline pipeline,
|
||||||
float compareRef,
|
wgpu::TextureFormat format,
|
||||||
wgpu::CompareFunction compare,
|
float compareRef,
|
||||||
std::vector<float> textureValues) {
|
wgpu::CompareFunction compare,
|
||||||
|
std::vector<float> textureValues) {
|
||||||
queue.WriteBuffer(mUniformBuffer, 0, &compareRef, sizeof(float));
|
queue.WriteBuffer(mUniformBuffer, 0, &compareRef, sizeof(float));
|
||||||
|
|
||||||
wgpu::SamplerDescriptor samplerDesc;
|
wgpu::SamplerDescriptor samplerDesc;
|
||||||
samplerDesc.compare = compare;
|
samplerDesc.compare = compare;
|
||||||
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
|
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
|
||||||
|
|
||||||
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
wgpu::Texture inputTexture = CreateInputTexture(format);
|
||||||
{{0, sampler},
|
wgpu::TextureViewDescriptor inputViewDesc = {};
|
||||||
{1, mInputTexture.CreateView()},
|
inputViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
|
||||||
{2, mUniformBuffer},
|
|
||||||
{3, mOutputBuffer}});
|
wgpu::Buffer outputBuffer = CreateOutputBuffer();
|
||||||
|
|
||||||
|
wgpu::BindGroup bindGroup =
|
||||||
|
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
||||||
|
{{0, sampler},
|
||||||
|
{1, inputTexture.CreateView(&inputViewDesc)},
|
||||||
|
{2, mUniformBuffer},
|
||||||
|
{3, outputBuffer}});
|
||||||
|
|
||||||
for (float textureValue : textureValues) {
|
for (float textureValue : textureValues) {
|
||||||
// Set the input depth texture to the provided texture value
|
// Set the input depth texture to the provided texture value
|
||||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||||
UpdateInputTexture(commandEncoder, textureValue);
|
UpdateInputDepth(commandEncoder, inputTexture, textureValue);
|
||||||
|
|
||||||
// Sample into the output buffer
|
// Sample into the output buffer
|
||||||
{
|
{
|
||||||
|
@ -375,63 +556,212 @@ class DepthSamplingTest : public DawnTest {
|
||||||
float* expected =
|
float* expected =
|
||||||
CompareFunctionPasses(compareRef, compare, textureValue) ? &float1 : &float0;
|
CompareFunctionPasses(compareRef, compare, textureValue) ? &float1 : &float0;
|
||||||
|
|
||||||
EXPECT_BUFFER_U32_EQ(*reinterpret_cast<uint32_t*>(expected), mOutputBuffer, 0);
|
EXPECT_BUFFER_U32_EQ(*reinterpret_cast<uint32_t*>(expected), outputBuffer, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wgpu::Buffer mUniformBuffer;
|
wgpu::Buffer mUniformBuffer;
|
||||||
wgpu::Buffer mTextureUploadBuffer;
|
|
||||||
wgpu::Texture mInputTexture;
|
|
||||||
wgpu::Texture mOutputTexture;
|
|
||||||
wgpu::Buffer mOutputBuffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Test that sampling a depth texture with a render pipeline works
|
// Test that sampling a depth texture with a render/compute pipeline works
|
||||||
TEST_P(DepthSamplingTest, SampleRender) {
|
TEST_P(DepthStencilSamplingTest, SampleDepth) {
|
||||||
// Test 0, between [0, 1], and 1.
|
for (wgpu::TextureFormat format : kDepthFormats) {
|
||||||
DoSamplingTest(CreateSamplingRenderPipeline(), kNormalizedTextureValues);
|
// Test 0, between [0, 1], and 1.
|
||||||
|
DoSamplingTest(TestAspect::Depth, CreateSamplingRenderPipeline({TestAspect::Depth}, 0),
|
||||||
|
format, kNormalizedTextureValues);
|
||||||
|
|
||||||
|
DoSamplingTest(TestAspect::Depth, CreateSamplingComputePipeline({TestAspect::Depth}, 0),
|
||||||
|
format, kNormalizedTextureValues);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that sampling a depth texture with a compute pipeline works
|
// Test that sampling a stencil texture with a render/compute pipeline works
|
||||||
TEST_P(DepthSamplingTest, SampleCompute) {
|
TEST_P(DepthStencilSamplingTest, SampleStencil) {
|
||||||
// Test 0, between [0, 1], and 1.
|
for (wgpu::TextureFormat format : kStencilFormats) {
|
||||||
DoSamplingTest(CreateSamplingComputePipeline(), kNormalizedTextureValues);
|
DoSamplingTest(TestAspect::Stencil, CreateSamplingRenderPipeline({TestAspect::Stencil}, 0),
|
||||||
|
format, kStencilValues);
|
||||||
|
|
||||||
|
DoSamplingTest(TestAspect::Stencil, CreateSamplingComputePipeline({TestAspect::Stencil}, 0),
|
||||||
|
format, kStencilValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that sampling a depth/stencil texture at components 1, 2, and 3 yield 0, 0, and 1
|
||||||
|
// respectively
|
||||||
|
TEST_P(DepthStencilSamplingTest, SampleExtraComponents) {
|
||||||
|
// TODO(enga): In Metal, color textures' unspecified default components values
|
||||||
|
// are (0, 0, 0, 1). Depth/stencil textures are undefined! Figure out what
|
||||||
|
// to do here.
|
||||||
|
// See Section 6.10 of the Metal Shading Language Specification
|
||||||
|
DAWN_SKIP_TEST_IF(IsMetal());
|
||||||
|
|
||||||
|
float expectedDepth[4] = {0, 0, 0, 1};
|
||||||
|
uint8_t expectedStencil[4] = {0, 0, 0, 1};
|
||||||
|
|
||||||
|
for (uint32_t component : {1, 2, 3}) {
|
||||||
|
DoSamplingTest<float>(
|
||||||
|
TestAspect::Depth, CreateSamplingRenderPipeline({TestAspect::Depth}, component),
|
||||||
|
wgpu::TextureFormat::Depth24PlusStencil8, {0.2f}, {expectedDepth[component]});
|
||||||
|
|
||||||
|
DoSamplingTest<float>(
|
||||||
|
TestAspect::Depth, CreateSamplingComputePipeline({TestAspect::Depth}, component),
|
||||||
|
wgpu::TextureFormat::Depth24PlusStencil8, {0.2f}, {expectedDepth[component]});
|
||||||
|
|
||||||
|
DoSamplingTest<uint8_t>(
|
||||||
|
TestAspect::Stencil, CreateSamplingRenderPipeline({TestAspect::Stencil}, component),
|
||||||
|
wgpu::TextureFormat::Depth24PlusStencil8, {uint8_t(37)}, {expectedStencil[component]});
|
||||||
|
|
||||||
|
DoSamplingTest<uint8_t>(
|
||||||
|
TestAspect::Stencil, CreateSamplingComputePipeline({TestAspect::Stencil}, component),
|
||||||
|
wgpu::TextureFormat::Depth24PlusStencil8, {uint8_t(37)}, {expectedStencil[component]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test sampling both depth and stencil with a render/compute pipeline works.
|
||||||
|
TEST_P(DepthStencilSamplingTest, SampleDepthAndStencilRender) {
|
||||||
|
wgpu::SamplerDescriptor samplerDesc;
|
||||||
|
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
|
||||||
|
|
||||||
|
wgpu::Texture inputTexture = CreateInputTexture(wgpu::TextureFormat::Depth24PlusStencil8);
|
||||||
|
|
||||||
|
wgpu::TextureViewDescriptor depthViewDesc = {};
|
||||||
|
depthViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
|
||||||
|
|
||||||
|
wgpu::TextureViewDescriptor stencilViewDesc = {};
|
||||||
|
stencilViewDesc.aspect = wgpu::TextureAspect::StencilOnly;
|
||||||
|
|
||||||
|
// With render pipeline
|
||||||
|
{
|
||||||
|
wgpu::RenderPipeline pipeline =
|
||||||
|
CreateSamplingRenderPipeline({TestAspect::Depth, TestAspect::Stencil}, 0);
|
||||||
|
|
||||||
|
wgpu::BindGroup bindGroup =
|
||||||
|
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
||||||
|
{
|
||||||
|
{0, sampler},
|
||||||
|
{1, inputTexture.CreateView(&depthViewDesc)},
|
||||||
|
{2, inputTexture.CreateView(&stencilViewDesc)},
|
||||||
|
});
|
||||||
|
|
||||||
|
wgpu::Texture depthOutput = CreateOutputTexture(wgpu::TextureFormat::R32Float);
|
||||||
|
wgpu::Texture stencilOutput = CreateOutputTexture(wgpu::TextureFormat::R8Uint);
|
||||||
|
|
||||||
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||||
|
|
||||||
|
// Initialize both depth and stencil aspects.
|
||||||
|
utils::ComboRenderPassDescriptor passDescriptor({}, inputTexture.CreateView());
|
||||||
|
passDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.43f;
|
||||||
|
passDescriptor.cDepthStencilAttachmentInfo.clearStencil = 31;
|
||||||
|
|
||||||
|
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||||
|
pass.EndPass();
|
||||||
|
|
||||||
|
// Render into the output textures
|
||||||
|
{
|
||||||
|
utils::ComboRenderPassDescriptor passDescriptor(
|
||||||
|
{depthOutput.CreateView(), stencilOutput.CreateView()});
|
||||||
|
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||||
|
pass.SetPipeline(pipeline);
|
||||||
|
pass.SetBindGroup(0, bindGroup);
|
||||||
|
pass.Draw(1);
|
||||||
|
pass.EndPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
|
EXPECT_TEXTURE_EQ(passDescriptor.cDepthStencilAttachmentInfo.clearDepth, depthOutput, 0, 0);
|
||||||
|
EXPECT_TEXTURE_EQ(uint8_t(passDescriptor.cDepthStencilAttachmentInfo.clearStencil),
|
||||||
|
stencilOutput, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// With compute pipeline
|
||||||
|
{
|
||||||
|
wgpu::ComputePipeline pipeline =
|
||||||
|
CreateSamplingComputePipeline({TestAspect::Depth, TestAspect::Stencil}, 0);
|
||||||
|
|
||||||
|
wgpu::Buffer depthOutput = CreateOutputBuffer();
|
||||||
|
wgpu::Buffer stencilOutput = CreateOutputBuffer();
|
||||||
|
|
||||||
|
wgpu::BindGroup bindGroup =
|
||||||
|
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
||||||
|
{{0, sampler},
|
||||||
|
{1, inputTexture.CreateView(&depthViewDesc)},
|
||||||
|
{2, depthOutput},
|
||||||
|
{3, inputTexture.CreateView(&stencilViewDesc)},
|
||||||
|
{4, stencilOutput}});
|
||||||
|
|
||||||
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||||
|
// Initialize both depth and stencil aspects.
|
||||||
|
utils::ComboRenderPassDescriptor passDescriptor({}, inputTexture.CreateView());
|
||||||
|
passDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.43f;
|
||||||
|
passDescriptor.cDepthStencilAttachmentInfo.clearStencil = 31;
|
||||||
|
|
||||||
|
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||||
|
pass.EndPass();
|
||||||
|
|
||||||
|
// Sample into the output buffers
|
||||||
|
{
|
||||||
|
wgpu::ComputePassEncoder pass = commandEncoder.BeginComputePass();
|
||||||
|
pass.SetPipeline(pipeline);
|
||||||
|
pass.SetBindGroup(0, bindGroup);
|
||||||
|
pass.Dispatch(1);
|
||||||
|
pass.EndPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
|
uint32_t expectedValueU32 = 0;
|
||||||
|
memcpy(&expectedValueU32, &passDescriptor.cDepthStencilAttachmentInfo.clearDepth,
|
||||||
|
sizeof(float));
|
||||||
|
EXPECT_BUFFER_U32_EQ(expectedValueU32, depthOutput, 0);
|
||||||
|
|
||||||
|
expectedValueU32 = 0;
|
||||||
|
memcpy(&expectedValueU32, &passDescriptor.cDepthStencilAttachmentInfo.clearStencil,
|
||||||
|
sizeof(uint8_t));
|
||||||
|
EXPECT_BUFFER_U32_EQ(expectedValueU32, stencilOutput, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that sampling in a render pipeline with all of the compare functions works.
|
// Test that sampling in a render pipeline with all of the compare functions works.
|
||||||
TEST_P(DepthSamplingTest, CompareFunctionsRender) {
|
TEST_P(DepthStencilSamplingTest, CompareFunctionsRender) {
|
||||||
// Initialization via renderPass loadOp doesn't work on Mac Intel.
|
// Initialization via renderPass loadOp doesn't work on Mac Intel.
|
||||||
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
|
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
|
||||||
|
|
||||||
wgpu::RenderPipeline pipeline = CreateComparisonRenderPipeline();
|
wgpu::RenderPipeline pipeline = CreateComparisonRenderPipeline();
|
||||||
|
|
||||||
// Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs.
|
for (wgpu::TextureFormat format : kDepthFormats) {
|
||||||
for (float compareRef : kCompareRefs) {
|
// Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs.
|
||||||
// Test 0, below the ref, equal to, above the ref, and 1.
|
for (float compareRef : kCompareRefs) {
|
||||||
for (wgpu::CompareFunction f : kCompareFunctions) {
|
// Test 0, below the ref, equal to, above the ref, and 1.
|
||||||
DoCompareRefTest(pipeline, compareRef, f, kNormalizedTextureValues);
|
for (wgpu::CompareFunction f : kCompareFunctions) {
|
||||||
|
DoDepthCompareRefTest(pipeline, format, compareRef, f, kNormalizedTextureValues);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that sampling in a render pipeline with all of the compare functions works.
|
// Test that sampling in a render pipeline with all of the compare functions works.
|
||||||
TEST_P(DepthSamplingTest, CompareFunctionsCompute) {
|
TEST_P(DepthStencilSamplingTest, CompareFunctionsCompute) {
|
||||||
// Initialization via renderPass loadOp doesn't work on Mac Intel.
|
// Initialization via renderPass loadOp doesn't work on Mac Intel.
|
||||||
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
|
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
|
||||||
|
|
||||||
wgpu::ComputePipeline pipeline = CreateComparisonComputePipeline();
|
wgpu::ComputePipeline pipeline = CreateComparisonComputePipeline();
|
||||||
|
|
||||||
// Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs.
|
for (wgpu::TextureFormat format : kDepthFormats) {
|
||||||
for (float compareRef : kCompareRefs) {
|
// Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs.
|
||||||
// Test 0, below the ref, equal to, above the ref, and 1.
|
for (float compareRef : kCompareRefs) {
|
||||||
for (wgpu::CompareFunction f : kCompareFunctions) {
|
// Test 0, below the ref, equal to, above the ref, and 1.
|
||||||
DoCompareRefTest(pipeline, compareRef, f, kNormalizedTextureValues);
|
for (wgpu::CompareFunction f : kCompareFunctions) {
|
||||||
|
DoDepthCompareRefTest(pipeline, format, compareRef, f, kNormalizedTextureValues);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(DepthSamplingTest,
|
DAWN_INSTANTIATE_TEST(DepthStencilSamplingTest,
|
||||||
D3D12Backend(),
|
D3D12Backend(),
|
||||||
MetalBackend(),
|
MetalBackend(),
|
||||||
OpenGLBackend(),
|
OpenGLBackend(),
|
||||||
|
|
|
@ -15,9 +15,23 @@
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include "common/Math.h"
|
#include "common/Math.h"
|
||||||
|
#include "dawn/EnumClassBitmasks.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace wgpu {
|
||||||
|
enum class TestEnum {
|
||||||
|
A = 0x1,
|
||||||
|
B = 0x2,
|
||||||
|
C = 0x4,
|
||||||
|
};
|
||||||
|
} // namespace wgpu
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct wgpu::IsDawnBitmask<wgpu::TestEnum> {
|
||||||
|
static constexpr bool enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
// Tests for ScanForward
|
// Tests for ScanForward
|
||||||
TEST(Math, ScanForward) {
|
TEST(Math, ScanForward) {
|
||||||
// Test extrema
|
// Test extrema
|
||||||
|
@ -260,3 +274,32 @@ TEST(Math, RoundUp) {
|
||||||
ASSERT_EQ(RoundUp(0x7FFFFFFFFFFFFFFFull, 0x8000000000000000ull), 0x8000000000000000ull);
|
ASSERT_EQ(RoundUp(0x7FFFFFFFFFFFFFFFull, 0x8000000000000000ull), 0x8000000000000000ull);
|
||||||
ASSERT_EQ(RoundUp(1, 1), 1u);
|
ASSERT_EQ(RoundUp(1, 1), 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests for IsSubset
|
||||||
|
TEST(Math, IsSubset) {
|
||||||
|
// single value is a subset
|
||||||
|
ASSERT_TRUE(IsSubset(0b100, 0b101));
|
||||||
|
ASSERT_FALSE(IsSubset(0b010, 0b101));
|
||||||
|
ASSERT_TRUE(IsSubset(0b001, 0b101));
|
||||||
|
|
||||||
|
// empty set is a subset
|
||||||
|
ASSERT_TRUE(IsSubset(0b000, 0b101));
|
||||||
|
|
||||||
|
// equal-to is a subset
|
||||||
|
ASSERT_TRUE(IsSubset(0b101, 0b101));
|
||||||
|
|
||||||
|
// superset is not a subset
|
||||||
|
ASSERT_FALSE(IsSubset(0b111, 0b101));
|
||||||
|
|
||||||
|
// only empty is a subset of empty
|
||||||
|
ASSERT_FALSE(IsSubset(0b100, 0b000));
|
||||||
|
ASSERT_FALSE(IsSubset(0b010, 0b000));
|
||||||
|
ASSERT_FALSE(IsSubset(0b001, 0b000));
|
||||||
|
ASSERT_TRUE(IsSubset(0b000, 0b000));
|
||||||
|
|
||||||
|
// Test with enums
|
||||||
|
ASSERT_TRUE(IsSubset(wgpu::TestEnum::A, wgpu::TestEnum::A));
|
||||||
|
ASSERT_TRUE(IsSubset(wgpu::TestEnum::A, wgpu::TestEnum::A | wgpu::TestEnum::B));
|
||||||
|
ASSERT_FALSE(IsSubset(wgpu::TestEnum::C, wgpu::TestEnum::A | wgpu::TestEnum::B));
|
||||||
|
ASSERT_FALSE(IsSubset(wgpu::TestEnum::A | wgpu::TestEnum::C, wgpu::TestEnum::A));
|
||||||
|
}
|
||||||
|
|
|
@ -311,10 +311,8 @@ TEST_F(BindGroupValidationTest, TextureComponentType) {
|
||||||
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, uintTextureView}}));
|
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, uintTextureView}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test which depth-stencil formats are allowed to be sampled.
|
// Test which depth-stencil formats are allowed to be sampled (all).
|
||||||
// This is a regression test for a change in dawn_native mistakenly allowing the depth24plus formats
|
TEST_F(BindGroupValidationTest, SamplingDepthStencilTexture) {
|
||||||
// to be sampled without proper backend support.
|
|
||||||
TEST_F(BindGroupValidationTest, SamplingDepthTexture) {
|
|
||||||
wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(
|
wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(
|
||||||
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture}});
|
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture}});
|
||||||
|
|
||||||
|
@ -330,20 +328,30 @@ TEST_F(BindGroupValidationTest, SamplingDepthTexture) {
|
||||||
utils::MakeBindGroup(device, layout, {{0, texture.CreateView()}});
|
utils::MakeBindGroup(device, layout, {{0, texture.CreateView()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth24Plus is not allowed to be sampled.
|
// Depth24Plus is allowed to be sampled.
|
||||||
{
|
{
|
||||||
desc.format = wgpu::TextureFormat::Depth24Plus;
|
desc.format = wgpu::TextureFormat::Depth24Plus;
|
||||||
wgpu::Texture texture = device.CreateTexture(&desc);
|
wgpu::Texture texture = device.CreateTexture(&desc);
|
||||||
|
|
||||||
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, texture.CreateView()}}));
|
utils::MakeBindGroup(device, layout, {{0, texture.CreateView()}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth24PlusStencil8 is not allowed to be sampled.
|
// Depth24PlusStencil8 is allowed to be sampled, if the depth or stencil aspect is selected.
|
||||||
{
|
{
|
||||||
desc.format = wgpu::TextureFormat::Depth24PlusStencil8;
|
desc.format = wgpu::TextureFormat::Depth24PlusStencil8;
|
||||||
wgpu::Texture texture = device.CreateTexture(&desc);
|
wgpu::Texture texture = device.CreateTexture(&desc);
|
||||||
|
wgpu::TextureViewDescriptor viewDesc = {};
|
||||||
|
|
||||||
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, texture.CreateView()}}));
|
viewDesc.aspect = wgpu::TextureAspect::DepthOnly;
|
||||||
|
utils::MakeBindGroup(device, layout, {{0, texture.CreateView(&viewDesc)}});
|
||||||
|
|
||||||
|
wgpu::BindGroupLayoutEntry entry = {0, wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::SampledTexture};
|
||||||
|
entry.textureComponentType = wgpu::TextureComponentType::Uint;
|
||||||
|
layout = utils::MakeBindGroupLayout(device, {entry});
|
||||||
|
|
||||||
|
viewDesc.aspect = wgpu::TextureAspect::StencilOnly;
|
||||||
|
utils::MakeBindGroup(device, layout, {{0, texture.CreateView(&viewDesc)}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue