mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-01 20:21:23 +00:00
Validate MaxInterStageShaderComponents when creating shader module
According to the discussion[1], the sum of all the user-defined inter-stage component count and all the inter-stage builtin component count should be no more than MaxInterStageShaderComponents (currently in Dawn it is always 60). [1] https://github.com/gpuweb/gpuweb/issues/1962 BUG=dawn:1032 TEST=dawn_unittests Change-Id: Id5266b72b89c48f5b7073b8307f8f2c0512c8a33 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/61104 Commit-Queue: Kai Ninomiya <kainino@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
parent
9eb890dff4
commit
8d8fadbbe4
@ -1055,6 +1055,8 @@ namespace dawn_native {
|
||||
metadata->usedVertexInputs.set(location);
|
||||
}
|
||||
|
||||
// [[position]] must be declared in a vertex shader.
|
||||
uint32_t totalInterStageShaderComponents = 4;
|
||||
for (const auto& output_var : entryPoint.output_variables) {
|
||||
if (DAWN_UNLIKELY(!output_var.has_location_decoration)) {
|
||||
std::stringstream ss;
|
||||
@ -1082,10 +1084,20 @@ namespace dawn_native {
|
||||
metadata->interStageVariables[location].interpolationSampling,
|
||||
TintInterpolationSamplingToInterpolationSamplingType(
|
||||
output_var.interpolation_sampling));
|
||||
|
||||
totalInterStageShaderComponents +=
|
||||
metadata->interStageVariables[location].componentCount;
|
||||
}
|
||||
|
||||
if (DAWN_UNLIKELY(totalInterStageShaderComponents >
|
||||
kMaxInterStageShaderComponents)) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"Total vertex output components count exceeds limits");
|
||||
}
|
||||
}
|
||||
|
||||
if (metadata->stage == SingleShaderStage::Fragment) {
|
||||
uint32_t totalInterStageShaderComponents = 0;
|
||||
for (const auto& input_var : entryPoint.input_variables) {
|
||||
if (!input_var.has_location_decoration) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
@ -1111,6 +1123,25 @@ namespace dawn_native {
|
||||
metadata->interStageVariables[location].interpolationSampling,
|
||||
TintInterpolationSamplingToInterpolationSamplingType(
|
||||
input_var.interpolation_sampling));
|
||||
|
||||
totalInterStageShaderComponents +=
|
||||
metadata->interStageVariables[location].componentCount;
|
||||
}
|
||||
if (entryPoint.front_facing_used) {
|
||||
totalInterStageShaderComponents += 1;
|
||||
}
|
||||
if (entryPoint.input_sample_mask_used) {
|
||||
totalInterStageShaderComponents += 1;
|
||||
}
|
||||
if (entryPoint.sample_index_used) {
|
||||
totalInterStageShaderComponents += 1;
|
||||
}
|
||||
if (entryPoint.input_position_used) {
|
||||
totalInterStageShaderComponents += 4;
|
||||
}
|
||||
if (totalInterStageShaderComponents > kMaxInterStageShaderComponents) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"Total fragment input components count exceeds limits");
|
||||
}
|
||||
|
||||
for (const auto& output_var : entryPoint.output_variables) {
|
||||
|
@ -219,7 +219,7 @@ TEST_F(ShaderModuleValidationTest, MaximumShaderIOLocations) {
|
||||
auto generateShaderForTest = [](uint32_t maximumOutputLocation, wgpu::ShaderStage shaderStage) {
|
||||
std::ostringstream stream;
|
||||
stream << "struct ShaderIO {" << std::endl;
|
||||
for (uint32_t location = 0; location <= maximumOutputLocation; ++location) {
|
||||
for (uint32_t location = 1; location <= maximumOutputLocation; ++location) {
|
||||
stream << "[[location(" << location << ")]] var" << location << ": f32;" << std::endl;
|
||||
}
|
||||
switch (shaderStage) {
|
||||
@ -283,6 +283,156 @@ TEST_F(ShaderModuleValidationTest, MaximumShaderIOLocations) {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the maximum number of total inter-stage user-defined variable component count and
|
||||
// built-in variables cannot exceed kMaxInterStageShaderComponents.
|
||||
TEST_F(ShaderModuleValidationTest, MaximumInterStageShaderComponents) {
|
||||
auto generateShaderForTest = [](uint32_t totalUserDefinedInterStageShaderComponentCount,
|
||||
wgpu::ShaderStage shaderStage,
|
||||
const char* builtInDeclarations) {
|
||||
std::ostringstream stream;
|
||||
stream << "struct ShaderIO {" << std::endl << builtInDeclarations << std::endl;
|
||||
uint32_t vec4InputLocations = totalUserDefinedInterStageShaderComponentCount / 4;
|
||||
|
||||
for (uint32_t location = 0; location < vec4InputLocations; ++location) {
|
||||
stream << "[[location(" << location << ")]] var" << location << ": vec4<f32>;"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
uint32_t lastComponentCount = totalUserDefinedInterStageShaderComponentCount % 4;
|
||||
if (lastComponentCount > 0) {
|
||||
stream << "[[location(" << vec4InputLocations << ")]] var" << vec4InputLocations
|
||||
<< ": ";
|
||||
if (lastComponentCount == 1) {
|
||||
stream << "f32;";
|
||||
} else {
|
||||
stream << " vec" << lastComponentCount << "<f32>;";
|
||||
}
|
||||
stream << std::endl;
|
||||
}
|
||||
|
||||
switch (shaderStage) {
|
||||
case wgpu::ShaderStage::Vertex: {
|
||||
stream << R"(
|
||||
[[builtin(position)]] pos: vec4<f32>;
|
||||
};
|
||||
[[stage(vertex)]] fn main() -> ShaderIO {
|
||||
var shaderIO : ShaderIO;
|
||||
shaderIO.pos = vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
||||
return shaderIO;
|
||||
})";
|
||||
} break;
|
||||
|
||||
case wgpu::ShaderStage::Fragment: {
|
||||
stream << R"(
|
||||
};
|
||||
[[stage(fragment)]] fn main(shaderIO: ShaderIO) -> [[location(0)]] vec4<f32> {
|
||||
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
||||
})";
|
||||
} break;
|
||||
|
||||
case wgpu::ShaderStage::Compute:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
return stream.str();
|
||||
};
|
||||
|
||||
// Verify when there is no input builtin variable in a fragment shader, the total user-defined
|
||||
// input component count must be less than kMaxInterStageShaderComponents.
|
||||
{
|
||||
constexpr uint32_t kInterStageShaderComponentCount = kMaxInterStageShaderComponents;
|
||||
std::string correctFragmentShader =
|
||||
generateShaderForTest(kInterStageShaderComponentCount, wgpu::ShaderStage::Fragment, "");
|
||||
utils::CreateShaderModule(device, correctFragmentShader.c_str());
|
||||
|
||||
std::string errorFragmentShader = generateShaderForTest(kInterStageShaderComponentCount + 1,
|
||||
wgpu::ShaderStage::Fragment, "");
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, errorFragmentShader.c_str()));
|
||||
}
|
||||
|
||||
// [[position]] should be counted into the maximum inter-stage component count.
|
||||
// Note that in vertex shader we always have [[position]] so we don't need to specify it
|
||||
// again in the parameter "builtInDeclarations" of generateShaderForTest().
|
||||
{
|
||||
constexpr uint32_t kInterStageShaderComponentCount = kMaxInterStageShaderComponents - 4;
|
||||
std::string vertexShader =
|
||||
generateShaderForTest(kInterStageShaderComponentCount, wgpu::ShaderStage::Vertex, "");
|
||||
utils::CreateShaderModule(device, vertexShader.c_str());
|
||||
|
||||
std::string fragmentShader =
|
||||
generateShaderForTest(kInterStageShaderComponentCount, wgpu::ShaderStage::Fragment,
|
||||
"[[builtin(position)]] fragCoord: vec4<f32>;");
|
||||
utils::CreateShaderModule(device, fragmentShader.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
constexpr uint32_t kInterStageShaderComponentCount = kMaxInterStageShaderComponents - 3;
|
||||
std::string vertexShader =
|
||||
generateShaderForTest(kInterStageShaderComponentCount, wgpu::ShaderStage::Vertex, "");
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, vertexShader.c_str()));
|
||||
|
||||
std::string fragmentShader =
|
||||
generateShaderForTest(kInterStageShaderComponentCount, wgpu::ShaderStage::Fragment,
|
||||
"[[builtin(position)]] fragCoord: vec4<f32>;");
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, fragmentShader.c_str()));
|
||||
}
|
||||
|
||||
// [[front_facing]] should be counted into the maximum inter-stage component count.
|
||||
{
|
||||
const char* builtinDeclaration = "[[builtin(front_facing)]] frontFacing : bool;";
|
||||
|
||||
{
|
||||
std::string fragmentShader =
|
||||
generateShaderForTest(kMaxInterStageShaderComponents - 1,
|
||||
wgpu::ShaderStage::Fragment, builtinDeclaration);
|
||||
utils::CreateShaderModule(device, fragmentShader.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
std::string fragmentShader = generateShaderForTest(
|
||||
kMaxInterStageShaderComponents, wgpu::ShaderStage::Fragment, builtinDeclaration);
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, fragmentShader.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// [[sample_index]] should be counted into the maximum inter-stage component count.
|
||||
{
|
||||
const char* builtinDeclaration = "[[builtin(sample_index)]] sampleIndex: u32;";
|
||||
|
||||
{
|
||||
std::string fragmentShader =
|
||||
generateShaderForTest(kMaxInterStageShaderComponents - 1,
|
||||
wgpu::ShaderStage::Fragment, builtinDeclaration);
|
||||
utils::CreateShaderModule(device, fragmentShader.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
std::string fragmentShader = generateShaderForTest(
|
||||
kMaxInterStageShaderComponents, wgpu::ShaderStage::Fragment, builtinDeclaration);
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, fragmentShader.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// [[sample_mask]] should be counted into the maximum inter-stage component count.
|
||||
{
|
||||
const char* builtinDeclaration = "[[builtin(front_facing)]] frontFacing : bool;";
|
||||
|
||||
{
|
||||
std::string fragmentShader =
|
||||
generateShaderForTest(kMaxInterStageShaderComponents - 1,
|
||||
wgpu::ShaderStage::Fragment, builtinDeclaration);
|
||||
utils::CreateShaderModule(device, fragmentShader.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
std::string fragmentShader = generateShaderForTest(
|
||||
kMaxInterStageShaderComponents, wgpu::ShaderStage::Fragment, builtinDeclaration);
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, fragmentShader.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that we validate workgroup size limits.
|
||||
TEST_F(ShaderModuleValidationTest, ComputeWorkgroupSizeLimits) {
|
||||
DAWN_SKIP_TEST_IF(!HasToggleEnabled("use_tint_generator"));
|
||||
|
Loading…
x
Reference in New Issue
Block a user