Don't require ARB_separate_shader_objects on replay

* If it's not available we must also emulate program introspection to get proper
  reflection data.
This commit is contained in:
baldurk
2019-03-13 11:48:24 +00:00
parent 4d60276ea0
commit e1d39ef23b
7 changed files with 136 additions and 177 deletions
+3 -5
View File
@@ -19,13 +19,11 @@ On OpenGL ES, any context version 2.0 and above is supported.
Replay requirements
-------------------
RenderDoc assumes a certain minimum feature set on replay. On desktop this means you must be able to create a 3.2 context with the ``GL_ARB_separate_shader_objects`` extension available.
RenderDoc assumes a certain minimum feature set on replay. On desktop this means you must be able to create a 3.2 core context.
Theis extension should not require newer hardware than the base 3.2 context, but it might need an updated driver to be listed as available.
Also note that this is the *minimum* required functionality to replay, some analysis features will be disabled unless you have more capable hardware features such as GL_ARB_shader_image_load_store, GL_ARB_compute_shader and GL_ARB_gpu_shader5.
Also note that this is the *minimum* required extension set to replay, some analysis features will be disabled unless you have more capable hardware features such as GL_ARB_shader_image_load_store, GL_ARB_compute_shader and GL_ARB_gpu_shader5.
On OpenGL ES, you must be able to create a GLES 3 context to replay, again with the above ``GL_ARB_separate_shader_objects`` extension.
On OpenGL ES, you must be able to create a GLES 3 context to replay.
Multiple contexts & multithreading
----------------------------------
+10 -21
View File
@@ -106,27 +106,6 @@ bool CheckReplayContext()
if(!extensionString.empty())
RDCLOG("%s", extensionString.c_str());
string missingExts = "";
#define REQUIRE_EXTENSION(extname) \
if(!exts[extname]) \
missingExts += STRINGIZE(extname) " ";
// we require the below extensions on top of a 3.2 context. Some of these we could in theory
// do without, but support for them is so widespread it's not worthwhile
// needed for program pipelines, glProgramUniform*, and reflecting shaders on their own
// Possible to remove this with self-compiled SPIR-V for reflection - see above. Likewise
// convenience for our own pipelines when replacing single shaders or such.
REQUIRE_EXTENSION(ARB_separate_shader_objects);
if(!missingExts.empty())
{
RDCERR("RenderDoc requires these missing extensions: %s. Try updating your drivers.",
missingExts.c_str());
return false;
}
return true;
}
@@ -459,6 +438,16 @@ void FetchEnabledExtensions()
for(const std::string &e : extlist)
CheckExtFromString(e.c_str());
}
if(!HasExt[ARB_separate_shader_objects])
{
if(HasExt[ARB_program_interface_query])
RDCWARN(
"Because ARB_separate_shader_objects is not supported, forcibly disabling "
"ARB_program_interface_query");
HasExt[ARB_program_interface_query] = false;
}
}
void DoVendorChecks(GLPlatform &platform, GLWindowingData context)
+1 -2
View File
@@ -569,14 +569,13 @@ public:
struct ShaderData
{
ShaderData() : type(eGL_NONE), prog(0), version(0) {}
ShaderData() : type(eGL_NONE), 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
+37 -44
View File
@@ -77,10 +77,8 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
ShaderReflection *tesRefl = NULL;
ShaderReflection *gsRefl = NULL;
// non-program used separable programs of each shader.
// vsProg we can use on its own as there are no other stages to combine with, but for later stages
// we need the shaders themselves to re-link into a single program.
GLuint vsProg = 0;
// the program we'll be binding, that we attach shaders to
GLuint feedbackProg = drv.glCreateProgram();
// one shader per stage (vs = 0, etc)
GLuint stageShaders[4] = {};
@@ -123,7 +121,6 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
if(i == 0)
{
vsRefl = GetShader(pipeDetails.stageShaders[i], ShaderEntryPoint());
vsProg = m_pDriver->m_Shaders[pipeDetails.stageShaders[i]].prog;
}
else if(i == 2)
{
@@ -183,7 +180,6 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
if(i == 0)
{
vsRefl = GetShader(progDetails.stageShaders[0], ShaderEntryPoint());
vsProg = m_pDriver->m_Shaders[progDetails.stageShaders[0]].prog;
}
else if(i == 2 && progDetails.stageShaders[2] != ResourceId())
{
@@ -215,10 +211,13 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
return;
}
// attach the vertex shader
drv.glAttachShader(feedbackProg, stageShaders[0]);
list<string> matrixVaryings; // matrices need some fixup
vector<const char *> varyings;
CopyProgramAttribBindings(stageSrcPrograms[0], vsProg, vsRefl);
CopyProgramAttribBindings(stageSrcPrograms[0], feedbackProg, vsRefl);
varyings.clear();
@@ -323,11 +322,11 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
for(;;)
{
// specify current varyings & relink
drv.glTransformFeedbackVaryings(vsProg, (GLsizei)varyings.size(), &varyings[0],
drv.glTransformFeedbackVaryings(feedbackProg, (GLsizei)varyings.size(), &varyings[0],
eGL_INTERLEAVED_ATTRIBS);
drv.glLinkProgram(vsProg);
drv.glLinkProgram(feedbackProg);
drv.glGetProgramiv(vsProg, eGL_LINK_STATUS, &status);
drv.glGetProgramiv(feedbackProg, eGL_LINK_STATUS, &status);
// all good! Hopefully we'll mostly hit this
if(status == 1)
@@ -339,7 +338,7 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
break;
char buffer[1025] = {0};
drv.glGetProgramInfoLog(vsProg, 1024, NULL, buffer);
drv.glGetProgramInfoLog(feedbackProg, 1024, NULL, buffer);
// assume we're finished and can't retry any more after this.
// if we find a potential 'fixup' we'll set this back to false
@@ -386,7 +385,7 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
if(status == 0)
{
char buffer[1025] = {0};
drv.glGetProgramInfoLog(vsProg, 1024, NULL, buffer);
drv.glGetProgramInfoLog(feedbackProg, 1024, NULL, buffer);
RDCERR("Failed to fix-up. Link error making xfb vs program: %s", buffer);
m_PostVSData[eventId] = GLPostVSData();
@@ -395,18 +394,20 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
if(tmpShaders[i])
drv.glDeleteShader(tmpShaders[i]);
drv.glDeleteProgram(feedbackProg);
return;
}
// copy across any uniform values, bindings etc from the real program containing
// the vertex stage
CopyProgramUniforms(stageSrcPrograms[0], vsProg);
CopyProgramUniforms(stageSrcPrograms[0], feedbackProg);
// we don't want to do any work, so just discard before rasterizing
drv.glEnable(eGL_RASTERIZER_DISCARD);
// bind our program and do the feedback draw
drv.glUseProgram(vsProg);
drv.glUseProgram(feedbackProg);
drv.glBindProgramPipeline(0);
drv.glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, DebugData.feedbackObj);
@@ -702,6 +703,8 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
if(tmpShaders[i])
drv.glDeleteShader(tmpShaders[i]);
drv.glDeleteProgram(feedbackProg);
return;
}
@@ -800,12 +803,6 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
m_PostVSData[eventId].vsout.topo = drawcall->topology;
// set vsProg back to no varyings, for future use
drv.glTransformFeedbackVaryings(vsProg, 0, NULL, eGL_INTERLEAVED_ATTRIBS);
drv.glLinkProgram(vsProg);
GLuint lastFeedbackProg = 0;
if(tesRefl || gsRefl)
{
ShaderReflection *lastRefl = gsRefl;
@@ -815,12 +812,10 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
RDCASSERT(lastRefl);
lastFeedbackProg = drv.glCreateProgram();
// attach the shaders
for(int i = 0; i < 4; i++)
// attach the other non-vertex shaders
for(int i = 1; i < 4; i++)
if(stageShaders[i])
drv.glAttachShader(lastFeedbackProg, stageShaders[i]);
drv.glAttachShader(feedbackProg, stageShaders[i]);
varyings.clear();
@@ -876,11 +871,11 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
for(;;)
{
// specify current varyings & relink
drv.glTransformFeedbackVaryings(lastFeedbackProg, (GLsizei)varyings.size(), &varyings[0],
drv.glTransformFeedbackVaryings(feedbackProg, (GLsizei)varyings.size(), &varyings[0],
eGL_INTERLEAVED_ATTRIBS);
drv.glLinkProgram(lastFeedbackProg);
drv.glLinkProgram(feedbackProg);
drv.glGetProgramiv(lastFeedbackProg, eGL_LINK_STATUS, &status);
drv.glGetProgramiv(feedbackProg, eGL_LINK_STATUS, &status);
// all good! Hopefully we'll mostly hit this
if(status == 1)
@@ -892,7 +887,7 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
break;
char buffer[1025] = {0};
drv.glGetProgramInfoLog(lastFeedbackProg, 1024, NULL, buffer);
drv.glGetProgramInfoLog(feedbackProg, 1024, NULL, buffer);
// assume we're finished and can't retry any more after this.
// if we find a potential 'fixup' we'll set this back to false
@@ -940,33 +935,33 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
// detach the shaders now that linking is complete
for(int i = 0; i < 4; i++)
if(stageShaders[i])
drv.glDetachShader(lastFeedbackProg, stageShaders[i]);
drv.glDetachShader(feedbackProg, stageShaders[i]);
if(status == 0)
{
char buffer[1025] = {0};
drv.glGetProgramInfoLog(lastFeedbackProg, 1024, NULL, buffer);
drv.glGetProgramInfoLog(feedbackProg, 1024, NULL, buffer);
RDCERR("Failed to fix-up. Link error making xfb last program: %s", buffer);
}
else
{
// copy across any uniform values, bindings etc from the real program containing
// the vertex stage
CopyProgramUniforms(stageSrcPrograms[0], lastFeedbackProg);
CopyProgramUniforms(stageSrcPrograms[0], feedbackProg);
// if tessellation is enabled, bind & copy uniforms. Note, control shader is optional
// independent of eval shader (default values are used for the tessellation levels).
if(stageSrcPrograms[1])
CopyProgramUniforms(stageSrcPrograms[1], lastFeedbackProg);
CopyProgramUniforms(stageSrcPrograms[1], feedbackProg);
if(stageSrcPrograms[2])
CopyProgramUniforms(stageSrcPrograms[2], lastFeedbackProg);
CopyProgramUniforms(stageSrcPrograms[2], feedbackProg);
// if we have a geometry shader, bind & copy uniforms
if(stageSrcPrograms[3])
CopyProgramUniforms(stageSrcPrograms[3], lastFeedbackProg);
CopyProgramUniforms(stageSrcPrograms[3], feedbackProg);
// bind our program and do the feedback draw
drv.glUseProgram(lastFeedbackProg);
drv.glUseProgram(feedbackProg);
drv.glBindProgramPipeline(0);
drv.glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, DebugData.feedbackObj);
@@ -1042,11 +1037,11 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
if(lastRefl == gsRefl)
{
drv.glGetProgramiv(lastFeedbackProg, eGL_GEOMETRY_OUTPUT_TYPE, (GLint *)&shaderOutMode);
drv.glGetProgramiv(feedbackProg, eGL_GEOMETRY_OUTPUT_TYPE, (GLint *)&shaderOutMode);
GLint maxVerts = 1;
drv.glGetProgramiv(lastFeedbackProg, eGL_GEOMETRY_VERTICES_OUT, (GLint *)&maxVerts);
drv.glGetProgramiv(feedbackProg, eGL_GEOMETRY_VERTICES_OUT, (GLint *)&maxVerts);
if(shaderOutMode == eGL_TRIANGLE_STRIP)
{
@@ -1068,7 +1063,7 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
}
else if(lastRefl == tesRefl)
{
drv.glGetProgramiv(lastFeedbackProg, eGL_TESS_GEN_MODE, (GLint *)&shaderOutMode);
drv.glGetProgramiv(feedbackProg, eGL_TESS_GEN_MODE, (GLint *)&shaderOutMode);
uint32_t outputPrimitiveVerts = 1;
@@ -1289,8 +1284,7 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
if(error)
{
// delete temporary program we made
if(lastFeedbackProg)
drv.glDeleteProgram(lastFeedbackProg);
drv.glDeleteProgram(feedbackProg);
// restore replay state we trashed
drv.glUseProgram(rs.Program.name);
@@ -1429,9 +1423,8 @@ void GLReplay::InitPostVSBuffers(uint32_t eventId)
}
}
// delete temporary pipelines we made
if(lastFeedbackProg)
drv.glDeleteProgram(lastFeedbackProg);
// delete temporary program we made
drv.glDeleteProgram(feedbackProg);
// restore replay state we trashed
drv.glUseProgram(rs.Program.name);
+7 -7
View File
@@ -703,22 +703,22 @@ rdcarray<ShaderEntryPoint> GLReplay::GetShaderEntryPoints(ResourceId shader)
WrappedOpenGL::ShaderData &shaderDetails = m_pDriver->m_Shaders[shader];
if(shaderDetails.prog == 0)
if(shaderDetails.reflection.resourceId == ResourceId())
{
RDCERR("Can't get shader details without separable program");
RDCERR("Can't get shader details without successful reflect");
return {};
}
return {{"main", MakeShaderStage(shaderDetails.type)}};
return {{shaderDetails.reflection.entryPoint, shaderDetails.reflection.stage}};
}
ShaderReflection *GLReplay::GetShader(ResourceId shader, ShaderEntryPoint entry)
{
auto &shaderDetails = m_pDriver->m_Shaders[shader];
if(shaderDetails.prog == 0)
if(shaderDetails.reflection.resourceId == ResourceId())
{
RDCERR("Can't get shader details without separable program");
RDCERR("Can't get shader details without successful reflect");
return NULL;
}
@@ -996,7 +996,7 @@ void GLReplay::SavePipelineState()
auto &shaderDetails = m_pDriver->m_Shaders[pipeDetails.stageShaders[i]];
if(shaderDetails.prog == 0)
if(shaderDetails.reflection.resourceId == ResourceId())
stages[i]->reflection = refls[i] = NULL;
else
stages[i]->reflection = refls[i] = &shaderDetails.reflection;
@@ -1038,7 +1038,7 @@ void GLReplay::SavePipelineState()
{
auto &shaderDetails = m_pDriver->m_Shaders[progDetails.stageShaders[i]];
if(shaderDetails.prog == 0)
if(shaderDetails.reflection.resourceId == ResourceId())
stages[i]->reflection = refls[i] = NULL;
else
stages[i]->reflection = refls[i] = &shaderDetails.reflection;
+10 -6
View File
@@ -2351,7 +2351,7 @@ static ReflectionProperty ConvertProperty(GLenum prop)
return ret;
}
static glslang::TProgram *GetGlslangProgram(GLuint program)
static glslang::TProgram *GetGlslangProgram(GLuint program, bool *hasRealProgram = NULL)
{
if(driver == NULL)
{
@@ -2366,6 +2366,9 @@ static glslang::TProgram *GetGlslangProgram(GLuint program)
RDCERR("Don't have glslang program for reflecting program %u = %s", program, ToStr(id).c_str());
}
if(hasRealProgram)
*hasRealProgram = !driver->m_Programs[id].shaders.empty();
return driver->m_Programs[id].glslangProgram;
}
@@ -2388,7 +2391,8 @@ void APIENTRY _glGetProgramResourceiv(GLuint program, GLenum programInterface, G
GLsizei propCount, const GLenum *props, GLsizei bufSize,
GLsizei *length, GLint *params)
{
glslang::TProgram *glslangProgram = GetGlslangProgram(program);
bool hasRealProgram = true;
glslang::TProgram *glslangProgram = GetGlslangProgram(program, &hasRealProgram);
if(!glslangProgram)
{
@@ -2417,7 +2421,7 @@ void APIENTRY _glGetProgramResourceiv(GLuint program, GLenum programInterface, G
const char *name =
glslangGetProgramResourceName(glslangProgram, ConvertInterface(programInterface), index);
if(GL.glGetUniformLocation)
if(GL.glGetUniformLocation && hasRealProgram)
params[i] = GL.glGetUniformLocation(program, name);
}
else if(programInterface == eGL_PROGRAM_INPUT && params[i] < 0)
@@ -2425,7 +2429,7 @@ void APIENTRY _glGetProgramResourceiv(GLuint program, GLenum programInterface, G
const char *name =
glslangGetProgramResourceName(glslangProgram, ConvertInterface(programInterface), index);
if(GL.glGetAttribLocation)
if(GL.glGetAttribLocation && hasRealProgram)
params[i] = GL.glGetAttribLocation(program, name);
}
else if(programInterface == eGL_PROGRAM_OUTPUT && params[i] < 0)
@@ -2433,7 +2437,7 @@ void APIENTRY _glGetProgramResourceiv(GLuint program, GLenum programInterface, G
const char *name =
glslangGetProgramResourceName(glslangProgram, ConvertInterface(programInterface), index);
if(GL.glGetFragDataLocation)
if(GL.glGetFragDataLocation && hasRealProgram)
params[i] = GL.glGetFragDataLocation(program, name);
}
}
@@ -2444,7 +2448,7 @@ void APIENTRY _glGetProgramResourceiv(GLuint program, GLenum programInterface, G
const char *name =
glslangGetProgramResourceName(glslangProgram, ConvertInterface(programInterface), index);
if(GL.glGetUniformBlockIndex)
if(GL.glGetUniformBlockIndex && hasRealProgram)
{
GLuint blockIndex = GL.glGetUniformBlockIndex(program, name);
if(blockIndex != GL_INVALID_INDEX && GL.glGetActiveUniformBlockiv)
@@ -80,41 +80,6 @@ void WrappedOpenGL::ShaderData::ProcessSPIRVCompilation(WrappedOpenGL &drv, Reso
specIDs.assign(pConstantIndex, pConstantIndex + numSpecializationConstants);
specValues.assign(pConstantValue, pConstantValue + numSpecializationConstants);
}
GLuint sepshader = GL.glCreateShader(type);
if(sepshader)
{
GL.glShaderBinary(1, &sepshader, eGL_SHADER_BINARY_FORMAT_SPIR_V, reflection.rawBytes.data(),
(GLsizei)reflection.rawBytes.size());
GL.glSpecializeShader(sepshader, pEntryPoint, numSpecializationConstants, pConstantIndex,
pConstantValue);
GLint compiled = 0;
GL.glGetShaderiv(sepshader, eGL_COMPILE_STATUS, &compiled);
if(compiled)
{
prog = GL.glCreateProgram();
GL.glAttachShader(prog, sepshader);
GL.glProgramParameteri(prog, eGL_PROGRAM_SEPARABLE, GL_TRUE);
GL.glLinkProgram(prog);
drv.glGetProgramiv(prog, eGL_LINK_STATUS, &compiled);
if(!compiled)
{
RDCERR("Re-compiled but couldn't link SPIR-V program");
}
}
else
{
RDCERR("Couldn't re-compile SPIR-V shader");
}
GL.glDeleteShader(sepshader);
}
}
void WrappedOpenGL::ShaderData::ProcessCompilation(WrappedOpenGL &drv, ResourceId id,
@@ -224,8 +189,6 @@ void WrappedOpenGL::ShaderData::ProcessCompilation(WrappedOpenGL &drv, ResourceI
if(version == 0)
version = 100;
GLuint sepProg = prog;
GLint status = 0;
if(realShader == 0)
status = 1;
@@ -243,48 +206,87 @@ void WrappedOpenGL::ShaderData::ProcessCompilation(WrappedOpenGL &drv, ResourceI
// reflection
drv.PushInternalShader();
if(sepProg == 0 && status == 1)
sepProg = MakeSeparableShaderProgram(drv, type, sources, NULL);
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
{
prog = sepProg;
MakeShaderReflection(type, sepProg, reflection, outputUsage);
bool reflected = false;
vector<uint32_t> spirvwords;
// if we have separate shader object support, we can create a separable program and reflect it
// - this may or may not be emulated depending on if ARB_program_interface_query is supported.
if(HasExt[ARB_separate_shader_objects])
{
GLuint sepProg = MakeSeparableShaderProgram(drv, type, sources, NULL);
SPIRVCompilationSettings settings(SPIRVSourceLanguage::OpenGLGLSL,
SPIRVShaderStage(ShaderIdx(type)));
if(sepProg == 0)
{
RDCERR(
"Couldn't make separable program for shader via patching - functionality will be "
"broken.");
}
else
{
MakeShaderReflection(type, sepProg, reflection, outputUsage);
reflected = true;
string s = CompileSPIRV(settings, sources, spirvwords);
if(!spirvwords.empty())
ParseSPIRV(&spirvwords.front(), spirvwords.size(), spirv);
drv.glDeleteProgram(sepProg);
}
}
else
disassembly = s;
{
// if we don't have separate shader objects, we manually reflect directly with glslang to
// avoid having to litter MakeSeparableShaderProgram() and child functions with checks about
// whether separable programs are actually supported or if we're just faking it to reflect.
// In this case we forcibly emulate ARB_program_interface_query.
RDCASSERT(!HasExt[ARB_program_interface_query]);
reflection.resourceId = id;
reflection.entryPoint = "main";
// to do this, we need to create an empty program object and manually configure its glslang
// program.
GLuint fakeProgram = drv.glCreateProgram();
reflection.stage = MakeShaderStage(type);
ResourceId progid = drv.GetResourceManager()->GetID(ProgramRes(drv.GetCtx(), fakeProgram));
reflection.encoding = ShaderEncoding::GLSL;
reflection.rawBytes.assign((byte *)concatenated.c_str(), concatenated.size());
ProgramData &progDetails = drv.m_Programs[progid];
reflection.debugInfo.encoding = ShaderEncoding::GLSL;
progDetails.linked = true;
reflection.debugInfo.files.resize(1);
reflection.debugInfo.files[0].filename = "main.glsl";
reflection.debugInfo.files[0].contents = concatenated;
progDetails.glslangProgram = LinkProgramForReflection({glslangShader});
MakeShaderReflection(type, fakeProgram, reflection, outputUsage);
reflected = true;
drv.glDeleteProgram(fakeProgram);
}
if(reflected)
{
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);
else
disassembly = s;
reflection.resourceId = id;
reflection.entryPoint = "main";
reflection.stage = MakeShaderStage(type);
reflection.encoding = ShaderEncoding::GLSL;
reflection.rawBytes.assign((byte *)concatenated.c_str(), concatenated.size());
reflection.debugInfo.encoding = ShaderEncoding::GLSL;
reflection.debugInfo.files.resize(1);
reflection.debugInfo.files[0].filename = "main.glsl";
reflection.debugInfo.files[0].contents = concatenated;
}
}
drv.PopInternalShader();
@@ -400,10 +402,8 @@ bool WrappedOpenGL::Serialise_glShaderSource(SerialiserType &ser, GLuint shaderH
// Doing this means we support the case of recompiling a shader different ways
// and relinking a program before use, which is still moderately crazy and
// so people who do that should be moderately ashamed.
if(m_Shaders[liveId].prog)
if(m_Shaders[liveId].reflection.resourceId != ResourceId())
{
glDeleteProgram(m_Shaders[liveId].prog);
m_Shaders[liveId].prog = 0;
m_Shaders[liveId].spirv = SPVModule();
m_Shaders[liveId].reflection = ShaderReflection();
}
@@ -682,9 +682,6 @@ bool WrappedOpenGL::Serialise_glCreateShaderProgramv(SerialiserType &ser, GLenum
src.push_back(strings[i]);
GLuint real = GL.glCreateShaderProgramv(type, count, strings);
// we want a separate program that we can mess about with for making overlays
// and relink without having to worry about restoring the 'real' program state.
GLuint sepprog = MakeSeparableShaderProgram(*this, type, src, NULL);
GLResource res = ProgramRes(GetCtx(), real);
@@ -701,7 +698,6 @@ bool WrappedOpenGL::Serialise_glCreateShaderProgramv(SerialiserType &ser, GLenum
shadDetails.type = type;
shadDetails.sources.swap(src);
shadDetails.prog = sepprog;
shadDetails.ProcessCompilation(*this, Program, 0);
@@ -747,27 +743,7 @@ GLuint WrappedOpenGL::glCreateShaderProgramv(GLenum type, GLsizei count, const G
}
else
{
GetResourceManager()->AddLiveResource(id, res);
vector<string> src;
for(GLsizei i = 0; i < count; i++)
src.push_back(strings[i]);
GLuint sepprog = MakeSeparableShaderProgram(*this, type, src, NULL);
auto &progDetails = m_Programs[id];
progDetails.linked = true;
progDetails.shaders.push_back(id);
progDetails.stageShaders[ShaderIdx(type)] = id;
auto &shadDetails = m_Shaders[id];
shadDetails.type = type;
shadDetails.sources.swap(src);
shadDetails.prog = sepprog;
shadDetails.ProcessCompilation(*this, id, 0);
RDCERR("Should not use glCreateShaderProgramv internally on replay");
}
return real;