bool WrappedOpenGL::Serialise_glSamplerParameteri(GLuint sampler, GLenum pname, GLint param) { SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(SamplerRes(GetCtx(), sampler))); SERIALISE_ELEMENT(GLenum, PName, pname); int32_t ParamValue = 0; RDCCOMPILE_ASSERT(sizeof(int32_t) == sizeof(GLenum), "int32_t isn't the same size as GLenum - aliased serialising will break"); // special case a few parameters to serialise their value as an enum, not an int if(PName == GL_TEXTURE_WRAP_S || PName == GL_TEXTURE_WRAP_T || PName == GL_TEXTURE_WRAP_R || PName == GL_TEXTURE_MIN_FILTER || PName == GL_TEXTURE_MAG_FILTER || PName == GL_TEXTURE_COMPARE_MODE || PName == GL_TEXTURE_COMPARE_FUNC) { SERIALISE_ELEMENT(GLenum, Param, (GLenum)param); ParamValue = (int32_t)Param; } else { SERIALISE_ELEMENT(int32_t, Param, param); ParamValue = Param; } if(m_State < WRITING) { GLResource res = GetResourceManager()->GetLiveResource(id); m_Real.glSamplerParameteri(res.name, PName, ParamValue); } return true; }
bool WrappedOpenGL::Serialise_glPointParameteri(GLenum pname, GLint param) { SERIALISE_ELEMENT(GLenum, PName, pname); int32_t ParamValue = 0; RDCCOMPILE_ASSERT(sizeof(int32_t) == sizeof(GLenum), "int32_t isn't the same size as GLenum - aliased serialising will break"); // special case a few parameters to serialise their value as an enum, not an int if(PName == GL_POINT_SPRITE_COORD_ORIGIN) { SERIALISE_ELEMENT(GLenum, Param, (GLenum)param); ParamValue = (int32_t)Param; } else { SERIALISE_ELEMENT(int32_t, Param, param); ParamValue = Param; } if(m_State <= EXECUTING) { m_Real.glPointParameteri(PName, ParamValue); } return true; }
std::string DoStringise(const D3D12ResourceBarrierSubresource &el) { RDCCOMPILE_ASSERT(sizeof(D3D12ResourceBarrierSubresource) == sizeof(uint32_t), "Enum isn't uint sized"); if(el == D3D12AllSubresources) return "All Subresources"; return ToStr(uint32_t(el)); }
std::string DoStringise(const D3D12ComponentMapping &el) { RDCCOMPILE_ASSERT(sizeof(D3D12ComponentMapping) == sizeof(uint32_t), "Enum isn't uint sized"); std::string ret; // value should always be <= 5, see D3D12_SHADER_COMPONENT_MAPPING const char mapping[] = {'R', 'G', 'B', 'A', '0', '1', '?', '!'}; uint32_t swizzle = (uint32_t)el; for(int i = 0; i < 4; i++) ret += mapping[D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(i, swizzle)]; return ret; }
VkResult WrappedVulkan::vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData) { size_t totalSize = 16 + VK_UUID_SIZE + 4; // required header (16+UUID) and 4 0 bytes if(pDataSize && !pData) *pDataSize = totalSize; if(pDataSize && pData) { if(*pDataSize < totalSize) { memset(pData, 0, *pDataSize); return VK_INCOMPLETE; } uint32_t *ptr = (uint32_t *)pData; ptr[0] = (uint32_t)totalSize; ptr[1] = VK_PIPELINE_CACHE_HEADER_VERSION_ONE; // just in case the user expects a valid vendorID/deviceID, write the real one // MULTIDEVICE need to get the right physical device for this device ptr[2] = m_PhysicalDeviceData.props.vendorID; ptr[3] = m_PhysicalDeviceData.props.deviceID; MakeFakeUUID(); memcpy(ptr + 4, fakeRenderDocUUID, VK_UUID_SIZE); // [4], [5], [6], [7] RDCCOMPILE_ASSERT(VK_UUID_SIZE == 16, "VK_UUID_SIZE has changed"); // empty bytes ptr[8] = 0; } // we don't want the application to use pipeline caches at all, and especially // don't want to return any data for future use. We thus return a technically // valid but empty pipeline cache. Our UUID changes every run so in theory the // application should never provide an old cache, but just in case we will nop // it out in create pipeline cache return VK_SUCCESS; }
MeshDisplayPipelines VulkanDebugManager::CacheMeshDisplayPipelines(VkPipelineLayout pipeLayout, const MeshFormat &primary, const MeshFormat &secondary) { // generate a key to look up the map uint64_t key = 0; uint64_t bit = 0; if(primary.indexByteStride == 4) key |= 1ULL << bit; bit++; RDCASSERT((uint32_t)primary.topology < 64); key |= uint64_t((uint32_t)primary.topology & 0x3f) << bit; bit += 6; VkFormat primaryFmt = MakeVkFormat(primary.format); VkFormat secondaryFmt = secondary.vertexResourceId == ResourceId() ? VK_FORMAT_UNDEFINED : MakeVkFormat(secondary.format); RDCCOMPILE_ASSERT(VK_FORMAT_RANGE_SIZE <= 255, "Mesh pipeline cache key needs an extra bit for format"); key |= uint64_t((uint32_t)primaryFmt & 0xff) << bit; bit += 8; key |= uint64_t((uint32_t)secondaryFmt & 0xff) << bit; bit += 8; RDCASSERT(primary.vertexByteStride <= 0xffff); key |= uint64_t((uint32_t)primary.vertexByteStride & 0xffff) << bit; bit += 16; if(secondary.vertexResourceId != ResourceId()) { RDCASSERT(secondary.vertexByteStride <= 0xffff); key |= uint64_t((uint32_t)secondary.vertexByteStride & 0xffff) << bit; } bit += 16; if(primary.instanced) key |= 1ULL << bit; bit++; if(secondary.instanced) key |= 1ULL << bit; bit++; // only 64 bits, make sure they all fit RDCASSERT(bit < 64); MeshDisplayPipelines &cache = m_CachedMeshPipelines[key]; if(cache.pipes[(uint32_t)SolidShade::NoSolid] != VK_NULL_HANDLE) return cache; const VkLayerDispatchTable *vt = ObjDisp(m_Device); VkResult vkr = VK_SUCCESS; // should we try and evict old pipelines from the cache here? // or just keep them forever VkVertexInputBindingDescription binds[] = { // primary {0, primary.vertexByteStride, primary.instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX}, // secondary {1, secondary.vertexByteStride, secondary.instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX}}; RDCASSERT(primaryFmt != VK_FORMAT_UNDEFINED); VkVertexInputAttributeDescription vertAttrs[] = { // primary { 0, 0, primaryFmt, 0, }, // secondary { 1, 0, primaryFmt, 0, }, }; VkPipelineVertexInputStateCreateInfo vi = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, NULL, 0, 1, binds, 2, vertAttrs, }; VkPipelineShaderStageCreateInfo stages[3] = { {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_ALL_GRAPHICS, VK_NULL_HANDLE, "main", NULL}, {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_ALL_GRAPHICS, VK_NULL_HANDLE, "main", NULL}, {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_ALL_GRAPHICS, VK_NULL_HANDLE, "main", NULL}, }; VkPipelineInputAssemblyStateCreateInfo ia = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, NULL, 0, primary.topology >= Topology::PatchList ? VK_PRIMITIVE_TOPOLOGY_POINT_LIST : MakeVkPrimitiveTopology(primary.topology), false, }; VkRect2D scissor = {{0, 0}, {16384, 16384}}; VkPipelineViewportStateCreateInfo vp = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, NULL, 0, 1, NULL, 1, &scissor}; VkPipelineRasterizationStateCreateInfo rs = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, NULL, 0, false, false, VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE, false, 0.0f, 0.0f, 0.0f, 1.0f, }; VkPipelineMultisampleStateCreateInfo msaa = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, NULL, 0, VULKAN_MESH_VIEW_SAMPLES, false, 0.0f, NULL, false, false}; VkPipelineDepthStencilStateCreateInfo ds = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, NULL, 0, true, true, VK_COMPARE_OP_LESS_OR_EQUAL, false, false, {VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0, 0, 0}, {VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0, 0, 0}, 0.0f, 1.0f, }; VkPipelineColorBlendAttachmentState attState = { false, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, 0xf, }; VkPipelineColorBlendStateCreateInfo cb = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, NULL, 0, false, VK_LOGIC_OP_NO_OP, 1, &attState, {1.0f, 1.0f, 1.0f, 1.0f}}; VkDynamicState dynstates[] = {VK_DYNAMIC_STATE_VIEWPORT}; VkPipelineDynamicStateCreateInfo dyn = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, NULL, 0, ARRAY_COUNT(dynstates), dynstates, }; VkRenderPass rp; // compatible render pass { VkAttachmentDescription attDesc[] = { {0, VK_FORMAT_R8G8B8A8_SRGB, VULKAN_MESH_VIEW_SAMPLES, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, {0, VK_FORMAT_D32_SFLOAT, VULKAN_MESH_VIEW_SAMPLES, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, }; VkAttachmentReference attRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; VkSubpassDescription sub = { 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, NULL, // inputs 1, &attRef, // color NULL, // resolve &dsRef, // depth-stencil 0, NULL, // preserve }; VkRenderPassCreateInfo rpinfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, NULL, 0, 2, attDesc, 1, &sub, 0, NULL, // dependencies }; vt->CreateRenderPass(Unwrap(m_Device), &rpinfo, NULL, &rp); } VkGraphicsPipelineCreateInfo pipeInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, NULL, 0, 2, stages, &vi, &ia, NULL, // tess &vp, &rs, &msaa, &ds, &cb, &dyn, Unwrap(pipeLayout), rp, 0, // sub pass VK_NULL_HANDLE, // base pipeline handle 0, // base pipeline index }; // wireframe pipeline stages[0].module = Unwrap(m_pDriver->GetShaderCache()->GetBuiltinModule(BuiltinShader::MeshVS)); stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; stages[1].module = Unwrap(m_pDriver->GetShaderCache()->GetBuiltinModule(BuiltinShader::MeshFS)); stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; rs.polygonMode = VK_POLYGON_MODE_LINE; rs.lineWidth = 1.0f; ds.depthTestEnable = false; vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, &cache.pipes[MeshDisplayPipelines::ePipe_Wire]); RDCASSERTEQUAL(vkr, VK_SUCCESS); ds.depthTestEnable = true; vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, &cache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); RDCASSERTEQUAL(vkr, VK_SUCCESS); // solid shading pipeline rs.polygonMode = VK_POLYGON_MODE_FILL; ds.depthTestEnable = false; vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, &cache.pipes[MeshDisplayPipelines::ePipe_Solid]); RDCASSERTEQUAL(vkr, VK_SUCCESS); ds.depthTestEnable = true; vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, &cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]); RDCASSERTEQUAL(vkr, VK_SUCCESS); if(secondary.vertexResourceId != ResourceId()) { // pull secondary information from second vertex buffer vertAttrs[1].binding = 1; vertAttrs[1].format = secondaryFmt; RDCASSERT(secondaryFmt != VK_FORMAT_UNDEFINED); vi.vertexBindingDescriptionCount = 2; vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, &cache.pipes[MeshDisplayPipelines::ePipe_Secondary]); RDCASSERTEQUAL(vkr, VK_SUCCESS); } vertAttrs[1].binding = 0; vi.vertexBindingDescriptionCount = 1; // flat lit pipeline, needs geometry shader to calculate face normals stages[2].module = Unwrap(m_pDriver->GetShaderCache()->GetBuiltinModule(BuiltinShader::MeshGS)); stages[2].stage = VK_SHADER_STAGE_GEOMETRY_BIT; pipeInfo.stageCount = 3; if(stages[2].module != VK_NULL_HANDLE) { vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, &cache.pipes[MeshDisplayPipelines::ePipe_Lit]); RDCASSERTEQUAL(vkr, VK_SUCCESS); } for(uint32_t i = 0; i < MeshDisplayPipelines::ePipe_Count; i++) if(cache.pipes[i] != VK_NULL_HANDLE) m_pDriver->GetResourceManager()->WrapResource(Unwrap(m_Device), cache.pipes[i]); vt->DestroyRenderPass(Unwrap(m_Device), rp, NULL); return cache; }
bool GLReplay::RenderTexture(TextureDisplay cfg) { MakeCurrentReplayContext(m_DebugCtx); WrappedOpenGL &gl = *m_pDriver; gl.glUseProgram(DebugData.texDisplayProg); auto &texDetails = m_pDriver->m_Textures[cfg.texid]; gl.glActiveTexture(eGL_TEXTURE0); gl.glBindTexture(eGL_TEXTURE_2D, texDetails.resource.name); if(cfg.mip == 0 && cfg.scale < 1.0f) gl.glBindSampler(0, DebugData.linearSampler); else gl.glBindSampler(0, DebugData.pointSampler); GLint tex_x = texDetails.width, tex_y = texDetails.height, tex_z = texDetails.depth; gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]); struct uboData { Vec2f Position; float Scale; float HDRMul; Vec4f Channels; float RangeMinimum; float InverseRangeSize; float MipLevel; float dummy2; Vec3f TextureResolutionPS; int OutputDisplayFormat; Vec2f OutputRes; int RawOutput; float Slice; }; uboData *ubo = (uboData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(uboData), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); RDCCOMPILE_ASSERT(sizeof(uboData) <= DebugData.UBOSize, "UBO data is too big"); float x = cfg.offx; float y = cfg.offy; ubo->Position.x = x; ubo->Position.y = y; ubo->Scale = cfg.scale; if(cfg.scale <= 0.0f) { float xscale = DebugData.outWidth/float(tex_x); float yscale = DebugData.outHeight/float(tex_y); ubo->Scale = RDCMIN(xscale, yscale); if(yscale > xscale) { ubo->Position.x = 0; ubo->Position.y = (DebugData.outHeight-(tex_y*ubo->Scale) )*0.5f; } else { ubo->Position.y = 0; ubo->Position.x = (DebugData.outWidth-(tex_x*ubo->Scale) )*0.5f; } } ubo->HDRMul = cfg.HDRMul; if(cfg.rangemax <= cfg.rangemin) cfg.rangemax += 0.00001f; ubo->Channels.x = cfg.Red ? 1.0f : 0.0f; ubo->Channels.y = cfg.Green ? 1.0f : 0.0f; ubo->Channels.z = cfg.Blue ? 1.0f : 0.0f; ubo->Channels.w = cfg.Alpha ? 1.0f : 0.0f; ubo->RangeMinimum = cfg.rangemin; ubo->InverseRangeSize = 1.0f/(cfg.rangemax-cfg.rangemin); ubo->MipLevel = (float)cfg.mip; ubo->OutputDisplayFormat = 0x2; // 2d. Unused for now ubo->RawOutput = cfg.rawoutput ? 1 : 0; ubo->TextureResolutionPS.x = float(tex_x); ubo->TextureResolutionPS.y = float(tex_y); ubo->TextureResolutionPS.z = float(tex_z); ubo->OutputRes.x = DebugData.outWidth; ubo->OutputRes.y = DebugData.outHeight; gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); if(cfg.rawoutput) { gl.glDisable(eGL_BLEND); } else { gl.glEnable(eGL_BLEND); gl.glBlendFunc(eGL_SRC_ALPHA, eGL_ONE_MINUS_SRC_ALPHA); } gl.glBindVertexArray(DebugData.emptyVAO); gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); gl.glBindSampler(0, 0); return true; }
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 WrappedVulkan::vkUpdateDescriptorSets( VkDevice device, uint32_t writeCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t copyCount, const VkCopyDescriptorSet* pDescriptorCopies) { { // need to count up number of descriptor infos, to be able to alloc enough space uint32_t numInfos = 0; for(uint32_t i=0; i < writeCount; i++) numInfos += pDescriptorWrites[i].descriptorCount; byte *memory = GetTempMemory(sizeof(VkDescriptorBufferInfo)*numInfos + sizeof(VkWriteDescriptorSet)*writeCount + sizeof(VkCopyDescriptorSet)*copyCount); RDCCOMPILE_ASSERT(sizeof(VkDescriptorBufferInfo) >= sizeof(VkDescriptorImageInfo), "Descriptor structs sizes are unexpected, ensure largest size is used"); VkWriteDescriptorSet *unwrappedWrites = (VkWriteDescriptorSet *)memory; VkCopyDescriptorSet *unwrappedCopies = (VkCopyDescriptorSet *)(unwrappedWrites + writeCount); VkDescriptorBufferInfo *nextDescriptors = (VkDescriptorBufferInfo *)(unwrappedCopies + copyCount); for(uint32_t i=0; i < writeCount; i++) { unwrappedWrites[i] = pDescriptorWrites[i]; unwrappedWrites[i].dstSet = Unwrap(unwrappedWrites[i].dstSet); VkDescriptorBufferInfo *bufInfos = nextDescriptors; VkDescriptorImageInfo *imInfos = (VkDescriptorImageInfo *)bufInfos; VkBufferView *bufViews = (VkBufferView *)bufInfos; nextDescriptors += pDescriptorWrites[i].descriptorCount; // unwrap and assign the appropriate array if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { unwrappedWrites[i].pTexelBufferView = (VkBufferView *)bufInfos; for(uint32_t j=0; j < pDescriptorWrites[i].descriptorCount; j++) bufViews[j] = Unwrap(pDescriptorWrites[i].pTexelBufferView[j]); } else if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) { unwrappedWrites[i].pImageInfo = (VkDescriptorImageInfo *)bufInfos; for(uint32_t j=0; j < pDescriptorWrites[i].descriptorCount; j++) { imInfos[j].imageView = Unwrap(pDescriptorWrites[i].pImageInfo[j].imageView); imInfos[j].sampler = Unwrap(pDescriptorWrites[i].pImageInfo[j].sampler); imInfos[j].imageLayout = pDescriptorWrites[i].pImageInfo[j].imageLayout; } } else { unwrappedWrites[i].pBufferInfo = bufInfos; for(uint32_t j=0; j < pDescriptorWrites[i].descriptorCount; j++) { bufInfos[j].buffer = Unwrap(pDescriptorWrites[i].pBufferInfo[j].buffer); bufInfos[j].offset = pDescriptorWrites[i].pBufferInfo[j].offset; bufInfos[j].range = pDescriptorWrites[i].pBufferInfo[j].range; } } } for(uint32_t i=0; i < copyCount; i++) { unwrappedCopies[i] = pDescriptorCopies[i]; unwrappedCopies[i].dstSet = Unwrap(unwrappedCopies[i].dstSet); unwrappedCopies[i].srcSet = Unwrap(unwrappedCopies[i].srcSet); } ObjDisp(device)->UpdateDescriptorSets(Unwrap(device), writeCount, unwrappedWrites, copyCount, unwrappedCopies); } bool capframe = false; { SCOPED_LOCK(m_CapTransitionLock); capframe = (m_State == WRITING_CAPFRAME); } if(capframe) { // don't have to mark referenced any of the resources pointed to by the descriptor set - that's handled // on queue submission by marking ref'd all the current bindings of the sets referenced by the cmd buffer for(uint32_t i=0; i < writeCount; i++) { { CACHE_THREAD_SERIALISER(); SCOPED_SERIALISE_CONTEXT(UPDATE_DESC_SET); Serialise_vkUpdateDescriptorSets(localSerialiser, device, 1, &pDescriptorWrites[i], 0, NULL); m_FrameCaptureRecord->AddChunk(scope.Get()); } // as long as descriptor sets are forced to have initial states, we don't have to mark them ref'd for // write here. The reason being that as long as we only mark them as ref'd when they're actually bound, // we can safely skip the ref here and it means any descriptor set updates of descriptor sets that are // never used in the frame can be ignored. //GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorWrites[i].destSet), eFrameRef_Write); } for(uint32_t i=0; i < copyCount; i++) { { CACHE_THREAD_SERIALISER(); SCOPED_SERIALISE_CONTEXT(UPDATE_DESC_SET); Serialise_vkUpdateDescriptorSets(localSerialiser, device, 0, NULL, 1, &pDescriptorCopies[i]); m_FrameCaptureRecord->AddChunk(scope.Get()); } // Like writes we don't have to mark the written descriptor set as used because unless it's bound somewhere // we don't need it anyway. However we DO have to mark the source set as used because it doesn't have to // be bound to still be needed (think about if the dest set is bound somewhere after this copy - what refs // the source set?). // At the same time as ref'ing the source set, we must ref all of its resources (via the bindFrameRefs). // We just ref all rather than looking at only the copied sets to keep things simple. // This does mean a slightly conservative ref'ing if the dest set doesn't end up getting bound, but we only // do this during frame capture so it's not too bad. //GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorCopies[i].destSet), eFrameRef_Write); { GetResourceManager()->MarkResourceFrameReferenced(GetResID(pDescriptorCopies[i].srcSet), eFrameRef_Read); VkResourceRecord *setrecord = GetRecord(pDescriptorCopies[i].srcSet); for(auto refit = setrecord->descInfo->bindFrameRefs.begin(); refit != setrecord->descInfo->bindFrameRefs.end(); ++refit) { GetResourceManager()->MarkResourceFrameReferenced(refit->first, refit->second.second); if(refit->second.first & DescriptorSetData::SPARSE_REF_BIT) { VkResourceRecord *record = GetResourceManager()->GetResourceRecord(refit->first); GetResourceManager()->MarkSparseMapReferenced(record->sparseInfo); } } } } } // need to track descriptor set contents whether capframing or idle if(m_State >= WRITING) { for(uint32_t i=0; i < writeCount; i++) { VkResourceRecord *record = GetRecord(pDescriptorWrites[i].dstSet); RDCASSERT(record->descInfo && record->descInfo->layout); const DescSetLayout &layout = *record->descInfo->layout; RDCASSERT(pDescriptorWrites[i].dstBinding < record->descInfo->descBindings.size()); DescriptorSetSlot *binding = record->descInfo->descBindings[pDescriptorWrites[i].dstBinding]; FrameRefType ref = eFrameRef_Write; switch(layout.bindings[pDescriptorWrites[i].dstBinding].descriptorType) { case VK_DESCRIPTOR_TYPE_SAMPLER: case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: ref = eFrameRef_Read; break; case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: ref = eFrameRef_Write; break; default: RDCERR("Unexpected descriptor type"); } // We need to handle the cases where these bindings are stale: // ie. image handle 0xf00baa is allocated // bound into a descriptor set // image is released // descriptor set is bound but this image is never used by shader etc. // // worst case, a new image or something has been added with this handle - // in this case we end up ref'ing an image that isn't actually used. // Worst worst case, we ref an image as write when actually it's not, but // this is likewise not a serious problem, and rather difficult to solve // (would need to version handles somehow, but don't have enough bits // to do that reliably). // // This is handled by RemoveBindFrameRef silently dropping id == ResourceId() for(uint32_t d=0; d < pDescriptorWrites[i].descriptorCount; d++) { DescriptorSetSlot &bind = binding[pDescriptorWrites[i].dstArrayElement + d]; if(bind.texelBufferView != VK_NULL_HANDLE) { record->RemoveBindFrameRef(GetResID(bind.texelBufferView)); if(GetRecord(bind.texelBufferView)->baseResource != ResourceId()) record->RemoveBindFrameRef(GetRecord(bind.texelBufferView)->baseResource); } if(bind.imageInfo.imageView != VK_NULL_HANDLE) { record->RemoveBindFrameRef(GetResID(bind.imageInfo.imageView)); record->RemoveBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource); if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId()) record->RemoveBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem); } if(bind.imageInfo.sampler != VK_NULL_HANDLE) { record->RemoveBindFrameRef(GetResID(bind.imageInfo.sampler)); } if(bind.bufferInfo.buffer != VK_NULL_HANDLE) { record->RemoveBindFrameRef(GetResID(bind.bufferInfo.buffer)); if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId()) record->RemoveBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource); } // NULL everything out now so that we don't accidentally reference an object // that was removed already bind.texelBufferView = VK_NULL_HANDLE; bind.bufferInfo.buffer = VK_NULL_HANDLE; bind.imageInfo.imageView = VK_NULL_HANDLE; bind.imageInfo.sampler = VK_NULL_HANDLE; if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { bind.texelBufferView = pDescriptorWrites[i].pTexelBufferView[d]; } else if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) { bind.imageInfo = pDescriptorWrites[i].pImageInfo[d]; // ignore descriptors not part of the write, by NULL'ing out those members // as they might not even point to a valid object if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) bind.imageInfo.imageView = VK_NULL_HANDLE; else if(pDescriptorWrites[i].descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) bind.imageInfo.sampler = VK_NULL_HANDLE; } else { bind.bufferInfo = pDescriptorWrites[i].pBufferInfo[d]; } if(bind.texelBufferView != VK_NULL_HANDLE) { record->AddBindFrameRef(GetResID(bind.texelBufferView), eFrameRef_Read, GetRecord(bind.texelBufferView)->sparseInfo != NULL); if(GetRecord(bind.texelBufferView)->baseResource != ResourceId()) record->AddBindFrameRef(GetRecord(bind.texelBufferView)->baseResource, ref); } if(bind.imageInfo.imageView != VK_NULL_HANDLE) { record->AddBindFrameRef(GetResID(bind.imageInfo.imageView), eFrameRef_Read, GetRecord(bind.imageInfo.imageView)->sparseInfo != NULL); record->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource, ref); if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId()) record->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem, eFrameRef_Read); } if(bind.imageInfo.sampler != VK_NULL_HANDLE) { record->AddBindFrameRef(GetResID(bind.imageInfo.sampler), eFrameRef_Read); } if(bind.bufferInfo.buffer != VK_NULL_HANDLE) { record->AddBindFrameRef(GetResID(bind.bufferInfo.buffer), eFrameRef_Read, GetRecord(bind.bufferInfo.buffer)->sparseInfo != NULL); if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId()) record->AddBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource, ref); } } } // this is almost identical to the above loop, except that instead of sourcing the descriptors // from the writedescriptor struct, we source it from our stored bindings on the source // descrpitor set for(uint32_t i=0; i < copyCount; i++) { VkResourceRecord *dstrecord = GetRecord(pDescriptorCopies[i].dstSet); RDCASSERT(dstrecord->descInfo && dstrecord->descInfo->layout); const DescSetLayout &layout = *dstrecord->descInfo->layout; VkResourceRecord *srcrecord = GetRecord(pDescriptorCopies[i].srcSet); RDCASSERT(pDescriptorCopies[i].dstBinding < dstrecord->descInfo->descBindings.size()); RDCASSERT(pDescriptorCopies[i].srcBinding < srcrecord->descInfo->descBindings.size()); DescriptorSetSlot *dstbinding = dstrecord->descInfo->descBindings[pDescriptorCopies[i].dstBinding]; DescriptorSetSlot *srcbinding = srcrecord->descInfo->descBindings[pDescriptorCopies[i].srcBinding]; FrameRefType ref = eFrameRef_Write; switch(layout.bindings[pDescriptorCopies[i].dstBinding].descriptorType) { case VK_DESCRIPTOR_TYPE_SAMPLER: case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: ref = eFrameRef_Read; break; case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: ref = eFrameRef_Write; break; default: RDCERR("Unexpected descriptor type"); } for(uint32_t d=0; d < pDescriptorCopies[i].descriptorCount; d++) { DescriptorSetSlot &bind = dstbinding[pDescriptorCopies[i].dstArrayElement + d]; if(bind.texelBufferView != VK_NULL_HANDLE) { dstrecord->RemoveBindFrameRef(GetResID(bind.texelBufferView)); if(GetRecord(bind.texelBufferView)->baseResource != ResourceId()) dstrecord->RemoveBindFrameRef(GetRecord(bind.texelBufferView)->baseResource); } if(bind.imageInfo.imageView != VK_NULL_HANDLE) { dstrecord->RemoveBindFrameRef(GetResID(bind.imageInfo.imageView)); dstrecord->RemoveBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource); if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId()) dstrecord->RemoveBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem); } if(bind.imageInfo.sampler != VK_NULL_HANDLE) { dstrecord->RemoveBindFrameRef(GetResID(bind.imageInfo.sampler)); } if(bind.bufferInfo.buffer != VK_NULL_HANDLE) { dstrecord->RemoveBindFrameRef(GetResID(bind.bufferInfo.buffer)); if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId()) dstrecord->RemoveBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource); } bind = srcbinding[pDescriptorCopies[i].srcArrayElement + d]; if(bind.texelBufferView != VK_NULL_HANDLE) { dstrecord->AddBindFrameRef(GetResID(bind.texelBufferView), eFrameRef_Read, GetRecord(bind.texelBufferView)->sparseInfo != NULL); if(GetRecord(bind.texelBufferView)->baseResource != ResourceId()) dstrecord->AddBindFrameRef(GetRecord(bind.texelBufferView)->baseResource, ref); } if(bind.imageInfo.imageView != VK_NULL_HANDLE) { dstrecord->AddBindFrameRef(GetResID(bind.imageInfo.imageView), eFrameRef_Read, GetRecord(bind.imageInfo.imageView)->sparseInfo != NULL); dstrecord->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResource, ref); if(GetRecord(bind.imageInfo.imageView)->baseResourceMem != ResourceId()) dstrecord->AddBindFrameRef(GetRecord(bind.imageInfo.imageView)->baseResourceMem, eFrameRef_Read); } if(bind.imageInfo.sampler != VK_NULL_HANDLE) { dstrecord->AddBindFrameRef(GetResID(bind.imageInfo.sampler), ref); } if(bind.bufferInfo.buffer != VK_NULL_HANDLE) { dstrecord->AddBindFrameRef(GetResID(bind.bufferInfo.buffer), eFrameRef_Read, GetRecord(bind.bufferInfo.buffer)->sparseInfo != NULL); if(GetRecord(bind.bufferInfo.buffer)->baseResource != ResourceId()) dstrecord->AddBindFrameRef(GetRecord(bind.bufferInfo.buffer)->baseResource, ref); } } } } }
string CompileSPIRV(SPIRVShaderStage shadType, const std::vector<std::string> &sources, vector<uint32_t> &spirv) { if(shadType >= eSPIRVInvalid) return "Invalid shader stage specified"; string errors = ""; const char **strs = new const char *[sources.size()]; for(size_t i=0; i < sources.size(); i++) strs[i] = sources[i].c_str(); RDCCOMPILE_ASSERT( (int)EShLangVertex == (int)eSPIRVVertex && (int)EShLangTessControl == (int)eSPIRVTessControl && (int)EShLangTessEvaluation == (int)eSPIRVTessEvaluation && (int)EShLangGeometry == (int)eSPIRVGeometry && (int)EShLangCompute == (int)eSPIRVCompute, "Shader language enums don't match"); { EShLanguage lang = EShLanguage(shadType); glslang::TShader *shader = new glslang::TShader(lang); shader->setStrings(strs, (int)sources.size()); bool success = shader->parse(&DefaultResources, 110, false, EShMessages(EShMsgSpvRules|EShMsgVulkanRules)); if(!success) { errors = "Shader failed to compile:\n\n"; errors += shader->getInfoLog(); errors += "\n\n"; errors += shader->getInfoDebugLog(); } else { glslang::TProgram *program = new glslang::TProgram(); program->addShader(shader); success = program->link(EShMsgDefault); if(!success) { errors = "Program failed to link:\n\n"; errors += program->getInfoLog(); errors += "\n\n"; errors += program->getInfoDebugLog(); } else { glslang::TIntermediate *intermediate = program->getIntermediate(lang); // if we successfully compiled and linked, we must have the stage we started with RDCASSERT(intermediate); glslang::GlslangToSpv(*intermediate, spirv); } delete program; } delete shader; } delete[] strs; return errors; }
void GLRenderState::FetchState(void *ctx, WrappedOpenGL *gl) { GLint boolread = 0; // TODO check GL_MAX_* // TODO check the extensions/core version for these is around { GLenum pnames[] = { eGL_CLIP_DISTANCE0, eGL_CLIP_DISTANCE1, eGL_CLIP_DISTANCE2, eGL_CLIP_DISTANCE3, eGL_CLIP_DISTANCE4, eGL_CLIP_DISTANCE5, eGL_CLIP_DISTANCE6, eGL_CLIP_DISTANCE7, eGL_COLOR_LOGIC_OP, eGL_CULL_FACE, eGL_DEPTH_CLAMP, eGL_DEPTH_TEST, eGL_DEPTH_BOUNDS_TEST_EXT, eGL_DITHER, eGL_FRAMEBUFFER_SRGB, eGL_LINE_SMOOTH, eGL_MULTISAMPLE, eGL_POLYGON_SMOOTH, eGL_POLYGON_OFFSET_FILL, eGL_POLYGON_OFFSET_LINE, eGL_POLYGON_OFFSET_POINT, eGL_PROGRAM_POINT_SIZE, eGL_PRIMITIVE_RESTART, eGL_PRIMITIVE_RESTART_FIXED_INDEX, eGL_SAMPLE_ALPHA_TO_COVERAGE, eGL_SAMPLE_ALPHA_TO_ONE, eGL_SAMPLE_COVERAGE, eGL_SAMPLE_MASK, eGL_RASTER_MULTISAMPLE_EXT, eGL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT, eGL_STENCIL_TEST, eGL_TEXTURE_CUBE_MAP_SEAMLESS, eGL_BLEND_ADVANCED_COHERENT_KHR, }; RDCCOMPILE_ASSERT(ARRAY_COUNT(pnames) == eEnabled_Count, "Wrong number of pnames"); for(GLuint i=0; i < eEnabled_Count; i++) { if(pnames[i] == eGL_BLEND_ADVANCED_COHERENT_KHR && !ExtensionSupported[ExtensionSupported_KHR_blend_equation_advanced_coherent]) { Enabled[i] = true; continue; } if((pnames[i] == eGL_RASTER_MULTISAMPLE_EXT || pnames[i] == eGL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT) && !ExtensionSupported[ExtensionSupported_EXT_raster_multisample]) { Enabled[i] = false; continue; } Enabled[i] = (m_Real->glIsEnabled(pnames[i]) == GL_TRUE); } } m_Real->glGetIntegerv(eGL_ACTIVE_TEXTURE, (GLint *)&ActiveTexture); // TODO fetch bindings for other types than 2D for(GLuint i=0; i < (GLuint)ARRAY_COUNT(Tex2D); i++) { m_Real->glActiveTexture(GLenum(eGL_TEXTURE0 + i)); m_Real->glGetIntegerv(eGL_TEXTURE_BINDING_2D, (GLint*)&Tex2D[i]); m_Real->glGetIntegerv(eGL_SAMPLER_BINDING, (GLint*)&Samplers[i]); } m_Real->glActiveTexture(ActiveTexture); m_Real->glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&VAO); m_Real->glGetIntegerv(eGL_TRANSFORM_FEEDBACK_BINDING, (GLint *)&FeedbackObj); // the spec says that you can only query for the format that was previously set, or you get // undefined results. Ie. if someone set ints, this might return anything. However there's also // no way to query for the type so we just have to hope for the best and hope most people are // sane and don't use these except for a default "all 0s" attrib. GLuint maxNumAttribs = 0; m_Real->glGetIntegerv(eGL_MAX_VERTEX_ATTRIBS, (GLint *)&maxNumAttribs); for(GLuint i=0; i < RDCMIN(maxNumAttribs, (GLuint)ARRAY_COUNT(GenericVertexAttribs)); i++) m_Real->glGetVertexAttribfv(i, eGL_CURRENT_VERTEX_ATTRIB, &GenericVertexAttribs[i].x); m_Real->glGetFloatv(eGL_POINT_FADE_THRESHOLD_SIZE, &PointFadeThresholdSize); m_Real->glGetIntegerv(eGL_POINT_SPRITE_COORD_ORIGIN, (GLint*)&PointSpriteOrigin); m_Real->glGetFloatv(eGL_LINE_WIDTH, &LineWidth); m_Real->glGetFloatv(eGL_POINT_SIZE, &PointSize); m_Real->glGetIntegerv(eGL_PRIMITIVE_RESTART_INDEX, (GLint *)&PrimitiveRestartIndex); if(GLCoreVersion >= 45 || ExtensionSupported[ExtensionSupported_ARB_clip_control]) { m_Real->glGetIntegerv(eGL_CLIP_ORIGIN, (GLint *)&ClipOrigin); m_Real->glGetIntegerv(eGL_CLIP_DEPTH_MODE, (GLint *)&ClipDepth); } else { ClipOrigin = eGL_LOWER_LEFT; ClipDepth = eGL_NEGATIVE_ONE_TO_ONE; } m_Real->glGetIntegerv(eGL_PROVOKING_VERTEX, (GLint *)&ProvokingVertex); m_Real->glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&Program); m_Real->glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&Pipeline); const GLenum shs[] = { eGL_VERTEX_SHADER, eGL_TESS_CONTROL_SHADER, eGL_TESS_EVALUATION_SHADER, eGL_GEOMETRY_SHADER, eGL_FRAGMENT_SHADER, VendorCheck[VendorCheck_AMD_pipeline_compute_query] ? eGL_NONE : eGL_COMPUTE_SHADER, }; RDCCOMPILE_ASSERT(ARRAY_COUNT(shs) == ARRAY_COUNT(Subroutines), "Subroutine array not the right size"); for(size_t s=0; s < ARRAY_COUNT(shs); s++) { GLuint prog = Program; if(prog == 0 && Pipeline != 0 && shs[s] != eGL_NONE) m_Real->glGetProgramPipelineiv(Pipeline, shs[s], (GLint *)&prog); if(prog == 0) continue; m_Real->glGetProgramStageiv(prog, shs[s], eGL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, &Subroutines[s].numSubroutines); for(GLint i=0; i < Subroutines[s].numSubroutines; i++) m_Real->glGetUniformSubroutineuiv(shs[s], i, &Subroutines[s].Values[s]); } m_Real->glGetIntegerv(eGL_ARRAY_BUFFER_BINDING, (GLint*)&BufferBindings[eBufIdx_Array]); m_Real->glGetIntegerv(eGL_COPY_READ_BUFFER_BINDING, (GLint*)&BufferBindings[eBufIdx_Copy_Read]); m_Real->glGetIntegerv(eGL_COPY_WRITE_BUFFER_BINDING, (GLint*)&BufferBindings[eBufIdx_Copy_Write]); m_Real->glGetIntegerv(eGL_DRAW_INDIRECT_BUFFER_BINDING, (GLint*)&BufferBindings[eBufIdx_Draw_Indirect]); m_Real->glGetIntegerv(eGL_DISPATCH_INDIRECT_BUFFER_BINDING, (GLint*)&BufferBindings[eBufIdx_Dispatch_Indirect]); m_Real->glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint*)&BufferBindings[eBufIdx_Pixel_Pack]); m_Real->glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint*)&BufferBindings[eBufIdx_Pixel_Unpack]); m_Real->glGetIntegerv(eGL_QUERY_BUFFER_BINDING, (GLint*)&BufferBindings[eBufIdx_Query]); m_Real->glGetIntegerv(eGL_TEXTURE_BUFFER_BINDING, (GLint*)&BufferBindings[eBufIdx_Texture]); struct { IdxRangeBuffer *bufs; int count; GLenum binding; GLenum start; GLenum size; GLenum maxcount; } idxBufs[] = { { AtomicCounter, ARRAY_COUNT(AtomicCounter), eGL_ATOMIC_COUNTER_BUFFER_BINDING, eGL_ATOMIC_COUNTER_BUFFER_START, eGL_ATOMIC_COUNTER_BUFFER_SIZE, eGL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, }, { ShaderStorage, ARRAY_COUNT(ShaderStorage), eGL_SHADER_STORAGE_BUFFER_BINDING, eGL_SHADER_STORAGE_BUFFER_START, eGL_SHADER_STORAGE_BUFFER_SIZE, eGL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, }, { TransformFeedback, ARRAY_COUNT(TransformFeedback), eGL_TRANSFORM_FEEDBACK_BUFFER_BINDING, eGL_TRANSFORM_FEEDBACK_BUFFER_START, eGL_TRANSFORM_FEEDBACK_BUFFER_SIZE, eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, }, { UniformBinding, ARRAY_COUNT(UniformBinding), eGL_UNIFORM_BUFFER_BINDING, eGL_UNIFORM_BUFFER_START, eGL_UNIFORM_BUFFER_SIZE, eGL_MAX_UNIFORM_BUFFER_BINDINGS, }, }; for(GLuint b=0; b < (GLuint)ARRAY_COUNT(idxBufs); b++) { GLint maxCount = 0; m_Real->glGetIntegerv(idxBufs[b].maxcount, &maxCount); for(int i=0; i < idxBufs[b].count && i < maxCount; i++) { m_Real->glGetIntegeri_v(idxBufs[b].binding, i, (GLint*)&idxBufs[b].bufs[i].name); m_Real->glGetInteger64i_v(idxBufs[b].start, i, (GLint64*)&idxBufs[b].bufs[i].start); m_Real->glGetInteger64i_v(idxBufs[b].size, i, (GLint64*)&idxBufs[b].bufs[i].size); } } for(GLuint i=0; i < (GLuint)ARRAY_COUNT(Blends); i++) { m_Real->glGetIntegeri_v(eGL_BLEND_EQUATION_RGB, i, (GLint*)&Blends[i].EquationRGB); m_Real->glGetIntegeri_v(eGL_BLEND_EQUATION_ALPHA, i, (GLint*)&Blends[i].EquationAlpha); m_Real->glGetIntegeri_v(eGL_BLEND_SRC_RGB, i, (GLint*)&Blends[i].SourceRGB); m_Real->glGetIntegeri_v(eGL_BLEND_SRC_ALPHA, i, (GLint*)&Blends[i].SourceAlpha); m_Real->glGetIntegeri_v(eGL_BLEND_DST_RGB, i, (GLint*)&Blends[i].DestinationRGB); m_Real->glGetIntegeri_v(eGL_BLEND_DST_ALPHA, i, (GLint*)&Blends[i].DestinationAlpha); Blends[i].Enabled = (m_Real->glIsEnabledi(eGL_BLEND, i) == GL_TRUE); } m_Real->glGetFloatv(eGL_BLEND_COLOR, &BlendColor[0]); for(GLuint i=0; i < (GLuint)ARRAY_COUNT(Viewports); i++) m_Real->glGetFloati_v(eGL_VIEWPORT, i, &Viewports[i].x); for(GLuint i=0; i < (GLuint)ARRAY_COUNT(Scissors); i++) { m_Real->glGetIntegeri_v(eGL_SCISSOR_BOX, i, &Scissors[i].x); Scissors[i].enabled = (m_Real->glIsEnabledi(eGL_SCISSOR_TEST, i) == GL_TRUE); } m_Real->glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&DrawFBO); m_Real->glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, (GLint *)&ReadFBO); m_Real->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, 0); m_Real->glBindFramebuffer(eGL_READ_FRAMEBUFFER, 0); for(size_t i=0; i < ARRAY_COUNT(DrawBuffers); i++) m_Real->glGetIntegerv(GLenum(eGL_DRAW_BUFFER0 + i), (GLint *)&DrawBuffers[i]); m_Real->glGetIntegerv(eGL_READ_BUFFER, (GLint *)&ReadBuffer); m_Real->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, DrawFBO); m_Real->glBindFramebuffer(eGL_READ_FRAMEBUFFER, ReadFBO); m_Real->glGetIntegerv(eGL_FRAGMENT_SHADER_DERIVATIVE_HINT, (GLint *)&Hints.Derivatives); m_Real->glGetIntegerv(eGL_LINE_SMOOTH_HINT, (GLint *)&Hints.LineSmooth); m_Real->glGetIntegerv(eGL_POLYGON_SMOOTH_HINT, (GLint *)&Hints.PolySmooth); m_Real->glGetIntegerv(eGL_TEXTURE_COMPRESSION_HINT, (GLint *)&Hints.TexCompression); m_Real->glGetBooleanv(eGL_DEPTH_WRITEMASK, &DepthWriteMask); m_Real->glGetFloatv(eGL_DEPTH_CLEAR_VALUE, &DepthClearValue); m_Real->glGetIntegerv(eGL_DEPTH_FUNC, (GLint *)&DepthFunc); for(GLuint i=0; i < (GLuint)ARRAY_COUNT(DepthRanges); i++) m_Real->glGetDoublei_v(eGL_DEPTH_RANGE, i, &DepthRanges[i].nearZ); m_Real->glGetDoublev(eGL_DEPTH_BOUNDS_TEST_EXT, &DepthBounds.nearZ); { m_Real->glGetIntegerv(eGL_STENCIL_FUNC, (GLint *)&StencilFront.func); m_Real->glGetIntegerv(eGL_STENCIL_BACK_FUNC, (GLint *)&StencilBack.func); m_Real->glGetIntegerv(eGL_STENCIL_REF, (GLint *)&StencilFront.ref); m_Real->glGetIntegerv(eGL_STENCIL_BACK_REF, (GLint *)&StencilBack.ref); GLint maskval; m_Real->glGetIntegerv(eGL_STENCIL_VALUE_MASK, &maskval); StencilFront.valuemask = uint8_t(maskval&0xff); m_Real->glGetIntegerv(eGL_STENCIL_BACK_VALUE_MASK, &maskval); StencilBack.valuemask = uint8_t(maskval&0xff); m_Real->glGetIntegerv(eGL_STENCIL_WRITEMASK, &maskval); StencilFront.writemask = uint8_t(maskval&0xff); m_Real->glGetIntegerv(eGL_STENCIL_BACK_WRITEMASK, &maskval); StencilBack.writemask = uint8_t(maskval&0xff); m_Real->glGetIntegerv(eGL_STENCIL_FAIL, (GLint *)&StencilFront.stencilFail); m_Real->glGetIntegerv(eGL_STENCIL_BACK_FAIL, (GLint *)&StencilBack.stencilFail); m_Real->glGetIntegerv(eGL_STENCIL_PASS_DEPTH_FAIL, (GLint *)&StencilFront.depthFail); m_Real->glGetIntegerv(eGL_STENCIL_BACK_PASS_DEPTH_FAIL, (GLint *)&StencilBack.depthFail); m_Real->glGetIntegerv(eGL_STENCIL_PASS_DEPTH_PASS, (GLint *)&StencilFront.pass); m_Real->glGetIntegerv(eGL_STENCIL_BACK_PASS_DEPTH_PASS, (GLint *)&StencilBack.pass); } m_Real->glGetIntegerv(eGL_STENCIL_CLEAR_VALUE, (GLint *)&StencilClearValue); for(size_t i=0; i < ARRAY_COUNT(ColorMasks); i++) m_Real->glGetBooleanv(eGL_COLOR_WRITEMASK, &ColorMasks[i].red); m_Real->glGetIntegeri_v(eGL_SAMPLE_MASK_VALUE, 0, (GLint *)&SampleMask[0]); m_Real->glGetIntegerv(eGL_SAMPLE_COVERAGE_VALUE, (GLint *)&SampleCoverage); m_Real->glGetIntegerv(eGL_SAMPLE_COVERAGE_INVERT, (GLint *)&boolread); SampleCoverageInvert = (boolread != 0); m_Real->glGetFloatv(eGL_MIN_SAMPLE_SHADING_VALUE, &MinSampleShading); if(ExtensionSupported[ExtensionSupported_EXT_raster_multisample]) m_Real->glGetIntegerv(eGL_RASTER_SAMPLES_EXT, (GLint *)&RasterSamples); else RasterSamples = 0; if(ExtensionSupported[ExtensionSupported_EXT_raster_multisample]) m_Real->glGetIntegerv(eGL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT, (GLint *)&RasterFixed); else RasterFixed = false; m_Real->glGetIntegerv(eGL_LOGIC_OP_MODE, (GLint *)&LogicOp); m_Real->glGetFloatv(eGL_COLOR_CLEAR_VALUE, &ColorClearValue.red); m_Real->glGetIntegerv(eGL_PATCH_VERTICES, &PatchParams.numVerts); m_Real->glGetFloatv(eGL_PATCH_DEFAULT_INNER_LEVEL, &PatchParams.defaultInnerLevel[0]); m_Real->glGetFloatv(eGL_PATCH_DEFAULT_OUTER_LEVEL, &PatchParams.defaultOuterLevel[0]); if(!VendorCheck[VendorCheck_AMD_polygon_mode_query]) { // This was listed in docs as enumeration[2] even though polygon mode can't be set independently for front // and back faces for a while, so pass large enough array to be sure. // AMD driver claims this doesn't exist anymore in core, so don't return any value, set to // default GL_FILL to be safe GLenum dummy[2] = { eGL_FILL, eGL_FILL }; m_Real->glGetIntegerv(eGL_POLYGON_MODE, (GLint *)&dummy); PolygonMode = dummy[0]; } else { PolygonMode = eGL_FILL; } m_Real->glGetFloatv(eGL_POLYGON_OFFSET_FACTOR, &PolygonOffset[0]); m_Real->glGetFloatv(eGL_POLYGON_OFFSET_UNITS, &PolygonOffset[1]); if(ExtensionSupported[ExtensionSupported_EXT_polygon_offset_clamp]) m_Real->glGetFloatv(eGL_POLYGON_OFFSET_CLAMP_EXT, &PolygonOffset[2]); else PolygonOffset[2] = 0.0f; m_Real->glGetIntegerv(eGL_FRONT_FACE, (GLint *)&FrontFace); m_Real->glGetIntegerv(eGL_CULL_FACE_MODE, (GLint *)&CullFace); }
void GLRenderState::ApplyState(void *ctx, WrappedOpenGL *gl) { { GLenum pnames[] = { eGL_CLIP_DISTANCE0, eGL_CLIP_DISTANCE1, eGL_CLIP_DISTANCE2, eGL_CLIP_DISTANCE3, eGL_CLIP_DISTANCE4, eGL_CLIP_DISTANCE5, eGL_CLIP_DISTANCE6, eGL_CLIP_DISTANCE7, eGL_COLOR_LOGIC_OP, eGL_CULL_FACE, eGL_DEPTH_CLAMP, eGL_DEPTH_TEST, eGL_DEPTH_BOUNDS_TEST_EXT, eGL_DITHER, eGL_FRAMEBUFFER_SRGB, eGL_LINE_SMOOTH, eGL_MULTISAMPLE, eGL_POLYGON_SMOOTH, eGL_POLYGON_OFFSET_FILL, eGL_POLYGON_OFFSET_LINE, eGL_POLYGON_OFFSET_POINT, eGL_PROGRAM_POINT_SIZE, eGL_PRIMITIVE_RESTART, eGL_PRIMITIVE_RESTART_FIXED_INDEX, eGL_SAMPLE_ALPHA_TO_COVERAGE, eGL_SAMPLE_ALPHA_TO_ONE, eGL_SAMPLE_COVERAGE, eGL_SAMPLE_MASK, eGL_RASTER_MULTISAMPLE_EXT, eGL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT, eGL_STENCIL_TEST, eGL_TEXTURE_CUBE_MAP_SEAMLESS, eGL_BLEND_ADVANCED_COHERENT_KHR, }; RDCCOMPILE_ASSERT(ARRAY_COUNT(pnames) == eEnabled_Count, "Wrong number of pnames"); for(GLuint i=0; i < eEnabled_Count; i++) { if(pnames[i] == eGL_BLEND_ADVANCED_COHERENT_KHR && !ExtensionSupported[ExtensionSupported_KHR_blend_equation_advanced_coherent]) continue; if((pnames[i] == eGL_RASTER_MULTISAMPLE_EXT || pnames[i] == eGL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT) && !ExtensionSupported[ExtensionSupported_EXT_raster_multisample]) continue; if(Enabled[i]) m_Real->glEnable(pnames[i]); else m_Real->glDisable(pnames[i]); } } for(GLuint i=0; i < (GLuint)ARRAY_COUNT(Tex2D); i++) { m_Real->glActiveTexture(GLenum(eGL_TEXTURE0 + i)); m_Real->glBindTexture(eGL_TEXTURE_2D, Tex2D[i]); m_Real->glBindSampler(i, Samplers[i]); } m_Real->glActiveTexture(ActiveTexture); m_Real->glBindVertexArray(VAO); m_Real->glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, FeedbackObj); // See FetchState(). The spec says that you have to SET the right format for the shader too, // but we couldn't query for the format so we can't set it here. GLuint maxNumAttribs = 0; m_Real->glGetIntegerv(eGL_MAX_VERTEX_ATTRIBS, (GLint *)&maxNumAttribs); for(GLuint i=0; i < RDCMIN(maxNumAttribs, (GLuint)ARRAY_COUNT(GenericVertexAttribs)); i++) m_Real->glVertexAttrib4fv(i, &GenericVertexAttribs[i].x); m_Real->glPointParameterf(eGL_POINT_FADE_THRESHOLD_SIZE, PointFadeThresholdSize); m_Real->glPointParameteri(eGL_POINT_SPRITE_COORD_ORIGIN, (GLint)PointSpriteOrigin); m_Real->glLineWidth(LineWidth); m_Real->glPointSize(PointSize); m_Real->glPrimitiveRestartIndex(PrimitiveRestartIndex); if(m_Real->glClipControl) // only available in 4.5+ m_Real->glClipControl(ClipOrigin, ClipDepth); m_Real->glProvokingVertex(ProvokingVertex); m_Real->glUseProgram(Program); m_Real->glBindProgramPipeline(Pipeline); GLenum shs[] = { eGL_VERTEX_SHADER, eGL_TESS_CONTROL_SHADER, eGL_TESS_EVALUATION_SHADER, eGL_GEOMETRY_SHADER, eGL_FRAGMENT_SHADER, eGL_COMPUTE_SHADER }; RDCCOMPILE_ASSERT(ARRAY_COUNT(shs) == ARRAY_COUNT(Subroutines), "Subroutine array not the right size"); for(size_t s=0; s < ARRAY_COUNT(shs); s++) if(Subroutines[s].numSubroutines > 0) m_Real->glUniformSubroutinesuiv(shs[s], Subroutines[s].numSubroutines, Subroutines[s].Values); m_Real->glBindBuffer(eGL_ARRAY_BUFFER, BufferBindings[eBufIdx_Array]); m_Real->glBindBuffer(eGL_COPY_READ_BUFFER, BufferBindings[eBufIdx_Copy_Read]); m_Real->glBindBuffer(eGL_COPY_WRITE_BUFFER, BufferBindings[eBufIdx_Copy_Write]); m_Real->glBindBuffer(eGL_DRAW_INDIRECT_BUFFER, BufferBindings[eBufIdx_Draw_Indirect]); m_Real->glBindBuffer(eGL_DISPATCH_INDIRECT_BUFFER, BufferBindings[eBufIdx_Dispatch_Indirect]); m_Real->glBindBuffer(eGL_PIXEL_PACK_BUFFER, BufferBindings[eBufIdx_Pixel_Pack]); m_Real->glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, BufferBindings[eBufIdx_Pixel_Unpack]); m_Real->glBindBuffer(eGL_QUERY_BUFFER, BufferBindings[eBufIdx_Query]); m_Real->glBindBuffer(eGL_TEXTURE_BUFFER, BufferBindings[eBufIdx_Texture]); struct { IdxRangeBuffer *bufs; int count; GLenum binding; GLenum maxcount; } idxBufs[] = { { AtomicCounter, ARRAY_COUNT(AtomicCounter), eGL_ATOMIC_COUNTER_BUFFER, eGL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, }, { ShaderStorage, ARRAY_COUNT(ShaderStorage), eGL_SHADER_STORAGE_BUFFER, eGL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, }, { TransformFeedback, ARRAY_COUNT(TransformFeedback), eGL_TRANSFORM_FEEDBACK_BUFFER, eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, }, { UniformBinding, ARRAY_COUNT(UniformBinding), eGL_UNIFORM_BUFFER, eGL_MAX_UNIFORM_BUFFER_BINDINGS, }, }; for(size_t b=0; b < ARRAY_COUNT(idxBufs); b++) { // only restore buffer bindings here if we were using the default transform feedback object if(idxBufs[b].binding == eGL_TRANSFORM_FEEDBACK_BUFFER && FeedbackObj) continue; GLint maxCount = 0; m_Real->glGetIntegerv(idxBufs[b].maxcount, &maxCount); for(int i=0; i < idxBufs[b].count && i < maxCount; i++) { if(idxBufs[b].bufs[i].name == 0 || (idxBufs[b].bufs[i].start == 0 && idxBufs[b].bufs[i].size == 0) ) m_Real->glBindBufferBase(idxBufs[b].binding, i, idxBufs[b].bufs[i].name); else m_Real->glBindBufferRange(idxBufs[b].binding, i, idxBufs[b].bufs[i].name, (GLintptr)idxBufs[b].bufs[i].start, (GLsizeiptr)idxBufs[b].bufs[i].size); } } for(GLuint i=0; i < (GLuint)ARRAY_COUNT(Blends); i++) { m_Real->glBlendFuncSeparatei(i, Blends[i].SourceRGB, Blends[i].DestinationRGB, Blends[i].SourceAlpha, Blends[i].DestinationAlpha); m_Real->glBlendEquationSeparatei(i, Blends[i].EquationRGB, Blends[i].EquationAlpha); if(Blends[i].Enabled) m_Real->glEnablei(eGL_BLEND, i); else m_Real->glDisablei(eGL_BLEND, i); } m_Real->glBlendColor(BlendColor[0], BlendColor[1], BlendColor[2], BlendColor[3]); m_Real->glViewportArrayv(0, ARRAY_COUNT(Viewports), &Viewports[0].x); for (GLuint s = 0; s < (GLuint)ARRAY_COUNT(Scissors); ++s) { m_Real->glScissorIndexedv(s, &Scissors[s].x); if (Scissors[s].enabled) m_Real->glEnablei(eGL_SCISSOR_TEST, s); else m_Real->glDisablei(eGL_SCISSOR_TEST, s); } GLenum DBs[8] = { eGL_NONE }; uint32_t numDBs = 0; for(GLuint i=0; i < (GLuint)ARRAY_COUNT(DrawBuffers); i++) { if(DrawBuffers[i] != eGL_NONE) { numDBs++; DBs[i] = DrawBuffers[i]; if(m_State < WRITING) { // since we are faking the default framebuffer with our own // to see the results, replace back/front/left/right with color attachment 0 if(DBs[i] == eGL_BACK_LEFT || DBs[i] == eGL_BACK_RIGHT || DBs[i] == eGL_FRONT_LEFT || DBs[i] == eGL_FRONT_RIGHT) DBs[i] = eGL_COLOR_ATTACHMENT0; // These aren't valid for glDrawBuffers but can be returned when we call glGet, // assume they mean left implicitly if(DBs[i] == eGL_BACK || DBs[i] == eGL_FRONT) DBs[i] = eGL_COLOR_ATTACHMENT0; } } else { break; } } // apply drawbuffers/readbuffer to default framebuffer m_Real->glBindFramebuffer(eGL_READ_FRAMEBUFFER, gl->GetFakeBBFBO()); m_Real->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, gl->GetFakeBBFBO()); m_Real->glDrawBuffers(numDBs, DBs); // see above for reasoning for this m_Real->glReadBuffer(eGL_COLOR_ATTACHMENT0); m_Real->glBindFramebuffer(eGL_READ_FRAMEBUFFER, ReadFBO); m_Real->glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, DrawFBO); m_Real->glHint(eGL_FRAGMENT_SHADER_DERIVATIVE_HINT, Hints.Derivatives); m_Real->glHint(eGL_LINE_SMOOTH_HINT, Hints.LineSmooth); m_Real->glHint(eGL_POLYGON_SMOOTH_HINT, Hints.PolySmooth); m_Real->glHint(eGL_TEXTURE_COMPRESSION_HINT, Hints.TexCompression); m_Real->glDepthMask(DepthWriteMask); m_Real->glClearDepth(DepthClearValue); m_Real->glDepthFunc(DepthFunc); for(GLuint i=0; i < (GLuint)ARRAY_COUNT(DepthRanges); i++) { double v[2] = { DepthRanges[i].nearZ, DepthRanges[i].farZ }; m_Real->glDepthRangeArrayv(i, 1, v); } if(m_Real->glDepthBoundsEXT) // extension, not always available m_Real->glDepthBoundsEXT(DepthBounds.nearZ, DepthBounds.farZ); { m_Real->glStencilFuncSeparate(eGL_FRONT, StencilFront.func, StencilFront.ref, StencilFront.valuemask); m_Real->glStencilFuncSeparate(eGL_BACK, StencilBack.func, StencilBack.ref, StencilBack.valuemask); m_Real->glStencilMaskSeparate(eGL_FRONT, StencilFront.writemask); m_Real->glStencilMaskSeparate(eGL_BACK, StencilBack.writemask); m_Real->glStencilOpSeparate(eGL_FRONT, StencilFront.stencilFail, StencilFront.depthFail, StencilFront.pass); m_Real->glStencilOpSeparate(eGL_BACK, StencilBack.stencilFail, StencilBack.depthFail, StencilBack.pass); } m_Real->glClearStencil((GLint)StencilClearValue); for(GLuint i=0; i < (GLuint)ARRAY_COUNT(ColorMasks); i++) m_Real->glColorMaski(i, ColorMasks[i].red, ColorMasks[i].green, ColorMasks[i].blue, ColorMasks[i].alpha); m_Real->glSampleMaski(0, (GLbitfield)SampleMask[0]); m_Real->glSampleCoverage(SampleCoverage, SampleCoverageInvert ? GL_TRUE : GL_FALSE); m_Real->glMinSampleShading(MinSampleShading); if(ExtensionSupported[ExtensionSupported_EXT_raster_multisample]) m_Real->glRasterSamplesEXT(RasterSamples, RasterFixed); m_Real->glLogicOp(LogicOp); m_Real->glClearColor(ColorClearValue.red, ColorClearValue.green, ColorClearValue.blue, ColorClearValue.alpha); m_Real->glPatchParameteri(eGL_PATCH_VERTICES, PatchParams.numVerts); m_Real->glPatchParameterfv(eGL_PATCH_DEFAULT_INNER_LEVEL, PatchParams.defaultInnerLevel); m_Real->glPatchParameterfv(eGL_PATCH_DEFAULT_OUTER_LEVEL, PatchParams.defaultOuterLevel); m_Real->glPolygonMode(eGL_FRONT_AND_BACK, PolygonMode); if(ExtensionSupported[ExtensionSupported_EXT_polygon_offset_clamp]) m_Real->glPolygonOffsetClampEXT(PolygonOffset[0], PolygonOffset[1], PolygonOffset[2]); else m_Real->glPolygonOffset(PolygonOffset[0], PolygonOffset[1]); m_Real->glFrontFace(FrontFace); m_Real->glCullFace(CullFace); }