mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 17:40:39 +00:00
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:
@@ -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
|
||||
----------------------------------
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user