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:57 +00:00
parent 4d60276ea0
commit e1d39ef23b
7 changed files with 136 additions and 177 deletions
+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;