Add wgpu::TextureComponentType::DepthComparison

And deprecate using ::Float in the bind group layout for
"shadow textures" in the pipeline (along with a deprecation test).

Adds the ability to be used with DepthComparison only to depth textures,
this could potentially a breaking change if users where doing
depth-comparison on float32 textures but that's not supported in WebGPU.

Bug: dawn:527
Change-Id: Ib28b0443e3002e0aa2811713b9e843c2417e13e7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30240
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Corentin Wallez 2020-10-16 14:13:16 +00:00 committed by Commit Bot service account
parent 2a8ada7951
commit 4196a546bf
16 changed files with 204 additions and 23 deletions

View File

@ -1549,7 +1549,8 @@
"values": [ "values": [
{"value": 0, "name": "float"}, {"value": 0, "name": "float"},
{"value": 1, "name": "sint"}, {"value": 1, "name": "sint"},
{"value": 2, "name": "uint"} {"value": 2, "name": "uint"},
{"value": 3, "name": "depth comparison"}
] ]
}, },
"texture copy view": { "texture copy view": {

View File

@ -121,6 +121,10 @@ namespace dawn_native {
if (viewDimension != wgpu::TextureViewDimension::e2D) { if (viewDimension != wgpu::TextureViewDimension::e2D) {
return DAWN_VALIDATION_ERROR("Multisampled binding must be 2D."); return DAWN_VALIDATION_ERROR("Multisampled binding must be 2D.");
} }
if (entry.textureComponentType == wgpu::TextureComponentType::DepthComparison) {
return DAWN_VALIDATION_ERROR(
"Multisampled binding must not be DepthComparison.");
}
break; break;
case wgpu::BindingType::WriteonlyStorageTexture: case wgpu::BindingType::WriteonlyStorageTexture:

View File

@ -36,6 +36,7 @@ namespace dawn_native {
case wgpu::TextureComponentType::Float: case wgpu::TextureComponentType::Float:
case wgpu::TextureComponentType::Sint: case wgpu::TextureComponentType::Sint:
case wgpu::TextureComponentType::Uint: case wgpu::TextureComponentType::Uint:
case wgpu::TextureComponentType::DepthComparison:
// When the compiler complains that you need to add a case statement here, please // When the compiler complains that you need to add a case statement here, please
// also add a corresponding static assert below! // also add a corresponding static assert below!
break; break;
@ -55,6 +56,11 @@ namespace dawn_native {
static_cast<ComponentTypeBit>( static_cast<ComponentTypeBit>(
1 << static_cast<uint32_t>(wgpu::TextureComponentType::Sint)), 1 << static_cast<uint32_t>(wgpu::TextureComponentType::Sint)),
""); "");
static_assert(
ComponentTypeBit::DepthComparison ==
static_cast<ComponentTypeBit>(
1 << static_cast<uint32_t>(wgpu::TextureComponentType::DepthComparison)),
"");
return static_cast<ComponentTypeBit>(1 << static_cast<uint32_t>(type)); return static_cast<ComponentTypeBit>(1 << static_cast<uint32_t>(type));
} }
@ -157,7 +163,8 @@ namespace dawn_native {
internalFormat.firstAspect.block.height = 1; internalFormat.firstAspect.block.height = 1;
internalFormat.firstAspect.baseType = wgpu::TextureComponentType::Float; internalFormat.firstAspect.baseType = wgpu::TextureComponentType::Float;
if (isDepthSampleable) { if (isDepthSampleable) {
internalFormat.firstAspect.supportedComponentTypes = ComponentTypeBit::Float; internalFormat.firstAspect.supportedComponentTypes =
ComponentTypeBit::Float | ComponentTypeBit::DepthComparison;
} else { } else {
internalFormat.firstAspect.supportedComponentTypes = ComponentTypeBit::None; internalFormat.firstAspect.supportedComponentTypes = ComponentTypeBit::None;
} }

View File

@ -34,6 +34,7 @@ namespace dawn_native {
Float = 0x1, Float = 0x1,
Sint = 0x2, Sint = 0x2,
Uint = 0x4, Uint = 0x4,
DepthComparison = 0x8,
}; };
// Converts an wgpu::TextureComponentType to its bitmask representation. // Converts an wgpu::TextureComponentType to its bitmask representation.

View File

@ -22,7 +22,7 @@
namespace dawn_native { namespace dawn_native {
MaybeError ValidateProgrammableStageDescriptor(const DeviceBase* device, MaybeError ValidateProgrammableStageDescriptor(DeviceBase* device,
const ProgrammableStageDescriptor* descriptor, const ProgrammableStageDescriptor* descriptor,
const PipelineLayoutBase* layout, const PipelineLayoutBase* layout,
SingleShaderStage stage) { SingleShaderStage stage) {
@ -36,7 +36,7 @@ namespace dawn_native {
if (layout != nullptr) { if (layout != nullptr) {
const EntryPointMetadata& metadata = const EntryPointMetadata& metadata =
module->GetEntryPoint(descriptor->entryPoint, stage); module->GetEntryPoint(descriptor->entryPoint, stage);
DAWN_TRY(ValidateCompatibilityWithPipelineLayout(metadata, layout)); DAWN_TRY(ValidateCompatibilityWithPipelineLayout(device, metadata, layout));
} }
return {}; return {};
} }

View File

@ -28,7 +28,7 @@
namespace dawn_native { namespace dawn_native {
MaybeError ValidateProgrammableStageDescriptor(const DeviceBase* device, MaybeError ValidateProgrammableStageDescriptor(DeviceBase* device,
const ProgrammableStageDescriptor* descriptor, const ProgrammableStageDescriptor* descriptor,
const PipelineLayoutBase* layout, const PipelineLayoutBase* layout,
SingleShaderStage stage); SingleShaderStage stage);

View File

@ -207,7 +207,8 @@ namespace dawn_native {
for (const StageAndDescriptor& stage : stages) { for (const StageAndDescriptor& stage : stages) {
const EntryPointMetadata& metadata = const EntryPointMetadata& metadata =
stage.second->module->GetEntryPoint(stage.second->entryPoint, stage.first); stage.second->module->GetEntryPoint(stage.second->entryPoint, stage.first);
ASSERT(ValidateCompatibilityWithPipelineLayout(metadata, pipelineLayout).IsSuccess()); ASSERT(ValidateCompatibilityWithPipelineLayout(device, metadata, pipelineLayout)
.IsSuccess());
} }
return pipelineLayout; return pipelineLayout;

View File

@ -369,7 +369,8 @@ namespace dawn_native {
return std::move(result); return std::move(result);
} }
MaybeError ValidateCompatibilityWithBindGroupLayout(BindGroupIndex group, MaybeError ValidateCompatibilityWithBindGroupLayout(DeviceBase* device,
BindGroupIndex group,
const EntryPointMetadata& entryPoint, const EntryPointMetadata& entryPoint,
const BindGroupLayoutBase* layout) { const BindGroupLayoutBase* layout) {
const BindGroupLayoutBase::BindingMap& layoutBindings = layout->GetBindingMap(); const BindGroupLayoutBase::BindingMap& layoutBindings = layout->GetBindingMap();
@ -424,11 +425,23 @@ namespace dawn_native {
case wgpu::BindingType::SampledTexture: case wgpu::BindingType::SampledTexture:
case wgpu::BindingType::MultisampledTexture: { case wgpu::BindingType::MultisampledTexture: {
if (layoutInfo.textureComponentType != shaderInfo.textureComponentType) { if (layoutInfo.textureComponentType != shaderInfo.textureComponentType) {
// TODO(dawn:527): Remove once the deprecation timeline is complete.
if (layoutInfo.textureComponentType ==
wgpu::TextureComponentType::Float &&
shaderInfo.textureComponentType ==
wgpu::TextureComponentType::DepthComparison) {
device->EmitDeprecationWarning(
"Using depth texture in the shader with "
"TextureComponentType::Float is deprecated use "
"TextureComponentType::DepthComparison in the bind group "
"layout instead.");
} else {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"The textureComponentType of the bind group layout entry is " "The textureComponentType of the bind group layout entry is "
"different from " + "different from " +
GetShaderDeclarationString(group, bindingNumber)); GetShaderDeclarationString(group, bindingNumber));
} }
}
if (layoutInfo.viewDimension != shaderInfo.viewDimension) { if (layoutInfo.viewDimension != shaderInfo.viewDimension) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
@ -554,11 +567,26 @@ namespace dawn_native {
SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed); SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed);
info->textureComponentType = info->textureComponentType =
SpirvBaseTypeToTextureComponentType(textureComponentType); SpirvBaseTypeToTextureComponentType(textureComponentType);
if (imageType.ms) { if (imageType.ms) {
info->type = wgpu::BindingType::MultisampledTexture; info->type = wgpu::BindingType::MultisampledTexture;
} else { } else {
info->type = wgpu::BindingType::SampledTexture; info->type = wgpu::BindingType::SampledTexture;
} }
if (imageType.depth) {
if (imageType.ms) {
return DAWN_VALIDATION_ERROR(
"Multisampled depth textures aren't supported");
}
if (info->textureComponentType !=
wgpu::TextureComponentType::Float) {
return DAWN_VALIDATION_ERROR(
"Depth textures must have a float type");
}
info->textureComponentType =
wgpu::TextureComponentType::DepthComparison;
}
break; break;
} }
case wgpu::BindingType::StorageBuffer: { case wgpu::BindingType::StorageBuffer: {
@ -600,7 +628,11 @@ namespace dawn_native {
} }
if (imageType.ms) { if (imageType.ms) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"Multisampled storage texture aren't supported"); "Multisampled storage textures aren't supported");
}
if (imageType.depth) {
return DAWN_VALIDATION_ERROR(
"Depth storage textures aren't supported");
} }
info->storageTextureFormat = storageTextureFormat; info->storageTextureFormat = storageTextureFormat;
info->viewDimension = info->viewDimension =
@ -749,10 +781,11 @@ namespace dawn_native {
return bufferSizes; return bufferSizes;
} }
MaybeError ValidateCompatibilityWithPipelineLayout(const EntryPointMetadata& entryPoint, MaybeError ValidateCompatibilityWithPipelineLayout(DeviceBase* device,
const EntryPointMetadata& entryPoint,
const PipelineLayoutBase* layout) { const PipelineLayoutBase* layout) {
for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) { for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
DAWN_TRY(ValidateCompatibilityWithBindGroupLayout(group, entryPoint, DAWN_TRY(ValidateCompatibilityWithBindGroupLayout(device, group, entryPoint,
layout->GetBindGroupLayout(group))); layout->GetBindGroupLayout(group)));
} }

View File

@ -41,7 +41,8 @@ namespace dawn_native {
MaybeError ValidateShaderModuleDescriptor(DeviceBase* device, MaybeError ValidateShaderModuleDescriptor(DeviceBase* device,
const ShaderModuleDescriptor* descriptor); const ShaderModuleDescriptor* descriptor);
MaybeError ValidateCompatibilityWithPipelineLayout(const EntryPointMetadata& entryPoint, MaybeError ValidateCompatibilityWithPipelineLayout(DeviceBase* device,
const EntryPointMetadata& entryPoint,
const PipelineLayoutBase* layout); const PipelineLayoutBase* layout);
RequiredBufferSizes ComputeRequiredBufferSizesForLayout(const EntryPointMetadata& entryPoint, RequiredBufferSizes ComputeRequiredBufferSizesForLayout(const EntryPointMetadata& entryPoint,

View File

@ -71,6 +71,9 @@ namespace dawn_native { namespace d3d12 {
case wgpu::TextureComponentType::Float: case wgpu::TextureComponentType::Float:
resolveParameters.ResolveMode = D3D12_RESOLVE_MODE_AVERAGE; resolveParameters.ResolveMode = D3D12_RESOLVE_MODE_AVERAGE;
break; break;
case wgpu::TextureComponentType::DepthComparison:
UNREACHABLE();
} }
resolveParameters.SubresourceCount = 1; resolveParameters.SubresourceCount = 1;

View File

@ -949,6 +949,9 @@ namespace dawn_native { namespace opengl {
gl.ClearBufferiv(GL_COLOR, i, appliedClearColor.data()); gl.ClearBufferiv(GL_COLOR, i, appliedClearColor.data());
break; break;
} }
case wgpu::TextureComponentType::DepthComparison:
UNREACHABLE();
} }
} }

View File

@ -334,6 +334,9 @@ namespace dawn_native { namespace vulkan {
} }
break; break;
} }
case wgpu::TextureComponentType::DepthComparison:
UNREACHABLE();
} }
attachmentCount++; attachmentCount++;
} }

