Add maxFragmentCombinedOutputResources and validation for it.
- Suppresses maxStorageTexturesPerShaderStage CTS test because it needs to be modified to adhere to the new limit as well. Bug: dawn:1665 Change-Id: I66c62bd94b613059633888210ec7e7b42dc3a1dc Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/122461 Commit-Queue: Loko Kung <lokokung@google.com> Reviewed-by: Austin Eng <enga@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
4268044143
commit
4f98dd4706
|
@ -1312,7 +1312,8 @@
|
||||||
{"name": "max compute workgroup size x", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
|
{"name": "max compute workgroup size x", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
|
||||||
{"name": "max compute workgroup size y", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
|
{"name": "max compute workgroup size y", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
|
||||||
{"name": "max compute workgroup size z", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
|
{"name": "max compute workgroup size z", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
|
||||||
{"name": "max compute workgroups per dimension", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"}
|
{"name": "max compute workgroups per dimension", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
|
||||||
|
{"name": "max fragment combined output resources", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"required limits": {
|
"required limits": {
|
||||||
|
|
|
@ -73,7 +73,8 @@
|
||||||
X(Maximum, maxInterStageShaderComponents, 60, 60) \
|
X(Maximum, maxInterStageShaderComponents, 60, 60) \
|
||||||
X(Maximum, maxInterStageShaderVariables, 16, 16) \
|
X(Maximum, maxInterStageShaderVariables, 16, 16) \
|
||||||
X(Maximum, maxColorAttachments, 8, 8) \
|
X(Maximum, maxColorAttachments, 8, 8) \
|
||||||
X(Maximum, maxColorAttachmentBytesPerSample, 32, 32)
|
X(Maximum, maxColorAttachmentBytesPerSample, 32, 32) \
|
||||||
|
X(Maximum, maxFragmentCombinedOutputResources, 8, 8)
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
#define LIMITS_EACH_GROUP(X) \
|
#define LIMITS_EACH_GROUP(X) \
|
||||||
|
|
|
@ -364,6 +364,36 @@ MaybeError ValidateFragmentState(DeviceBase* device,
|
||||||
const EntryPointMetadata& fragmentMetadata =
|
const EntryPointMetadata& fragmentMetadata =
|
||||||
descriptor->module->GetEntryPoint(descriptor->entryPoint);
|
descriptor->module->GetEntryPoint(descriptor->entryPoint);
|
||||||
|
|
||||||
|
// Iterates through the bindings on the fragment state to count the number of storage buffer and
|
||||||
|
// storage textures.
|
||||||
|
uint32_t maxFragmentCombinedOutputResources =
|
||||||
|
device->GetLimits().v1.maxFragmentCombinedOutputResources;
|
||||||
|
uint32_t fragmentCombinedOutputResources = 0;
|
||||||
|
for (uint32_t i = 0; i < descriptor->targetCount; i++) {
|
||||||
|
if (descriptor->targets[i].format != wgpu::TextureFormat::Undefined) {
|
||||||
|
fragmentCombinedOutputResources += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (BindGroupIndex group(0); group < fragmentMetadata.bindings.size(); ++group) {
|
||||||
|
for (const auto& [_, shaderBinding] : fragmentMetadata.bindings[group]) {
|
||||||
|
switch (shaderBinding.bindingType) {
|
||||||
|
case BindingInfoType::Buffer:
|
||||||
|
if (shaderBinding.buffer.type == wgpu::BufferBindingType::Storage) {
|
||||||
|
fragmentCombinedOutputResources += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BindingInfoType::StorageTexture:
|
||||||
|
fragmentCombinedOutputResources += 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DAWN_INVALID_IF(fragmentCombinedOutputResources > maxFragmentCombinedOutputResources,
|
||||||
|
"Number of fragment output resources (%u) exceeds the maximum (%u).",
|
||||||
|
fragmentCombinedOutputResources, maxFragmentCombinedOutputResources);
|
||||||
|
|
||||||
if (fragmentMetadata.usesFragDepth) {
|
if (fragmentMetadata.usesFragDepth) {
|
||||||
DAWN_INVALID_IF(
|
DAWN_INVALID_IF(
|
||||||
depthStencil == nullptr,
|
depthStencil == nullptr,
|
||||||
|
|
|
@ -548,7 +548,7 @@ TEST_P(MaxLimitTests, MaxBufferSizes) {
|
||||||
EXPECT_LE(baseLimits.maxStorageBufferBindingSize, baseLimits.maxBufferSize);
|
EXPECT_LE(baseLimits.maxStorageBufferBindingSize, baseLimits.maxBufferSize);
|
||||||
EXPECT_LE(baseLimits.maxUniformBufferBindingSize, baseLimits.maxBufferSize);
|
EXPECT_LE(baseLimits.maxUniformBufferBindingSize, baseLimits.maxBufferSize);
|
||||||
|
|
||||||
// Base limits eith tiering.
|
// Base limits with tiering.
|
||||||
GetAdapter().SetUseTieredLimits(true);
|
GetAdapter().SetUseTieredLimits(true);
|
||||||
wgpu::Limits tieredLimits = GetAdapterLimits().limits;
|
wgpu::Limits tieredLimits = GetAdapterLimits().limits;
|
||||||
EXPECT_LE(tieredLimits.maxStorageBufferBindingSize, tieredLimits.maxBufferSize);
|
EXPECT_LE(tieredLimits.maxStorageBufferBindingSize, tieredLimits.maxBufferSize);
|
||||||
|
@ -558,6 +558,21 @@ TEST_P(MaxLimitTests, MaxBufferSizes) {
|
||||||
GetAdapter().SetUseTieredLimits(false);
|
GetAdapter().SetUseTieredLimits(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verifies that supported fragment combined output resource limits meet base requirements.
|
||||||
|
TEST_P(MaxLimitTests, MaxFragmentCombinedOutputResources) {
|
||||||
|
// Base limits without tiering.
|
||||||
|
wgpu::Limits baseLimits = GetAdapterLimits().limits;
|
||||||
|
EXPECT_LE(baseLimits.maxColorAttachments, baseLimits.maxFragmentCombinedOutputResources);
|
||||||
|
|
||||||
|
// Base limits with tiering.
|
||||||
|
GetAdapter().SetUseTieredLimits(true);
|
||||||
|
wgpu::Limits tieredLimits = GetAdapterLimits().limits;
|
||||||
|
EXPECT_LE(tieredLimits.maxColorAttachments, tieredLimits.maxFragmentCombinedOutputResources);
|
||||||
|
|
||||||
|
// Unset tiered limit usage to avoid affecting other tests.
|
||||||
|
GetAdapter().SetUseTieredLimits(false);
|
||||||
|
}
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(MaxLimitTests,
|
DAWN_INSTANTIATE_TEST(MaxLimitTests,
|
||||||
D3D12Backend(),
|
D3D12Backend(),
|
||||||
MetalBackend(),
|
MetalBackend(),
|
||||||
|
|
|
@ -1420,6 +1420,118 @@ TEST_F(RenderPipelineValidationTest, BindingsFromCorrectEntryPoint) {
|
||||||
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
|
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that total fragment output resource validations must be less than limit.
|
||||||
|
TEST_F(RenderPipelineValidationTest, MaxFragmentCombinedOutputResources) {
|
||||||
|
static constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::R8Unorm;
|
||||||
|
wgpu::ColorTargetState kEmptyColorTargetState = {};
|
||||||
|
kEmptyColorTargetState.format = wgpu::TextureFormat::Undefined;
|
||||||
|
wgpu::ColorTargetState kColorTargetState = {};
|
||||||
|
kColorTargetState.format = kFormat;
|
||||||
|
|
||||||
|
// Creates a shader with the given number of output resources.
|
||||||
|
auto CreateShader = [&](uint32_t numBuffers, uint32_t numTextures) -> wgpu::ShaderModule {
|
||||||
|
// Header to declare storage buffer struct.
|
||||||
|
static constexpr std::string_view kHeader = "struct Buf { data : array<u32> }\n";
|
||||||
|
std::ostringstream bufferBindings;
|
||||||
|
std::ostringstream bufferOutputs;
|
||||||
|
for (uint32_t i = 0; i < numBuffers; i++) {
|
||||||
|
bufferBindings << "@group(0) @binding(" << i << ") var<storage, read_write> b" << i
|
||||||
|
<< ": Buf;\n";
|
||||||
|
bufferOutputs << " b" << i << ".data[i] = i;\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream textureBindings;
|
||||||
|
std::ostringstream textureOutputs;
|
||||||
|
for (uint32_t i = 0; i < numTextures; i++) {
|
||||||
|
textureBindings << "@group(1) @binding(" << i << ") var t" << i
|
||||||
|
<< ": texture_storage_1d<rgba8uint, write>;\n";
|
||||||
|
textureOutputs << " textureStore(t" << i << ", i, vec4u(i));\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream targetBindings;
|
||||||
|
std::ostringstream targetOutputs;
|
||||||
|
for (size_t i = 0; i < kMaxColorAttachments; i++) {
|
||||||
|
targetBindings << "@location(" << i << ") o" << i << " : vec4f, ";
|
||||||
|
targetOutputs << "vec4f(1), ";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream fsShader;
|
||||||
|
fsShader << kHeader;
|
||||||
|
fsShader << bufferBindings.str();
|
||||||
|
fsShader << textureBindings.str();
|
||||||
|
fsShader << "struct Outputs { " << targetBindings.str() << "}\n";
|
||||||
|
fsShader << "@fragment fn main(@builtin(sample_index) i : u32) -> Outputs {\n";
|
||||||
|
fsShader << bufferOutputs.str();
|
||||||
|
fsShader << textureOutputs.str();
|
||||||
|
fsShader << " return Outputs(" << targetOutputs.str() << ");\n";
|
||||||
|
fsShader << "}";
|
||||||
|
return utils::CreateShaderModule(device, fsShader.str().c_str());
|
||||||
|
};
|
||||||
|
|
||||||
|
utils::ComboRenderPipelineDescriptor descriptor;
|
||||||
|
descriptor.vertex.module = utils::CreateShaderModule(device, R"(
|
||||||
|
@vertex fn main() -> @builtin(position) vec4f {
|
||||||
|
return vec4f(0.0, 0.0, 0.0, 1.0);
|
||||||
|
})");
|
||||||
|
descriptor.vertex.entryPoint = "main";
|
||||||
|
descriptor.cFragment.targetCount = kMaxColorAttachments;
|
||||||
|
descriptor.cFragment.entryPoint = "main";
|
||||||
|
|
||||||
|
// Runs test using the given parameters.
|
||||||
|
auto DoTest = [&](uint32_t numBuffers, uint32_t numTextures,
|
||||||
|
const std::vector<uint32_t>& attachmentIndices, bool useDepthStencil,
|
||||||
|
bool shouldError) {
|
||||||
|
descriptor.cFragment.module = CreateShader(numBuffers, numTextures);
|
||||||
|
descriptor.cTargets.fill(kEmptyColorTargetState);
|
||||||
|
for (const uint32_t attachmentIndex : attachmentIndices) {
|
||||||
|
descriptor.cTargets[attachmentIndex] = kColorTargetState;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useDepthStencil) {
|
||||||
|
descriptor.EnableDepthStencil();
|
||||||
|
} else {
|
||||||
|
descriptor.DisableDepthStencil();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldError) {
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
|
||||||
|
} else {
|
||||||
|
device.CreateRenderPipeline(&descriptor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// All following tests assume we are using the default limits for the following:
|
||||||
|
// - maxStorageBuffersPerShaderStage = 8
|
||||||
|
// - maxStorageTexturesPerShaderStage = 4
|
||||||
|
// - maxColorAttachments = 8
|
||||||
|
// - maxFragmentCombinedOutputResources = 8
|
||||||
|
// Note we use the defaults for the validation tests because otherwise it is hard to verify that
|
||||||
|
// we are hitting the maxFragmentCombinedOutputResources limit validations versus potentially
|
||||||
|
// hitting other validation errors from the other limits.
|
||||||
|
|
||||||
|
// One of each resource with and without depth-stencil should pass. (Control)
|
||||||
|
DoTest(1, 1, {0}, false, false);
|
||||||
|
DoTest(1, 1, {0}, true, false);
|
||||||
|
|
||||||
|
// Max number of any single resource within limits should pass. Note we turn on depth stencil in
|
||||||
|
// some of these cases because empty attachments are not allowed.
|
||||||
|
DoTest(8, 0, {}, true, false);
|
||||||
|
DoTest(4, 4, {}, true, false);
|
||||||
|
DoTest(0, 4, {0, 1, 2, 3}, false, false);
|
||||||
|
DoTest(0, 0, {0, 1, 2, 3, 4, 5, 6, 7}, false, false);
|
||||||
|
DoTest(0, 0, {0, 1, 2, 3, 4, 5, 6, 7}, true, false);
|
||||||
|
|
||||||
|
// Max number of resources with different combinations should also pass.
|
||||||
|
DoTest(3, 2, {0, 3, 5}, false, false);
|
||||||
|
DoTest(2, 3, {2, 4, 6}, true, false);
|
||||||
|
DoTest(3, 3, {1, 7}, true, false);
|
||||||
|
|
||||||
|
// Max number of resources + 1 should fail.
|
||||||
|
DoTest(3, 3, {0, 3, 5}, false, true);
|
||||||
|
DoTest(3, 3, {2, 4, 6}, true, true);
|
||||||
|
DoTest(3, 3, {1, 5, 7}, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
// Tests validation for per-pixel accounting for render targets. The tests currently assume that the
|
// Tests validation for per-pixel accounting for render targets. The tests currently assume that the
|
||||||
// default maxColorAttachmentBytesPerSample limit of 32 is used.
|
// default maxColorAttachmentBytesPerSample limit of 32 is used.
|
||||||
TEST_P(DeprecationTests, RenderPipelineColorAttachmentBytesPerSample) {
|
TEST_P(DeprecationTests, RenderPipelineColorAttachmentBytesPerSample) {
|
||||||
|
@ -1504,7 +1616,9 @@ TEST_P(DeprecationTests, RenderPipelineColorAttachmentBytesPerSample) {
|
||||||
@vertex fn main() -> @builtin(position) vec4f {
|
@vertex fn main() -> @builtin(position) vec4f {
|
||||||
return vec4f(0.0, 0.0, 0.0, 1.0);
|
return vec4f(0.0, 0.0, 0.0, 1.0);
|
||||||
})");
|
})");
|
||||||
|
descriptor.vertex.entryPoint = "main";
|
||||||
descriptor.cFragment.module = CreateShader(testCase.formats);
|
descriptor.cFragment.module = CreateShader(testCase.formats);
|
||||||
|
descriptor.cFragment.entryPoint = "main";
|
||||||
descriptor.cFragment.targetCount = testCase.formats.size();
|
descriptor.cFragment.targetCount = testCase.formats.size();
|
||||||
for (size_t i = 0; i < testCase.formats.size(); i++) {
|
for (size_t i = 0; i < testCase.formats.size(); i++) {
|
||||||
descriptor.cTargets[i].format = testCase.formats.at(i);
|
descriptor.cTargets[i].format = testCase.formats.at(i);
|
||||||
|
|
|
@ -142,4 +142,8 @@ wgpu::DepthStencilState* ComboRenderPipelineDescriptor::EnableDepthStencil(
|
||||||
return &cDepthStencil;
|
return &cDepthStencil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComboRenderPipelineDescriptor::DisableDepthStencil() {
|
||||||
|
this->depthStencil = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
|
|
|
@ -48,6 +48,7 @@ class ComboRenderPipelineDescriptor : public wgpu::RenderPipelineDescriptor {
|
||||||
|
|
||||||
wgpu::DepthStencilState* EnableDepthStencil(
|
wgpu::DepthStencilState* EnableDepthStencil(
|
||||||
wgpu::TextureFormat format = wgpu::TextureFormat::Depth24PlusStencil8);
|
wgpu::TextureFormat format = wgpu::TextureFormat::Depth24PlusStencil8);
|
||||||
|
void DisableDepthStencil();
|
||||||
|
|
||||||
std::array<wgpu::VertexBufferLayout, kMaxVertexBuffers> cBuffers;
|
std::array<wgpu::VertexBufferLayout, kMaxVertexBuffers> cBuffers;
|
||||||
std::array<wgpu::VertexAttribute, kMaxVertexAttributes> cAttributes;
|
std::array<wgpu::VertexAttribute, kMaxVertexAttributes> cAttributes;
|
||||||
|
|
|
@ -484,6 +484,11 @@ crbug.com/1410936 [ monterey ] webgpu:web_platform,canvas,configure:viewFormats:
|
||||||
crbug.com/1410936 [ monterey ] webgpu:web_platform,canvas,configure:viewFormats:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="_undef_" [ Failure ]
|
crbug.com/1410936 [ monterey ] webgpu:web_platform,canvas,configure:viewFormats:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="_undef_" [ Failure ]
|
||||||
crbug.com/1410936 [ monterey ] webgpu:web_platform,canvas,getCurrentTexture:* [ Failure ]
|
crbug.com/1410936 [ monterey ] webgpu:web_platform,canvas,getCurrentTexture:* [ Failure ]
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# New maxFragmentCombinedOutputResources limit breaking dependent limit tests.
|
||||||
|
################################################################################
|
||||||
|
crbug.com/dawn/1665 webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipeline,at_over:limitTest="atMaximum" [ Failure ]
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# untriaged failures
|
# untriaged failures
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -507,8 +512,6 @@ crbug.com/dawn/0000 [ dawn-no-backend-validation nvidia-0x2184 ubuntu ] webgpu:a
|
||||||
crbug.com/dawn/0000 [ dawn-no-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createBindGroupLayout,at_over:limitTest="underDefault" [ RetryOnFailure ]
|
crbug.com/dawn/0000 [ dawn-no-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createBindGroupLayout,at_over:limitTest="underDefault" [ RetryOnFailure ]
|
||||||
crbug.com/dawn/0000 [ dawn-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipeline,at_over:limitTest="atDefault" [ RetryOnFailure ]
|
crbug.com/dawn/0000 [ dawn-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipeline,at_over:limitTest="atDefault" [ RetryOnFailure ]
|
||||||
crbug.com/dawn/0000 [ dawn-no-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipeline,at_over:limitTest="atDefault" [ RetryOnFailure ]
|
crbug.com/dawn/0000 [ dawn-no-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipeline,at_over:limitTest="atDefault" [ RetryOnFailure ]
|
||||||
crbug.com/dawn/0000 [ dawn-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipeline,at_over:limitTest="atMaximum" [ RetryOnFailure ]
|
|
||||||
crbug.com/dawn/0000 [ dawn-no-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipeline,at_over:limitTest="atMaximum" [ RetryOnFailure ]
|
|
||||||
crbug.com/dawn/0000 [ dawn-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipeline,at_over:limitTest="underDefault" [ RetryOnFailure ]
|
crbug.com/dawn/0000 [ dawn-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipeline,at_over:limitTest="underDefault" [ RetryOnFailure ]
|
||||||
crbug.com/dawn/0000 [ dawn-no-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipelineLayout,at_over:limitTest="atDefault" [ RetryOnFailure ]
|
crbug.com/dawn/0000 [ dawn-no-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipelineLayout,at_over:limitTest="atDefault" [ RetryOnFailure ]
|
||||||
crbug.com/dawn/0000 [ dawn-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipelineLayout,at_over:limitTest="atMaximum" [ RetryOnFailure ]
|
crbug.com/dawn/0000 [ dawn-backend-validation nvidia-0x2184 ubuntu ] webgpu:api,validation,capability_checks,limits,maxStorageTexturesPerShaderStage:createPipelineLayout,at_over:limitTest="atMaximum" [ RetryOnFailure ]
|
||||||
|
|
Loading…
Reference in New Issue