mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
Improve handling of multi-dimensional array input/outputs from shaders
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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<SigParameter> &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"(
|
||||
|
||||
@@ -1086,10 +1086,7 @@ static void AddSigParameter(rdcarray<SigParameter> &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<SigParameter> &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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 <name> would exactly match the name string of an active
|
||||
// resource if "[0]" were appended to <name>, 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 <name> would exactly match the name string of an active
|
||||
// resource if "[0]" were appended to <name>, 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,
|
||||
|
||||
@@ -85,7 +85,8 @@ void glslangGetProgramInterfaceiv(glslang::TProgram *program, ReflectionInterfac
|
||||
void glslangGetProgramResourceiv(glslang::TProgram *program, ReflectionInterface programInterface,
|
||||
uint32_t index, const rdcarray<ReflectionProperty> &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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 <typename SerialiserType>
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
@@ -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']
|
||||
|
||||
|
||||
Reference in New Issue
Block a user