mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-03 05:01:27 +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);
|
metadata->usedVertexInputs.set(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [[position]] must be declared in a vertex shader.
|
||||||
|
uint32_t totalInterStageShaderComponents = 4;
|
||||||
for (const auto& output_var : entryPoint.output_variables) {
|
for (const auto& output_var : entryPoint.output_variables) {
|
||||||
if (DAWN_UNLIKELY(!output_var.has_location_decoration)) {
|
if (DAWN_UNLIKELY(!output_var.has_location_decoration)) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
@ -1082,10 +1084,20 @@ namespace dawn_native {
|
|||||||
metadata->interStageVariables[location].interpolationSampling,
|
metadata->interStageVariables[location].interpolationSampling,
|
||||||
TintInterpolationSamplingToInterpolationSamplingType(
|
TintInterpolationSamplingToInterpolationSamplingType(
|
||||||
output_var.interpolation_sampling));
|
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) {
|
if (metadata->stage == SingleShaderStage::Fragment) {
|
||||||
|
uint32_t totalInterStageShaderComponents = 0;
|
||||||
for (const auto& input_var : entryPoint.input_variables) {
|
for (const auto& input_var : entryPoint.input_variables) {
|
||||||
if (!input_var.has_location_decoration) {
|
if (!input_var.has_location_decoration) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
@ -1111,6 +1123,25 @@ namespace dawn_native {
|
|||||||
metadata->interStageVariables[location].interpolationSampling,
|
metadata->interStageVariables[location].interpolationSampling,
|
||||||
TintInterpolationSamplingToInterpolationSamplingType(
|
TintInterpolationSamplingToInterpolationSamplingType(
|
||||||
input_var.interpolation_sampling));
|
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) {
|
for (const auto& output_var : entryPoint.output_variables) {
|
||||||
|
@ -219,7 +219,7 @@ TEST_F(ShaderModuleValidationTest, MaximumShaderIOLocations) {
|
|||||||
auto generateShaderForTest = [](uint32_t maximumOutputLocation, wgpu::ShaderStage shaderStage) {
|
auto generateShaderForTest = [](uint32_t maximumOutputLocation, wgpu::ShaderStage shaderStage) {
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
stream << "struct ShaderIO {" << std::endl;
|
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;
|
stream << "[[location(" << location << ")]] var" << location << ": f32;" << std::endl;
|
||||||
}
|
}
|
||||||
switch (shaderStage) {
|
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.
|
// Tests that we validate workgroup size limits.
|
||||||
TEST_F(ShaderModuleValidationTest, ComputeWorkgroupSizeLimits) {
|
TEST_F(ShaderModuleValidationTest, ComputeWorkgroupSizeLimits) {
|
||||||
DAWN_SKIP_TEST_IF(!HasToggleEnabled("use_tint_generator"));
|
DAWN_SKIP_TEST_IF(!HasToggleEnabled("use_tint_generator"));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user