diff --git a/docs/behind_scenes/opengl_support.rst b/docs/behind_scenes/opengl_support.rst index 5051935c5..127ebdbae 100644 --- a/docs/behind_scenes/opengl_support.rst +++ b/docs/behind_scenes/opengl_support.rst @@ -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 ---------------------------------- diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index 8a1871c10..26e120700 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -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) diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 4b51fddc1..82158d438 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -569,14 +569,13 @@ public: struct ShaderData { - ShaderData() : type(eGL_NONE), prog(0), version(0) {} + ShaderData() : type(eGL_NONE), version(0) {} GLenum type; vector sources; vector 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 diff --git a/renderdoc/driver/gl/gl_postvs.cpp b/renderdoc/driver/gl/gl_postvs.cpp index efc622b45..315fdd317 100644 --- a/renderdoc/driver/gl/gl_postvs.cpp +++ b/renderdoc/driver/gl/gl_postvs.cpp @@ -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 matrixVaryings; // matrices need some fixup vector 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); diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 395f075d6..726151e1c 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -703,22 +703,22 @@ rdcarray 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; diff --git a/renderdoc/driver/gl/wrappers/gl_emulated.cpp b/renderdoc/driver/gl/wrappers/gl_emulated.cpp index 045ab7708..22141a255 100644 --- a/renderdoc/driver/gl/wrappers/gl_emulated.cpp +++ b/renderdoc/driver/gl/wrappers/gl_emulated.cpp @@ -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) diff --git a/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp index 035303918..9fe4b870d 100644 --- a/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp @@ -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 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 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 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;