View File

@ -1058,6 +1058,8 @@ namespace dawn_native { namespace vulkan {
clearColorValue.uint32[2] = uClearColor; clearColorValue.uint32[2] = uClearColor;
clearColorValue.uint32[3] = uClearColor; clearColorValue.uint32[3] = uClearColor;
break; break;
case wgpu::TextureComponentType::DepthComparison:
UNREACHABLE();
} }
device->fn.CmdClearColorImage(recordingContext->commandBuffer, GetHandle(), device->fn.CmdClearColorImage(recordingContext->commandBuffer, GetHandle(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,

View File

@ -118,6 +118,50 @@ TEST_P(DeprecationTests, BGLEntryMultisampledBooleanTracking) {
utils::MakeBindGroup(device, bgl, {{0, texture4Sample.CreateView()}}); utils::MakeBindGroup(device, bgl, {{0, texture4Sample.CreateView()}});
} }
// Test that compiling a pipeline with TextureComponentType::Float in the BGL when ::DepthComparison
// is expected emits a deprecation warning but isn't an error.
TEST_P(DeprecationTests, TextureComponentTypeFloatWhenDepthComparisonIsExpected) {
wgpu::ShaderModule module =
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
#version 450
layout(set = 0, binding = 0) uniform samplerShadow samp;
layout(set = 0, binding = 1) uniform texture2D tex;
void main() {
texture(sampler2DShadow(tex, samp), vec3(0.5, 0.5, 0.5));
}
)");
{
wgpu::BindGroupLayout goodBgl = utils::MakeBindGroupLayout(
device,
{{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ComparisonSampler},
{1, wgpu::ShaderStage::Compute, wgpu::BindingType::SampledTexture, false, 0, false,
wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::DepthComparison}});
wgpu::ComputePipelineDescriptor goodDesc;
goodDesc.layout = utils::MakeBasicPipelineLayout(device, &goodBgl);
goodDesc.computeStage.module = module;
goodDesc.computeStage.entryPoint = "main";
device.CreateComputePipeline(&goodDesc);
}
{
wgpu::BindGroupLayout badBgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ComparisonSampler},
{1, wgpu::ShaderStage::Compute, wgpu::BindingType::SampledTexture, false, 0,
false, wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::Float}});
wgpu::ComputePipelineDescriptor badDesc;
badDesc.layout = utils::MakeBasicPipelineLayout(device, &badBgl);
badDesc.computeStage.module = module;
badDesc.computeStage.entryPoint = "main";
EXPECT_DEPRECATION_WARNING(device.CreateComputePipeline(&badDesc));
}
}
DAWN_INSTANTIATE_TEST(DeprecationTests, DAWN_INSTANTIATE_TEST(DeprecationTests,
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),

View File

@ -151,8 +151,10 @@ class DepthSamplingTest : public DawnTest {
// TODO(dawn:367): Cannot use GetBindGroupLayout for comparison samplers without shader // TODO(dawn:367): Cannot use GetBindGroupLayout for comparison samplers without shader
// reflection data. // reflection data.
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::ComparisonSampler}, device,
{1, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture}, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::ComparisonSampler},
{1, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture, false, 0, false,
wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::DepthComparison},
{2, wgpu::ShaderStage::Fragment, wgpu::BindingType::UniformBuffer}}); {2, wgpu::ShaderStage::Fragment, wgpu::BindingType::UniformBuffer}});
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device); utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
@ -185,8 +187,10 @@ class DepthSamplingTest : public DawnTest {
// TODO(dawn:367): Cannot use GetBindGroupLayout without shader reflection data. // TODO(dawn:367): Cannot use GetBindGroupLayout without shader reflection data.
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ComparisonSampler}, device,
{1, wgpu::ShaderStage::Compute, wgpu::BindingType::SampledTexture}, {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ComparisonSampler},
{1, wgpu::ShaderStage::Compute, wgpu::BindingType::SampledTexture, false, 0, false,
wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::DepthComparison},
{2, wgpu::ShaderStage::Compute, wgpu::BindingType::UniformBuffer}, {2, wgpu::ShaderStage::Compute, wgpu::BindingType::UniformBuffer},
{3, wgpu::ShaderStage::Compute, wgpu::BindingType::StorageBuffer}}); {3, wgpu::ShaderStage::Compute, wgpu::BindingType::StorageBuffer}});

