From a98a8c49a76b7dfc9af370546fc6d99600ee05ff Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 3 Feb 2020 13:14:45 +0000 Subject: [PATCH] Improve handling of multi-dimensional array input/outputs from shaders --- renderdoc/api/replay/shader_types.h | 7 +- renderdoc/data/glsl_shaders.cpp | 301 +++++++++++++++++- renderdoc/driver/gl/gl_shader_refl.cpp | 8 - renderdoc/driver/gl/wrappers/gl_emulated.cpp | 5 +- .../driver/shaders/spirv/glslang_compile.cpp | 58 +++- .../driver/shaders/spirv/glslang_compile.h | 3 +- .../driver/shaders/spirv/spirv_reflect.cpp | 61 ++-- renderdoc/replay/renderdoc_serialise.inl | 3 +- util/test/demos/vk/vk_vertex_attr_zoo.cpp | 12 +- util/test/tests/Vulkan/VK_Vertex_Attr_Zoo.py | 17 +- 10 files changed, 406 insertions(+), 69 deletions(-) diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 2003237ff..cbdb44682 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -603,7 +603,7 @@ struct SigParameter regIndex == o.regIndex && systemValue == o.systemValue && compType == o.compType && regChannelMask == o.regChannelMask && channelUsedMask == o.channelUsedMask && needSemanticIndex == o.needSemanticIndex && compCount == o.compCount && - stream == o.stream && arrayIndex == o.arrayIndex; + stream == o.stream; } bool operator<(const SigParameter &o) const { @@ -631,8 +631,6 @@ struct SigParameter return compCount < o.compCount; if(!(stream == o.stream)) return stream < o.stream; - if(!(arrayIndex == o.arrayIndex)) - return arrayIndex < o.arrayIndex; return false; } @@ -675,9 +673,6 @@ shader itself, for APIs that pack signatures together. "Selects a stream for APIs that provide multiple output streams for the same named output."); uint32_t stream = 0; - DOCUMENT("If this element is part of an array, indicates the index, or :data:`NoIndex` if not."); - uint32_t arrayIndex = ~0U; - static const uint32_t NoIndex = ~0U; }; diff --git a/renderdoc/data/glsl_shaders.cpp b/renderdoc/data/glsl_shaders.cpp index 0fc99c449..753cf00f7 100644 --- a/renderdoc/data/glsl_shaders.cpp +++ b/renderdoc/data/glsl_shaders.cpp @@ -1428,7 +1428,7 @@ void main() { } }; - SECTION("matrix and array outputs") + SECTION("matrix and 1D array outputs") { rdcstr source = R"( #version 450 core @@ -1480,7 +1480,6 @@ void main() INFO("signature element: " << sig.varName.c_str()); CHECK(sig.regIndex == 0); - CHECK(sig.arrayIndex == 0); CHECK(sig.systemValue == ShaderBuiltin::Undefined); CHECK(sig.compType == CompType::Float); CHECK(sig.compCount == 3); @@ -1494,7 +1493,6 @@ void main() INFO("signature element: " << sig.varName.c_str()); CHECK(sig.regIndex == 1); - CHECK(sig.arrayIndex == 1); CHECK(sig.systemValue == ShaderBuiltin::Undefined); CHECK(sig.compType == CompType::Float); CHECK(sig.compCount == 3); @@ -1508,7 +1506,6 @@ void main() INFO("signature element: " << sig.varName.c_str()); CHECK(sig.regIndex == 2); - CHECK(sig.arrayIndex == 2); CHECK(sig.systemValue == ShaderBuiltin::Undefined); CHECK(sig.compType == CompType::Float); CHECK(sig.compCount == 3); @@ -1548,7 +1545,6 @@ void main() INFO("signature element: " << sig.varName.c_str()); CHECK(sig.regIndex == 9); - CHECK(sig.arrayIndex == 0); CHECK(sig.systemValue == ShaderBuiltin::Undefined); CHECK(sig.compType == CompType::Float); CHECK(sig.compCount == 2); @@ -1562,7 +1558,6 @@ void main() INFO("signature element: " << sig.varName.c_str()); CHECK(sig.regIndex == 10); - CHECK(sig.arrayIndex == 0); CHECK(sig.systemValue == ShaderBuiltin::Undefined); CHECK(sig.compType == CompType::Float); CHECK(sig.compCount == 2); @@ -1576,7 +1571,6 @@ void main() INFO("signature element: " << sig.varName.c_str()); CHECK(sig.regIndex == 11); - CHECK(sig.arrayIndex == 1); CHECK(sig.systemValue == ShaderBuiltin::Undefined); CHECK(sig.compType == CompType::Float); CHECK(sig.compCount == 2); @@ -1590,7 +1584,6 @@ void main() INFO("signature element: " << sig.varName.c_str()); CHECK(sig.regIndex == 12); - CHECK(sig.arrayIndex == 1); CHECK(sig.systemValue == ShaderBuiltin::Undefined); CHECK(sig.compType == CompType::Float); CHECK(sig.compCount == 2); @@ -1600,6 +1593,298 @@ void main() } }; + // this is an annoying one. We want to specify a location explicitly to be GL/SPIR-V compatible, + // but on GL if we specify a location the location assignment handling breaks. Since we only + // need to handle this for tests (real drivers will let us query the locations when needed) AND + // it's an extremely obtuse scenario, we just let GL have no location + const rdcstr locDefine = (testType == ShaderType::GLSPIRV || testType == ShaderType::Vulkan) + ? "#define LOC(l) layout(location = l)" + : "#define LOC(l)"; + + SECTION("nested struct/array inputs/outputs") + { + rdcstr source = R"( +#version 450 core + +)" + locDefine + R"( + +struct leaf +{ + float x; +}; + +struct nest +{ + float a[2]; + leaf b[2]; +}; + +struct base +{ + float a; + vec3 b; + nest c[2]; +}; + +layout(binding = 0, std140) uniform ubo_block { + base inB; +} ubo_root; + +LOC(0) out base outB; + +void main() +{ + gl_Position = vec4(0, 0, 0, 1); + outB = ubo_root.inB; +} + +)"; + + ShaderReflection refl; + ShaderBindpointMapping mapping; + compile(ShaderStage::Vertex, source, "main", refl, mapping); + + REQUIRE_ARRAY_SIZE(refl.outputSignature.size(), 11); + { + CHECK(refl.outputSignature[0].varName.contains("gl_Position")); + { + const SigParameter &sig = refl.outputSignature[0]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 0); + CHECK(sig.systemValue == ShaderBuiltin::Position); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 4); + CHECK(sig.regChannelMask == 0xf); + CHECK(sig.channelUsedMask == 0xf); + } + + CHECK(refl.outputSignature[1].varName == "outB.a"); + { + const SigParameter &sig = refl.outputSignature[1]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 0); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 1); + CHECK(sig.regChannelMask == 0x1); + CHECK(sig.channelUsedMask == 0x1); + } + + CHECK(refl.outputSignature[2].varName == "outB.b"); + { + const SigParameter &sig = refl.outputSignature[2]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 1); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 3); + CHECK(sig.regChannelMask == 0x7); + CHECK(sig.channelUsedMask == 0x7); + } + + CHECK(refl.outputSignature[3].varName == "outB.c[0].a[0]"); + { + const SigParameter &sig = refl.outputSignature[3]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 2); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 1); + CHECK(sig.regChannelMask == 0x1); + CHECK(sig.channelUsedMask == 0x1); + } + + CHECK(refl.outputSignature[4].varName == "outB.c[0].a[1]"); + { + const SigParameter &sig = refl.outputSignature[4]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 3); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 1); + CHECK(sig.regChannelMask == 0x1); + CHECK(sig.channelUsedMask == 0x1); + } + + CHECK(refl.outputSignature[5].varName == "outB.c[0].b[0].x"); + { + const SigParameter &sig = refl.outputSignature[5]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 4); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 1); + CHECK(sig.regChannelMask == 0x1); + CHECK(sig.channelUsedMask == 0x1); + } + + CHECK(refl.outputSignature[6].varName == "outB.c[0].b[1].x"); + { + const SigParameter &sig = refl.outputSignature[6]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 5); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 1); + CHECK(sig.regChannelMask == 0x1); + CHECK(sig.channelUsedMask == 0x1); + } + + CHECK(refl.outputSignature[7].varName == "outB.c[1].a[0]"); + { + const SigParameter &sig = refl.outputSignature[7]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 6); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 1); + CHECK(sig.regChannelMask == 0x1); + CHECK(sig.channelUsedMask == 0x1); + } + + CHECK(refl.outputSignature[8].varName == "outB.c[1].a[1]"); + { + const SigParameter &sig = refl.outputSignature[8]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 7); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 1); + CHECK(sig.regChannelMask == 0x1); + CHECK(sig.channelUsedMask == 0x1); + } + + CHECK(refl.outputSignature[9].varName == "outB.c[1].b[0].x"); + { + const SigParameter &sig = refl.outputSignature[9]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 8); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 1); + CHECK(sig.regChannelMask == 0x1); + CHECK(sig.channelUsedMask == 0x1); + } + + CHECK(refl.outputSignature[10].varName == "outB.c[1].b[1].x"); + { + const SigParameter &sig = refl.outputSignature[10]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 9); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 1); + CHECK(sig.regChannelMask == 0x1); + CHECK(sig.channelUsedMask == 0x1); + } + } + } + + SECTION("multi-dimensional array inputs/outputs") + { + rdcstr source = R"( +#version 450 core + +)" + locDefine + R"( + +LOC(0) in vec3 inarr[1][3][2]; + +LOC(0) out vec3 outarr[1][3][2]; + +void main() +{ + gl_Position = vec4(0, 0, 0, 1); + for(int i=0; i < 1*3*2; i++) + outarr[(i/6)][(i/2)%3][i%2] = inarr[(i/6)][(i/2)%3][i%2]; +} + +)"; + + ShaderReflection refl; + ShaderBindpointMapping mapping; + compile(ShaderStage::Vertex, source, "main", refl, mapping); + + REQUIRE_ARRAY_SIZE(refl.samplers.size(), 0); + REQUIRE_ARRAY_SIZE(refl.constantBlocks.size(), 0); + REQUIRE_ARRAY_SIZE(refl.readOnlyResources.size(), 0); + REQUIRE_ARRAY_SIZE(refl.readWriteResources.size(), 0); + + REQUIRE(refl.inputSignature.size() >= 6); + + // glslang will insert gl_VertexID and gl_InstanceID here in SPIR-V compilation + CHECK((refl.inputSignature.size() == 6 || refl.inputSignature.size() == 8)); + + REQUIRE_ARRAY_SIZE(refl.outputSignature.size(), 7); + for(size_t i = 0; i < 2; i++) + { + const rdcarray &sigarray = (i == 0) ? refl.inputSignature : refl.outputSignature; + size_t idx = 0; + + if(i == 0) + { + if(sigarray[0].varName.contains("gl_VertexID")) + { + // skip without checking + idx++; + } + if(sigarray[1].varName.contains("gl_InstanceID")) + { + // skip without checking + idx++; + } + } + else if(i == 1) + { + CHECK(sigarray[0].varName.contains("gl_Position")); + { + const SigParameter &sig = sigarray[0]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == 0); + CHECK(sig.systemValue == ShaderBuiltin::Position); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 4); + CHECK(sig.regChannelMask == 0xf); + CHECK(sig.channelUsedMask == 0xf); + } + + idx++; + } + + for(uint32_t a = 0; a < 6; a++) + { + rdcstr expectedName = StringFormat::Fmt("%sarr[%d][%d][%d]", i == 0 ? "in" : "out", a / 6, + (a / 2) % 3, (a % 2)); + + CHECK(sigarray[idx].varName == expectedName); + { + const SigParameter &sig = sigarray[idx]; + INFO("signature element: " << sig.varName.c_str()); + + CHECK(sig.regIndex == a); + CHECK(sig.systemValue == ShaderBuiltin::Undefined); + CHECK(sig.compType == CompType::Float); + CHECK(sig.compCount == 3); + CHECK(sig.regChannelMask == 0x7); + CHECK(sig.channelUsedMask == 0x7); + } + + idx++; + } + } + }; + SECTION("shader input/output blocks") { rdcstr source = R"( diff --git a/renderdoc/driver/gl/gl_shader_refl.cpp b/renderdoc/driver/gl/gl_shader_refl.cpp index 90b6e2fc4..8e4cf333a 100644 --- a/renderdoc/driver/gl/gl_shader_refl.cpp +++ b/renderdoc/driver/gl/gl_shader_refl.cpp @@ -1086,10 +1086,7 @@ static void AddSigParameter(rdcarray &sigs, uint32_t ®Index, s.regIndex += arrayIdx; if(arrayIdx >= 0) - { - s.arrayIndex = arrayIdx; s.varName = StringFormat::Fmt("%s[%d]", nm, arrayIdx); - } sigs.push_back(s); } @@ -1107,14 +1104,9 @@ static void AddSigParameter(rdcarray &sigs, uint32_t ®Index, s.regIndex += r; if(arrayIdx >= 0) - { - s.arrayIndex = arrayIdx; s.varName = StringFormat::Fmt("%s[%d]:row%d", nm, arrayIdx, r); - } else - { s.varName = StringFormat::Fmt("%s:row%d", nm, r); - } sigs.push_back(s); } diff --git a/renderdoc/driver/gl/wrappers/gl_emulated.cpp b/renderdoc/driver/gl/wrappers/gl_emulated.cpp index 2aaecdadf..2669e18a6 100644 --- a/renderdoc/driver/gl/wrappers/gl_emulated.cpp +++ b/renderdoc/driver/gl/wrappers/gl_emulated.cpp @@ -2497,7 +2497,7 @@ GLuint APIENTRY _glGetProgramResourceIndex(GLuint program, GLenum programInterfa return 0; } - return glslangGetProgramResourceIndex(glslangProgram, name); + return glslangGetProgramResourceIndex(glslangProgram, ConvertInterface(programInterface), name); } void APIENTRY _glGetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, @@ -3483,7 +3483,8 @@ void APIENTRY _testStub_GetActiveUniformBlockiv(GLuint program, GLuint uniformBl GLint APIENTRY _testStub_AttribLocation(GLuint program, const GLchar *name) { - GLuint index = GL.glGetProgramResourceIndex(program, eGL_UNIFORM_BLOCK, name); + GLuint index = GL.glGetProgramResourceIndex(program, eGL_PROGRAM_INPUT, name); + RDCASSERT(index != GL_INVALID_INDEX); GLenum prop = eGL_LOCATION; GLint value = -1; diff --git a/renderdoc/driver/shaders/spirv/glslang_compile.cpp b/renderdoc/driver/shaders/spirv/glslang_compile.cpp index 4275caea0..deed9a005 100644 --- a/renderdoc/driver/shaders/spirv/glslang_compile.cpp +++ b/renderdoc/driver/shaders/spirv/glslang_compile.cpp @@ -610,21 +610,59 @@ void glslangGetProgramResourceiv(glslang::TProgram *program, ReflectionInterface } } -uint32_t glslangGetProgramResourceIndex(glslang::TProgram *program, const char *name) +uint32_t glslangGetProgramResourceIndex(glslang::TProgram *program, + ReflectionInterface programInterface, const char *name) { - uint32_t idx = program->getReflectionIndex(name); + rdcstr n = name; - // Additionally, if would exactly match the name string of an active - // resource if "[0]" were appended to , the index of the matched - // resource is returned. - if(idx == ~0U) + for(int pass = 0; pass < 2; pass++) { - rdcstr arraysuffixed = name; - arraysuffixed += "[0]"; - idx = program->getReflectionIndex(arraysuffixed.c_str()); + // glslang namespaces aggregates that it blows up with our reflection settings, assuming we + // don't get an exact match for the name try with the appropriate prefix for this interface + if(pass == 1 && programInterface == ReflectionInterface::Input) + n = "in " + n; + else if(pass == 1 && programInterface == ReflectionInterface::Output) + n = "out " + n; + else if(pass == 1) + break; + + uint32_t idx = program->getReflectionIndex(n.c_str()); + + // Additionally, if would exactly match the name string of an active + // resource if "[0]" were appended to , the index of the matched + // resource is returned. + if(idx == ~0U) + { + rdcstr arraysuffixed = n; + arraysuffixed += "[0]"; + idx = program->getReflectionIndex(arraysuffixed.c_str()); + } + + // for I/O inputs, if the name ended in an array index, try and subtract that, query for the + // name with [0]. + if((programInterface == ReflectionInterface::Input || + programInterface == ReflectionInterface::Output) && + idx == ~0U && n.back() == ']') + { + rdcstr unsuffixed = n; + unsuffixed.pop_back(); + + while(unsuffixed.back() >= '0' && unsuffixed.back() <= '9') + unsuffixed.pop_back(); + + if(unsuffixed.back() == '[') + { + unsuffixed.pop_back(); + unsuffixed += "[0]"; + idx = program->getReflectionIndex(unsuffixed.c_str()); + } + } + + if(idx != ~0U) + return idx; } - return idx; + return ~0U; } const char *glslangGetProgramResourceName(glslang::TProgram *program, diff --git a/renderdoc/driver/shaders/spirv/glslang_compile.h b/renderdoc/driver/shaders/spirv/glslang_compile.h index 034932e1d..752762458 100644 --- a/renderdoc/driver/shaders/spirv/glslang_compile.h +++ b/renderdoc/driver/shaders/spirv/glslang_compile.h @@ -85,7 +85,8 @@ void glslangGetProgramInterfaceiv(glslang::TProgram *program, ReflectionInterfac void glslangGetProgramResourceiv(glslang::TProgram *program, ReflectionInterface programInterface, uint32_t index, const rdcarray &props, int32_t bufSize, int32_t *length, int32_t *params); -uint32_t glslangGetProgramResourceIndex(glslang::TProgram *program, const char *name); +uint32_t glslangGetProgramResourceIndex(glslang::TProgram *program, + ReflectionInterface programInterface, const char *name); const char *glslangGetProgramResourceName(glslang::TProgram *program, ReflectionInterface programInterface, uint32_t index); diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp index 98ffd0b0b..ccbf90d4d 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp @@ -2100,32 +2100,29 @@ void Reflector::AddSignatureParameter(const bool isInput, const ShaderStage stag isArray = true; varType = &dataTypes[varType->InnerType()]; - // for geometry/tessellation evaluation shaders, ignore the root level of array-ness for inputs - if((stage == ShaderStage::Geometry || stage == ShaderStage::Tess_Eval) && isInput && - parentStructID == 0) - arraySize = 1; - - // for tessellation control shaders, ignore the root level of array-ness for both inputs and - // outputs - if(stage == ShaderStage::Tess_Control && parentStructID == 0) - arraySize = 1; - - // step through multi-dimensional arrays - while(varType->type == DataType::ArrayType) - varType = &dataTypes[varType->InnerType()]; - - // if this is a root array in the geometry shader, don't reflect it as an array - if(stage == ShaderStage::Geometry && isInput && parentStructID == 0) + // if this is the first array level, we sometimes ignore it. + if(patch.accessChain.empty()) { - arraySize = 1; - isArray = false; + // for geometry/tessellation evaluation shaders, ignore the root level of array-ness for + // inputs + if((stage == ShaderStage::Geometry || stage == ShaderStage::Tess_Eval) && isInput) + arraySize = 1; + + // for tessellation control shaders, ignore the root level of array-ness for both inputs and + // outputs + if(stage == ShaderStage::Tess_Control) + arraySize = 1; + + // if this is a root array in the geometry shader, don't reflect it as an array either + if(stage == ShaderStage::Geometry && isInput) + isArray = false; } + + // arrays will need an extra access chain index + patch.accessChain.push_back(0U); } - // arrays will need an extra access chain index - if(isArray) - patch.accessChain.push_back(0U); - + // if the current type is a struct, recurse for each member if(varType->type == DataType::StructType) { for(uint32_t a = 0; a < arraySize; a++) @@ -2167,6 +2164,23 @@ void Reflector::AddSignatureParameter(const bool isInput, const ShaderStage stag return; } + // similarly for arrays (this happens for multi-dimensional arrays + if(varType->type == DataType::ArrayType) + { + for(uint32_t a = 0; a < arraySize; a++) + { + AddSignatureParameter(isInput, stage, globalID, varType->id, regIndex, patch, + varName + StringFormat::Fmt("[%u]", a), *varType, {}, sigarray, + patchData, specInfo); + + // increment the array-index access chain value + patch.accessChain.back()++; + patch.isArraySubsequentElement = true; + } + + return; + } + switch(varType->scalar().type) { case Op::TypeBool: @@ -2191,10 +2205,7 @@ void Reflector::AddSignatureParameter(const bool isInput, const ShaderStage stag rdcstr n = varName; if(isArray) - { n += StringFormat::Fmt("[%u]", a); - sig.arrayIndex = a; - } sig.varName = n; diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index efeb1c870..61c09b905 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -165,9 +165,8 @@ void DoSerialise(SerialiserType &ser, SigParameter &el) SERIALISE_MEMBER(needSemanticIndex); SERIALISE_MEMBER(compCount); SERIALISE_MEMBER(stream); - SERIALISE_MEMBER(arrayIndex); - SIZE_CHECK(104); + SIZE_CHECK(96); } template diff --git a/util/test/demos/vk/vk_vertex_attr_zoo.cpp b/util/test/demos/vk/vk_vertex_attr_zoo.cpp index 7779635b5..8bebe230a 100644 --- a/util/test/demos/vk/vk_vertex_attr_zoo.cpp +++ b/util/test/demos/vk/vk_vertex_attr_zoo.cpp @@ -182,7 +182,7 @@ struct SimpleWrapper struct MyStruct { float a; - float b[2]; + float b[2][3]; ArrayWrapper c; SimpleWrapper d[2]; }; @@ -202,12 +202,16 @@ void main() OutDummy = vec4(0,0,0,0); outData.outStruct.a = 1.1f; - outData.outStruct.b[0] = 2.2f; - outData.outStruct.b[1] = 3.3f; outData.outStruct.c.foo[0] = 4.4f; outData.outStruct.c.foo[1] = 5.5f; outData.outStruct.d[0].foo = 6.6f; outData.outStruct.d[1].foo = 7.7f; + outData.outStruct.b[0][0] = 2.2f; + outData.outStruct.b[0][1] = 3.3f; + outData.outStruct.b[0][2] = 8.8f; + outData.outStruct.b[1][0] = 9.9f; + outData.outStruct.b[1][1] = 9.1f; + outData.outStruct.b[1][2] = 8.2f; } )EOSHADER"; @@ -233,7 +237,7 @@ struct SimpleWrapper struct MyStruct { float a; - float b[2]; + float b[2][3]; ArrayWrapper c; SimpleWrapper d[2]; }; diff --git a/util/test/tests/Vulkan/VK_Vertex_Attr_Zoo.py b/util/test/tests/Vulkan/VK_Vertex_Attr_Zoo.py index 7966d9ad5..410433532 100644 --- a/util/test/tests/Vulkan/VK_Vertex_Attr_Zoo.py +++ b/util/test/tests/Vulkan/VK_Vertex_Attr_Zoo.py @@ -103,12 +103,16 @@ class VK_Vertex_Attr_Zoo(rdtest.TestCase): ref = { 0: { 'outData.outStruct.a': [1.1], - 'outData.outStruct.b[0]': [2.2], - 'outData.outStruct.b[1]': [3.3], 'outData.outStruct.c.foo[0]': [4.4], 'outData.outStruct.c.foo[1]': [5.5], 'outData.outStruct.d[0].foo': [6.6], 'outData.outStruct.d[1].foo': [7.7], + 'outData.outStruct.b[0][0]': [2.2], + 'outData.outStruct.b[0][1]': [3.3], + 'outData.outStruct.b[0][2]': [8.8], + 'outData.outStruct.b[1][0]': [9.9], + 'outData.outStruct.b[1][1]': [9.1], + 'outData.outStruct.b[1][2]': [8.2], }, } @@ -116,7 +120,14 @@ class VK_Vertex_Attr_Zoo(rdtest.TestCase): rdtest.log.success("Nested vertex output data is as expected") - # The array-of-structs data is a broken in transform feedback + # The array-of-structs or array-of-arrays data is a broken in transform feedback + del ref[0]['outData.outStruct.b[0][0]'] + del ref[0]['outData.outStruct.b[0][1]'] + del ref[0]['outData.outStruct.b[0][2]'] + del ref[0]['outData.outStruct.b[1][0]'] + del ref[0]['outData.outStruct.b[1][1]'] + del ref[0]['outData.outStruct.b[1][2]'] + del ref[0]['outData.outStruct.d[0].foo'] del ref[0]['outData.outStruct.d[1].foo']