From c1d07f6bc3e89f40f483f4a1fe367dd84fd4f06f Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 20 Feb 2024 19:35:38 +0000 Subject: [PATCH] Implement Get*Descriptor for virtual descriptor storage in D3D11 & GL --- renderdoc/api/replay/d3d11_pipestate.h | 18 + renderdoc/api/replay/gl_pipestate.h | 18 + renderdoc/driver/d3d11/d3d11_renderstate.h | 48 +++ renderdoc/driver/d3d11/d3d11_replay.cpp | 286 +++++++++++++- renderdoc/driver/gl/gl_renderstate.h | 66 ++++ renderdoc/driver/gl/gl_replay.cpp | 418 +++++++++++++++++++++ renderdoc/driver/gl/gl_resources.cpp | 6 +- renderdoc/driver/gl/gl_resources.h | 2 +- renderdoc/replay/renderdoc_serialise.inl | 12 +- 9 files changed, 866 insertions(+), 8 deletions(-) diff --git a/renderdoc/api/replay/d3d11_pipestate.h b/renderdoc/api/replay/d3d11_pipestate.h index b9450b2fd..0ca46a6d5 100644 --- a/renderdoc/api/replay/d3d11_pipestate.h +++ b/renderdoc/api/replay/d3d11_pipestate.h @@ -783,6 +783,24 @@ struct State )"); Shader computeShader; + DOCUMENT(R"(The virtual descriptor storage. + +:type: ResourceId +)"); + ResourceId descriptorStore; + + DOCUMENT(R"(The number of descriptors in the virtual descriptor storage. + +:type: int +)"); + uint32_t descriptorCount; + + DOCUMENT(R"(The byte size of a descriptor in the virtual descriptor storage. + +:type: int +)"); + uint32_t descriptorByteSize; + DOCUMENT(R"(The stream-out pipeline stage. :type: D3D11StreamOut diff --git a/renderdoc/api/replay/gl_pipestate.h b/renderdoc/api/replay/gl_pipestate.h index 4eb559b7f..3b1bad3ea 100644 --- a/renderdoc/api/replay/gl_pipestate.h +++ b/renderdoc/api/replay/gl_pipestate.h @@ -913,6 +913,24 @@ struct State )"); rdcarray images; + DOCUMENT(R"(The virtual descriptor storage. + +:type: ResourceId +)"); + ResourceId descriptorStore; + + DOCUMENT(R"(The number of descriptors in the virtual descriptor storage. + +:type: int +)"); + uint32_t descriptorCount; + + DOCUMENT(R"(The byte size of a descriptor in the virtual descriptor storage. + +:type: int +)"); + uint32_t descriptorByteSize; + DOCUMENT(R"(The transform feedback stage. :type: GLFeedback diff --git a/renderdoc/driver/d3d11/d3d11_renderstate.h b/renderdoc/driver/d3d11/d3d11_renderstate.h index f0e964b94..62b1f5f04 100644 --- a/renderdoc/driver/d3d11/d3d11_renderstate.h +++ b/renderdoc/driver/d3d11/d3d11_renderstate.h @@ -33,6 +33,54 @@ class WrappedID3D11Device; class WrappedID3D11DeviceContext; class D3D11ResourceManager; +// mapping of 'index in descriptor store' to fixed bindings, linearly in a given stage's members +enum class D3D11DescriptorMapping : uint32_t +{ + CBs = 0, + SRVs = CBs + D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, + Samplers = SRVs + D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, + UAVs = Samplers + D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, + Count = UAVs + D3D11_1_UAV_SLOT_COUNT, + Invalid = ~0U, +}; + +struct D3D11DescriptorLocation +{ + ShaderStage stage; + D3D11DescriptorMapping type; + uint32_t idx; +}; + +inline D3D11DescriptorLocation DecodeD3D11DescriptorIndex(uint32_t idx) +{ + ShaderStage stage = ShaderStage(idx / (uint32_t)D3D11DescriptorMapping::Count); + + idx %= (uint32_t)D3D11DescriptorMapping::Count; + + if((uint32_t)stage > (uint32_t)ShaderStage::Compute) + return {stage, D3D11DescriptorMapping::Invalid, 0}; + + // go in reverse order to handle each case with a >= +#define HANDLE_TYPE(type) \ + else if(idx >= (uint32_t)D3D11DescriptorMapping::type) return { \ + stage, \ + D3D11DescriptorMapping::type, \ + idx - (uint32_t)D3D11DescriptorMapping::type, \ + } + HANDLE_TYPE(UAVs); + HANDLE_TYPE(Samplers); + HANDLE_TYPE(SRVs); + HANDLE_TYPE(CBs); +#undef HANDLE_TYPE + + return {stage, D3D11DescriptorMapping::Invalid, 0}; +} + +inline uint32_t EncodeD3D11DescriptorIndex(const D3D11DescriptorLocation &idx) +{ + return (uint32_t)idx.stage * (uint32_t)D3D11DescriptorMapping::Count + (uint32_t)idx.type + idx.idx; +} + struct D3D11RenderState { enum EmptyInit diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index 1c2ce5963..55f05c16c 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -741,6 +741,11 @@ void D3D11Replay::SavePipelineState(uint32_t eventId) D3D11ResourceManager *rm = m_pDevice->GetResourceManager(); + ret.descriptorStore = m_pImmediateContext->GetDescriptorsID(); + ret.descriptorCount = + EncodeD3D11DescriptorIndex({ShaderStage::Compute, D3D11DescriptorMapping::Count, 0}); + ret.descriptorByteSize = 1; + ret.inputAssembly.bytecode = NULL; ret.inputAssembly.resourceId = ResourceId(); ret.inputAssembly.layouts.clear(); @@ -1671,14 +1676,243 @@ rdcarray D3D11Replay::GetDescriptors(ResourceId descriptorStore, if(descriptorStore != m_pImmediateContext->GetDescriptorsID()) { - RDCERR("Descriptors query for invalid descriptor store on fixed bindings API (D3D11)"); + RDCERR( + "Descriptors query for invalid descriptor descriptorStore on fixed bindings API (D3D11)"); return ret; } + D3D11RenderState *rs = m_pDevice->GetImmediateContext()->GetCurrentPipelineState(); + D3D11ResourceManager *rm = m_pDevice->GetResourceManager(); + size_t count = 0; for(const DescriptorRange &r : ranges) count += r.count; ret.resize(count); + + const D3D11RenderState::Shader *srcArr[] = {&rs->VS, &rs->HS, &rs->DS, &rs->GS, &rs->PS, &rs->CS}; + + size_t dst = 0; + for(const DescriptorRange &r : ranges) + { + uint32_t descriptorId = r.offset; + + for(uint32_t i = 0; i < r.count; i++, dst++, descriptorId++) + { + D3D11DescriptorLocation idx = DecodeD3D11DescriptorIndex(descriptorId); + const D3D11RenderState::Shader &src = *srcArr[(uint32_t)idx.stage]; + + if(idx.type == D3D11DescriptorMapping::CBs) + { + ret[dst].type = DescriptorType::ConstantBuffer; + + ret[dst].resource = rm->GetOriginalID(GetIDForDeviceChild(src.ConstantBuffers[idx.idx])); + ret[dst].byteOffset = src.CBOffsets[idx.idx] * sizeof(Vec4f); + ret[dst].byteSize = src.CBCounts[idx.idx] * sizeof(Vec4f); + } + else if(idx.type == D3D11DescriptorMapping::SRVs) + { + ID3D11ShaderResourceView *view = src.SRVs[idx.idx]; + + ret[dst].view = rm->GetOriginalID(GetIDForDeviceChild(view)); + + ret[dst].type = DescriptorType::Image; + if(ret[dst].view != ResourceId()) + { + D3D11_SHADER_RESOURCE_VIEW_DESC desc; + view->GetDesc(&desc); + + ret[dst].format = MakeResourceFormat(desc.Format); + + ID3D11Resource *res = NULL; + view->GetResource(&res); + + ret[dst].elementByteSize = + desc.Format == DXGI_FORMAT_UNKNOWN ? 1 : GetByteSize(1, 1, 1, desc.Format, 0); + + ret[dst].resource = rm->GetOriginalID(GetIDForDeviceChild(res)); + + ret[dst].textureType = MakeTextureDim(desc.ViewDimension); + + if(desc.ViewDimension == D3D11_SRV_DIMENSION_BUFFER) + { + ret[dst].type = DescriptorType::TypedBuffer; + + D3D11_BUFFER_DESC bufdesc; + ((ID3D11Buffer *)res)->GetDesc(&bufdesc); + + if(bufdesc.StructureByteStride > 0 && desc.Format == DXGI_FORMAT_UNKNOWN) + { + ret[dst].elementByteSize = bufdesc.StructureByteStride; + ret[dst].type = DescriptorType::Buffer; + } + + ret[dst].byteOffset = desc.Buffer.FirstElement * ret[dst].elementByteSize; + ret[dst].byteSize = desc.Buffer.NumElements * ret[dst].elementByteSize; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_BUFFEREX) + { + ret[dst].type = DescriptorType::TypedBuffer; + + ret[dst].flags = DescriptorFlags(desc.BufferEx.Flags); + + D3D11_BUFFER_DESC bufdesc; + ((ID3D11Buffer *)res)->GetDesc(&bufdesc); + + if(bufdesc.StructureByteStride > 0 && desc.Format == DXGI_FORMAT_UNKNOWN) + { + ret[dst].elementByteSize = bufdesc.StructureByteStride; + ret[dst].type = DescriptorType::Buffer; + } + + ret[dst].byteOffset = desc.BufferEx.FirstElement * ret[dst].elementByteSize; + ret[dst].byteSize = desc.BufferEx.NumElements * ret[dst].elementByteSize; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE1D) + { + ret[dst].firstMip = desc.Texture1D.MostDetailedMip & 0xff; + ret[dst].numMips = desc.Texture1D.MipLevels & 0xff; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE1DARRAY) + { + ret[dst].firstMip = desc.Texture1DArray.MostDetailedMip & 0xff; + ret[dst].numMips = desc.Texture1DArray.MipLevels & 0xff; + ret[dst].numSlices = desc.Texture1DArray.ArraySize & 0xffff; + ret[dst].firstSlice = desc.Texture1DArray.FirstArraySlice & 0xffff; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2D) + { + ret[dst].firstMip = desc.Texture2D.MostDetailedMip & 0xff; + ret[dst].numMips = desc.Texture2D.MipLevels & 0xff; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DARRAY) + { + ret[dst].firstMip = desc.Texture2DArray.MostDetailedMip & 0xff; + ret[dst].numMips = desc.Texture2DArray.MipLevels & 0xff; + ret[dst].firstSlice = desc.Texture2DArray.FirstArraySlice & 0xffff; + ret[dst].numSlices = desc.Texture2DArray.ArraySize & 0xffff; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DMS) + { + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY) + { + ret[dst].numSlices = desc.Texture2DMSArray.ArraySize & 0xffff; + ret[dst].firstSlice = desc.Texture2DMSArray.FirstArraySlice & 0xffff; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D) + { + ret[dst].firstMip = desc.Texture3D.MostDetailedMip & 0xff; + ret[dst].numMips = desc.Texture3D.MipLevels & 0xff; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBE) + { + ret[dst].firstMip = desc.TextureCube.MostDetailedMip & 0xff; + ret[dst].numMips = desc.TextureCube.MipLevels & 0xff; + ret[dst].numSlices = 6; + } + else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) + { + ret[dst].firstMip = desc.TextureCubeArray.MostDetailedMip & 0xff; + ret[dst].numMips = desc.TextureCubeArray.MipLevels & 0xff; + ret[dst].firstSlice = desc.TextureCubeArray.First2DArrayFace & 0xffff; + ret[dst].numSlices = (desc.TextureCubeArray.NumCubes * 6) & 0xffff; + } + + SAFE_RELEASE(res); + } + } + else if(idx.type == D3D11DescriptorMapping::UAVs) + { + ID3D11UnorderedAccessView *view = NULL; + + if(idx.stage == ShaderStage::Compute) + view = rs->CSUAVs[idx.idx]; + else if(idx.idx >= rs->OM.UAVStartSlot) + view = rs->OM.UAVs[idx.idx - rs->OM.UAVStartSlot]; + + ret[dst].view = rm->GetOriginalID(GetIDForDeviceChild(view)); + + ret[dst].type = DescriptorType::ReadWriteImage; + if(ret[dst].view != ResourceId()) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC desc; + view->GetDesc(&desc); + + ID3D11Resource *res = NULL; + view->GetResource(&res); + + ret[dst].bufferStructCount = 0; + + ret[dst].elementByteSize = + desc.Format == DXGI_FORMAT_UNKNOWN ? 1 : GetByteSize(1, 1, 1, desc.Format, 0); + + ret[dst].textureType = MakeTextureDim(desc.ViewDimension); + + ret[dst].secondary = ResourceId(); + + if(desc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER && + (desc.Buffer.Flags & (D3D11_BUFFER_UAV_FLAG_APPEND | D3D11_BUFFER_UAV_FLAG_COUNTER))) + { + ret[dst].bufferStructCount = GetDebugManager()->GetStructCount(view); + + ret[dst].secondary = GetDebugManager()->GetCounterBufferID(view); + } + + ret[dst].resource = rm->GetOriginalID(GetIDForDeviceChild(res)); + + ret[dst].format = MakeResourceFormat(desc.Format); + + if(desc.ViewDimension == D3D11_UAV_DIMENSION_BUFFER) + { + ret[dst].type = DescriptorType::ReadWriteBuffer; + + if(desc.Format != DXGI_FORMAT_UNKNOWN) + ret[dst].type = DescriptorType::ReadWriteTypedBuffer; + + ret[dst].flags = DescriptorFlags(desc.Buffer.Flags); + + D3D11_BUFFER_DESC bufdesc; + ((ID3D11Buffer *)res)->GetDesc(&bufdesc); + + if(bufdesc.StructureByteStride > 0 && desc.Format == DXGI_FORMAT_UNKNOWN) + ret[dst].elementByteSize = bufdesc.StructureByteStride; + + ret[dst].byteOffset = desc.Buffer.FirstElement * ret[dst].elementByteSize; + ret[dst].byteSize = desc.Buffer.NumElements * ret[dst].elementByteSize; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE1D) + { + ret[dst].firstMip = desc.Texture1D.MipSlice & 0xff; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE1DARRAY) + { + ret[dst].numSlices = desc.Texture1DArray.ArraySize & 0xffff; + ret[dst].firstSlice = desc.Texture1DArray.FirstArraySlice & 0xffff; + ret[dst].firstMip = desc.Texture1DArray.MipSlice & 0xff; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE2D) + { + ret[dst].firstMip = desc.Texture2D.MipSlice & 0xff; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE2DARRAY) + { + ret[dst].numSlices = desc.Texture2DArray.ArraySize & 0xffff; + ret[dst].firstSlice = desc.Texture2DArray.FirstArraySlice & 0xffff; + ret[dst].firstMip = desc.Texture2DArray.MipSlice & 0xff; + } + else if(desc.ViewDimension == D3D11_UAV_DIMENSION_TEXTURE3D) + { + ret[dst].numSlices = desc.Texture3D.WSize & 0xffff; + ret[dst].firstSlice = desc.Texture3D.FirstWSlice & 0xffff; + ret[dst].firstMip = desc.Texture3D.MipSlice & 0xff; + } + + SAFE_RELEASE(res); + } + } + } + } + return ret; } @@ -1689,14 +1923,62 @@ rdcarray D3D11Replay::GetSamplerDescriptors(ResourceId descri if(descriptorStore != m_pImmediateContext->GetDescriptorsID()) { - RDCERR("Descriptors query for invalid descriptor store on fixed bindings API (D3D11)"); + RDCERR( + "Descriptors query for invalid descriptor descriptorStore on fixed bindings API (D3D11)"); return ret; } + D3D11RenderState *rs = m_pDevice->GetImmediateContext()->GetCurrentPipelineState(); + D3D11ResourceManager *rm = m_pDevice->GetResourceManager(); + size_t count = 0; for(const DescriptorRange &r : ranges) count += r.count; ret.resize(count); + + const D3D11RenderState::Shader *srcArr[] = {&rs->VS, &rs->HS, &rs->DS, &rs->GS, &rs->PS, &rs->CS}; + + size_t dst = 0; + for(const DescriptorRange &r : ranges) + { + uint32_t descriptorId = r.offset; + + for(uint32_t i = 0; i < r.count; i++, dst++, descriptorId++) + { + D3D11DescriptorLocation idx = DecodeD3D11DescriptorIndex(descriptorId); + + if(idx.type != D3D11DescriptorMapping::Samplers) + continue; + + ID3D11SamplerState *samp = srcArr[(uint32_t)idx.stage]->Samplers[idx.idx]; + + ret[dst].type = DescriptorType::Sampler; + ret[dst].object = rm->GetOriginalID(GetIDForDeviceChild(samp)); + + if(ret[dst].object != ResourceId()) + { + D3D11_SAMPLER_DESC desc; + samp->GetDesc(&desc); + + ret[dst].addressU = MakeAddressMode(desc.AddressU); + ret[dst].addressV = MakeAddressMode(desc.AddressV); + ret[dst].addressW = MakeAddressMode(desc.AddressW); + + ret[dst].borderColorValue.floatValue = desc.BorderColor; + ret[dst].borderColorType = CompType::Float; + + ret[dst].compareFunction = MakeCompareFunc(desc.ComparisonFunc); + ret[dst].filter = MakeFilter(desc.Filter); + ret[dst].maxAnisotropy = 0; + if(ret[dst].filter.mip == FilterMode::Anisotropic) + ret[dst].maxAnisotropy = (float)desc.MaxAnisotropy; + ret[dst].maxLOD = desc.MaxLOD; + ret[dst].minLOD = desc.MinLOD; + ret[dst].mipBias = desc.MipLODBias; + } + } + } + return ret; } diff --git a/renderdoc/driver/gl/gl_renderstate.h b/renderdoc/driver/gl/gl_renderstate.h index 5aaaa09dd..ba815b02d 100644 --- a/renderdoc/driver/gl/gl_renderstate.h +++ b/renderdoc/driver/gl/gl_renderstate.h @@ -68,6 +68,72 @@ struct PixelUnpackState : public PixelStorageState void ResetPixelPackState(bool compressed, GLint alignment); void ResetPixelUnpackState(bool compressed, GLint alignment); +// mapping of 'index in descriptor store' to fixed bindings, linearly in GLRenderState members +enum class GLDescriptorMapping : uint32_t +{ + Tex1D = 0, + Tex2D = Tex1D + 128, + Tex3D = Tex2D + 128, + Tex1DArray = Tex3D + 128, + Tex2DArray = Tex1DArray + 128, + TexCubeArray = Tex2DArray + 128, + TexRect = TexCubeArray + 128, + TexBuffer = TexRect + 128, + TexCube = TexBuffer + 128, + Tex2DMS = TexCube + 128, + Tex2DMSArray = Tex2DMS + 128, + Images = Tex2DMSArray + 128, + AtomicCounter = Images + 8, + ShaderStorage = AtomicCounter + 8, + UniformBinding = ShaderStorage + 96, + BareUniforms = UniformBinding + 84, + Count = BareUniforms + 6, + Invalid = ~0U, +}; + +struct GLDescriptorLocation +{ + GLDescriptorMapping type; + uint32_t idx; +}; + +inline GLDescriptorLocation DecodeGLDescriptorIndex(uint32_t idx) +{ + if(idx >= (uint32_t)GLDescriptorMapping::Count) + return {GLDescriptorMapping::Invalid, 0}; + + // go in reverse order to handle each case with a >= +#define HANDLE_TYPE(type) \ + else if(idx >= (uint32_t)GLDescriptorMapping::type) return { \ + GLDescriptorMapping::type, \ + idx - (uint32_t)GLDescriptorMapping::type, \ + } + HANDLE_TYPE(BareUniforms); + HANDLE_TYPE(UniformBinding); + HANDLE_TYPE(ShaderStorage); + HANDLE_TYPE(AtomicCounter); + HANDLE_TYPE(Images); + HANDLE_TYPE(Tex2DMSArray); + HANDLE_TYPE(Tex2DMS); + HANDLE_TYPE(TexCube); + HANDLE_TYPE(TexBuffer); + HANDLE_TYPE(TexRect); + HANDLE_TYPE(TexCubeArray); + HANDLE_TYPE(Tex2DArray); + HANDLE_TYPE(Tex1DArray); + HANDLE_TYPE(Tex3D); + HANDLE_TYPE(Tex2D); + HANDLE_TYPE(Tex1D); +#undef HANDLE_TYPE + + return {GLDescriptorMapping::Invalid, 0}; +} + +inline uint32_t EncodeGLDescriptorIndex(const GLDescriptorLocation &idx) +{ + return (uint32_t)idx.type + idx.idx; +} + struct GLRenderState { GLRenderState(); diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 2f13adf9d..bcbd198f9 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -848,6 +848,10 @@ void GLReplay::SavePipelineState(uint32_t eventId) ContextPair &ctx = drv.GetCtx(); + pipe.descriptorStore = m_pDriver->m_DescriptorsID; + pipe.descriptorCount = EncodeGLDescriptorIndex({GLDescriptorMapping::Count, 0}); + pipe.descriptorByteSize = 1; + GLuint vao = 0; drv.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&vao); pipe.vertexInput.vertexArrayObject = rm->GetOriginalID(rm->GetResID(VertexArrayRes(ctx, vao))); @@ -2131,10 +2135,244 @@ rdcarray GLReplay::GetDescriptors(ResourceId descriptorStore, return ret; } + MakeCurrentReplayContext(&m_ReplayCtx); + WrappedOpenGL &drv = *m_pDriver; + GLResourceManager *rm = m_pDriver->GetResourceManager(); + + ContextPair &ctx = drv.GetCtx(); + + GLRenderState rs; + rs.FetchState(&drv); + size_t count = 0; for(const DescriptorRange &r : ranges) count += r.count; ret.resize(count); + + size_t dst = 0; + for(const DescriptorRange &r : ranges) + { + uint32_t descriptorId = r.offset; + + for(uint32_t i = 0; i < r.count; i++, dst++, descriptorId++) + { + GLDescriptorLocation idx = DecodeGLDescriptorIndex(descriptorId); + + if(idx.type == GLDescriptorMapping::Invalid) + { + } + else if(idx.type == GLDescriptorMapping::BareUniforms) + { + // not feasible to emulate backing store for bare uniforms. We could synthesise our own byte + // layout and query uniform values into a buffer but... let's not. + ret[dst].type = DescriptorType::ConstantBuffer; + ret[dst].byteSize = 16 * 1024; + } + else if(idx.type == GLDescriptorMapping::UniformBinding) + { + ret[dst].type = DescriptorType::ConstantBuffer; + if(rs.UniformBinding[idx.idx].res.name != 0) + { + ret[dst].resource = rm->GetOriginalID(rm->GetResID(rs.UniformBinding[idx.idx].res)); + ret[dst].byteOffset = rs.UniformBinding[idx.idx].start; + ret[dst].byteSize = rs.UniformBinding[idx.idx].size; + } + } + else if(idx.type == GLDescriptorMapping::AtomicCounter) + { + ret[dst].type = DescriptorType::ReadWriteBuffer; + if(rs.AtomicCounter[idx.idx].res.name != 0) + { + ret[dst].resource = rm->GetOriginalID(rm->GetResID(rs.AtomicCounter[idx.idx].res)); + ret[dst].byteOffset = rs.AtomicCounter[idx.idx].start; + ret[dst].byteSize = rs.AtomicCounter[idx.idx].size; + } + } + else if(idx.type == GLDescriptorMapping::ShaderStorage) + { + ret[dst].type = DescriptorType::ReadWriteBuffer; + if(rs.ShaderStorage[idx.idx].res.name != 0) + { + ret[dst].resource = rm->GetOriginalID(rm->GetResID(rs.ShaderStorage[idx.idx].res)); + ret[dst].byteOffset = rs.ShaderStorage[idx.idx].start; + ret[dst].byteSize = rs.ShaderStorage[idx.idx].size; + } + } + else if(idx.type == GLDescriptorMapping::Images) + { + ret[dst].type = DescriptorType::ReadWriteImage; + if(rs.Images[idx.idx].res.name != 0) + { + ResourceId id = rm->GetResID(rs.Images[idx.idx].res); + ret[dst].resource = rm->GetOriginalID(id); + ret[dst].firstMip = rs.Images[idx.idx].level & 0xff; + ret[dst].numMips = 1; + ret[dst].firstSlice = rs.Images[idx.idx].layer & 0xffff; + if(rs.Images[idx.idx].access == eGL_READ_ONLY) + { + ret[dst].flags = DescriptorFlags::ReadOnlyAccess; + } + else if(rs.Images[idx.idx].access == eGL_WRITE_ONLY) + { + ret[dst].flags = DescriptorFlags::WriteOnlyAccess; + } + ret[dst].format = MakeResourceFormat(eGL_TEXTURE_2D, rs.Images[idx.idx].format); + + CacheTexture(id); + + ret[dst].textureType = m_CachedTextures[id].type; + if(ret[dst].textureType == TextureType::Texture3D) + ret[dst].numSlices = rs.Images[idx.idx].layered + ? (m_CachedTextures[id].depth >> ret[dst].firstMip) & 0xffff + : 1; + else + ret[dst].numSlices = + rs.Images[idx.idx].layered ? m_CachedTextures[id].arraysize & 0xffff : 1; + + if(ret[dst].textureType == TextureType::Buffer) + ret[dst].type = DescriptorType::ReadWriteTypedBuffer; + } + } + else + { + ret[dst].type = DescriptorType::ImageSampler; + if(idx.type == GLDescriptorMapping::TexBuffer) + ret[dst].type = DescriptorType::TypedBuffer; + + drv.glActiveTexture(GLenum(eGL_TEXTURE0 + idx.idx)); + + GLuint tex = 0; + GLenum target = eGL_NONE; + + if(idx.type == GLDescriptorMapping::TexCubeArray && !HasExt[ARB_texture_cube_map_array]) + { + tex = 0; + target = eGL_TEXTURE_CUBE_MAP_ARRAY; + } + else + { + switch(idx.type) + { + case GLDescriptorMapping::Tex1D: + target = eGL_TEXTURE_1D; + ret[dst].textureType = TextureType::Texture1D; + break; + case GLDescriptorMapping::Tex2D: + target = eGL_TEXTURE_2D; + ret[dst].textureType = TextureType::Texture2D; + break; + case GLDescriptorMapping::Tex3D: + target = eGL_TEXTURE_3D; + ret[dst].textureType = TextureType::Texture3D; + break; + case GLDescriptorMapping::Tex1DArray: + target = eGL_TEXTURE_1D_ARRAY; + ret[dst].textureType = TextureType::Texture1DArray; + break; + case GLDescriptorMapping::Tex2DArray: + target = eGL_TEXTURE_2D_ARRAY; + ret[dst].textureType = TextureType::Texture2DArray; + break; + case GLDescriptorMapping::TexCubeArray: + target = eGL_TEXTURE_CUBE_MAP_ARRAY; + ret[dst].textureType = TextureType::TextureCubeArray; + break; + case GLDescriptorMapping::TexRect: + target = eGL_TEXTURE_RECTANGLE; + ret[dst].textureType = TextureType::TextureRect; + break; + case GLDescriptorMapping::TexBuffer: + target = eGL_TEXTURE_BUFFER; + ret[dst].textureType = TextureType::Buffer; + break; + case GLDescriptorMapping::TexCube: + target = eGL_TEXTURE_CUBE_MAP; + ret[dst].textureType = TextureType::TextureCube; + break; + case GLDescriptorMapping::Tex2DMS: + target = eGL_TEXTURE_2D_MULTISAMPLE; + ret[dst].textureType = TextureType::Texture2DMS; + break; + case GLDescriptorMapping::Tex2DMSArray: + target = eGL_TEXTURE_2D_MULTISAMPLE_ARRAY; + ret[dst].textureType = TextureType::Texture2DMSArray; + break; + case GLDescriptorMapping::AtomicCounter: + case GLDescriptorMapping::ShaderStorage: + case GLDescriptorMapping::BareUniforms: + case GLDescriptorMapping::UniformBinding: + case GLDescriptorMapping::Images: + case GLDescriptorMapping::Invalid: + case GLDescriptorMapping::Count: target = eGL_NONE; break; + } + } + + if(target == eGL_NONE) + continue; + + GLenum binding = TextureBinding(target); + + drv.glGetIntegerv(binding, (GLint *)&tex); + + if(tex == 0) + continue; + + GLint firstMip = 0, numMips = 1; + + if(target != eGL_TEXTURE_BUFFER) + { + drv.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_BASE_LEVEL, &firstMip); + drv.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_MAX_LEVEL, &numMips); + + numMips = numMips - firstMip + 1; + } + + ResourceId id = rm->GetResID(TextureRes(ctx, tex)); + ret[dst].resource = rm->GetOriginalID(id); + ret[dst].firstMip = firstMip & 0xff; + ret[dst].numMips = numMips & 0xff; + + GLenum levelQueryType = + target == eGL_TEXTURE_CUBE_MAP ? eGL_TEXTURE_CUBE_MAP_POSITIVE_X : target; + GLenum fmt = eGL_NONE; + drv.glGetTexLevelParameteriv(levelQueryType, 0, eGL_TEXTURE_INTERNAL_FORMAT, (GLint *)&fmt); + ret[dst].format = MakeResourceFormat(target, fmt); + if(IsDepthStencilFormat(fmt)) + { + GLint depthMode = eGL_DEPTH_COMPONENT; + + if(HasExt[ARB_stencil_texturing]) + drv.glGetTextureParameterivEXT(tex, target, eGL_DEPTH_STENCIL_TEXTURE_MODE, &depthMode); + + ret[dst].format = ResourceFormat(); + ret[dst].format.type = ResourceFormatType::Regular; + ret[dst].format.compByteWidth = 1; + ret[dst].format.compCount = 1; + if(depthMode == eGL_DEPTH_COMPONENT) + ret[dst].format.compType = CompType::Depth; + else if(depthMode == eGL_STENCIL_INDEX) + ret[dst].format.compType = CompType::UInt; + } + + GLenum swizzles[4] = {eGL_RED, eGL_GREEN, eGL_BLUE, eGL_ALPHA}; + if(target != eGL_TEXTURE_BUFFER && + (HasExt[ARB_texture_swizzle] || HasExt[EXT_texture_swizzle])) + GetTextureSwizzle(tex, target, swizzles); + + ret[dst].swizzle.red = MakeSwizzle(swizzles[0]); + ret[dst].swizzle.green = MakeSwizzle(swizzles[1]); + ret[dst].swizzle.blue = MakeSwizzle(swizzles[2]); + ret[dst].swizzle.alpha = MakeSwizzle(swizzles[3]); + + GLuint samp = 0; + if(HasExt[ARB_sampler_objects]) + drv.glGetIntegerv(eGL_SAMPLER_BINDING, (GLint *)&samp); + + ret[dst].secondary = rm->GetOriginalID(rm->GetResID(SamplerRes(ctx, samp))); + } + } + } + return ret; } @@ -2149,10 +2387,190 @@ rdcarray GLReplay::GetSamplerDescriptors(ResourceId descripto return ret; } + MakeCurrentReplayContext(&m_ReplayCtx); + WrappedOpenGL &drv = *m_pDriver; + GLResourceManager *rm = m_pDriver->GetResourceManager(); + + ContextPair &ctx = drv.GetCtx(); + size_t count = 0; for(const DescriptorRange &r : ranges) count += r.count; ret.resize(count); + + size_t dst = 0; + for(const DescriptorRange &r : ranges) + { + uint32_t descriptorId = r.offset; + + for(uint32_t i = 0; i < r.count; i++, dst++, descriptorId++) + { + GLDescriptorLocation idx = DecodeGLDescriptorIndex(descriptorId); + + if(idx.type == GLDescriptorMapping::Invalid || idx.type == GLDescriptorMapping::Images || + idx.type == GLDescriptorMapping::AtomicCounter || + idx.type == GLDescriptorMapping::ShaderStorage || + idx.type == GLDescriptorMapping::UniformBinding) + continue; + + drv.glActiveTexture(GLenum(eGL_TEXTURE0 + idx.idx)); + + GLuint tex = 0; + GLenum target = eGL_NONE; + + if(idx.type == GLDescriptorMapping::TexCubeArray && !HasExt[ARB_texture_cube_map_array]) + { + tex = 0; + target = eGL_TEXTURE_CUBE_MAP_ARRAY; + } + else + { + switch(idx.type) + { + case GLDescriptorMapping::Tex1D: target = eGL_TEXTURE_1D; break; + case GLDescriptorMapping::Tex2D: target = eGL_TEXTURE_2D; break; + case GLDescriptorMapping::Tex3D: target = eGL_TEXTURE_3D; break; + case GLDescriptorMapping::Tex1DArray: target = eGL_TEXTURE_1D_ARRAY; break; + case GLDescriptorMapping::Tex2DArray: target = eGL_TEXTURE_2D_ARRAY; break; + case GLDescriptorMapping::TexCubeArray: target = eGL_TEXTURE_CUBE_MAP_ARRAY; break; + case GLDescriptorMapping::TexRect: target = eGL_TEXTURE_RECTANGLE; break; + case GLDescriptorMapping::TexBuffer: target = eGL_TEXTURE_BUFFER; break; + case GLDescriptorMapping::TexCube: target = eGL_TEXTURE_CUBE_MAP; break; + case GLDescriptorMapping::Tex2DMS: target = eGL_TEXTURE_2D_MULTISAMPLE; break; + case GLDescriptorMapping::Tex2DMSArray: target = eGL_TEXTURE_2D_MULTISAMPLE_ARRAY; break; + case GLDescriptorMapping::AtomicCounter: + case GLDescriptorMapping::ShaderStorage: + case GLDescriptorMapping::BareUniforms: + case GLDescriptorMapping::UniformBinding: + case GLDescriptorMapping::Images: + case GLDescriptorMapping::Invalid: + case GLDescriptorMapping::Count: target = eGL_NONE; break; + } + } + + if(target == eGL_NONE) + continue; + + GLenum binding = TextureBinding(target); + + GLuint samp = 0; + if(HasExt[ARB_sampler_objects]) + drv.glGetIntegerv(eGL_SAMPLER_BINDING, (GLint *)&samp); + + drv.glGetIntegerv(binding, (GLint *)&tex); + + if(samp == 0 && tex == 0) + continue; + + ret[dst].object = rm->GetOriginalID(rm->GetResID(SamplerRes(ctx, samp))); + + // GL has separate sampler objects but they don't exist as separate sampler descriptors + ret[dst].type = DescriptorType::ImageSampler; + + if(samp != 0) + drv.glGetSamplerParameterfv(samp, eGL_TEXTURE_BORDER_COLOR, + ret[dst].borderColorValue.floatValue.data()); + else + drv.glGetTextureParameterfvEXT(tex, target, eGL_TEXTURE_BORDER_COLOR, + ret[dst].borderColorValue.floatValue.data()); + + ret[dst].borderColorType = CompType::Float; + + GLint v; + v = 0; + if(samp != 0) + drv.glGetSamplerParameteriv(samp, eGL_TEXTURE_WRAP_S, &v); + else + drv.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_WRAP_S, &v); + ret[dst].addressU = MakeAddressMode((GLenum)v); + + v = 0; + if(samp != 0) + drv.glGetSamplerParameteriv(samp, eGL_TEXTURE_WRAP_T, &v); + else + drv.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_WRAP_T, &v); + ret[dst].addressV = MakeAddressMode((GLenum)v); + + v = 0; + if(samp != 0) + drv.glGetSamplerParameteriv(samp, eGL_TEXTURE_WRAP_R, &v); + else + drv.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_WRAP_R, &v); + ret[dst].addressW = MakeAddressMode((GLenum)v); + + // GLES 3 is always seamless + if(IsGLES && GLCoreVersion > 30) + { + ret[dst].seamlessCubemaps = true; + } + else if(!IsGLES) + { + // on GLES 2 this is always going to be false, GL has a toggle + ret[dst].seamlessCubemaps = drv.glIsEnabled(eGL_TEXTURE_CUBE_MAP_SEAMLESS) != GL_FALSE; + } + + v = 0; + if(samp != 0) + drv.glGetSamplerParameteriv(samp, eGL_TEXTURE_COMPARE_FUNC, &v); + else + drv.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_COMPARE_FUNC, &v); + ret[dst].compareFunction = MakeCompareFunc((GLenum)v); + + GLint minf = 0; + GLint magf = 0; + if(samp != 0) + drv.glGetSamplerParameteriv(samp, eGL_TEXTURE_MIN_FILTER, &minf); + else + drv.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_MIN_FILTER, &minf); + + if(samp != 0) + drv.glGetSamplerParameteriv(samp, eGL_TEXTURE_MAG_FILTER, &magf); + else + drv.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_MAG_FILTER, &magf); + + if(HasExt[ARB_texture_filter_anisotropic]) + { + if(samp != 0) + drv.glGetSamplerParameterfv(samp, eGL_TEXTURE_MAX_ANISOTROPY, &ret[dst].maxAnisotropy); + else + drv.glGetTextureParameterfvEXT(tex, target, eGL_TEXTURE_MAX_ANISOTROPY, + &ret[dst].maxAnisotropy); + } + else + { + ret[dst].maxAnisotropy = 0.0f; + } + + ret[dst].filter = MakeFilter((GLenum)minf, (GLenum)magf, ret[dst].maxAnisotropy); + + v = 0; + if(samp != 0) + drv.glGetSamplerParameteriv(samp, eGL_TEXTURE_COMPARE_MODE, &v); + else + drv.glGetTextureParameterivEXT(tex, target, eGL_TEXTURE_COMPARE_MODE, &v); + ret[dst].filter.filter = (GLenum)v == eGL_COMPARE_REF_TO_TEXTURE ? FilterFunction::Comparison + : FilterFunction::Normal; + + if(samp != 0) + drv.glGetSamplerParameterfv(samp, eGL_TEXTURE_MAX_LOD, &ret[dst].maxLOD); + else + drv.glGetTextureParameterfvEXT(tex, target, eGL_TEXTURE_MAX_LOD, &ret[dst].maxLOD); + + if(samp != 0) + drv.glGetSamplerParameterfv(samp, eGL_TEXTURE_MIN_LOD, &ret[dst].minLOD); + else + drv.glGetTextureParameterfvEXT(tex, target, eGL_TEXTURE_MIN_LOD, &ret[dst].minLOD); + + if(!IsGLES) + { + if(samp != 0) + drv.glGetSamplerParameterfv(samp, eGL_TEXTURE_LOD_BIAS, &ret[dst].mipBias); + else + drv.glGetTextureParameterfvEXT(tex, target, eGL_TEXTURE_LOD_BIAS, &ret[dst].mipBias); + } + } + } + return ret; } diff --git a/renderdoc/driver/gl/gl_resources.cpp b/renderdoc/driver/gl/gl_resources.cpp index b3fb26462..1e3c60f2d 100644 --- a/renderdoc/driver/gl/gl_resources.cpp +++ b/renderdoc/driver/gl/gl_resources.cpp @@ -2052,9 +2052,9 @@ GLint CubeTargetIndex(GLenum face) return 0; } -GLenum TextureTarget(GLenum target) +GLenum TextureTarget(GLenum binding) { - switch(target) + switch(binding) { case eGL_TEXTURE_BINDING_1D: return eGL_TEXTURE_1D; case eGL_TEXTURE_BINDING_1D_ARRAY: return eGL_TEXTURE_1D_ARRAY; @@ -2076,7 +2076,7 @@ GLenum TextureTarget(GLenum target) default: break; } - return target; + return binding; } bool IsProxyTarget(GLenum target) diff --git a/renderdoc/driver/gl/gl_resources.h b/renderdoc/driver/gl/gl_resources.h index 2a8f33836..5c098e5b9 100644 --- a/renderdoc/driver/gl/gl_resources.h +++ b/renderdoc/driver/gl/gl_resources.h @@ -61,7 +61,7 @@ GLenum GetViewCastedFormat(GLenum internalFormat, CompType typeCast); bool IsCubeFace(GLenum target); GLint CubeTargetIndex(GLenum face); GLenum TextureBinding(GLenum target); -GLenum TextureTarget(GLenum target); +GLenum TextureTarget(GLenum binding); bool IsProxyTarget(GLenum target); GLenum BufferBinding(GLenum target); diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 4aeca9080..d0aaa8cc5 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -1435,6 +1435,10 @@ void DoSerialise(SerialiserType &ser, D3D11Pipe::State &el) SERIALISE_MEMBER(pixelShader); SERIALISE_MEMBER(computeShader); + SERIALISE_MEMBER(descriptorStore); + SERIALISE_MEMBER(descriptorCount); + SERIALISE_MEMBER(descriptorByteSize); + SERIALISE_MEMBER(streamOut); SERIALISE_MEMBER(rasterizer); @@ -1442,7 +1446,7 @@ void DoSerialise(SerialiserType &ser, D3D11Pipe::State &el) SERIALISE_MEMBER(predication); - SIZE_CHECK(2088); + SIZE_CHECK(2104); } #pragma endregion D3D11 pipeline state @@ -2026,6 +2030,10 @@ void DoSerialise(SerialiserType &ser, GLPipe::State &el) SERIALISE_MEMBER(shaderStorageBuffers); SERIALISE_MEMBER(images); + SERIALISE_MEMBER(descriptorStore); + SERIALISE_MEMBER(descriptorCount); + SERIALISE_MEMBER(descriptorByteSize); + SERIALISE_MEMBER(transformFeedback); SERIALISE_MEMBER(rasterizer); @@ -2036,7 +2044,7 @@ void DoSerialise(SerialiserType &ser, GLPipe::State &el) SERIALISE_MEMBER(hints); - SIZE_CHECK(1952); + SIZE_CHECK(1968); } #pragma endregion OpenGL pipeline state