Emulate ARB_program_interface_query using glslang's reflection

* In particular it wasn't added until GLES 3.1, and we need it during capture to
  determine the uniforms and other things, so we emulate the subset of queries
  that we need ourselves.
This commit is contained in:
baldurk
2018-07-06 17:09:11 +01:00
parent f00832f2f9
commit 08616c9ad1
8 changed files with 668 additions and 122 deletions
+3 -3
View File
@@ -580,11 +580,11 @@ WrappedOpenGL::WrappedOpenGL(GLPlatform &platform)
m_DeviceRecord = m_ContextRecord = NULL;
ResourceIDGen::SetReplayResourceIDs();
InitSPIRVCompiler();
RenderDoc::Inst().RegisterShutdownFunction(&ShutdownSPIRVCompiler);
}
InitSPIRVCompiler();
RenderDoc::Inst().RegisterShutdownFunction(&ShutdownSPIRVCompiler);
m_FakeBB_FBO = 0;
m_FakeBB_Color = 0;
m_FakeBB_DepthStencil = 0;
+79 -72
View File
@@ -252,78 +252,6 @@ private:
map<ResourceId, BufferData> m_Buffers;
// map with key being mip level, value being stored data
typedef std::map<int, std::vector<byte>> CompressedDataStore;
struct ShaderData
{
ShaderData() : type(eGL_NONE), prog(0), version(0) {}
GLenum type;
vector<string> sources;
vector<string> includepaths;
SPVModule spirv;
std::string disassembly;
ShaderReflection reflection;
GLuint prog;
int version;
// used for if the application actually uploaded SPIR-V
std::vector<uint32_t> spirvWords;
// the parameters passed to glSpecializeShader
std::string entryPoint;
std::vector<uint32_t> specIDs;
std::vector<uint32_t> specValues;
// pre-calculated bindpoint mapping for SPIR-V shaders. NOT valid for normal GLSL shaders
ShaderBindpointMapping mapping;
void ProcessCompilation(WrappedOpenGL &drv, ResourceId id, GLuint realShader);
void ProcessSPIRVCompilation(WrappedOpenGL &drv, ResourceId id, GLuint realShader,
const GLchar *pEntryPoint, GLuint numSpecializationConstants,
const GLuint *pConstantIndex, const GLuint *pConstantValue);
};
struct ProgramData
{
ProgramData() : linked(false) { RDCEraseEl(stageShaders); }
vector<ResourceId> shaders;
map<GLint, GLint> locationTranslate;
// this flag indicates the program was created with glCreateShaderProgram and cannot be relinked
// again (because that function implicitly detaches and destroys the shader). However we only
// need to relink when restoring things like frag data or attrib bindings which must be relinked
// to apply - and since the application *also* could not have relinked them, they must be
// unchanged since creation. So in this case, we can skip the relink since it was impossible for
// the application to modify anything.
bool shaderProgramUnlinkable = false;
bool linked;
ResourceId stageShaders[6];
};
struct PipelineData
{
PipelineData()
{
RDCEraseEl(stagePrograms);
RDCEraseEl(stageShaders);
}
struct ProgramUse
{
ProgramUse(ResourceId id_, GLbitfield use_) : id(id_), use(use_) {}
ResourceId id;
GLbitfield use;
};
ResourceId stagePrograms[6];
ResourceId stageShaders[6];
};
map<ResourceId, ShaderData> m_Shaders;
map<ResourceId, ProgramData> m_Programs;
map<ResourceId, PipelineData> m_Pipelines;
vector<pair<ResourceId, Replacement>> m_DependentReplacements;
GLuint m_FakeBB_FBO;
@@ -612,6 +540,85 @@ public:
void StartFrameCapture(void *dev, void *wnd);
bool EndFrameCapture(void *dev, void *wnd);
// map with key being mip level, value being stored data
typedef std::map<int, std::vector<byte>> CompressedDataStore;
struct ShaderData
{
ShaderData() : type(eGL_NONE), prog(0), version(0) {}
GLenum type;
vector<string> sources;
vector<string> includepaths;
SPVModule spirv;
std::string disassembly;
ShaderReflection reflection;
GLuint prog;
int version;
// used only when we're capturing and don't have driver-side reflection so we need to emulate
glslang::TShader *glslangShader = NULL;
// used for if the application actually uploaded SPIR-V
std::vector<uint32_t> spirvWords;
// the parameters passed to glSpecializeShader
std::string entryPoint;
std::vector<uint32_t> specIDs;
std::vector<uint32_t> specValues;
// pre-calculated bindpoint mapping for SPIR-V shaders. NOT valid for normal GLSL shaders
ShaderBindpointMapping mapping;
void ProcessCompilation(WrappedOpenGL &drv, ResourceId id, GLuint realShader);
void ProcessSPIRVCompilation(WrappedOpenGL &drv, ResourceId id, GLuint realShader,
const GLchar *pEntryPoint, GLuint numSpecializationConstants,
const GLuint *pConstantIndex, const GLuint *pConstantValue);
};
struct ProgramData
{
ProgramData() : linked(false) { RDCEraseEl(stageShaders); }
vector<ResourceId> shaders;
map<GLint, GLint> locationTranslate;
// this flag indicates the program was created with glCreateShaderProgram and cannot be relinked
// again (because that function implicitly detaches and destroys the shader). However we only
// need to relink when restoring things like frag data or attrib bindings which must be relinked
// to apply - and since the application *also* could not have relinked them, they must be
// unchanged since creation. So in this case, we can skip the relink since it was impossible for
// the application to modify anything.
bool shaderProgramUnlinkable = false;
bool linked;
ResourceId stageShaders[6];
// used only when we're capturing and don't have driver-side reflection so we need to emulate
glslang::TProgram *glslangProgram = NULL;
};
struct PipelineData
{
PipelineData()
{
RDCEraseEl(stagePrograms);
RDCEraseEl(stageShaders);
}
struct ProgramUse
{
ProgramUse(ResourceId id_, GLbitfield use_) : id(id_), use(use_) {}
ResourceId id;
GLbitfield use;
};
ResourceId stagePrograms[6];
ResourceId stageShaders[6];
};
std::map<ResourceId, ShaderData> m_Shaders;
std::map<ResourceId, ProgramData> m_Programs;
std::map<ResourceId, PipelineData> m_Pipelines;
struct TextureData
{
TextureData()
+15 -10
View File
@@ -764,19 +764,24 @@ static void ForAllProgramUniforms(SerialiserType *ser, CaptureState state, GLuin
}
// apply SSBO bindings
for(const ProgramBinding &bind : serialisedUniforms.SSBOBindings)
// GLES does not allow modification of SSBO bindings - which is good as we don't need to restore
// them, since they're immutable.
if(!IsGLES)
{
GLuint idx = GL.glGetProgramResourceIndex(progDst, eGL_SHADER_STORAGE_BLOCK, bind.Name.c_str());
if(idx != GL_INVALID_INDEX)
for(const ProgramBinding &bind : serialisedUniforms.SSBOBindings)
{
if(GL.glShaderStorageBlockBinding)
GLuint idx =
GL.glGetProgramResourceIndex(progDst, eGL_SHADER_STORAGE_BLOCK, bind.Name.c_str());
if(idx != GL_INVALID_INDEX)
{
GL.glShaderStorageBlockBinding(progDst, idx, bind.Binding);
}
else
{
// TODO glShaderStorageBlockBinding is not core GLES
RDCERR("glShaderStorageBlockBinding is not supported!");
if(GL.glShaderStorageBlockBinding)
{
GL.glShaderStorageBlockBinding(progDst, idx, bind.Binding);
}
else
{
RDCERR("glShaderStorageBlockBinding is not supported!");
}
}
}
}
@@ -30,6 +30,7 @@
#include "driver/gl/gl_dispatch_table.h"
#include "driver/gl/gl_driver.h"
#include "driver/gl/gl_resources.h"
#include "driver/shaders/spirv/spirv_common.h"
namespace glEmulate
{
@@ -1386,6 +1387,199 @@ void APIENTRY _glClearBufferData(GLenum target, GLenum internalformat, GLenum fo
#pragma region GLES Compatibility
static ReflectionInterface ConvertInterface(GLenum programInterface)
{
ReflectionInterface ret = ReflectionInterface::Uniform;
switch(programInterface)
{
case eGL_PROGRAM_INPUT: ret = ReflectionInterface::Input; break;
case eGL_PROGRAM_OUTPUT: ret = ReflectionInterface::Output; break;
case eGL_UNIFORM: ret = ReflectionInterface::Uniform; break;
case eGL_UNIFORM_BLOCK: ret = ReflectionInterface::UniformBlock; break;
case eGL_SHADER_STORAGE_BLOCK: ret = ReflectionInterface::ShaderStorageBlock; break;
case eGL_ATOMIC_COUNTER_BUFFER: ret = ReflectionInterface::AtomicCounterBuffer; break;
default:
RDCERR("Unexpected program interface being queried: %s", ToStr(programInterface).c_str());
break;
}
return ret;
}
static ReflectionProperty ConvertProperty(GLenum prop)
{
ReflectionProperty ret = ReflectionProperty::ActiveResources;
switch(prop)
{
case eGL_ACTIVE_RESOURCES: ret = ReflectionProperty::ActiveResources; break;
case eGL_BUFFER_BINDING: ret = ReflectionProperty::BufferBinding; break;
case eGL_TOP_LEVEL_ARRAY_STRIDE: ret = ReflectionProperty::TopLevelArrayStride; break;
case eGL_BLOCK_INDEX: ret = ReflectionProperty::BlockIndex; break;
case eGL_ARRAY_SIZE: ret = ReflectionProperty::ArraySize; break;
case eGL_IS_ROW_MAJOR: ret = ReflectionProperty::IsRowMajor; break;
case eGL_NUM_ACTIVE_VARIABLES: ret = ReflectionProperty::NumActiveVariables; break;
case eGL_BUFFER_DATA_SIZE: ret = ReflectionProperty::BufferDataSize; break;
case eGL_NAME_LENGTH: ret = ReflectionProperty::NameLength; break;
case eGL_TYPE: ret = ReflectionProperty::Type; break;
case eGL_LOCATION_COMPONENT: ret = ReflectionProperty::LocationComponent; break;
case eGL_REFERENCED_BY_VERTEX_SHADER: ret = ReflectionProperty::ReferencedByVertexShader; break;
case eGL_REFERENCED_BY_TESS_CONTROL_SHADER:
ret = ReflectionProperty::ReferencedByTessControlShader;
break;
case eGL_REFERENCED_BY_TESS_EVALUATION_SHADER:
ret = ReflectionProperty::ReferencedByTessEvaluationShader;
break;
case eGL_REFERENCED_BY_GEOMETRY_SHADER:
ret = ReflectionProperty::ReferencedByGeometryShader;
break;
case eGL_REFERENCED_BY_FRAGMENT_SHADER:
ret = ReflectionProperty::ReferencedByFragmentShader;
break;
case eGL_REFERENCED_BY_COMPUTE_SHADER:
ret = ReflectionProperty::ReferencedByComputeShader;
break;
case eGL_ATOMIC_COUNTER_BUFFER_INDEX: ret = ReflectionProperty::AtomicCounterBufferIndex; break;
case eGL_OFFSET: ret = ReflectionProperty::Offset; break;
case eGL_MATRIX_STRIDE: ret = ReflectionProperty::MatrixStride; break;
case eGL_ARRAY_STRIDE: ret = ReflectionProperty::ArrayStride; break;
case eGL_LOCATION: ret = ReflectionProperty::Location; break;
default: RDCERR("Unexpected program property being queried: %s", ToStr(prop).c_str()); break;
}
return ret;
}
void APIENTRY _glGetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname,
GLint *params)
{
if(driver == NULL)
{
RDCERR("No driver available, can't emulate glGetProgramInterfaceiv");
*params = 0;
return;
}
ResourceId id = driver->GetResourceManager()->GetID(ProgramRes(driver->GetCtx(), program));
WrappedOpenGL::ProgramData &details = driver->m_Programs[id];
if(!details.glslangProgram)
{
*params = 0;
return;
}
glslangGetProgramInterfaceiv(details.glslangProgram, ConvertInterface(programInterface),
ConvertProperty(pname), params);
}
void APIENTRY _glGetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index,
GLsizei propCount, const GLenum *props, GLsizei bufSize,
GLsizei *length, GLint *params)
{
if(driver == NULL)
{
RDCERR("No driver available, can't emulate glGetProgramResourceiv");
if(length)
*length = 0;
if(params)
memset(params, 0, sizeof(GLint) * bufSize);
return;
}
ResourceId id = driver->GetResourceManager()->GetID(ProgramRes(driver->GetCtx(), program));
WrappedOpenGL::ProgramData &details = driver->m_Programs[id];
if(!details.glslangProgram)
{
if(length)
*length = 0;
if(params)
memset(params, 0, sizeof(GLint) * bufSize);
return;
}
std::vector<ReflectionProperty> properties(propCount);
for(GLsizei i = 0; i < propCount; i++)
properties[i] = ConvertProperty(props[i]);
glslangGetProgramResourceiv(details.glslangProgram, ConvertInterface(programInterface), index,
properties, bufSize, length, params);
// fetch locations by hand from the driver
for(GLsizei i = 0; i < propCount; i++)
{
if(props[i] == eGL_LOCATION)
{
if(params[i] >= 0)
{
const char *name = glslangGetProgramResourceName(details.glslangProgram,
ConvertInterface(programInterface), index);
if(programInterface == eGL_UNIFORM)
params[i] = GL.glGetUniformLocation(program, name);
else if(programInterface == eGL_PROGRAM_INPUT)
params[i] = GL.glGetAttribLocation(program, name);
else
params[i] = index;
}
}
}
}
void APIENTRY _glGetProgramResourceName(GLuint program, GLenum programInterface, GLuint index,
GLsizei bufSize, GLsizei *length, GLchar *name)
{
if(driver == NULL)
{
RDCERR("No driver available, can't emulate glGetProgramResourceName");
if(length)
*length = 0;
if(name && bufSize)
memset(name, 0, bufSize);
return;
}
ResourceId id = driver->GetResourceManager()->GetID(ProgramRes(driver->GetCtx(), program));
WrappedOpenGL::ProgramData &details = driver->m_Programs[id];
if(!details.glslangProgram)
{
if(length)
*length = 0;
if(name && bufSize)
memset(name, 0, bufSize);
return;
}
const char *fetchedName = glslangGetProgramResourceName(
details.glslangProgram, ConvertInterface(programInterface), index);
if(fetchedName)
{
size_t nameLen = strlen(fetchedName);
if(length)
*length = (int32_t)nameLen;
memcpy(name, fetchedName, RDCMIN((size_t)bufSize, nameLen));
name[bufSize - 1] = 0;
if(nameLen < (size_t)bufSize)
name[nameLen] = 0;
}
else
{
if(length)
*length = 0;
if(name && bufSize)
memset(name, 0, bufSize);
}
}
void APIENTRY _glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
{
if(driver == NULL)
@@ -1812,6 +2006,10 @@ void GLDispatchTable::EmulateRequiredExtensions()
{
EMULATE_FUNC(glGetTexLevelParameteriv);
EMULATE_FUNC(glGetTexLevelParameterfv);
EMULATE_FUNC(glGetProgramInterfaceiv);
EMULATE_FUNC(glGetProgramResourceiv);
EMULATE_FUNC(glGetProgramResourceName);
}
if(GLCoreVersion < 32)
@@ -234,42 +234,50 @@ void WrappedOpenGL::ShaderData::ProcessCompilation(WrappedOpenGL &drv, ResourceI
else
drv.glGetShaderiv(realShader, eGL_COMPILE_STATUS, &status);
if(sepProg == 0 && status == 1)
sepProg = MakeSeparableShaderProgram(drv, type, sources, NULL);
if(status == 0)
if(IsCaptureMode(drv.GetState()))
{
RDCDEBUG("Real shader failed to compile, so skipping separable program and reflection.");
}
else if(sepProg == 0)
{
RDCERR(
"Couldn't make separable program for shader via patching - functionality will be broken.");
glslangShader = CompileShaderForReflection(SPIRVShaderStage(ShaderIdx(type)), sources);
}
else
{
prog = sepProg;
MakeShaderReflection(type, sepProg, reflection, pointSizeUsed, clipDistanceUsed);
if(sepProg == 0 && status == 1)
sepProg = MakeSeparableShaderProgram(drv, type, sources, NULL);
vector<uint32_t> spirvwords;
SPIRVCompilationSettings settings(SPIRVSourceLanguage::OpenGLGLSL,
SPIRVShaderStage(ShaderIdx(type)));
string s = CompileSPIRV(settings, sources, spirvwords);
if(!spirvwords.empty())
ParseSPIRV(&spirvwords.front(), spirvwords.size(), spirv);
if(status == 0)
{
RDCDEBUG("Real shader failed to compile, so skipping separable program and reflection.");
}
else if(sepProg == 0)
{
RDCERR(
"Couldn't make separable program for shader via patching - functionality will be "
"broken.");
}
else
disassembly = s;
{
prog = sepProg;
MakeShaderReflection(type, sepProg, reflection, pointSizeUsed, clipDistanceUsed);
reflection.resourceId = id;
reflection.entryPoint = "main";
vector<uint32_t> spirvwords;
reflection.stage = MakeShaderStage(type);
SPIRVCompilationSettings settings(SPIRVSourceLanguage::OpenGLGLSL,
SPIRVShaderStage(ShaderIdx(type)));
reflection.debugInfo.files.resize(1);
reflection.debugInfo.files[0].filename = "main.glsl";
reflection.debugInfo.files[0].contents = concatenated;
string s = CompileSPIRV(settings, sources, spirvwords);
if(!spirvwords.empty())
ParseSPIRV(&spirvwords.front(), spirvwords.size(), spirv);
else
disassembly = s;
reflection.resourceId = id;
reflection.entryPoint = "main";
reflection.stage = MakeShaderStage(type);
reflection.debugInfo.files.resize(1);
reflection.debugInfo.files[0].filename = "main.glsl";
reflection.debugInfo.files[0].contents = concatenated;
}
}
}
@@ -330,10 +338,10 @@ GLuint WrappedOpenGL::glCreateShader(GLenum type)
else
{
GetResourceManager()->AddLiveResource(id, res);
m_Shaders[id].type = type;
}
m_Shaders[id].type = type;
return real;
}
@@ -415,7 +423,10 @@ void WrappedOpenGL::glShaderSource(GLuint shader, GLsizei count, const GLchar *c
record->AddChunk(scope.Get());
}
}
else
// if we're capturing and don't have ARB_program_interface_query we're going to have to emulate
// it using glslang for compilation and reflection
if(IsReplayMode(m_State) || !HasExt[ARB_program_interface_query])
{
ResourceId id = GetResourceManager()->GetID(ShaderRes(GetCtx(), shader));
m_Shaders[id].sources.clear();
@@ -466,10 +477,14 @@ void WrappedOpenGL::glCompileShader(GLuint shader)
record->AddChunk(scope.Get());
}
}
else
{
ResourceId id = GetResourceManager()->GetID(ShaderRes(GetCtx(), shader));
m_Shaders[id].ProcessCompilation(*this, id, shader);
// if we're capturing and don't have ARB_program_interface_query we're going to have to emulate
// it using glslang for compilation and reflection
if(IsReplayMode(m_State) || !HasExt[ARB_program_interface_query])
m_Shaders[id].ProcessCompilation(*this, id, shader);
}
}
@@ -539,7 +554,10 @@ void WrappedOpenGL::glAttachShader(GLuint program, GLuint shader)
progRecord->AddChunk(scope.Get());
}
}
else
// if we're capturing and don't have ARB_program_interface_query we're going to have to emulate
// it using glslang for compilation and reflection
if(IsReplayMode(m_State) || !HasExt[ARB_program_interface_query])
{
ResourceId progid = GetResourceManager()->GetID(ProgramRes(GetCtx(), program));
ResourceId shadid = GetResourceManager()->GetID(ShaderRes(GetCtx(), shader));
@@ -608,7 +626,10 @@ void WrappedOpenGL::glDetachShader(GLuint program, GLuint shader)
progRecord->AddChunk(scope.Get());
}
}
else
// if we're capturing and don't have ARB_program_interface_query we're going to have to emulate
// it using glslang for compilation and reflection
if(IsReplayMode(m_State) || !HasExt[ARB_program_interface_query])
{
ResourceId progid = GetResourceManager()->GetID(ProgramRes(GetCtx(), program));
ResourceId shadid = GetResourceManager()->GetID(ShaderRes(GetCtx(), shader));
@@ -797,7 +818,7 @@ GLuint WrappedOpenGL::glCreateProgram()
record->AddChunk(chunk);
}
else
{
GetResourceManager()->AddLiveResource(id, res);
@@ -857,7 +878,7 @@ void WrappedOpenGL::glLinkProgram(GLuint program)
record->AddChunk(scope.Get());
}
}
else
{
ResourceId progid = GetResourceManager()->GetID(ProgramRes(GetCtx(), program));
@@ -873,6 +894,25 @@ void WrappedOpenGL::glLinkProgram(GLuint program)
progDetails.stageShaders[s] = progDetails.shaders[sh];
}
}
if(IsCaptureMode(m_State) && !HasExt[ARB_program_interface_query])
{
std::vector<glslang::TShader *> glslangShaders;
for(ResourceId id : progDetails.shaders)
{
glslang::TShader *s = m_Shaders[id].glslangShader;
if(s == NULL)
{
RDCERR("Shader attached with no compiled glslang reflection shader!");
continue;
}
glslangShaders.push_back(m_Shaders[id].glslangShader);
}
progDetails.glslangProgram = LinkProgramForReflection(glslangShaders);
}
}
}
@@ -31,6 +31,8 @@
#include "3rdparty/glslang/glslang/Public/ShaderLang.h"
static bool inited = false;
std::vector<glslang::TShader *> allocatedShaders;
std::vector<glslang::TProgram *> allocatedPrograms;
void InitSPIRVCompiler()
{
@@ -45,6 +47,16 @@ void ShutdownSPIRVCompiler()
{
if(inited)
{
// programs must be deleted before shaders
for(glslang::TProgram *program : allocatedPrograms)
delete program;
for(glslang::TShader *shader : allocatedShaders)
delete shader;
allocatedPrograms.clear();
allocatedShaders.clear();
glslang::FinalizeProcess();
}
}
@@ -276,3 +288,174 @@ void FillSpecConstantVariables(const rdcarray<ShaderConstant> &invars,
}
}
}
void glslangGetProgramInterfaceiv(glslang::TProgram *program, ReflectionInterface programInterface,
ReflectionProperty pname, int32_t *params)
{
*params = 0;
if(pname == ReflectionProperty::ActiveResources)
{
switch(programInterface)
{
case ReflectionInterface::Input: *params = program->getNumLiveAttributes(); break;
case ReflectionInterface::Output:
// unsupported
*params = 0;
break;
case ReflectionInterface::Uniform: *params = program->getNumLiveUniformVariables(); break;
case ReflectionInterface::UniformBlock: *params = program->getNumLiveUniformBlocks(); break;
case ReflectionInterface::ShaderStorageBlock:
// unsupported
*params = 0;
break;
case ReflectionInterface::AtomicCounterBuffer:
// unsupported
*params = 0;
break;
}
}
else
{
RDCERR("Unsupported reflection property %d", pname);
}
}
void glslangGetProgramResourceiv(glslang::TProgram *program, ReflectionInterface programInterface,
uint32_t index, const std::vector<ReflectionProperty> &props,
int32_t bufSize, int32_t *length, int32_t *params)
{
if(programInterface == ReflectionInterface::Output ||
programInterface == ReflectionInterface::ShaderStorageBlock ||
programInterface == ReflectionInterface::AtomicCounterBuffer)
{
RDCWARN("unsupported program interface");
}
// all of our properties are single-element values, so we just loop up to buffer size or number of
// properties, whichever comes first.
for(size_t i = 0; i < RDCMIN((size_t)bufSize, props.size()); i++)
{
switch(props[i])
{
case ReflectionProperty::ActiveResources:
RDCERR("Unhandled reflection property ActiveResources");
params[i] = 0;
break;
case ReflectionProperty::BufferBinding:
RDCASSERT(programInterface == ReflectionInterface::UniformBlock);
params[i] = program->getUniformBlockBinding(index);
break;
case ReflectionProperty::TopLevelArrayStride:
// TODO glslang doesn't give us this
params[i] = 16;
break;
case ReflectionProperty::BlockIndex:
RDCASSERT(programInterface == ReflectionInterface::Uniform);
params[i] = program->getUniformBlockIndex(index);
break;
case ReflectionProperty::ArraySize:
if(programInterface == ReflectionInterface::Uniform)
params[i] = program->getUniformArraySize(index);
else if(programInterface == ReflectionInterface::Input)
// TODO assuming all inputs are non-arrayed
params[i] = 1;
else
RDCERR("Unsupported interface for ArraySize query");
break;
case ReflectionProperty::IsRowMajor:
// TODO glslang doesn't expose this, assume column major.
params[i] = 0;
break;
case ReflectionProperty::NumActiveVariables:
// TODO glslang doesn't give us this
params[i] = 1;
break;
case ReflectionProperty::BufferDataSize:
RDCASSERT(programInterface == ReflectionInterface::UniformBlock);
params[i] = program->getUniformBlockSize(index);
break;
case ReflectionProperty::NameLength:
// The name length includes a terminating null character.
if(programInterface == ReflectionInterface::Uniform)
params[i] = (int32_t)strlen(program->getUniformName(index)) + 1;
else if(programInterface == ReflectionInterface::UniformBlock)
params[i] = (int32_t)strlen(program->getUniformBlockName(index)) + 1;
else if(programInterface == ReflectionInterface::Input)
params[i] = (int32_t)strlen(program->getAttributeName(index)) + 1;
else
RDCERR("Unsupported interface for NameLEngth query");
break;
case ReflectionProperty::Type:
if(programInterface == ReflectionInterface::Uniform)
params[i] = program->getUniformType(index);
else if(programInterface == ReflectionInterface::Input)
params[i] = program->getAttributeType(index);
else
RDCERR("Unsupported interface for Type query");
break;
case ReflectionProperty::LocationComponent:
// TODO glslang doesn't give us this information
params[i] = 0;
break;
case ReflectionProperty::ReferencedByVertexShader:
case ReflectionProperty::ReferencedByTessControlShader:
case ReflectionProperty::ReferencedByTessEvaluationShader:
case ReflectionProperty::ReferencedByGeometryShader:
case ReflectionProperty::ReferencedByFragmentShader:
case ReflectionProperty::ReferencedByComputeShader:
// TODO glslang doesn't give us this information
params[i] = 1;
break;
case ReflectionProperty::AtomicCounterBufferIndex:
RDCERR("Atomic counters not supported");
break;
case ReflectionProperty::Offset:
RDCASSERT(programInterface == ReflectionInterface::Uniform);
params[i] = program->getUniformBufferOffset(index);
break;
case ReflectionProperty::MatrixStride:
RDCASSERT(programInterface == ReflectionInterface::Uniform);
// TODO glslang doesn't give us this information
params[i] = 64;
break;
case ReflectionProperty::ArrayStride:
RDCASSERT(programInterface == ReflectionInterface::Uniform);
// TODO glslang doesn't give us this information
params[i] = 64;
break;
case ReflectionProperty::Location:
// have to query the actual implementation, which is handled elsewhere. We return either -1
// for uniforms that don't have a location (i.e. are in a block) or 0 for bare uniforms
if(programInterface == ReflectionInterface::Uniform)
params[i] = program->getUniformBlockIndex(index) >= 0 ? -1 : 0;
else if(programInterface == ReflectionInterface::Input)
params[i] = index;
break;
}
}
}
const char *glslangGetProgramResourceName(glslang::TProgram *program,
ReflectionInterface programInterface, uint32_t index)
{
const char *fetchedName = "";
switch(programInterface)
{
case ReflectionInterface::Input: fetchedName = program->getAttributeName(index); break;
case ReflectionInterface::Output: RDCWARN("Output attributes unsupported"); break;
case ReflectionInterface::Uniform: fetchedName = program->getUniformName(index); break;
case ReflectionInterface::UniformBlock:
fetchedName = program->getUniformBlockName(index);
break;
case ReflectionInterface::ShaderStorageBlock:
RDCWARN("shader storage blocks unsupported");
break;
case ReflectionInterface::AtomicCounterBuffer:
RDCWARN("atomic counter buffers unsupported");
break;
}
return fetchedName;
}
+57 -1
View File
@@ -159,4 +159,60 @@ struct SpecConstant
void FillSpecConstantVariables(const rdcarray<ShaderConstant> &invars,
std::vector<ShaderVariable> &outvars,
const std::vector<SpecConstant> &specInfo);
const std::vector<SpecConstant> &specInfo);
namespace glslang
{
class TShader;
class TProgram;
};
glslang::TShader *CompileShaderForReflection(SPIRVShaderStage stage,
const std::vector<std::string> &sources);
glslang::TProgram *LinkProgramForReflection(const std::vector<glslang::TShader *> &shaders);
enum class ReflectionInterface
{
Input,
Output,
Uniform,
UniformBlock,
ShaderStorageBlock,
AtomicCounterBuffer,
};
enum class ReflectionProperty
{
ActiveResources,
BufferBinding,
TopLevelArrayStride,
BlockIndex,
ArraySize,
IsRowMajor,
NumActiveVariables,
BufferDataSize,
NameLength,
Type,
LocationComponent,
ReferencedByVertexShader,
ReferencedByTessControlShader,
ReferencedByTessEvaluationShader,
ReferencedByGeometryShader,
ReferencedByFragmentShader,
ReferencedByComputeShader,
AtomicCounterBufferIndex,
Offset,
MatrixStride,
ArrayStride,
Location,
};
void glslangGetProgramInterfaceiv(glslang::TProgram *program, ReflectionInterface programInterface,
ReflectionProperty pname, int32_t *params);
void glslangGetProgramResourceiv(glslang::TProgram *program, ReflectionInterface programInterface,
uint32_t index, const std::vector<ReflectionProperty> &props,
int32_t bufSize, int32_t *length, int32_t *params);
const char *glslangGetProgramResourceName(glslang::TProgram *program,
ReflectionInterface programInterface, uint32_t index);
@@ -212,3 +212,60 @@ string CompileSPIRV(const SPIRVCompilationSettings &settings,
return errors;
}
extern std::vector<glslang::TShader *> allocatedShaders;
extern std::vector<glslang::TProgram *> allocatedPrograms;
glslang::TShader *CompileShaderForReflection(SPIRVShaderStage stage,
const std::vector<std::string> &sources)
{
EShLanguage lang = EShLanguage(stage);
glslang::TShader *shader = new glslang::TShader(lang);
const char **strs = new const char *[sources.size()];
for(size_t i = 0; i < sources.size(); i++)
strs[i] = sources[i].c_str();
shader->setStrings(strs, (int)sources.size());
if(shader->parse(&DefaultResources, 100, false, EShMsgRelaxedErrors))
{
allocatedShaders.push_back(shader);
return shader;
}
else
{
RDCERR("glslang failed to compile shader:\n\n%s\n\n%s", shader->getInfoLog(),
shader->getInfoDebugLog());
delete shader;
return NULL;
}
}
glslang::TProgram *LinkProgramForReflection(const std::vector<glslang::TShader *> &shaders)
{
glslang::TProgram *program = new glslang::TProgram();
for(glslang::TShader *shader : shaders)
program->addShader(shader);
if(program->link(EShMsgDefault))
{
program->buildReflection();
allocatedPrograms.push_back(program);
return program;
}
else
{
RDCERR("glslang failed to link program:\n\n%s\n\n%s", program->getInfoLog(),
program->getInfoDebugLog());
delete program;
return NULL;
}
}