void CopyProgramAttribBindings(const GLHookSet &gl, GLuint progsrc, GLuint progdst, ShaderReflection *refl) { // copy over attrib bindings for(const SigParameter &sig : refl->inputSignature) { // skip built-ins if(sig.systemValue != ShaderBuiltin::Undefined) continue; GLint idx = gl.glGetAttribLocation(progsrc, sig.varName.c_str()); if(idx >= 0) gl.glBindAttribLocation(progdst, (GLuint)idx, sig.varName.c_str()); } }
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 GetFramebufferMipAndLayer(const GLHookSet &gl, GLenum framebuffer, GLenum attachment, GLint *mip, GLint *layer) { gl.glGetFramebufferAttachmentParameteriv(framebuffer, attachment, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, mip); GLenum face = eGL_NONE; gl.glGetFramebufferAttachmentParameteriv( framebuffer, attachment, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE, (GLint *)&face); if(face == 0) { gl.glGetFramebufferAttachmentParameteriv(framebuffer, attachment, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER, layer); } else { *layer = CubeTargetIndex(face); } }
int GetNumMips(const GLHookSet &gl, GLenum target, GLuint tex, GLuint w, GLuint h, GLuint d) { int mips = 1; GLint immut = 0; gl.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_IMMUTABLE_FORMAT, &immut); if(immut) gl.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_IMMUTABLE_LEVELS, (GLint *)&mips); else mips = CalcNumMips(w, h, d); GLint maxLevel = 1000; gl.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_MAX_LEVEL, &maxLevel); mips = RDCMIN(mips, maxLevel+1); if(immut == 0) { // check to see if all mips are set, or clip the number of mips to those that are // set. if(target == eGL_TEXTURE_CUBE_MAP) target = eGL_TEXTURE_CUBE_MAP_POSITIVE_X; for(int i=0; i < mips; i++) { GLint width = 0; gl.glGetTextureLevelParameterivEXT(tex, target, i, eGL_TEXTURE_WIDTH, &width); if(width == 0) { mips = i; break; } } } return RDCMAX(1, mips); }
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!"); } } } } } } }
static void ForAllProgramUniforms(SerialiserType *ser, CaptureState state, const GLHookSet &gl, GLuint progSrc, GLuint progDst, map<GLint, GLint> *locTranslate) { const bool ReadSourceProgram = CopyUniforms || (SerialiseUniforms && ser && ser->IsWriting()); const bool WriteDestProgram = CopyUniforms || (SerialiseUniforms && ser && ser->IsReading()); RDCCOMPILE_ASSERT((CopyUniforms && !SerialiseUniforms) || (!CopyUniforms && SerialiseUniforms), "Invalid call to ForAllProgramUniforms"); // this struct will be serialised with the uniform binding data, or if we're just copying it will // be used to store the data fetched from the source program, before being applied to the // destination program. It's slightly redundant since we could unify the loops (as the code used // to do) but it's much better for code organisation and clarity to have a single path whether // serialising or not. ProgramUniforms serialisedUniforms; // if we're reading the source program, iterate over the interfaces and fetch the data. if(CheckConstParam(ReadSourceProgram)) { const size_t numProps = 5; GLenum resProps[numProps] = { eGL_BLOCK_INDEX, eGL_TYPE, eGL_NAME_LENGTH, eGL_ARRAY_SIZE, eGL_LOCATION, }; GLint values[numProps]; GLint NumUniforms = 0; gl.glGetProgramInterfaceiv(progSrc, eGL_UNIFORM, eGL_ACTIVE_RESOURCES, &NumUniforms); // this is a very conservative figure - many uniforms will be in UBOs and so will be ignored serialisedUniforms.ValueUniforms.reserve(NumUniforms); for(GLint i = 0; i < NumUniforms; i++) { GLenum type = eGL_NONE; int32_t arraySize = 0; int32_t srcLocation = 0; string basename; bool isArray = false; gl.glGetProgramResourceiv(progSrc, eGL_UNIFORM, i, numProps, resProps, numProps, NULL, values); // we don't need to consider uniforms within UBOs if(values[0] >= 0) continue; // get the metadata we need for fetching the data type = (GLenum)values[1]; arraySize = values[3]; srcLocation = values[4]; char n[1024] = {0}; gl.glGetProgramResourceName(progSrc, eGL_UNIFORM, i, values[2], NULL, n); if(arraySize > 1) { isArray = true; size_t len = strlen(n); if(n[len - 3] == '[' && n[len - 2] == '0' && n[len - 1] == ']') n[len - 3] = 0; } else { arraySize = 1; } basename = n; // push it onto the list serialisedUniforms.ValueUniforms.push_back(ProgramUniform()); ProgramUniform &uniform = serialisedUniforms.ValueUniforms.back(); uniform.Basename = basename; uniform.IsArray = isArray; uniform.Values.resize(arraySize); // loop over every element in the array (arraySize = 1 for non arrays) for(GLint arr = 0; arr < arraySize; arr++) { ProgramUniformValue &uniformVal = uniform.Values[arr]; uniformVal.Type = type; uniformVal.Location = srcLocation; std::string name = basename; // append the subscript if this item is an array. if(isArray) { name += StringFormat::Fmt("[%d]", arr); uniformVal.Location = srcLocation = gl.glGetUniformLocation(progSrc, name.c_str()); } // fetch the data into the ProgramUniformValue, with the appropriate method for its type double *dv = uniformVal.data.dval; float *fv = uniformVal.data.fval; int32_t *iv = uniformVal.data.ival; uint32_t *uiv = uniformVal.data.uval; switch(type) { case eGL_FLOAT_MAT4: case eGL_FLOAT_MAT4x3: case eGL_FLOAT_MAT4x2: case eGL_FLOAT_MAT3: case eGL_FLOAT_MAT3x4: case eGL_FLOAT_MAT3x2: case eGL_FLOAT_MAT2: case eGL_FLOAT_MAT2x4: case eGL_FLOAT_MAT2x3: case eGL_FLOAT: case eGL_FLOAT_VEC2: case eGL_FLOAT_VEC3: case eGL_FLOAT_VEC4: gl.glGetUniformfv(progSrc, srcLocation, fv); break; case eGL_DOUBLE_MAT4: case eGL_DOUBLE_MAT4x3: case eGL_DOUBLE_MAT4x2: case eGL_DOUBLE_MAT3: case eGL_DOUBLE_MAT3x4: case eGL_DOUBLE_MAT3x2: case eGL_DOUBLE_MAT2: case eGL_DOUBLE_MAT2x4: case eGL_DOUBLE_MAT2x3: case eGL_DOUBLE: case eGL_DOUBLE_VEC2: case eGL_DOUBLE_VEC3: case eGL_DOUBLE_VEC4: gl.glGetUniformdv(progSrc, srcLocation, dv); break; // treat all samplers as just an int (since they just store their binding value) case eGL_SAMPLER_1D: case eGL_SAMPLER_2D: case eGL_SAMPLER_3D: case eGL_SAMPLER_CUBE: case eGL_SAMPLER_CUBE_MAP_ARRAY: case eGL_SAMPLER_1D_SHADOW: case eGL_SAMPLER_2D_SHADOW: case eGL_SAMPLER_1D_ARRAY: case eGL_SAMPLER_2D_ARRAY: case eGL_SAMPLER_1D_ARRAY_SHADOW: case eGL_SAMPLER_2D_ARRAY_SHADOW: case eGL_SAMPLER_2D_MULTISAMPLE: case eGL_SAMPLER_2D_MULTISAMPLE_ARRAY: case eGL_SAMPLER_CUBE_SHADOW: case eGL_SAMPLER_CUBE_MAP_ARRAY_SHADOW: case eGL_SAMPLER_BUFFER: case eGL_SAMPLER_2D_RECT: case eGL_SAMPLER_2D_RECT_SHADOW: case eGL_INT_SAMPLER_1D: case eGL_INT_SAMPLER_2D: case eGL_INT_SAMPLER_3D: case eGL_INT_SAMPLER_CUBE: case eGL_INT_SAMPLER_CUBE_MAP_ARRAY: case eGL_INT_SAMPLER_1D_ARRAY: case eGL_INT_SAMPLER_2D_ARRAY: case eGL_INT_SAMPLER_2D_MULTISAMPLE: case eGL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case eGL_INT_SAMPLER_BUFFER: case eGL_INT_SAMPLER_2D_RECT: case eGL_UNSIGNED_INT_SAMPLER_1D: case eGL_UNSIGNED_INT_SAMPLER_2D: case eGL_UNSIGNED_INT_SAMPLER_3D: case eGL_UNSIGNED_INT_SAMPLER_CUBE: case eGL_UNSIGNED_INT_SAMPLER_1D_ARRAY: case eGL_UNSIGNED_INT_SAMPLER_2D_ARRAY: case eGL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case eGL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case eGL_UNSIGNED_INT_SAMPLER_BUFFER: case eGL_UNSIGNED_INT_SAMPLER_2D_RECT: case eGL_IMAGE_1D: case eGL_IMAGE_2D: case eGL_IMAGE_3D: case eGL_IMAGE_2D_RECT: case eGL_IMAGE_CUBE: case eGL_IMAGE_BUFFER: case eGL_IMAGE_1D_ARRAY: case eGL_IMAGE_2D_ARRAY: case eGL_IMAGE_CUBE_MAP_ARRAY: case eGL_IMAGE_2D_MULTISAMPLE: case eGL_IMAGE_2D_MULTISAMPLE_ARRAY: case eGL_INT_IMAGE_1D: case eGL_INT_IMAGE_2D: case eGL_INT_IMAGE_3D: case eGL_INT_IMAGE_2D_RECT: case eGL_INT_IMAGE_CUBE: case eGL_INT_IMAGE_BUFFER: case eGL_INT_IMAGE_1D_ARRAY: case eGL_INT_IMAGE_2D_ARRAY: case eGL_INT_IMAGE_2D_MULTISAMPLE: case eGL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: case eGL_UNSIGNED_INT_IMAGE_1D: case eGL_UNSIGNED_INT_IMAGE_2D: case eGL_UNSIGNED_INT_IMAGE_3D: case eGL_UNSIGNED_INT_IMAGE_2D_RECT: case eGL_UNSIGNED_INT_IMAGE_CUBE: case eGL_UNSIGNED_INT_IMAGE_BUFFER: case eGL_UNSIGNED_INT_IMAGE_1D_ARRAY: case eGL_UNSIGNED_INT_IMAGE_2D_ARRAY: case eGL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: case eGL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: case eGL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: case eGL_UNSIGNED_INT_ATOMIC_COUNTER: case eGL_INT: case eGL_INT_VEC2: case eGL_INT_VEC3: case eGL_INT_VEC4: gl.glGetUniformiv(progSrc, srcLocation, iv); break; // bools are unsigned integers case eGL_UNSIGNED_INT: case eGL_BOOL: case eGL_UNSIGNED_INT_VEC2: case eGL_BOOL_VEC2: case eGL_UNSIGNED_INT_VEC3: case eGL_BOOL_VEC3: case eGL_UNSIGNED_INT_VEC4: case eGL_BOOL_VEC4: gl.glGetUniformuiv(progSrc, srcLocation, uiv); break; default: RDCERR("Unhandled uniform type '%s'", ToStr(type).c_str()); } } } // now find how many UBOs we have, and store their binding indices GLint numUBOs = 0; gl.glGetProgramInterfaceiv(progSrc, eGL_UNIFORM_BLOCK, eGL_ACTIVE_RESOURCES, &numUBOs); serialisedUniforms.UBOBindings.reserve(numUBOs); for(GLint i = 0; i < numUBOs; i++) { GLenum prop = eGL_BUFFER_BINDING; uint32_t bind = 0; gl.glGetProgramResourceiv(progSrc, eGL_UNIFORM_BLOCK, i, 1, &prop, 1, NULL, (GLint *)&bind); char n[1024] = {0}; gl.glGetProgramResourceName(progSrc, eGL_UNIFORM_BLOCK, i, 1023, NULL, n); serialisedUniforms.UBOBindings.push_back(ProgramBinding(n, bind)); } // finally, if SSBOs are supported on this implementation, fetch their bindings GLint numSSBOs = 0; if(HasExt[ARB_shader_storage_buffer_object]) gl.glGetProgramInterfaceiv(progSrc, eGL_SHADER_STORAGE_BLOCK, eGL_ACTIVE_RESOURCES, &numSSBOs); serialisedUniforms.SSBOBindings.reserve(numSSBOs); for(GLint i = 0; i < numSSBOs; i++) { GLenum prop = eGL_BUFFER_BINDING; uint32_t bind = 0; gl.glGetProgramResourceiv(progSrc, eGL_SHADER_STORAGE_BLOCK, i, 1, &prop, 1, NULL, (GLint *)&bind); char n[1024] = {0}; gl.glGetProgramResourceName(progSrc, eGL_SHADER_STORAGE_BLOCK, i, 1023, NULL, n); serialisedUniforms.SSBOBindings.push_back(ProgramBinding(n, bind)); } } // now serialise all the bindings if we are serialising if(CheckConstParam(SerialiseUniforms) && ser) { ser->Serialise("ProgramUniforms", serialisedUniforms); } // if we are writing to a destination program and replaying, then apply the stored data from // serialisedUniforms if(CheckConstParam(WriteDestProgram) && IsReplayMode(state)) { // loop over the loose global uniforms, see if there is an equivalent, and apply it. for(const ProgramUniform &uniform : serialisedUniforms.ValueUniforms) { for(size_t arr = 0; arr < uniform.Values.size(); arr++) { const ProgramUniformValue &val = uniform.Values[arr]; std::string name = uniform.Basename; if(uniform.IsArray) name += StringFormat::Fmt("[%u]", (uint32_t)arr); GLint dstLocation = gl.glGetUniformLocation(progDst, name.c_str()); if(locTranslate) (*locTranslate)[val.Location] = dstLocation; // don't try and apply the uniform if the new location is -1 if(dstLocation == -1) continue; const double *dv = val.data.dval; const float *fv = val.data.fval; const int32_t *iv = val.data.ival; const uint32_t *uiv = val.data.uval; // call the appropriate function to apply the data to the destination program switch(val.Type) { case eGL_FLOAT_MAT4: gl.glProgramUniformMatrix4fv(progDst, dstLocation, 1, false, fv); break; case eGL_FLOAT_MAT4x3: gl.glProgramUniformMatrix4x3fv(progDst, dstLocation, 1, false, fv); break; case eGL_FLOAT_MAT4x2: gl.glProgramUniformMatrix4x2fv(progDst, dstLocation, 1, false, fv); break; case eGL_FLOAT_MAT3: gl.glProgramUniformMatrix3fv(progDst, dstLocation, 1, false, fv); break; case eGL_FLOAT_MAT3x4: gl.glProgramUniformMatrix3x4fv(progDst, dstLocation, 1, false, fv); break; case eGL_FLOAT_MAT3x2: gl.glProgramUniformMatrix3x2fv(progDst, dstLocation, 1, false, fv); break; case eGL_FLOAT_MAT2: gl.glProgramUniformMatrix2fv(progDst, dstLocation, 1, false, fv); break; case eGL_FLOAT_MAT2x4: gl.glProgramUniformMatrix2x4fv(progDst, dstLocation, 1, false, fv); break; case eGL_FLOAT_MAT2x3: gl.glProgramUniformMatrix2x3fv(progDst, dstLocation, 1, false, fv); break; case eGL_DOUBLE_MAT4: gl.glProgramUniformMatrix4dv(progDst, dstLocation, 1, false, dv); break; case eGL_DOUBLE_MAT4x3: gl.glProgramUniformMatrix4x3dv(progDst, dstLocation, 1, false, dv); break; case eGL_DOUBLE_MAT4x2: gl.glProgramUniformMatrix4x2dv(progDst, dstLocation, 1, false, dv); break; case eGL_DOUBLE_MAT3: gl.glProgramUniformMatrix3dv(progDst, dstLocation, 1, false, dv); break; case eGL_DOUBLE_MAT3x4: gl.glProgramUniformMatrix3x4dv(progDst, dstLocation, 1, false, dv); break; case eGL_DOUBLE_MAT3x2: gl.glProgramUniformMatrix3x2dv(progDst, dstLocation, 1, false, dv); break; case eGL_DOUBLE_MAT2: gl.glProgramUniformMatrix2dv(progDst, dstLocation, 1, false, dv); break; case eGL_DOUBLE_MAT2x4: gl.glProgramUniformMatrix2x4dv(progDst, dstLocation, 1, false, dv); break; case eGL_DOUBLE_MAT2x3: gl.glProgramUniformMatrix2x3dv(progDst, dstLocation, 1, false, dv); break; case eGL_FLOAT: gl.glProgramUniform1fv(progDst, dstLocation, 1, fv); break; case eGL_FLOAT_VEC2: gl.glProgramUniform2fv(progDst, dstLocation, 1, fv); break; case eGL_FLOAT_VEC3: gl.glProgramUniform3fv(progDst, dstLocation, 1, fv); break; case eGL_FLOAT_VEC4: gl.glProgramUniform4fv(progDst, dstLocation, 1, fv); break; case eGL_DOUBLE: gl.glProgramUniform1dv(progDst, dstLocation, 1, dv); break; case eGL_DOUBLE_VEC2: gl.glProgramUniform2dv(progDst, dstLocation, 1, dv); break; case eGL_DOUBLE_VEC3: gl.glProgramUniform3dv(progDst, dstLocation, 1, dv); break; case eGL_DOUBLE_VEC4: gl.glProgramUniform4dv(progDst, dstLocation, 1, dv); break; case eGL_IMAGE_1D: case eGL_IMAGE_2D: case eGL_IMAGE_3D: case eGL_IMAGE_2D_RECT: case eGL_IMAGE_CUBE: case eGL_IMAGE_BUFFER: case eGL_IMAGE_1D_ARRAY: case eGL_IMAGE_2D_ARRAY: case eGL_IMAGE_CUBE_MAP_ARRAY: case eGL_IMAGE_2D_MULTISAMPLE: case eGL_IMAGE_2D_MULTISAMPLE_ARRAY: case eGL_INT_IMAGE_1D: case eGL_INT_IMAGE_2D: case eGL_INT_IMAGE_3D: case eGL_INT_IMAGE_2D_RECT: case eGL_INT_IMAGE_CUBE: case eGL_INT_IMAGE_BUFFER: case eGL_INT_IMAGE_1D_ARRAY: case eGL_INT_IMAGE_2D_ARRAY: case eGL_INT_IMAGE_2D_MULTISAMPLE: case eGL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: case eGL_UNSIGNED_INT_IMAGE_1D: case eGL_UNSIGNED_INT_IMAGE_2D: case eGL_UNSIGNED_INT_IMAGE_3D: case eGL_UNSIGNED_INT_IMAGE_2D_RECT: case eGL_UNSIGNED_INT_IMAGE_CUBE: case eGL_UNSIGNED_INT_IMAGE_BUFFER: case eGL_UNSIGNED_INT_IMAGE_1D_ARRAY: case eGL_UNSIGNED_INT_IMAGE_2D_ARRAY: case eGL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: case eGL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: case eGL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: case eGL_UNSIGNED_INT_ATOMIC_COUNTER: if(IsGLES) // Image uniforms cannot be re-assigned in GLES. break; // deliberate fall-through // treat all samplers as just an int (since they just store their binding value) case eGL_SAMPLER_1D: case eGL_SAMPLER_2D: case eGL_SAMPLER_3D: case eGL_SAMPLER_CUBE: case eGL_SAMPLER_CUBE_MAP_ARRAY: case eGL_SAMPLER_1D_SHADOW: case eGL_SAMPLER_2D_SHADOW: case eGL_SAMPLER_1D_ARRAY: case eGL_SAMPLER_2D_ARRAY: case eGL_SAMPLER_1D_ARRAY_SHADOW: case eGL_SAMPLER_2D_ARRAY_SHADOW: case eGL_SAMPLER_2D_MULTISAMPLE: case eGL_SAMPLER_2D_MULTISAMPLE_ARRAY: case eGL_SAMPLER_CUBE_SHADOW: case eGL_SAMPLER_CUBE_MAP_ARRAY_SHADOW: case eGL_SAMPLER_BUFFER: case eGL_SAMPLER_2D_RECT: case eGL_SAMPLER_2D_RECT_SHADOW: case eGL_INT_SAMPLER_1D: case eGL_INT_SAMPLER_2D: case eGL_INT_SAMPLER_3D: case eGL_INT_SAMPLER_CUBE: case eGL_INT_SAMPLER_CUBE_MAP_ARRAY: case eGL_INT_SAMPLER_1D_ARRAY: case eGL_INT_SAMPLER_2D_ARRAY: case eGL_INT_SAMPLER_2D_MULTISAMPLE: case eGL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case eGL_INT_SAMPLER_BUFFER: case eGL_INT_SAMPLER_2D_RECT: case eGL_UNSIGNED_INT_SAMPLER_1D: case eGL_UNSIGNED_INT_SAMPLER_2D: case eGL_UNSIGNED_INT_SAMPLER_3D: case eGL_UNSIGNED_INT_SAMPLER_CUBE: case eGL_UNSIGNED_INT_SAMPLER_1D_ARRAY: case eGL_UNSIGNED_INT_SAMPLER_2D_ARRAY: case eGL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case eGL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case eGL_UNSIGNED_INT_SAMPLER_BUFFER: case eGL_UNSIGNED_INT_SAMPLER_2D_RECT: case eGL_INT: gl.glProgramUniform1iv(progDst, dstLocation, 1, iv); break; case eGL_INT_VEC2: gl.glProgramUniform2iv(progDst, dstLocation, 1, iv); break; case eGL_INT_VEC3: gl.glProgramUniform3iv(progDst, dstLocation, 1, iv); break; case eGL_INT_VEC4: gl.glProgramUniform4iv(progDst, dstLocation, 1, iv); break; case eGL_UNSIGNED_INT: case eGL_BOOL: gl.glProgramUniform1uiv(progDst, dstLocation, 1, uiv); break; case eGL_UNSIGNED_INT_VEC2: case eGL_BOOL_VEC2: gl.glProgramUniform2uiv(progDst, dstLocation, 1, uiv); break; case eGL_UNSIGNED_INT_VEC3: case eGL_BOOL_VEC3: gl.glProgramUniform3uiv(progDst, dstLocation, 1, uiv); break; case eGL_UNSIGNED_INT_VEC4: case eGL_BOOL_VEC4: gl.glProgramUniform4uiv(progDst, dstLocation, 1, uiv); break; default: RDCERR("Unhandled uniform type '%s'", ToStr(val.Type).c_str()); } } } // apply UBO bindings for(const ProgramBinding &bind : serialisedUniforms.UBOBindings) { GLuint idx = gl.glGetUniformBlockIndex(progDst, bind.Name.c_str()); if(idx != GL_INVALID_INDEX) gl.glUniformBlockBinding(progDst, idx, bind.Binding); } // apply SSBO bindings for(const ProgramBinding &bind : serialisedUniforms.SSBOBindings) { GLuint idx = gl.glGetProgramResourceIndex(progDst, eGL_SHADER_STORAGE_BLOCK, bind.Name.c_str()); if(idx != GL_INVALID_INDEX) { if(gl.glShaderStorageBlockBinding) { gl.glShaderStorageBlockBinding(progDst, idx, bind.Binding); } else { // TODO glShaderStorageBlockBinding is not core GLES RDCERR("glShaderStorageBlockBinding is not supported!"); } } } } }
void EmulateLuminanceFormat(const GLHookSet &gl, GLuint tex, GLenum target, GLenum &internalFormat, GLenum &dataFormat) { GLenum swizzle[] = { eGL_RED, eGL_GREEN, eGL_BLUE, eGL_ALPHA }; bool dataFormatLum = (dataFormat == eGL_LUMINANCE || dataFormat == eGL_LUMINANCE_ALPHA || dataFormat == eGL_ALPHA || dataFormat == eGL_INTENSITY); switch((int)internalFormat) { case eGL_INTENSITY: case eGL_INTENSITY8_EXT: internalFormat = eGL_R8; if(dataFormatLum) dataFormat = eGL_RED; swizzle[0] = swizzle[1] = swizzle[2] = swizzle[3] = eGL_RED; // intensity replicates across all 4 of RGBA break; case eGL_INTENSITY16_EXT: internalFormat = eGL_R16; if(dataFormatLum) dataFormat = eGL_RED; swizzle[0] = swizzle[1] = swizzle[2] = swizzle[3] = eGL_RED; // intensity replicates across all 4 of RGBA break; case eGL_ALPHA: case eGL_ALPHA8_EXT: internalFormat = eGL_R8; if(dataFormatLum) dataFormat = eGL_RED; swizzle[0] = swizzle[1] = swizzle[2] = eGL_NONE; swizzle[3] = eGL_RED; // single component alpha channel break; case eGL_LUMINANCE: case eGL_LUMINANCE8_EXT: internalFormat = eGL_R8; if(dataFormatLum) dataFormat = eGL_RED; swizzle[0] = swizzle[1] = swizzle[2] = eGL_RED; swizzle[3] = (GLenum)1; // alpha explicitly set to 1 in luminance formats break; case eGL_SLUMINANCE8_EXT: internalFormat = eGL_SRGB8; if(dataFormatLum) dataFormat = eGL_RED; swizzle[0] = swizzle[1] = swizzle[2] = eGL_RED; swizzle[3] = (GLenum)1; // alpha explicitly set to 1 in luminance formats break; case eGL_LUMINANCE16_EXT: internalFormat = eGL_R16; if(dataFormatLum) dataFormat = eGL_RED; swizzle[0] = swizzle[1] = swizzle[2] = eGL_RED; swizzle[3] = (GLenum)1; // alpha explicitly set to 1 in luminance formats break; case eGL_LUMINANCE32F_ARB: internalFormat = eGL_R32F; if(dataFormatLum) dataFormat = eGL_RED; swizzle[0] = swizzle[1] = swizzle[2] = eGL_RED; swizzle[3] = (GLenum)1; // alpha explicitly set to 1 in luminance formats break; case eGL_LUMINANCE32I_EXT: internalFormat = eGL_R32I; if(dataFormatLum) dataFormat = eGL_RED; swizzle[0] = swizzle[1] = swizzle[2] = eGL_RED; swizzle[3] = (GLenum)1; // alpha explicitly set to 1 in luminance formats break; case eGL_LUMINANCE32UI_EXT: internalFormat = eGL_R32UI; if(dataFormatLum) dataFormat = eGL_RED; swizzle[0] = swizzle[1] = swizzle[2] = eGL_RED; swizzle[3] = (GLenum)1; // alpha explicitly set to 1 in luminance formats break; case eGL_LUMINANCE_ALPHA: case eGL_LUMINANCE8_ALPHA8_EXT: internalFormat = eGL_RG8; if(dataFormatLum) dataFormat = eGL_RG; swizzle[0] = swizzle[1] = swizzle[2] = eGL_RED; swizzle[3] = eGL_GREEN; break; case eGL_SLUMINANCE8_ALPHA8_EXT: internalFormat = eGL_SRGB8_ALPHA8; if(dataFormatLum) dataFormat = eGL_RG; swizzle[0] = swizzle[1] = swizzle[2] = eGL_RED; swizzle[3] = eGL_GREEN; break; case eGL_LUMINANCE16_ALPHA16_EXT: internalFormat = eGL_RG16; if(dataFormatLum) dataFormat = eGL_RG; swizzle[0] = swizzle[1] = swizzle[2] = eGL_RED; swizzle[3] = eGL_GREEN; break; default: return; } if(tex) gl.glTextureParameterivEXT(tex, target, eGL_TEXTURE_SWIZZLE_RGBA, (GLint *)swizzle); }
GLenum GetSizedFormat(const GLHookSet &gl, GLenum target, GLenum internalFormat) { switch(internalFormat) { case eGL_RED: case eGL_RG: case eGL_RGB: case eGL_RGBA: case eGL_DEPTH_COMPONENT: case eGL_DEPTH_STENCIL: break; default: return internalFormat; // already explicitly sized } switch(target) { case eGL_TEXTURE_CUBE_MAP_POSITIVE_X: case eGL_TEXTURE_CUBE_MAP_NEGATIVE_X: case eGL_TEXTURE_CUBE_MAP_POSITIVE_Y: case eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case eGL_TEXTURE_CUBE_MAP_POSITIVE_Z: case eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z: target = eGL_TEXTURE_CUBE_MAP; default: break; } GLint red, depth; if(gl.glGetInternalformativ) { gl.glGetInternalformativ(target, internalFormat, eGL_INTERNALFORMAT_RED_SIZE, sizeof(GLint), &red); gl.glGetInternalformativ(target, internalFormat, eGL_INTERNALFORMAT_DEPTH_SIZE, sizeof(GLint), &depth); } else { // without the query function, just default to sensible defaults red = 8; depth = 32; } switch(internalFormat) { case eGL_RED: if(red == 32) return eGL_R32F; else if(red == 16) return eGL_R16; else return eGL_R8; case eGL_RG: if(red == 32) return eGL_RG32F; else if(red == 16) return eGL_RG16; else return eGL_RG8; case eGL_RGB: if(red == 32) return eGL_RGB32F; else if(red == 16) return eGL_RGB16; else return eGL_RGB8; case eGL_RGBA: if(red == 32) return eGL_RGBA32F; else if(red == 16) return eGL_RGBA16; else return eGL_RGBA8; case eGL_DEPTH_COMPONENT: if(depth == 32) return eGL_DEPTH_COMPONENT32F; else if(depth == 16) return eGL_DEPTH_COMPONENT16; else return eGL_DEPTH_COMPONENT24; case eGL_DEPTH_STENCIL: if(depth == 32) return eGL_DEPTH32F_STENCIL8; else return eGL_DEPTH24_STENCIL8; default: break; } return internalFormat; }
GLenum GetSizedFormat(const GLHookSet &gl, GLenum target, GLenum internalFormat) { switch(internalFormat) { // pick sized format ourselves for generic formats case eGL_COMPRESSED_RED: return eGL_COMPRESSED_RED_RGTC1; case eGL_COMPRESSED_RG: return eGL_COMPRESSED_RG_RGTC2; case eGL_COMPRESSED_RGB: return eGL_COMPRESSED_RGB_S3TC_DXT1_EXT; case eGL_COMPRESSED_RGBA: return eGL_COMPRESSED_RGBA_S3TC_DXT5_EXT; case eGL_COMPRESSED_SRGB: return eGL_COMPRESSED_SRGB_S3TC_DXT1_EXT; case eGL_COMPRESSED_SRGB_ALPHA: return eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; // only one sized format for SRGB case eGL_SRGB: return eGL_SRGB8; case eGL_SRGB_ALPHA: return eGL_SRGB8_ALPHA8; case eGL_RED: case eGL_RG: case eGL_RGB: case eGL_RGBA: case eGL_DEPTH_COMPONENT: case eGL_STENCIL: case eGL_STENCIL_INDEX: case eGL_DEPTH_STENCIL: break; default: return internalFormat; // already explicitly sized } switch(target) { case eGL_TEXTURE_CUBE_MAP_POSITIVE_X: case eGL_TEXTURE_CUBE_MAP_NEGATIVE_X: case eGL_TEXTURE_CUBE_MAP_POSITIVE_Y: case eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case eGL_TEXTURE_CUBE_MAP_POSITIVE_Z: case eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z: target = eGL_TEXTURE_CUBE_MAP; default: break; } GLint red, depth, stencil; if(gl.glGetInternalformativ) { gl.glGetInternalformativ(target, internalFormat, eGL_INTERNALFORMAT_RED_SIZE, sizeof(GLint), &red); gl.glGetInternalformativ(target, internalFormat, eGL_INTERNALFORMAT_DEPTH_SIZE, sizeof(GLint), &depth); gl.glGetInternalformativ(target, internalFormat, eGL_INTERNALFORMAT_STENCIL_SIZE, sizeof(GLint), &stencil); } else { // without the query function, just default to sensible defaults red = 8; depth = 32; stencil = 8; } switch(internalFormat) { case eGL_RED: if(red == 32) return eGL_R32F; else if(red == 16) return eGL_R16; else return eGL_R8; case eGL_RG: if(red == 32) return eGL_RG32F; else if(red == 16) return eGL_RG16; else return eGL_RG8; case eGL_RGB: if(red == 32) return eGL_RGB32F; else if(red == 16) return eGL_RGB16; else return eGL_RGB8; case eGL_RGBA: if(red == 32) return eGL_RGBA32F; else if(red == 16) return eGL_RGBA16; else return eGL_RGBA8; case eGL_STENCIL: case eGL_STENCIL_INDEX: if(stencil == 16) return eGL_STENCIL_INDEX16; else return eGL_STENCIL_INDEX8; case eGL_DEPTH_COMPONENT: if(depth == 32) return eGL_DEPTH_COMPONENT32F; else if(depth == 16) return eGL_DEPTH_COMPONENT16; else return eGL_DEPTH_COMPONENT24; case eGL_DEPTH_STENCIL: if(depth == 32) return eGL_DEPTH32F_STENCIL8; else return eGL_DEPTH24_STENCIL8; default: break; } return internalFormat; }