View File

@ -345,6 +345,41 @@ TEST_F(BindGroupValidationTest, SamplingDepthTexture) {
} }
} }
// Check that a texture must have a correct format for DepthComparison
TEST_F(BindGroupValidationTest, TextureComponentTypeDepthComparison) {
wgpu::BindGroupLayout depthLayout = utils::MakeBindGroupLayout(
device,
{{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture, false, 0, false,
wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::DepthComparison}});
// Control case: setting a depth texture works.
wgpu::Texture depthTexture =
CreateTexture(wgpu::TextureUsage::Sampled, wgpu::TextureFormat::Depth32Float, 1);
utils::MakeBindGroup(device, depthLayout, {{0, depthTexture.CreateView()}});
// Error case: setting a Float typed texture view fails.
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, depthLayout, {{0, mSampledTextureView}}));
}
// Check that a depth texture is allowed to be used for both TextureComponentType::Float and
// ::DepthComparison
TEST_F(BindGroupValidationTest, TextureComponentTypeForDepthTexture) {
wgpu::BindGroupLayout depthLayout = utils::MakeBindGroupLayout(
device,
{{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture, false, 0, false,
wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::DepthComparison}});
wgpu::BindGroupLayout floatLayout = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture, false, 0,
false, wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::Float}});
wgpu::Texture depthTexture =
CreateTexture(wgpu::TextureUsage::Sampled, wgpu::TextureFormat::Depth32Float, 1);
utils::MakeBindGroup(device, depthLayout, {{0, depthTexture.CreateView()}});
utils::MakeBindGroup(device, floatLayout, {{0, depthTexture.CreateView()}});
}
// Check that a texture must have the correct dimension // Check that a texture must have the correct dimension
TEST_F(BindGroupValidationTest, TextureDimension) { TEST_F(BindGroupValidationTest, TextureDimension) {
wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout( wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(
@ -900,7 +935,7 @@ TEST_F(BindGroupLayoutValidationTest, DynamicBufferNumberLimit) {
} }
// Test that multisampled textures must be 2D sampled textures // Test that multisampled textures must be 2D sampled textures
TEST_F(BindGroupLayoutValidationTest, MultisampledTextures) { TEST_F(BindGroupLayoutValidationTest, MultisampledTextureViewDimension) {
// Multisampled 2D texture works. // Multisampled 2D texture works.
utils::MakeBindGroupLayout( utils::MakeBindGroupLayout(
device, { device, {
@ -958,6 +993,45 @@ TEST_F(BindGroupLayoutValidationTest, MultisampledTextures) {
})); }));
} }
// Test that multisampled textures cannot be DepthComparison
TEST_F(BindGroupLayoutValidationTest, MultisampledTextureComponentType) {
// Multisampled float component type works.
utils::MakeBindGroupLayout(
device, {
{0, wgpu::ShaderStage::Compute, wgpu::BindingType::MultisampledTexture, false,
0, false, wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::Float},
});
// Multisampled float (defaulted) component type works.
utils::MakeBindGroupLayout(
device, {
{0, wgpu::ShaderStage::Compute, wgpu::BindingType::MultisampledTexture, false,
0, false, wgpu::TextureViewDimension::e2D},
});
// Multisampled uint component type works.
utils::MakeBindGroupLayout(
device, {
{0, wgpu::ShaderStage::Compute, wgpu::BindingType::MultisampledTexture, false,
0, false, wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::Uint},
});
// Multisampled sint component type works.
utils::MakeBindGroupLayout(
device, {
{0, wgpu::ShaderStage::Compute, wgpu::BindingType::MultisampledTexture, false,
0, false, wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::Sint},
});
// Multisampled depth comparison component typeworks.
ASSERT_DEVICE_ERROR(utils::MakeBindGroupLayout(
device,
{
{0, wgpu::ShaderStage::Compute, wgpu::BindingType::MultisampledTexture, false, 0, false,
wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::DepthComparison},
}));
}
// Test that it is an error to pass multisampled=true for non-texture bindings // Test that it is an error to pass multisampled=true for non-texture bindings
TEST_F(BindGroupLayoutValidationTest, MultisampledMustBeTexture) { TEST_F(BindGroupLayoutValidationTest, MultisampledMustBeTexture) {
// Base: Multisampled 2D texture works. // Base: Multisampled 2D texture works.