Add GL input attribute dynamic binding information to pipe state

This commit is contained in:
baldurk
2024-04-10 18:58:51 +01:00
parent 2bbe1a8cd9
commit 292bb596dc
9 changed files with 129 additions and 81 deletions
@@ -1394,9 +1394,7 @@ void GLPipelineStateViewer::setState()
if(state.vertexShader.shaderResourceId != ResourceId())
{
int attrib = -1;
if(i < state.vertexShader.bindpointMapping.inputAttributes.count())
attrib = state.vertexShader.bindpointMapping.inputAttributes[i];
int attrib = a.boundShaderInput;
if(attrib >= 0 && attrib < state.vertexShader.reflection->inputSignature.count())
{
@@ -2342,11 +2342,9 @@ void VulkanPipelineStateViewer::setState()
if(state.vertexShader.resourceId != ResourceId())
{
int attrib = -1;
if((int32_t)a.location < state.vertexShader.bindpointMapping.inputAttributes.count())
attrib = state.vertexShader.bindpointMapping.inputAttributes[a.location];
uint32_t attrib = a.location;
if(attrib >= 0 && attrib < state.vertexShader.reflection->inputSignature.count())
if(attrib < state.vertexShader.reflection->inputSignature.size())
{
name = state.vertexShader.reflection->inputSignature[attrib].varName;
usedSlot = true;
+13 -1
View File
@@ -43,7 +43,8 @@ struct VertexAttribute
bool operator==(const VertexAttribute &o) const
{
return enabled == o.enabled && floatCast == o.floatCast && format == o.format &&
return enabled == o.enabled && floatCast == o.floatCast &&
boundShaderInput == o.boundShaderInput && format == o.format &&
!memcmp(&genericValue, &o.genericValue, sizeof(genericValue)) &&
vertexBufferSlot == o.vertexBufferSlot && byteOffset == o.byteOffset;
}
@@ -53,6 +54,8 @@ struct VertexAttribute
return enabled < o.enabled;
if(!(floatCast == o.floatCast))
return floatCast < o.floatCast;
if(!(boundShaderInput == o.boundShaderInput))
return boundShaderInput < o.boundShaderInput;
if(!(format == o.format))
return format < o.format;
if(memcmp(&genericValue, &o.genericValue, sizeof(genericValue)) < 0)
@@ -73,6 +76,15 @@ glVertexAttribIFormat) so they will be cast.
)");
bool floatCast = false;
DOCUMENT(R"(This lists which shader input is bound to this attribute, as an index in the
:data:`ShaderReflection.inputSignature` list.
If any value is set to ``-1`` then the attribute is unbound.
:type: int
)");
int32_t boundShaderInput = -1;
DOCUMENT(R"(The format describing how the vertex attribute is interpreted.
:type: ResourceFormat
+29 -58
View File
@@ -858,13 +858,7 @@ rdcarray<VertexInputAttribute> PipeState::GetVertexInputs() const
int num = 0;
for(int i = 0; i < attrs.count(); i++)
{
int attrib = -1;
if(m_GL->vertexShader.reflection != NULL)
attrib = m_GL->vertexShader.bindpointMapping.inputAttributes[i];
else
attrib = i;
if(attrib >= 0)
if(attrs[i].boundShaderInput >= 0)
num++;
}
@@ -887,15 +881,14 @@ rdcarray<VertexInputAttribute> PipeState::GetVertexInputs() const
if(m_GL->vertexShader.reflection != NULL)
{
int attrib = m_GL->vertexShader.bindpointMapping.inputAttributes[i];
int attrib = attrs[i].boundShaderInput;
if(attrib == -1 || attrib >= m_GL->vertexShader.reflection->inputSignature.count())
continue;
const SigParameter &sigParam = m_GL->vertexShader.reflection->inputSignature[attrib];
if(attrib >= 0 && attrib < m_GL->vertexShader.reflection->inputSignature.count())
ret[a].name = sigParam.varName;
if(attrib == -1)
continue;
ret[a].name = sigParam.varName;
VarType varType = sigParam.varType;
@@ -937,59 +930,37 @@ rdcarray<VertexInputAttribute> PipeState::GetVertexInputs() const
{
const rdcarray<VKPipe::VertexAttribute> &attrs = m_Vulkan->vertexInput.attributes;
int num = 0;
for(int i = 0; i < attrs.count(); i++)
{
int attrib = -1;
if(m_Vulkan->vertexShader.reflection != NULL)
{
if(attrs[i].location <
(uint32_t)m_Vulkan->vertexShader.bindpointMapping.inputAttributes.count())
attrib = m_Vulkan->vertexShader.bindpointMapping.inputAttributes[attrs[i].location];
}
else
attrib = i;
if(attrib >= 0)
num++;
}
int a = 0;
rdcarray<VertexInputAttribute> ret;
ret.resize(num);
for(int i = 0; i < attrs.count() && a < num; i++)
ret.resize(attrs.size());
for(size_t i = 0; i < attrs.size(); i++)
{
ret[a].name = "attr" + ToStr((uint32_t)i);
memset(&ret[a].genericValue, 0, sizeof(PixelValue));
ret[a].vertexBuffer = (int)attrs[i].binding;
ret[a].byteOffset = attrs[i].byteOffset;
ret[a].perInstance = false;
ret[a].instanceRate = 1;
if(attrs[i].binding < (uint32_t)m_Vulkan->vertexInput.bindings.count())
ret[i].name = "attr" + ToStr((uint32_t)i);
memset(&ret[i].genericValue, 0, sizeof(PixelValue));
ret[i].vertexBuffer = (int)attrs[i].binding;
ret[i].byteOffset = attrs[i].byteOffset;
ret[i].perInstance = false;
ret[i].instanceRate = 1;
if(attrs[i].binding < m_Vulkan->vertexInput.bindings.size())
{
ret[a].perInstance = m_Vulkan->vertexInput.bindings[attrs[i].binding].perInstance;
ret[a].instanceRate = m_Vulkan->vertexInput.bindings[attrs[i].binding].instanceDivisor;
ret[i].perInstance = m_Vulkan->vertexInput.bindings[attrs[i].binding].perInstance;
ret[i].instanceRate = m_Vulkan->vertexInput.bindings[attrs[i].binding].instanceDivisor;
}
ret[a].format = attrs[i].format;
ret[a].used = true;
ret[a].genericEnabled = false;
ret[i].format = attrs[i].format;
ret[i].used = true;
ret[i].genericEnabled = false;
if(m_Vulkan->vertexShader.reflection != NULL)
{
int attrib = -1;
if(attrs[i].location <
(uint32_t)m_Vulkan->vertexShader.bindpointMapping.inputAttributes.count())
attrib = m_Vulkan->vertexShader.bindpointMapping.inputAttributes[attrs[i].location];
if(attrib >= 0 && attrib < m_Vulkan->vertexShader.reflection->inputSignature.count())
ret[a].name = m_Vulkan->vertexShader.reflection->inputSignature[attrib].varName;
if(attrib == -1)
continue;
const rdcarray<SigParameter> &sig = m_Vulkan->vertexShader.reflection->inputSignature;
for(const SigParameter &attr : sig)
{
if(attr.regIndex == attrs[i].location && attr.systemValue == ShaderBuiltin::Undefined)
{
ret[i].name = attr.varName;
break;
}
}
}
a++;
}
return ret;
+3
View File
@@ -618,6 +618,9 @@ GLint GetNumVertexBuffers();
struct ShaderReflection;
struct ShaderBindpointMapping;
void EvaluateVertexAttributeBinds(GLuint curProg, const ShaderReflection *refl, bool spirv,
rdcarray<int32_t> &vertexAttrBindings);
void EvaluateSPIRVBindpointMapping(GLuint curProg, int shadIdx, const ShaderReflection *refl,
ShaderBindpointMapping &mapping);
+21
View File
@@ -1078,6 +1078,7 @@ void GLReplay::SavePipelineState(uint32_t eventId)
stages[i]->bindpointMapping = ShaderBindpointMapping();
}
rdcarray<int32_t> vertexAttrBindings;
if(curProg == 0)
{
drv.glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&curProg);
@@ -1119,10 +1120,16 @@ void GLReplay::SavePipelineState(uint32_t eventId)
spirv[i] = true;
EvaluateSPIRVBindpointMapping(curProg, (int)i, refls[i], stages[i]->bindpointMapping);
if(i == 0)
EvaluateVertexAttributeBinds(curProg, refls[i], true, vertexAttrBindings);
}
else
{
GetBindpointMapping(curProg, (int)i, refls[i], stages[i]->bindpointMapping);
if(i == 0)
EvaluateVertexAttributeBinds(curProg, refls[i], false, vertexAttrBindings);
}
mappings[i] = &stages[i]->bindpointMapping;
@@ -1164,10 +1171,16 @@ void GLReplay::SavePipelineState(uint32_t eventId)
spirv[i] = true;
EvaluateSPIRVBindpointMapping(curProg, (int)i, refls[i], stages[i]->bindpointMapping);
if(i == 0)
EvaluateVertexAttributeBinds(curProg, refls[i], true, vertexAttrBindings);
}
else
{
GetBindpointMapping(curProg, (int)i, refls[i], stages[i]->bindpointMapping);
if(i == 0)
EvaluateVertexAttributeBinds(curProg, refls[i], false, vertexAttrBindings);
}
mappings[i] = &stages[i]->bindpointMapping;
@@ -1182,6 +1195,14 @@ void GLReplay::SavePipelineState(uint32_t eventId)
}
}
for(size_t i = 0; i < pipe.vertexInput.attributes.size(); i++)
{
if(i < vertexAttrBindings.size())
pipe.vertexInput.attributes[i].boundShaderInput = vertexAttrBindings[i];
else
pipe.vertexInput.attributes[i].boundShaderInput = -1;
}
// !!!NOTE!!! This function will MODIFY the refls[] binding arrays.
// See inside this function for what it does and why.
for(size_t i = 0; i < ARRAY_COUNT(refls); i++)
+53
View File
@@ -2394,6 +2394,59 @@ void MakeShaderReflection(GLenum shadType, GLuint sepProg, ShaderReflection &ref
// TODO: fill in Interfaces with shader subroutines?
}
void EvaluateVertexAttributeBinds(GLuint curProg, const ShaderReflection *refl, bool spirv,
rdcarray<int32_t> &vertexAttrBindings)
{
GLint numVAttribBindings = 16;
GL.glGetIntegerv(eGL_MAX_VERTEX_ATTRIBS, &numVAttribBindings);
vertexAttrBindings.resize(numVAttribBindings);
for(int32_t i = 0; i < numVAttribBindings; i++)
vertexAttrBindings[i] = -1;
if(!refl)
return;
if(spirv)
{
for(size_t i = 0; i < refl->inputSignature.size(); i++)
if(refl->inputSignature[i].systemValue == ShaderBuiltin::Undefined)
return;
}
for(int32_t i = 0; i < refl->inputSignature.count(); i++)
{
// skip system inputs, as some drivers will return a location for them
if(refl->inputSignature[i].systemValue != ShaderBuiltin::Undefined)
continue;
// SPIR-V has fixed bindings
if(spirv)
{
vertexAttrBindings[refl->inputSignature[i].regIndex] = (int32_t)i;
continue;
}
int32_t matrixRow = 0;
rdcstr varName = refl->inputSignature[i].varName;
int32_t offs = varName.find(":col");
if(offs >= 0)
{
matrixRow = varName[offs + 4] - '0';
varName.resize(offs);
}
GLint loc = GL.glGetAttribLocation(curProg, varName.c_str());
if(loc >= 0 && loc < numVAttribBindings)
{
vertexAttrBindings[loc + matrixRow] = i;
}
}
}
void GetBindpointMapping(GLuint curProg, int shadIdx, const ShaderReflection *refl,
ShaderBindpointMapping &mapping)
{
+5 -14
View File
@@ -220,23 +220,14 @@ bool WrappedOpenGL::Check_SafeDraw(bool indexed)
{
const ShaderData &shaderDetails = m_Shaders[vs];
ShaderBindpointMapping mapping;
rdcarray<int32_t> vertexAttrBindings;
EvaluateVertexAttributeBinds(prog, shaderDetails.reflection, !shaderDetails.spirvWords.empty(),
vertexAttrBindings);
// get bindpoint mapping
if(!shaderDetails.spirvWords.empty())
{
mapping = shaderDetails.mapping;
EvaluateSPIRVBindpointMapping(prog, 0, shaderDetails.reflection, mapping);
}
else
{
GetBindpointMapping(prog, 0, shaderDetails.reflection, mapping);
}
for(int attrib = 0; attrib < mapping.inputAttributes.count(); attrib++)
for(int attrib = 0; attrib < vertexAttrBindings.count(); attrib++)
{
// skip attributes that don't map to the shader, they're unused
int reflIndex = mapping.inputAttributes[attrib];
int reflIndex = vertexAttrBindings[attrib];
if(reflIndex >= 0 && reflIndex < shaderDetails.reflection->inputSignature.count())
{
// check that this attribute is in-bounds, and enabled. If so then the driver will read from
+2 -1
View File
@@ -1785,12 +1785,13 @@ void DoSerialise(SerialiserType &ser, GLPipe::VertexAttribute &el)
{
SERIALISE_MEMBER(enabled);
SERIALISE_MEMBER(floatCast);
SERIALISE_MEMBER(boundShaderInput);
SERIALISE_MEMBER(format);
SERIALISE_MEMBER(genericValue);
SERIALISE_MEMBER(vertexBufferSlot);
SERIALISE_MEMBER(byteOffset);
SIZE_CHECK(32);
SIZE_CHECK(40);
}
template <typename SerialiserType>