void CopyProgramFragDataBindings(const GLHookSet &gl, GLuint progsrc, GLuint progdst, ShaderReflection *refl) { uint64_t used = 0; // copy over fragdata bindings for(size_t i = 0; i < refl->outputSignature.size(); i++) { // only look at colour outputs (should be the only outputs from fs) if(refl->outputSignature[i].systemValue != ShaderBuiltin::ColorOutput) continue; if(!strncmp("gl_", refl->outputSignature[i].varName.c_str(), 3)) continue; // GL_INVALID_OPERATION if name starts with reserved gl_ prefix GLint idx = gl.glGetFragDataLocation(progsrc, refl->outputSignature[i].varName.c_str()); if(idx >= 0) { uint64_t mask = 1ULL << idx; if(used & mask) { RDCWARN("Multiple signatures bound to output %zu, ignoring %s", i, refl->outputSignature[i].varName.c_str()); continue; } used |= mask; if(gl.glBindFragDataLocation) { gl.glBindFragDataLocation(progdst, (GLuint)idx, refl->outputSignature[i].varName.c_str()); } else { // glBindFragDataLocation is not core GLES, but it is in GL_EXT_blend_func_extended // TODO what to do if that extension is not supported RDCERR("glBindFragDataLocation is not supported!"); } } } }
void SerialiseProgramBindings(SerialiserType &ser, CaptureState state, const GLHookSet &gl, GLuint prog) { std::vector<ProgramBinding> InputBindings; std::vector<ProgramBinding> OutputBindings; if(ser.IsWriting()) { char buf[128] = {}; for(int sigType = 0; sigType < 2; sigType++) { GLenum sigEnum = (sigType == 0 ? eGL_PROGRAM_INPUT : eGL_PROGRAM_OUTPUT); std::vector<ProgramBinding> &bindings = (sigType == 0 ? InputBindings : OutputBindings); int32_t NumAttributes = 0; gl.glGetProgramInterfaceiv(prog, sigEnum, eGL_ACTIVE_RESOURCES, (GLint *)&NumAttributes); bindings.reserve(NumAttributes); for(GLint i = 0; i < NumAttributes; i++) { gl.glGetProgramResourceName(prog, sigEnum, i, 128, NULL, buf); ProgramBinding bind; bind.Name = buf; if(sigType == 0) bind.Binding = gl.glGetAttribLocation(prog, buf); else bind.Binding = gl.glGetFragDataLocation(prog, buf); bindings.push_back(bind); } } } SERIALISE_ELEMENT(InputBindings); SERIALISE_ELEMENT(OutputBindings); if(ser.IsReading() && IsReplayMode(state)) { for(int sigType = 0; sigType < 2; sigType++) { const std::vector<ProgramBinding> &bindings = (sigType == 0 ? InputBindings : OutputBindings); uint64_t used = 0; for(const ProgramBinding &bind : bindings) { if(bind.Binding >= 0) { uint64_t mask = 1ULL << bind.Binding; if(used & mask) { RDCWARN("Multiple %s items bound to location %d, ignoring %s", sigType == 0 ? "attrib" : "fragdata", bind.Binding, bind.Name.c_str()); continue; } used |= mask; if(!strncmp("gl_", bind.Name.c_str(), 3)) continue; // GL_INVALID_OPERATION if name starts with reserved gl_ prefix (for both // glBindAttribLocation and glBindFragDataLocation) if(sigType == 0) { gl.glBindAttribLocation(prog, (GLuint)bind.Binding, bind.Name.c_str()); } else { if(gl.glBindFragDataLocation) { gl.glBindFragDataLocation(prog, (GLuint)bind.Binding, bind.Name.c_str()); } else { // glBindFragDataLocation is not core GLES, but it is in GL_EXT_blend_func_extended // TODO what to do if that extension is not supported RDCERR("glBindFragDataLocation is not supported!"); } } } } } } }