PostVSMeshData GLReplay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) { PostVSMeshData ret; RDCEraseEl(ret); GLNOTIMP("GLReplay::GetPostVSBuffers"); return ret; }
bool GLReplay::IsOutputWindowVisible(uint64_t id) { if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end()) return false; GLNOTIMP("Optimisation missing - output window always returning true"); return true; }
ShaderReflection *GLReplay::GetShader(ResourceId id) { WrappedOpenGL &gl = *m_pDriver; MakeCurrentReplayContext(&m_ReplayCtx); GLuint curProg = 0; gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint*)&curProg); auto &progDetails = m_pDriver->m_Programs[m_pDriver->GetResourceManager()->GetID(ProgramRes(curProg))]; auto &shaderDetails = m_pDriver->m_Shaders[id]; auto &refl = shaderDetails.reflection; // initialise reflection data // TODO: do this earlier. In glLinkProgram? if(refl.DebugInfo.files.count == 0) { refl.DebugInfo.entryFunc = "main"; refl.DebugInfo.compileFlags = 0; create_array_uninit(refl.DebugInfo.files, shaderDetails.sources.size()); for(size_t i=0; i < shaderDetails.sources.size(); i++) { refl.DebugInfo.files[i].first = StringFormat::Fmt("source%u.glsl", (uint32_t)i); refl.DebugInfo.files[i].second = shaderDetails.sources[i]; } refl.Disassembly = ""; vector<ShaderResource> resources; GLint numUniforms = 0; gl.glGetProgramInterfaceiv(curProg, eGL_UNIFORM, eGL_ACTIVE_RESOURCES, &numUniforms); const size_t numProps = 6; GLenum resProps[numProps] = { eGL_REFERENCED_BY_VERTEX_SHADER, eGL_TYPE, eGL_NAME_LENGTH, eGL_LOCATION, eGL_BLOCK_INDEX, eGL_ARRAY_SIZE, }; if(shaderDetails.type == eGL_VERTEX_SHADER) resProps[0] = eGL_REFERENCED_BY_VERTEX_SHADER; if(shaderDetails.type == eGL_TESS_CONTROL_SHADER) resProps[0] = eGL_REFERENCED_BY_TESS_CONTROL_SHADER; if(shaderDetails.type == eGL_TESS_EVALUATION_SHADER) resProps[0] = eGL_REFERENCED_BY_TESS_EVALUATION_SHADER; if(shaderDetails.type == eGL_GEOMETRY_SHADER) resProps[0] = eGL_REFERENCED_BY_GEOMETRY_SHADER; if(shaderDetails.type == eGL_FRAGMENT_SHADER) resProps[0] = eGL_REFERENCED_BY_FRAGMENT_SHADER; if(shaderDetails.type == eGL_COMPUTE_SHADER) resProps[0] = eGL_REFERENCED_BY_COMPUTE_SHADER; for(GLint u=0; u < numUniforms; u++) { GLint values[numProps]; gl.glGetProgramResourceiv(curProg, eGL_UNIFORM, u, numProps, resProps, numProps, NULL, values); // skip if unused by this stage if(values[0] == GL_FALSE) continue; ShaderResource res; res.IsSampler = false; // no separate sampler objects in GL if(values[1] == GL_SAMPLER_2D) { res.IsSRV = true; res.IsTexture = true; res.IsUAV = false; res.resType = eResType_Texture2D; res.variableType.descriptor.name = "sampler2D"; res.variableType.descriptor.rows = 1; res.variableType.descriptor.cols = 4; res.variableType.descriptor.elements = 1; } else if(values[1] == GL_INT_SAMPLER_1D) { res.IsSRV = true; res.IsTexture = true; res.IsUAV = false; res.resType = eResType_Texture1D; res.variableType.descriptor.name = "isampler1D"; res.variableType.descriptor.rows = 1; res.variableType.descriptor.cols = 4; res.variableType.descriptor.elements = 1; } else { // fill in more sampler types continue; } res.variableAddress = values[3]; create_array_uninit(res.name, values[2]+1); gl.glGetProgramResourceName(curProg, eGL_UNIFORM, u, values[2]+1, NULL, res.name.elems); res.name.count--; // trim off trailing null resources.push_back(res); } refl.Resources = resources; vector<ShaderConstant> globalUniforms; for(GLint u=0; u < numUniforms; u++) { GLint values[numProps]; gl.glGetProgramResourceiv(curProg, eGL_UNIFORM, u, numProps, resProps, numProps, NULL, values); // skip if unused by this stage if(values[0] == GL_FALSE) continue; // don't look at block uniforms just yet if(values[4] != -1) { GLNOTIMP("Not fetching uniforms in UBOs (should become their own ConstantBlocks)"); continue; } ShaderConstant var; if(values[1] == GL_FLOAT_VEC4) { var.type.descriptor.name = "vec4"; var.type.descriptor.rows = 1; var.type.descriptor.cols = 4; var.type.descriptor.elements = values[5]; } else if(values[1] == GL_FLOAT_VEC3) { var.type.descriptor.name = "vec3"; var.type.descriptor.rows = 1; var.type.descriptor.cols = 3; var.type.descriptor.elements = values[5]; } else if(values[1] == GL_FLOAT_MAT4) { var.type.descriptor.name = "mat4"; var.type.descriptor.rows = 4; var.type.descriptor.cols = 4; var.type.descriptor.elements = values[5]; } else { // fill in more uniform types continue; } var.reg.vec = values[3]; var.reg.comp = 0; create_array_uninit(var.name, values[2]+1); gl.glGetProgramResourceName(curProg, eGL_UNIFORM, u, values[2]+1, NULL, var.name.elems); var.name.count--; // trim off trailing null if(strchr(var.name.elems, '.')) { GLNOTIMP("Variable contains . - structure not reconstructed"); } globalUniforms.push_back(var); } vector<ConstantBlock> cbuffers; if(!globalUniforms.empty()) { ConstantBlock globals; globals.name = "Globals"; globals.bufferAddress = -1; globals.variables = globalUniforms; cbuffers.push_back(globals); } // here we would iterate over UNIFORM_BLOCKs or similar // TODO: fill in Interfaces with shader subroutines? // TODO: find a way of generating input/output signature. // The only way I can think of doing this is to generate separable programs for each // shader stage, but that requires modifying the glsl to redeclare built-in blocks if necessary. refl.ConstantBlocks = cbuffers; } // update samplers with latest uniform values for(int32_t i=0; i < refl.Resources.count; i++) { if(refl.Resources.elems[i].IsSRV && refl.Resources.elems[i].IsTexture) gl.glGetUniformiv(curProg, refl.Resources.elems[i].variableAddress, (GLint *)&refl.Resources.elems[i].bindPoint); } return &refl; }
FetchBuffer GLReplay::GetBuffer(ResourceId id) { FetchBuffer ret; MakeCurrentReplayContext(&m_ReplayCtx); auto &res = m_pDriver->m_Buffers[id]; if(res.resource.Namespace == eResUnknown) { RDCERR("Details for invalid buffer id %llu requested", id); RDCEraseEl(ret); return ret; } WrappedOpenGL &gl = *m_pDriver; ret.ID = m_pDriver->GetResourceManager()->GetOriginalID(id); gl.glBindBuffer(res.curType, res.resource.name); ret.structureSize = 0; GLNOTIMP("Not fetching structure size (if there's an equivalent)"); ret.creationFlags = 0; switch(res.curType) { case eGL_ARRAY_BUFFER: ret.creationFlags = eBufferCreate_VB; break; case eGL_ELEMENT_ARRAY_BUFFER: ret.creationFlags = eBufferCreate_IB; break; default: RDCERR("Unexpected buffer type %hs", ToStr::Get(res.curType).c_str()); } GLint size; gl.glGetBufferParameteriv(res.curType, eGL_BUFFER_SIZE, &size); ret.byteSize = ret.length = (uint32_t)size; if(res.size == 0) { RDCWARN("BufferData::size didn't get filled out, setting at last minute"); res.size = ret.byteSize; } string str = ""; char name[128] = {0}; gl.glGetObjectLabel(eGL_BUFFER, res.resource.name, 127, NULL, name); str = name; ret.customName = true; if(str == "") { ret.customName = false; str = StringFormat::Fmt("Buffer %llu", ret.ID); } ret.name = widen(str); return ret; }
FetchTexture GLReplay::GetTexture(ResourceId id) { FetchTexture tex; MakeCurrentReplayContext(&m_ReplayCtx); auto &res = m_pDriver->m_Textures[id]; if(res.resource.Namespace == eResUnknown) { RDCERR("Details for invalid texture id %llu requested", id); RDCEraseEl(tex); return tex; } WrappedOpenGL &gl = *m_pDriver; tex.ID = m_pDriver->GetResourceManager()->GetOriginalID(id); gl.glBindTexture(res.curType, res.resource.name); // if I call this for levels 1, 2, .. etc. Can I get sizes that aren't mip dimensions? GLint width = 1, height = 1, depth = 1, samples=1; gl.glGetTexLevelParameteriv(res.curType, 0, eGL_TEXTURE_WIDTH, &width); gl.glGetTexLevelParameteriv(res.curType, 0, eGL_TEXTURE_HEIGHT, &height); gl.glGetTexLevelParameteriv(res.curType, 0, eGL_TEXTURE_DEPTH, &depth); gl.glGetTexLevelParameteriv(res.curType, 0, eGL_TEXTURE_SAMPLES, &samples); if(res.width == 0) { RDCWARN("TextureData::width didn't get filled out, setting at last minute"); res.width = width; } if(res.height == 0) { RDCWARN("TextureData::height didn't get filled out, setting at last minute"); res.height = height; } if(res.depth == 0) { RDCWARN("TextureData::depth didn't get filled out, setting at last minute"); res.depth = depth; } // reasonably common defaults tex.msQual = 0; tex.msSamp = 1; tex.width = tex.height = tex.depth = tex.arraysize = 1; tex.cubemap = false; switch(res.curType) { case eGL_TEXTURE_1D: case eGL_TEXTURE_BUFFER: tex.dimension = 1; tex.width = (uint32_t)width; break; case eGL_TEXTURE_1D_ARRAY: tex.dimension = 1; tex.width = (uint32_t)width; tex.arraysize = depth; break; case eGL_TEXTURE_2D: case eGL_TEXTURE_RECTANGLE: case eGL_TEXTURE_2D_MULTISAMPLE: case eGL_TEXTURE_CUBE_MAP: tex.dimension = 2; tex.width = (uint32_t)width; tex.height = (uint32_t)height; tex.cubemap = (res.curType == eGL_TEXTURE_CUBE_MAP); tex.msSamp = (res.curType == eGL_TEXTURE_2D_MULTISAMPLE ? samples : 1); break; case eGL_TEXTURE_2D_ARRAY: case eGL_TEXTURE_2D_MULTISAMPLE_ARRAY: case eGL_TEXTURE_CUBE_MAP_ARRAY: tex.dimension = 2; tex.width = (uint32_t)width; tex.height = (uint32_t)height; tex.arraysize = depth; tex.cubemap = (res.curType == eGL_TEXTURE_CUBE_MAP_ARRAY); tex.msSamp = (res.curType == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY ? samples : 1); break; case eGL_TEXTURE_3D: tex.dimension = 3; tex.width = (uint32_t)width; tex.height = (uint32_t)height; tex.depth = (uint32_t)depth; break; default: tex.dimension = 2; RDCERR("Unexpected texture enum %hs", ToStr::Get(res.curType).c_str()); } GLint immut = 0; gl.glGetTexParameteriv(res.curType, eGL_TEXTURE_IMMUTABLE_FORMAT, &immut); if(immut) { gl.glGetTexParameteriv(res.curType, eGL_TEXTURE_IMMUTABLE_LEVELS, &immut); tex.mips = (uint32_t)immut; } else { // assuming complete texture GLint mips = 1; gl.glGetTexParameteriv(res.curType, eGL_TEXTURE_MAX_LEVEL, &mips); tex.mips = (uint32_t)mips; } tex.numSubresources = tex.mips*tex.arraysize; // surely this will be the same for each level... right? that would be insane if it wasn't GLint fmt = 0; gl.glGetTexLevelParameteriv(res.curType, 0, eGL_TEXTURE_INTERNAL_FORMAT, &fmt); tex.format = MakeResourceFormat(gl, res.curType, (GLenum)fmt); string str = ""; char name[128] = {0}; gl.glGetObjectLabel(eGL_TEXTURE, res.resource.name, 127, NULL, name); str = name; tex.customName = true; if(str == "") { tex.customName = false; str = StringFormat::Fmt("Texture%dD %llu", tex.dimension, tex.ID); } tex.name = widen(str); tex.creationFlags = eTextureCreate_SRV; if(tex.format.compType == eCompType_Depth) tex.creationFlags |= eTextureCreate_DSV; GLNOTIMP("creationFlags are not calculated yet"); tex.byteSize = 0; GLNOTIMP("Not calculating bytesize"); return tex; }
vector<EventUsage> GLReplay::GetUsage(ResourceId id) { GLNOTIMP("GetUsage"); return vector<EventUsage>(); }
void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) { GLNOTIMP("GLReplay::InitPostVSBuffers"); }