From 788b408bc2aa9bbd30c79f22faf779818caf5476 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 17 Mar 2022 15:59:25 +0000 Subject: [PATCH] Add test for GL reflection & reconstruction of runtime arrays --- renderdoc/data/glsl_shaders.cpp | 531 +++++++++++++++++++++++++++++++- 1 file changed, 527 insertions(+), 4 deletions(-) diff --git a/renderdoc/data/glsl_shaders.cpp b/renderdoc/data/glsl_shaders.cpp index e5dcd5b2a..650286628 100644 --- a/renderdoc/data/glsl_shaders.cpp +++ b/renderdoc/data/glsl_shaders.cpp @@ -1170,6 +1170,533 @@ void main() { } }; +#define REQUIRE_ARRAY_SIZE(size, min) \ + REQUIRE(size >= min); \ + CHECK(size == min); + + SECTION("Infinite arrays") + { + rdcstr source = R"( +#version 450 core + +layout(binding = 0, std430) buffer ssbo0 +{ + float blah; + vec4 normal_array[3]; + vec4 non_array; +} ssbo_root0; + +layout(binding = 0, std430) buffer ssbo1 +{ + float blah; + vec4 normal_array[3]; + vec4 bounded_array[5]; +} ssbo_root1; + +layout(binding = 2, std430) buffer ssbo2 +{ + float blah; + vec4 normal_array[3]; + vec4 infinite_array[]; +} ssbo_root2; + +struct glstruct +{ + float a; + int b; +}; + +struct struct_with_arrays +{ + float a[2]; + int b; +}; + +layout(binding = 3, std430) buffer ssbo3 +{ + float blah; + struct_with_arrays test; + glstruct s[2]; +} ssbo_root3; + +layout(binding = 4, std430) buffer ssbo4 +{ + float blah; + struct_with_arrays test; + glstruct s[]; +} ssbo_root4; + +layout(binding = 4, std430) buffer ssbo5 +{ + float ssbo5_blah; + struct_with_arrays ssbo5_test; + glstruct ssbo5_s[2]; +}; + +layout(binding = 5, std430) buffer ssbo6 +{ + float ssbo6_blah; + struct_with_arrays ssbo6_test; + glstruct ssbo6_s[]; +}; + +layout(binding = 0, std140) uniform ubo_block +{ + float blah; + vec4 normal_array[3]; + vec4 infinite_array[]; +} ubo_root; + +void main() { + ssbo_root0.blah = 0.0f; + ssbo_root1.blah = 0.0f; + ssbo_root2.blah = 0.0f; + ssbo_root3.s[0].a = 0.0f; + ssbo_root4.s[0].a = 0.0f; + ssbo5_blah = 0.0f; + ssbo6_blah = 0.0f; + gl_FragDepth = ubo_root.blah + ubo_root.normal_array[0].x + ubo_root.infinite_array[4].x; +} + +)"; + + ShaderReflection refl; + ShaderBindpointMapping mapping; + compile(ShaderStage::Fragment, source, "main", refl, mapping); + + REQUIRE_ARRAY_SIZE(refl.constantBlocks.size(), 1); + { + // blocks get different reflected names in SPIR-V + const rdcstr ubo_name = testType == ShaderType::GLSL ? "ubo_block" : "ubo_root"; + + CHECK(refl.constantBlocks[0].name == ubo_name); + { + const ConstantBlock &cblock = refl.constantBlocks[0]; + INFO("UBO: " << cblock.name.c_str()); + + // GLSL reflects out a root structure + if(testType == ShaderType::GLSL) + { + REQUIRE_ARRAY_SIZE(cblock.variables.size(), 1); + + CHECK(cblock.variables[0].name == ubo_name); + } + + const rdcarray &ubo_root = + testType == ShaderType::GLSL ? cblock.variables[0].type.members : cblock.variables; + + REQUIRE_ARRAY_SIZE(ubo_root.size(), 3); + { + CHECK(ubo_root[0].name == "blah"); + { + const ShaderConstant &member = ubo_root[0]; + INFO("UBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.elements == 1); + } + + CHECK(ubo_root[1].name == "normal_array"); + { + const ShaderConstant &member = ubo_root[1]; + INFO("UBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.columns == 4); + CHECK(member.type.descriptor.elements == 3); + } + + CHECK(ubo_root[2].name == "infinite_array"); + { + const ShaderConstant &member = ubo_root[2]; + INFO("UBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.columns == 4); + // UBOs don't really support infinite arrays - it will just be declared big enough for + // the amount used statically + CHECK(member.type.descriptor.elements == 5); + } + } + } + } + + REQUIRE_ARRAY_SIZE(refl.readWriteResources.size(), 7); + { + // blocks get different reflected names in SPIR-V + const rdcstr ssbo_name = testType == ShaderType::GLSL ? "ssbo" : "ssbo_root"; + const rdcstr ssbo_suffix = testType == ShaderType::GLSL ? "" : "_var"; + + CHECK(refl.readWriteResources[0].name == ssbo_name + "0"); + { + const ShaderResource &res = refl.readWriteResources[0]; + INFO("read-write resource: " << res.name.c_str()); + + REQUIRE_ARRAY_SIZE(res.variableType.members.size(), 3); + { + CHECK(res.variableType.members[0].name == "blah"); + { + const ShaderConstant &member = res.variableType.members[0]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.elements == 1); + } + + CHECK(res.variableType.members[1].name == "normal_array"); + { + const ShaderConstant &member = res.variableType.members[1]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.columns == 4); + CHECK(member.type.descriptor.elements == 3); + } + + CHECK(res.variableType.members[2].name == "non_array"); + { + const ShaderConstant &member = res.variableType.members[2]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.columns == 4); + CHECK(member.type.descriptor.elements == 1); + } + } + } + + CHECK(refl.readWriteResources[1].name == ssbo_name + "1"); + { + const ShaderResource &res = refl.readWriteResources[1]; + INFO("read-write resource: " << res.name.c_str()); + + REQUIRE_ARRAY_SIZE(res.variableType.members.size(), 3); + { + CHECK(res.variableType.members[0].name == "blah"); + { + const ShaderConstant &member = res.variableType.members[0]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.elements == 1); + } + + CHECK(res.variableType.members[1].name == "normal_array"); + { + const ShaderConstant &member = res.variableType.members[1]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.columns == 4); + CHECK(member.type.descriptor.elements == 3); + } + + CHECK(res.variableType.members[2].name == "bounded_array"); + { + const ShaderConstant &member = res.variableType.members[2]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.columns == 4); + CHECK(member.type.descriptor.elements == 5); + } + } + } + + CHECK(refl.readWriteResources[2].name == ssbo_name + "2"); + { + const ShaderResource &res = refl.readWriteResources[2]; + INFO("read-write resource: " << res.name.c_str()); + + REQUIRE_ARRAY_SIZE(res.variableType.members.size(), 3); + { + CHECK(res.variableType.members[0].name == "blah"); + { + const ShaderConstant &member = res.variableType.members[0]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.elements == 1); + } + + CHECK(res.variableType.members[1].name == "normal_array"); + { + const ShaderConstant &member = res.variableType.members[1]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.columns == 4); + CHECK(member.type.descriptor.elements == 3); + } + + CHECK(res.variableType.members[2].name == "infinite_array"); + { + const ShaderConstant &member = res.variableType.members[2]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.columns == 4); + CHECK(member.type.descriptor.elements == ~0U); + } + } + } + + CHECK(refl.readWriteResources[3].name == ssbo_name + "3"); + { + const ShaderResource &res = refl.readWriteResources[3]; + INFO("read-write resource: " << res.name.c_str()); + + REQUIRE_ARRAY_SIZE(res.variableType.members.size(), 3); + { + CHECK(res.variableType.members[0].name == "blah"); + { + const ShaderConstant &member = res.variableType.members[0]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.elements == 1); + } + + CHECK(res.variableType.members[1].name == "test"); + { + const ShaderConstant &member = res.variableType.members[1]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Struct); + CHECK(member.type.descriptor.elements == 1); + + REQUIRE_ARRAY_SIZE(member.type.members.size(), 2); + { + CHECK(member.type.members[0].name == "a"); + { + const ShaderConstant &submember = member.type.members[0]; + INFO("SSBO submember: " << submember.name.c_str()); + + CHECK(submember.type.descriptor.type == VarType::Float); + CHECK(submember.type.descriptor.columns == 1); + CHECK(submember.type.descriptor.elements == 2); + } + + CHECK(member.type.members[1].name == "b"); + { + const ShaderConstant &submember = member.type.members[1]; + INFO("SSBO submember: " << submember.name.c_str()); + + CHECK(submember.type.descriptor.type == VarType::SInt); + CHECK(submember.type.descriptor.columns == 1); + CHECK(submember.type.descriptor.elements == 1); + } + } + } + + CHECK(res.variableType.members[2].name == "s"); + { + const ShaderConstant &member = res.variableType.members[2]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Struct); + if(testType == ShaderType::GLSL) + { + // GL has no way of telling us the fixed size of a trailing array of structs, so we + // report that it's infinite + CHECK(member.type.descriptor.elements == ~0U); + } + else + { + CHECK(member.type.descriptor.elements == 2); + } + } + } + } + + CHECK(refl.readWriteResources[4].name == ssbo_name + "4"); + { + const ShaderResource &res = refl.readWriteResources[4]; + INFO("read-write resource: " << res.name.c_str()); + + REQUIRE_ARRAY_SIZE(res.variableType.members.size(), 3); + { + CHECK(res.variableType.members[0].name == "blah"); + { + const ShaderConstant &member = res.variableType.members[0]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.elements == 1); + } + + CHECK(res.variableType.members[1].name == "test"); + { + const ShaderConstant &member = res.variableType.members[1]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Struct); + CHECK(member.type.descriptor.elements == 1); + + REQUIRE_ARRAY_SIZE(member.type.members.size(), 2); + { + CHECK(member.type.members[0].name == "a"); + { + const ShaderConstant &submember = member.type.members[0]; + INFO("SSBO submember: " << submember.name.c_str()); + + CHECK(submember.type.descriptor.type == VarType::Float); + CHECK(submember.type.descriptor.columns == 1); + CHECK(submember.type.descriptor.elements == 2); + } + + CHECK(member.type.members[1].name == "b"); + { + const ShaderConstant &submember = member.type.members[1]; + INFO("SSBO submember: " << submember.name.c_str()); + + CHECK(submember.type.descriptor.type == VarType::SInt); + CHECK(submember.type.descriptor.columns == 1); + CHECK(submember.type.descriptor.elements == 1); + } + } + } + + CHECK(res.variableType.members[2].name == "s"); + { + const ShaderConstant &member = res.variableType.members[2]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Struct); + CHECK(member.type.descriptor.elements == ~0U); + } + } + } + + CHECK(refl.readWriteResources[5].name == "ssbo5" + ssbo_suffix); + { + const ShaderResource &res = refl.readWriteResources[5]; + INFO("read-write resource: " << res.name.c_str()); + + REQUIRE_ARRAY_SIZE(res.variableType.members.size(), 3); + { + CHECK(res.variableType.members[0].name == "ssbo5_blah"); + { + const ShaderConstant &member = res.variableType.members[0]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.elements == 1); + } + + CHECK(res.variableType.members[1].name == "ssbo5_test"); + { + const ShaderConstant &member = res.variableType.members[1]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Struct); + CHECK(member.type.descriptor.elements == 1); + + REQUIRE_ARRAY_SIZE(member.type.members.size(), 2); + { + CHECK(member.type.members[0].name == "a"); + { + const ShaderConstant &submember = member.type.members[0]; + INFO("SSBO submember: " << submember.name.c_str()); + + CHECK(submember.type.descriptor.type == VarType::Float); + CHECK(submember.type.descriptor.columns == 1); + CHECK(submember.type.descriptor.elements == 2); + } + + CHECK(member.type.members[1].name == "b"); + { + const ShaderConstant &submember = member.type.members[1]; + INFO("SSBO submember: " << submember.name.c_str()); + + CHECK(submember.type.descriptor.type == VarType::SInt); + CHECK(submember.type.descriptor.columns == 1); + CHECK(submember.type.descriptor.elements == 1); + } + } + } + + CHECK(res.variableType.members[2].name == "ssbo5_s"); + { + const ShaderConstant &member = res.variableType.members[2]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Struct); + if(testType == ShaderType::GLSL) + { + // GL has no way of telling us the fixed size of a trailing array of structs, so we + // report that it's infinite + CHECK(member.type.descriptor.elements == ~0U); + } + else + { + CHECK(member.type.descriptor.elements == 2); + } + } + } + } + + CHECK(refl.readWriteResources[6].name == "ssbo6" + ssbo_suffix); + { + const ShaderResource &res = refl.readWriteResources[6]; + INFO("read-write resource: " << res.name.c_str()); + + REQUIRE_ARRAY_SIZE(res.variableType.members.size(), 3); + { + CHECK(res.variableType.members[0].name == "ssbo6_blah"); + { + const ShaderConstant &member = res.variableType.members[0]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Float); + CHECK(member.type.descriptor.elements == 1); + } + + CHECK(res.variableType.members[1].name == "ssbo6_test"); + { + const ShaderConstant &member = res.variableType.members[1]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Struct); + CHECK(member.type.descriptor.elements == 1); + + REQUIRE_ARRAY_SIZE(member.type.members.size(), 2); + { + CHECK(member.type.members[0].name == "a"); + { + const ShaderConstant &submember = member.type.members[0]; + INFO("SSBO submember: " << submember.name.c_str()); + + CHECK(submember.type.descriptor.type == VarType::Float); + CHECK(submember.type.descriptor.columns == 1); + CHECK(submember.type.descriptor.elements == 2); + } + + CHECK(member.type.members[1].name == "b"); + { + const ShaderConstant &submember = member.type.members[1]; + INFO("SSBO submember: " << submember.name.c_str()); + + CHECK(submember.type.descriptor.type == VarType::SInt); + CHECK(submember.type.descriptor.columns == 1); + CHECK(submember.type.descriptor.elements == 1); + } + } + } + + CHECK(res.variableType.members[2].name == "ssbo6_s"); + { + const ShaderConstant &member = res.variableType.members[2]; + INFO("SSBO member: " << member.name.c_str()); + + CHECK(member.type.descriptor.type == VarType::Struct); + CHECK(member.type.descriptor.elements == ~0U); + } + } + } + } + } + SECTION("SSBOs") { rdcstr source = R"( @@ -1209,10 +1736,6 @@ void main() { )"; -#define REQUIRE_ARRAY_SIZE(size, min) \ - REQUIRE(size >= min); \ - CHECK(size == min); - ShaderReflection refl; ShaderBindpointMapping mapping; compile(ShaderStage::Fragment, source, "main", refl, mapping);