Instead of tracking layout, query variable's offset & stride

* It's unfortunate to have to use program introspection so heavily like
  this (perhaps there should be a GL-specific shader reflection structure
  like DXBC where these locations and strides could be cached), but it's
  not too bad and handles any arbitrary layout
This commit is contained in:
baldurk
2014-08-14 17:08:45 +01:00
parent bd4efeedcd
commit 4352317f52
2 changed files with 85 additions and 42 deletions
+81 -38
View File
@@ -1171,12 +1171,12 @@ void GLReplay::SavePipelineState()
pipe.m_FB.Stencil = rm->GetOriginalID(rm->GetID(TextureRes(ctx, curStencil)));
}
void GLReplay::FillCBufferValue(WrappedOpenGL &gl, GLuint prog, bool bufferBacked, bool rowMajor, uint32_t locA, uint32_t locB,
size_t &dataoffset, const vector<byte> &data, ShaderVariable &outVar)
void GLReplay::FillCBufferValue(WrappedOpenGL &gl, GLuint prog, bool bufferBacked, bool rowMajor,
uint32_t offs, uint32_t matStride, const vector<byte> &data, ShaderVariable &outVar)
{
const byte *bufdata = data.empty() ? NULL : &data[dataoffset];
size_t datasize = data.size() - dataoffset;
if(dataoffset > data.size()) datasize = 0;
const byte *bufdata = data.empty() ? NULL : &data[offs];
size_t datasize = data.size() - offs;
if(offs > data.size()) datasize = 0;
if(bufferBacked)
{
@@ -1184,27 +1184,51 @@ void GLReplay::FillCBufferValue(WrappedOpenGL &gl, GLuint prog, bool bufferBacke
if(outVar.rows > 1 && outVar.columns > 1)
{
if(rowMajor) rangelen = outVar.rows*4*sizeof(float);
else rangelen = outVar.columns*4*sizeof(float);
uint32_t *dest = &outVar.value.uv[0];
if(rowMajor)
{
for(uint32_t r=0; r < outVar.rows; r++)
{
if(datasize > 0)
memcpy((byte *)dest, bufdata, RDCMIN(rangelen, outVar.columns*sizeof(float)));
datasize -= RDCMIN(datasize, matStride);
bufdata += matStride;
dest += outVar.columns;
}
}
else
{
for(uint32_t c=0; c < outVar.columns; c++)
{
if(datasize > 0)
memcpy((byte *)dest, bufdata, RDCMIN(rangelen, outVar.rows*sizeof(float)));
datasize -= RDCMIN(datasize, matStride);
bufdata += matStride;
dest += outVar.rows;
}
}
}
else
{
if(datasize > 0)
memcpy(&outVar.value.uv[0], bufdata, RDCMIN(rangelen, datasize));
}
if(datasize > 0)
memcpy(&outVar.value.uv[0], bufdata, RDCMIN(rangelen, datasize));
dataoffset += rangelen;
}
else
{
switch(outVar.type)
{
case eVar_Float:
gl.glGetUniformfv(prog, locA, outVar.value.fv);
gl.glGetUniformfv(prog, offs, outVar.value.fv);
break;
case eVar_Int:
gl.glGetUniformiv(prog, locA, outVar.value.iv);
gl.glGetUniformiv(prog, offs, outVar.value.iv);
break;
case eVar_UInt:
gl.glGetUniformuiv(prog, locA, outVar.value.uv);
gl.glGetUniformuiv(prog, offs, outVar.value.uv);
break;
case eVar_Double:
RDCUNIMPLEMENTED("Double uniform variables");
@@ -1223,9 +1247,9 @@ void GLReplay::FillCBufferValue(WrappedOpenGL &gl, GLuint prog, bool bufferBacke
}
}
void GLReplay::FillCBufferVariables(WrappedOpenGL &gl, GLuint prog, bool bufferBacked,
void GLReplay::FillCBufferVariables(WrappedOpenGL &gl, GLuint prog, bool bufferBacked, string prefix,
const rdctype::array<ShaderConstant> &variables, vector<ShaderVariable> &outvars,
size_t &dataoffset, const vector<byte> &data)
const vector<byte> &data)
{
for(int32_t i=0; i < variables.count; i++)
{
@@ -1242,7 +1266,7 @@ void GLReplay::FillCBufferVariables(WrappedOpenGL &gl, GLuint prog, bool bufferB
if(desc.elements == 1)
{
vector<ShaderVariable> ov;
FillCBufferVariables(gl, prog, bufferBacked, variables[i].type.members, ov, dataoffset, data);
FillCBufferVariables(gl, prog, bufferBacked, prefix + var.name.elems + ".", variables[i].type.members, ov, data);
var.members = ov;
}
else
@@ -1254,42 +1278,62 @@ void GLReplay::FillCBufferVariables(WrappedOpenGL &gl, GLuint prog, bool bufferB
arrEl.name = StringFormat::Fmt("%s[%u]", var.name.elems, a);
vector<ShaderVariable> ov;
FillCBufferVariables(gl, prog, bufferBacked, variables[i].type.members, ov, dataoffset, data);
FillCBufferVariables(gl, prog, bufferBacked, prefix + arrEl.name.elems + ".", variables[i].type.members, ov, data);
arrEl.members = ov;
arrelems.push_back(arrEl);
}
var.members = arrelems;
}
dataoffset = AlignUp16(dataoffset);
}
else
{
RDCEraseEl(var.value);
// need to query offset and strides as there's no way to know what layout was used
// (and if it's not an std layout it's implementation defined :( )
string fullname = prefix + var.name.elems;
if(desc.elements == 1)
GLuint idx = gl.glGetProgramResourceIndex(prog, eGL_UNIFORM, fullname.c_str());
if(idx == GL_INVALID_INDEX)
{
FillCBufferValue(gl, prog, bufferBacked, desc.rowMajorStorage ? true : false,
variables[i].reg.vec, variables[i].reg.comp, dataoffset, data, var);
RDCERR("Can't find program resource index for %hs", fullname.c_str());
}
else
{
vector<ShaderVariable> elems;
for(uint32_t a=0; a < desc.elements; a++)
GLenum props[] = { eGL_OFFSET, eGL_MATRIX_STRIDE, eGL_ARRAY_STRIDE, eGL_LOCATION };
GLint values[] = { 0, 0, 0, 0 };
gl.glGetProgramResourceiv(prog, eGL_UNIFORM, idx, ARRAY_COUNT(props), props, ARRAY_COUNT(props), NULL, values);
if(!bufferBacked)
{
ShaderVariable el = var;
el.name = StringFormat::Fmt("%s[%u]", var.name.elems, a);
uint32_t arrayoffs = bufferBacked ? a : a*sizeof(float)*4;
FillCBufferValue(gl, prog, bufferBacked, desc.rowMajorStorage ? true : false,
variables[i].reg.vec + arrayoffs, 0, dataoffset, data, el);
elems.push_back(el);
values[0] = values[3];
values[2] = 1;
}
var.members = elems;
if(desc.elements == 1)
{
FillCBufferValue(gl, prog, bufferBacked, desc.rowMajorStorage ? true : false,
values[0], values[1], data, var);
}
else
{
vector<ShaderVariable> elems;
for(uint32_t a=0; a < desc.elements; a++)
{
ShaderVariable el = var;
el.name = StringFormat::Fmt("%s[%u]", var.name.elems, a);
FillCBufferValue(gl, prog, bufferBacked, desc.rowMajorStorage ? true : false,
values[0] + values[2] * a, values[1], data, el);
elems.push_back(el);
}
var.members = elems;
}
}
}
@@ -1316,8 +1360,7 @@ void GLReplay::FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector
auto cblock = shaderDetails.reflection.ConstantBlocks.elems[cbufSlot];
size_t offs = 0;
FillCBufferVariables(gl, curProg, cblock.bufferBacked ? true : false, cblock.variables, outvars, offs, data);
FillCBufferVariables(gl, curProg, cblock.bufferBacked ? true : false, "", cblock.variables, outvars, data);
}
#pragma endregion
+4 -4
View File
@@ -131,11 +131,11 @@ class GLReplay : public IReplayDriver
void SetReplayData(GLWindowingData data);
private:
void FillCBufferValue(WrappedOpenGL &gl, GLuint prog, bool bufferBacked, bool rowMajor, uint32_t locA, uint32_t locB,
size_t &dataoffset, const vector<byte> &data, ShaderVariable &outVar);
void FillCBufferVariables(WrappedOpenGL &gl, GLuint prog, bool bufferBacked,
void FillCBufferValue(WrappedOpenGL &gl, GLuint prog, bool bufferBacked, bool rowMajor, uint32_t offs, uint32_t matStride,
const vector<byte> &data, ShaderVariable &outVar);
void FillCBufferVariables(WrappedOpenGL &gl, GLuint prog, bool bufferBacked, string prefix,
const rdctype::array<ShaderConstant> &variables, vector<ShaderVariable> &outvars,
size_t &dataoffset, const vector<byte> &data);
const vector<byte> &data);
void GetMapping(WrappedOpenGL &gl, GLuint curProg, int shadIdx, ShaderReflection *refl, ShaderBindpointMapping &mapping);