diff --git a/renderdoc/api/replay/gl_pipestate.h b/renderdoc/api/replay/gl_pipestate.h index eae6463e9..d124c5663 100644 --- a/renderdoc/api/replay/gl_pipestate.h +++ b/renderdoc/api/replay/gl_pipestate.h @@ -591,8 +591,8 @@ struct Attachment bool operator==(const Attachment &o) const { - return resourceId == o.resourceId && slice == o.slice && mipLevel == o.mipLevel && - swizzle == o.swizzle; + return resourceId == o.resourceId && slice == o.slice && numSlices == o.numSlices && + mipLevel == o.mipLevel && swizzle == o.swizzle; } bool operator<(const Attachment &o) const { @@ -610,6 +610,8 @@ struct Attachment ResourceId resourceId; DOCUMENT("The slice of the texture that's used in the attachment."); uint32_t slice = 0; + DOCUMENT("The number of slices of the texture that are used in the attachment."); + uint32_t numSlices = 1; DOCUMENT("The mip of the texture that's used in the attachment."); uint32_t mipLevel = 0; DOCUMENT("A :class:`TextureSwizzle4` indicating the swizzle applied to this texture."); diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 52f3e147d..0936a1969 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -249,9 +249,8 @@ public: RDCEraseEl(ret); return ret; } - ResourceId RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents) + ResourceId RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents) { return ResourceId(); } diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index 04910f525..4aad8c32d 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -1055,8 +1055,7 @@ MeshFormat ReplayProxy::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint template ResourceId ReplayProxy::Proxied_RenderOverlay(ParamSerialiser ¶mser, ReturnSerialiser &retser, - ResourceId texid, const Subresource &sub, - CompType typeCast, FloatVector clearCol, + ResourceId texid, FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, const rdcarray &passEvents) { @@ -1067,8 +1066,6 @@ ResourceId ReplayProxy::Proxied_RenderOverlay(ParamSerialiser ¶mser, ReturnS { BEGIN_PARAMS(); SERIALISE_ELEMENT(texid); - SERIALISE_ELEMENT(sub); - SERIALISE_ELEMENT(typeCast); SERIALISE_ELEMENT(overlay); SERIALISE_ELEMENT(clearCol); SERIALISE_ELEMENT(eventId); @@ -1079,7 +1076,7 @@ ResourceId ReplayProxy::Proxied_RenderOverlay(ParamSerialiser ¶mser, ReturnS { REMOTE_EXECUTION(); if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored) - ret = m_Remote->RenderOverlay(texid, sub, typeCast, clearCol, overlay, eventId, passEvents); + ret = m_Remote->RenderOverlay(texid, clearCol, overlay, eventId, passEvents); } SERIALISE_RETURN(ret); @@ -1087,11 +1084,10 @@ ResourceId ReplayProxy::Proxied_RenderOverlay(ParamSerialiser ¶mser, ReturnS return ret; } -ResourceId ReplayProxy::RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents) +ResourceId ReplayProxy::RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents) { - PROXY_FUNCTION(RenderOverlay, texid, sub, typeCast, clearCol, overlay, eventId, passEvents); + PROXY_FUNCTION(RenderOverlay, texid, clearCol, overlay, eventId, passEvents); } template @@ -2832,8 +2828,7 @@ bool ReplayProxy::Tick(int type) case eReplayProxy_ContinueDebug: ContinueDebug(NULL); break; case eReplayProxy_FreeDebugger: FreeDebugger(NULL); break; case eReplayProxy_RenderOverlay: - RenderOverlay(ResourceId(), Subresource(), CompType::Typeless, FloatVector(), - DebugOverlay::NoOverlay, 0, rdcarray()); + RenderOverlay(ResourceId(), FloatVector(), DebugOverlay::NoOverlay, 0, rdcarray()); break; case eReplayProxy_PixelHistory: PixelHistory(rdcarray(), ResourceId(), 0, 0, Subresource(), CompType::Typeless); diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index 23c78aacf..690b28c45 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -506,9 +506,9 @@ public: IMPLEMENT_FUNCTION_PROXIED(MeshFormat, GetPostVSBuffers, uint32_t eventId, uint32_t instID, uint32_t viewID, MeshDataStage stage); - IMPLEMENT_FUNCTION_PROXIED(ResourceId, RenderOverlay, ResourceId texid, const Subresource &sub, - CompType typeCast, FloatVector clearCol, DebugOverlay overlay, - uint32_t eventId, const rdcarray &passEvents); + IMPLEMENT_FUNCTION_PROXIED(ResourceId, RenderOverlay, ResourceId texid, FloatVector clearCol, + DebugOverlay overlay, uint32_t eventId, + const rdcarray &passEvents); IMPLEMENT_FUNCTION_PROXIED(rdcarray, GetShaderEntryPoints, ResourceId shader); IMPLEMENT_FUNCTION_PROXIED(ShaderReflection *, GetShader, ResourceId pipeline, ResourceId, diff --git a/renderdoc/driver/d3d11/d3d11_overlay.cpp b/renderdoc/driver/d3d11/d3d11_overlay.cpp index 8f34bd620..0c8e47b57 100644 --- a/renderdoc/driver/d3d11/d3d11_overlay.cpp +++ b/renderdoc/driver/d3d11/d3d11_overlay.cpp @@ -38,11 +38,66 @@ #include "data/hlsl/hlsl_cbuffers.h" -ResourceId D3D11Replay::RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents) +static void SetRTVDesc(D3D11_RENDER_TARGET_VIEW_DESC &rtDesc, const D3D11_TEXTURE2D_DESC &texDesc, + const RenderOutputSubresource &sub) { - TextureShaderDetails details = GetDebugManager()->GetShaderDetails(texid, typeCast, false); + if(texDesc.ArraySize > 1) + { + if(texDesc.SampleDesc.Count > 1) + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; + rtDesc.Texture2DMSArray.FirstArraySlice = sub.slice; + rtDesc.Texture2DMSArray.ArraySize = sub.numSlices; + } + else + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtDesc.Texture2DArray.FirstArraySlice = sub.slice; + rtDesc.Texture2DArray.ArraySize = sub.numSlices; + rtDesc.Texture2DArray.MipSlice = sub.mip; + } + } + else + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtDesc.Texture2D.MipSlice = sub.mip; + + if(texDesc.SampleDesc.Count > 1) + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + } +} + +RenderOutputSubresource D3D11Replay::GetRenderOutputSubresource(ResourceId id) +{ + id = m_pDevice->GetResourceManager()->GetOriginalID(id); + + for(size_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + const D3D11Pipe::View &rt = m_CurPipelineState.outputMerger.renderTargets[i]; + + if(rt.viewResourceId == id || rt.resourceResourceId == id) + return RenderOutputSubresource(rt.firstMip, rt.firstSlice, rt.numSlices); + } + + const D3D11Pipe::View &dsv = m_CurPipelineState.outputMerger.depthTarget; + if(dsv.viewResourceId == id || dsv.resourceResourceId == id) + return RenderOutputSubresource(dsv.firstMip, dsv.firstSlice, dsv.numSlices); + + return RenderOutputSubresource(~0U, ~0U, 0); +} + +ResourceId D3D11Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents) +{ + TextureShaderDetails details = GetDebugManager()->GetShaderDetails(texid, CompType::Float, false); + + RenderOutputSubresource sub = GetRenderOutputSubresource(texid); + + if(sub.slice == ~0U) + { + RDCERR("Rendering overlay for %s couldn't find output to get subresource.", ToStr(texid).c_str()); + sub = RenderOutputSubresource(0, 0, 1); + } D3D11MarkerRegion renderoverlay(StringFormat::Fmt("RenderOverlay %d", overlay)); @@ -52,7 +107,7 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, const Subresource &sub, realTexDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; realTexDesc.Usage = D3D11_USAGE_DEFAULT; realTexDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - realTexDesc.ArraySize = 1; + realTexDesc.ArraySize = details.texArraySize; realTexDesc.MipLevels = details.texMips; realTexDesc.CPUAccessFlags = 0; realTexDesc.MiscFlags = 0; @@ -80,6 +135,7 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, const Subresource &sub, // need to recreate backing custom render tex if(realTexDesc.Width != customTexDesc.Width || realTexDesc.Height != customTexDesc.Height || realTexDesc.Format != customTexDesc.Format || realTexDesc.MipLevels != customTexDesc.MipLevels || + realTexDesc.ArraySize != customTexDesc.ArraySize || realTexDesc.SampleDesc.Count != customTexDesc.SampleDesc.Count || realTexDesc.SampleDesc.Quality != customTexDesc.SampleDesc.Quality) { @@ -144,17 +200,31 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, const Subresource &sub, SAFE_RELEASE(realDepth); } - D3D11_RENDER_TARGET_VIEW_DESC rtDesc; - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + ID3D11RenderTargetView *rtv = NULL; + D3D11_RENDER_TARGET_VIEW_DESC rtDesc = {}; rtDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - rtDesc.Texture2D.MipSlice = sub.mip; - if(realTexDesc.SampleDesc.Count > 1 || realTexDesc.SampleDesc.Quality > 0) + // clear all mips and all slices first + for(UINT mip = 0; mip < realTexDesc.MipLevels; mip++) { - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + SetRTVDesc(rtDesc, realTexDesc, RenderOutputSubresource(mip, 0, realTexDesc.ArraySize)); + + HRESULT hr = m_pDevice->CreateRenderTargetView(wrappedCustomRenderTex, &rtDesc, &rtv); + if(FAILED(hr)) + { + RDCERR("Failed to create custom render tex for mip %u RTV HRESULT: %s", mip, ToStr(hr).c_str()); + } + else + { + FLOAT black[] = {0.0f, 0.0f, 0.0f, 0.0f}; + m_pImmediateContext->ClearRenderTargetView(rtv, black); + } + + SAFE_RELEASE(rtv); } - ID3D11RenderTargetView *rtv = NULL; + SetRTVDesc(rtDesc, realTexDesc, sub); + HRESULT hr = m_pDevice->CreateRenderTargetView(wrappedCustomRenderTex, &rtDesc, &rtv); if(FAILED(hr)) { @@ -162,9 +232,6 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, const Subresource &sub, return m_Overlay.resourceId; } - FLOAT black[] = {0.0f, 0.0f, 0.0f, 0.0f}; - m_pImmediateContext->ClearRenderTargetView(rtv, black); - if(renderDepth) { m_pImmediateContext->CopyResource(renderDepth, preDrawDepth); @@ -611,7 +678,7 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, const Subresource &sub, m_pImmediateContext->ClearRenderTargetView(state.OM.RenderTargets[i], &clearCol.x); // Try to clear depth as well, to help debug shadow rendering - if(state.OM.DepthView && IsDepthFormat(details.srvFormat)) + if(state.OM.DepthView && IsDepthFormat(details.texFmt)) { if(state.OM.DepthStencilState) { diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index 4734c79a8..b58ac3e3b 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -871,31 +871,41 @@ void D3D11Replay::SavePipelineState(uint32_t eventId) { view.firstMip = desc.Texture1D.MostDetailedMip; view.numMips = desc.Texture1D.MipLevels; + view.firstSlice = 0; + view.numSlices = 1; } else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE1DARRAY) { - view.numSlices = desc.Texture1DArray.ArraySize; - view.firstSlice = desc.Texture1DArray.FirstArraySlice; view.firstMip = desc.Texture1DArray.MostDetailedMip; view.numMips = desc.Texture1DArray.MipLevels; + view.numSlices = desc.Texture1DArray.ArraySize; + view.firstSlice = desc.Texture1DArray.FirstArraySlice; } else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2D) { view.firstMip = desc.Texture2D.MostDetailedMip; view.numMips = desc.Texture2D.MipLevels; + view.firstSlice = 0; + view.numSlices = 1; } else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DARRAY) { - view.numSlices = desc.Texture2DArray.ArraySize; - view.firstSlice = desc.Texture2DArray.FirstArraySlice; view.firstMip = desc.Texture2DArray.MostDetailedMip; view.numMips = desc.Texture2DArray.MipLevels; + view.firstSlice = desc.Texture2DArray.FirstArraySlice; + view.numSlices = desc.Texture2DArray.ArraySize; } else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DMS) { + view.firstMip = 0; + view.numMips = 1; + view.firstSlice = 0; + view.numSlices = 1; } else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY) { + view.firstMip = 0; + view.numMips = 1; view.numSlices = desc.Texture2DMSArray.ArraySize; view.firstSlice = desc.Texture2DMSArray.FirstArraySlice; } @@ -903,19 +913,22 @@ void D3D11Replay::SavePipelineState(uint32_t eventId) { view.firstMip = desc.Texture3D.MostDetailedMip; view.numMips = desc.Texture3D.MipLevels; + view.firstSlice = 0; + view.numSlices = 1; } else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBE) { - view.numSlices = 6; view.firstMip = desc.TextureCube.MostDetailedMip; view.numMips = desc.TextureCube.MipLevels; + view.firstSlice = 0; + view.numSlices = 6; } else if(desc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) { - view.numSlices = desc.TextureCubeArray.NumCubes * 6; - view.firstSlice = desc.TextureCubeArray.First2DArrayFace; view.firstMip = desc.TextureCubeArray.MostDetailedMip; view.numMips = desc.TextureCubeArray.MipLevels; + view.firstSlice = desc.TextureCubeArray.First2DArrayFace; + view.numSlices = desc.TextureCubeArray.NumCubes * 6; } SAFE_RELEASE(res); @@ -3369,22 +3382,6 @@ ResourceId D3D11Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, return m_CustomShaderResourceId; } -bool D3D11Replay::IsRenderOutput(ResourceId id) -{ - for(size_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) - { - if(m_CurPipelineState.outputMerger.renderTargets[i].viewResourceId == id || - m_CurPipelineState.outputMerger.renderTargets[i].resourceResourceId == id) - return true; - } - - if(m_CurPipelineState.outputMerger.depthTarget.viewResourceId == id || - m_CurPipelineState.outputMerger.depthTarget.resourceResourceId == id) - return true; - - return false; -} - ResourceId D3D11Replay::CreateProxyTexture(const TextureDescription &templateTex) { ResourceId ret; diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index f697fe5ff..041739e80 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -242,9 +242,8 @@ public: uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y); - ResourceId RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents); + ResourceId RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents); void BuildCustomShader(ShaderEncoding sourceEncoding, const bytebuf &source, const rdcstr &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id, @@ -252,8 +251,8 @@ public: ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, CompType typeCast); - bool IsRenderOutput(ResourceId id); - + RenderOutputSubresource GetRenderOutputSubresource(ResourceId id); + bool IsRenderOutput(ResourceId id) { return GetRenderOutputSubresource(id).mip != ~0U; } void FileChanged() {} private: bool m_WARP; diff --git a/renderdoc/driver/d3d12/d3d12_overlay.cpp b/renderdoc/driver/d3d12/d3d12_overlay.cpp index b1cb6dba6..130b3f5e1 100644 --- a/renderdoc/driver/d3d12/d3d12_overlay.cpp +++ b/renderdoc/driver/d3d12/d3d12_overlay.cpp @@ -200,15 +200,75 @@ struct D3D12QuadOverdrawCallback : public D3D12DrawcallCallback D3D12RenderState m_PrevState; }; -ResourceId D3D12Replay::RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents) +static void SetRTVDesc(D3D12_RENDER_TARGET_VIEW_DESC &rtDesc, const D3D12_RESOURCE_DESC &texDesc, + const RenderOutputSubresource &sub) +{ + if(texDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D && texDesc.DepthOrArraySize > 1) + { + if(texDesc.SampleDesc.Count > 1) + { + rtDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY; + rtDesc.Texture2DMSArray.FirstArraySlice = sub.slice; + rtDesc.Texture2DMSArray.ArraySize = sub.numSlices; + } + else + { + rtDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; + rtDesc.Texture2DArray.FirstArraySlice = sub.slice; + rtDesc.Texture2DArray.ArraySize = sub.numSlices; + rtDesc.Texture2DArray.MipSlice = sub.mip; + } + } + else + { + rtDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rtDesc.Texture2D.MipSlice = sub.mip; + + if(texDesc.SampleDesc.Count > 1) + rtDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; + } +} + +RenderOutputSubresource D3D12Replay::GetRenderOutputSubresource(ResourceId id) +{ + const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState; + + D3D12Pipe::View view; + + for(size_t i = 0; i < rs.rts.size(); i++) + { + if(id == rs.rts[i].GetResResourceId()) + { + FillResourceView(view, &rs.rts[i]); + return RenderOutputSubresource(view.firstMip, view.firstSlice, view.numSlices); + } + } + + if(id == rs.dsv.GetResResourceId()) + { + FillResourceView(view, &rs.dsv); + return RenderOutputSubresource(view.firstMip, view.firstSlice, view.numSlices); + } + + return RenderOutputSubresource(~0U, ~0U, 0); +} + +ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents) { ID3D12Resource *resource = m_pDevice->GetResourceList()[texid]; if(resource == NULL) return ResourceId(); + RenderOutputSubresource sub = GetRenderOutputSubresource(texid); + + if(sub.slice == ~0U) + { + RDCERR("Rendering overlay for %s couldn't find output to get subresource.", ToStr(texid).c_str()); + sub = RenderOutputSubresource(0, 0, 1); + } + D3D12MarkerRegion renderoverlay(m_pDevice->GetQueue(), StringFormat::Fmt("RenderOverlay %d", overlay)); @@ -216,11 +276,13 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, const Subresource &sub, rdcarray barriers; int resType = 0; - GetDebugManager()->PrepareTextureSampling(resource, typeCast, resType, barriers); + GetDebugManager()->PrepareTextureSampling(resource, CompType::Float, resType, barriers); D3D12_RESOURCE_DESC overlayTexDesc; overlayTexDesc.Alignment = 0; - overlayTexDesc.DepthOrArraySize = 1; + overlayTexDesc.DepthOrArraySize = resourceDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D + ? resourceDesc.DepthOrArraySize + : 1; overlayTexDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; overlayTexDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; overlayTexDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; @@ -248,6 +310,7 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, const Subresource &sub, if(overlayTexDesc.Width != currentOverlayDesc.Width || overlayTexDesc.Height != currentOverlayDesc.Height || overlayTexDesc.Format != currentOverlayDesc.Format || + overlayTexDesc.DepthOrArraySize != currentOverlayDesc.DepthOrArraySize || overlayTexDesc.MipLevels != currentOverlayDesc.MipLevels || overlayTexDesc.SampleDesc.Count != currentOverlayDesc.SampleDesc.Count || overlayTexDesc.SampleDesc.Quality != currentOverlayDesc.SampleDesc.Quality) @@ -353,23 +416,25 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, const Subresource &sub, list->Close(); } - D3D12_RENDER_TARGET_VIEW_DESC rtDesc = {}; - rtDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - rtDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - rtDesc.Texture2D.MipSlice = sub.mip; - rtDesc.Texture2D.PlaneSlice = 0; - - if(overlayTexDesc.SampleDesc.Count > 1 || overlayTexDesc.SampleDesc.Quality > 0) - rtDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; - D3D12_CPU_DESCRIPTOR_HANDLE rtv = GetDebugManager()->GetCPUHandle(OVERLAY_RTV); - - m_pDevice->CreateRenderTargetView(wrappedCustomRenderTex, &rtDesc, rtv); + D3D12_RENDER_TARGET_VIEW_DESC rtDesc = {}; + rtDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; ID3D12GraphicsCommandList *list = m_pDevice->GetNewList(); - FLOAT black[] = {0.0f, 0.0f, 0.0f, 0.0f}; - list->ClearRenderTargetView(rtv, black, 0, NULL); + // clear all mips and all slices first + for(UINT mip = 0; mip < overlayTexDesc.MipLevels; mip++) + { + SetRTVDesc(rtDesc, overlayTexDesc, + RenderOutputSubresource(mip, 0, overlayTexDesc.DepthOrArraySize)); + + m_pDevice->CreateRenderTargetView(wrappedCustomRenderTex, &rtDesc, rtv); + FLOAT black[] = {0.0f, 0.0f, 0.0f, 0.0f}; + list->ClearRenderTargetView(rtv, black, 0, NULL); + } + + SetRTVDesc(rtDesc, overlayTexDesc, sub); + m_pDevice->CreateRenderTargetView(wrappedCustomRenderTex, &rtDesc, rtv); D3D12_CPU_DESCRIPTOR_HANDLE dsv = {}; diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 441da275c..89b455749 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -654,28 +654,42 @@ void D3D12Replay::FillResourceView(D3D12Pipe::View &view, const D3D12Descriptor else if(rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE1D) { view.firstMip = rtv.Texture1D.MipSlice; + view.numMips = 1; + view.firstSlice = 0; + view.numSlices = 1; } else if(rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE1DARRAY) { + view.firstMip = rtv.Texture1DArray.MipSlice; + view.numMips = 1; view.numSlices = rtv.Texture1DArray.ArraySize; view.firstSlice = rtv.Texture1DArray.FirstArraySlice; - view.firstMip = rtv.Texture1DArray.MipSlice; } else if(rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2D) { view.firstMip = rtv.Texture2D.MipSlice; + view.numMips = 1; + view.firstSlice = 0; + view.numSlices = 1; } else if(rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2DARRAY) { view.numSlices = rtv.Texture2DArray.ArraySize; view.firstSlice = rtv.Texture2DArray.FirstArraySlice; view.firstMip = rtv.Texture2DArray.MipSlice; + view.numMips = 1; } else if(rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2DMS) { + view.firstMip = 0; + view.numMips = 1; + view.firstSlice = 0; + view.numSlices = 1; } else if(rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY) { + view.firstMip = 0; + view.numMips = 1; view.numSlices = rtv.Texture2DMSArray.ArraySize; view.firstSlice = rtv.Texture2DArray.FirstArraySlice; } @@ -684,6 +698,7 @@ void D3D12Replay::FillResourceView(D3D12Pipe::View &view, const D3D12Descriptor view.numSlices = rtv.Texture3D.WSize; view.firstSlice = rtv.Texture3D.FirstWSlice; view.firstMip = rtv.Texture3D.MipSlice; + view.numMips = 1; } } else if(desc->GetType() == D3D12DescriptorType::DSV) @@ -2597,22 +2612,6 @@ bool D3D12Replay::GetHistogram(ResourceId texid, const Subresource &sub, CompTyp return true; } -bool D3D12Replay::IsRenderOutput(ResourceId id) -{ - const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState; - - id = m_pDevice->GetResourceManager()->GetLiveID(id); - - for(size_t i = 0; i < rs.rts.size(); i++) - if(id == rs.rts[i].GetResResourceId()) - return true; - - if(id == rs.dsv.GetResResourceId()) - return true; - - return false; -} - rdcarray D3D12Replay::GetPassEvents(uint32_t eventId) { rdcarray passEvents; diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index 14089217c..55e285266 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -197,9 +197,8 @@ public: uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y); - ResourceId RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents); + ResourceId RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents); void BuildCustomShader(ShaderEncoding sourceEncoding, const bytebuf &source, const rdcstr &entry, const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id, @@ -207,8 +206,8 @@ public: ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, CompType typeCast); - bool IsRenderOutput(ResourceId id); - + RenderOutputSubresource GetRenderOutputSubresource(ResourceId id); + bool IsRenderOutput(ResourceId id) { return GetRenderOutputSubresource(id).mip != ~0U; } void FileChanged() {} AMDCounters *GetAMDCounters() { return m_pAMDCounters; } private: diff --git a/renderdoc/driver/gl/gl_overlay.cpp b/renderdoc/driver/gl/gl_overlay.cpp index d02bae503..e4d0c6294 100644 --- a/renderdoc/driver/gl/gl_overlay.cpp +++ b/renderdoc/driver/gl/gl_overlay.cpp @@ -227,12 +227,91 @@ bool GLReplay::CreateOverlayProgram(GLuint Program, GLuint Pipeline, GLuint frag return HasSPIRVShaders; } -ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents) +RenderOutputSubresource GLReplay::GetRenderOutputSubresource(ResourceId id) +{ + id = m_pDriver->GetResourceManager()->GetOriginalID(id); + + for(const GLPipe::Attachment &att : m_CurPipelineState.framebuffer.drawFBO.colorAttachments) + { + if(att.resourceId == id) + return RenderOutputSubresource(att.mipLevel, att.slice, att.numSlices); + } + + for(const GLPipe::Attachment &att : {m_CurPipelineState.framebuffer.drawFBO.depthAttachment, + m_CurPipelineState.framebuffer.drawFBO.stencilAttachment}) + { + if(att.resourceId == id) + return RenderOutputSubresource(att.mipLevel, att.slice, att.numSlices); + } + + return RenderOutputSubresource(~0U, ~0U, 0); +} + +void GLReplay::BindFramebufferTexture(RenderOutputSubresource &sub, GLenum texBindingEnum, + GLint numSamples) { WrappedOpenGL &drv = *m_pDriver; + if(sub.numSlices > 1) + { + if(IsGLES) + { + if(HasExt[OVR_multiview]) + { + if(texBindingEnum == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) + { + drv.glFramebufferTextureMultisampleMultiviewOVR(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, + DebugData.overlayTex, sub.mip, numSamples, + sub.slice, sub.numSlices); + } + else + { + drv.glFramebufferTextureMultiviewOVR(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, + DebugData.overlayTex, sub.mip, sub.slice, + sub.numSlices); + } + } + else + { + RDCERR("Multiple slices bound without OVR_multiview"); + // without OVR_multiview we can't bind the whole array, so just bind slice 0 + drv.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, DebugData.overlayTex, + sub.mip, sub.slice); + } + } + else + { + drv.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, DebugData.overlayTex, sub.mip); + } + } + else + { + if(texBindingEnum == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY || texBindingEnum == eGL_TEXTURE_2D_ARRAY) + { + drv.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, DebugData.overlayTex, + sub.mip, sub.slice); + } + else + { + drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texBindingEnum, + DebugData.overlayTex, sub.mip); + } + } +} + +ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents) +{ + WrappedOpenGL &drv = *m_pDriver; + + RenderOutputSubresource sub = GetRenderOutputSubresource(texid); + + if(sub.slice == ~0U) + { + RDCERR("Rendering overlay for %s couldn't find output to get subresource.", ToStr(texid).c_str()); + sub = RenderOutputSubresource(0, 0, 1); + } + MakeCurrentReplayContext(&m_ReplayCtx); GLMarkerRegion renderoverlay(StringFormat::Fmt("RenderOverlay %d", overlay)); @@ -356,10 +435,26 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com GLenum texBindingEnum = eGL_TEXTURE_2D; GLenum texQueryEnum = eGL_TEXTURE_BINDING_2D; + GLint texSlices = texDetails.depth; + if(TextureTarget(texDetails.curType) == eGL_TEXTURE_3D) + texSlices = 1; + if(texDetails.samples > 1) { texBindingEnum = eGL_TEXTURE_2D_MULTISAMPLE; texQueryEnum = eGL_TEXTURE_BINDING_2D_MULTISAMPLE; + + if(texSlices > 1) + { + texBindingEnum = eGL_TEXTURE_2D_MULTISAMPLE_ARRAY; + texQueryEnum = eGL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY; + } + } + + if(texSlices > 1) + { + texBindingEnum = eGL_TEXTURE_2D_ARRAY; + texQueryEnum = eGL_TEXTURE_BINDING_2D_ARRAY; } GLint texMips = GetNumMips(texDetails.curType, texDetails.resource.name, texDetails.width, @@ -368,7 +463,8 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com // resize (or create) the overlay texture and FBO if necessary if(DebugData.overlayTexWidth != texDetails.width || DebugData.overlayTexHeight != texDetails.height || - DebugData.overlayTexSamples != texDetails.samples || DebugData.overlayTexMips != texMips) + DebugData.overlayTexSamples != texDetails.samples || DebugData.overlayTexMips != texMips || + DebugData.overlayTexSlices != texSlices) { if(DebugData.overlayFBO) { @@ -389,11 +485,21 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com DebugData.overlayTexHeight = texDetails.height; DebugData.overlayTexSamples = texDetails.samples; DebugData.overlayTexMips = texMips; + DebugData.overlayTexSlices = texSlices; if(DebugData.overlayTexSamples > 1) { - drv.glTextureStorage2DMultisampleEXT(DebugData.overlayTex, texBindingEnum, texDetails.samples, - eGL_RGBA16F, texDetails.width, texDetails.height, true); + if(DebugData.overlayTexSlices > 1) + { + drv.glTextureStorage3DMultisampleEXT(DebugData.overlayTex, texBindingEnum, + texDetails.samples, eGL_RGBA16F, texDetails.width, + texDetails.height, texSlices, true); + } + else + { + drv.glTextureStorage2DMultisampleEXT(DebugData.overlayTex, texBindingEnum, texDetails.samples, + eGL_RGBA16F, texDetails.width, texDetails.height, true); + } } else { @@ -407,12 +513,26 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com type = eGL_UNSIGNED_BYTE; } - drv.glTextureImage2DEXT(DebugData.overlayTex, texBindingEnum, 0, internalFormat, - texDetails.width, texDetails.height, 0, format, type, NULL); - for(GLint i = 1; i < texMips; i++) - drv.glTextureImage2DEXT(DebugData.overlayTex, texBindingEnum, i, internalFormat, - RDCMAX(1, texDetails.width >> i), RDCMAX(1, texDetails.height >> i), - 0, format, type, NULL); + if(texSlices > 1) + { + drv.glTextureImage3DEXT(DebugData.overlayTex, texBindingEnum, 0, internalFormat, + texDetails.width, texDetails.height, texSlices, 0, format, type, + NULL); + for(GLint i = 1; i < texMips; i++) + drv.glTextureImage3DEXT(DebugData.overlayTex, texBindingEnum, i, internalFormat, + RDCMAX(1, texDetails.width >> i), RDCMAX(1, texDetails.height >> i), + texSlices, 0, format, type, NULL); + } + else + { + drv.glTextureImage2DEXT(DebugData.overlayTex, texBindingEnum, 0, internalFormat, + texDetails.width, texDetails.height, 0, format, type, NULL); + for(GLint i = 1; i < texMips; i++) + drv.glTextureImage2DEXT(DebugData.overlayTex, texBindingEnum, i, internalFormat, + RDCMAX(1, texDetails.width >> i), + RDCMAX(1, texDetails.height >> i), 0, format, type, NULL); + } + drv.glTexParameteri(texBindingEnum, eGL_TEXTURE_MAX_LEVEL, texMips - 1); drv.glTexParameteri(texBindingEnum, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); drv.glTexParameteri(texBindingEnum, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); @@ -430,14 +550,6 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com drv.glDisable(eGL_STENCIL_TEST); drv.glStencilMask(0); - GLfloat black[4] = {}; - for(GLint i = 0; i < texMips; i++) - { - drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texBindingEnum, - DebugData.overlayTex, i); - drv.glClearBufferfv(eGL_COLOR, 0, black); - } - drv.glBindTexture(texBindingEnum, curTex); } @@ -446,9 +558,34 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com drv.glBindFramebuffer(eGL_FRAMEBUFFER, DebugData.overlayFBO); - // bind the desired mip - drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texBindingEnum, - DebugData.overlayTex, sub.mip); + // clear the overlay texture to black + { + GLfloat black[4] = {}; + if(texSlices > 1) + { + for(GLint s = 0; s < texSlices; s++) + { + for(GLint m = 0; m < texMips; m++) + { + drv.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, + DebugData.overlayTex, m, s); + drv.glClearBufferfv(eGL_COLOR, 0, black); + } + } + } + else + { + for(GLint m = 0; m < texMips; m++) + { + drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texBindingEnum, + DebugData.overlayTex, m); + drv.glClearBufferfv(eGL_COLOR, 0, black); + } + } + } + + // bind the desired mip/slice/slices + BindFramebufferTexture(sub, texBindingEnum, texDetails.samples); // disable several tests/allow rendering - some overlays will override // these states but commonly we don't want to inherit these states from @@ -731,27 +868,55 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com drv.glGenTextures(1, &depthCopy); drv.glBindTexture(copyBindingEnum, depthCopy); - if(DebugData.overlayTexSamples > 1) + if(DebugData.overlayTexSlices > 1) { - drv.glTextureStorage2DMultisampleEXT(depthCopy, copyBindingEnum, DebugData.overlayTexSamples, - fmt, DebugData.overlayTexWidth, - DebugData.overlayTexHeight, true); + if(DebugData.overlayTexSamples > 1) + { + drv.glTextureStorage3DMultisampleEXT( + depthCopy, copyBindingEnum, DebugData.overlayTexSamples, fmt, DebugData.overlayTexWidth, + DebugData.overlayTexHeight, DebugData.overlayTexSlices, true); + } + else + { + drv.glTextureImage3DEXT(depthCopy, copyBindingEnum, 0, fmt, DebugData.overlayTexWidth, + DebugData.overlayTexHeight, DebugData.overlayTexSlices, 0, + GetBaseFormat(fmt), GetDataType(fmt), NULL); + for(GLint i = 1; i < texMips; i++) + drv.glTextureImage3DEXT( + depthCopy, copyBindingEnum, i, fmt, RDCMAX(1, DebugData.overlayTexWidth >> i), + RDCMAX(1, DebugData.overlayTexHeight >> i), DebugData.overlayTexSlices, 0, + GetBaseFormat(fmt), GetDataType(fmt), NULL); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAX_LEVEL, 0); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + } } else { - drv.glTextureImage2DEXT(depthCopy, copyBindingEnum, 0, fmt, DebugData.overlayTexWidth, - DebugData.overlayTexHeight, 0, GetBaseFormat(fmt), GetDataType(fmt), - NULL); - for(GLint i = 1; i < texMips; i++) - drv.glTextureImage2DEXT(depthCopy, copyBindingEnum, i, fmt, - RDCMAX(1, DebugData.overlayTexWidth >> i), - RDCMAX(1, DebugData.overlayTexHeight >> i), 0, GetBaseFormat(fmt), + if(DebugData.overlayTexSamples > 1) + { + drv.glTextureStorage2DMultisampleEXT( + depthCopy, copyBindingEnum, DebugData.overlayTexSamples, fmt, + DebugData.overlayTexWidth, DebugData.overlayTexHeight, true); + } + else + { + drv.glTextureImage2DEXT(depthCopy, copyBindingEnum, 0, fmt, DebugData.overlayTexWidth, + DebugData.overlayTexHeight, 0, GetBaseFormat(fmt), GetDataType(fmt), NULL); - drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAX_LEVEL, 0); - drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); - drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); - drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); - drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + for(GLint i = 1; i < texMips; i++) + drv.glTextureImage2DEXT(depthCopy, copyBindingEnum, i, fmt, + RDCMAX(1, DebugData.overlayTexWidth >> i), + RDCMAX(1, DebugData.overlayTexHeight >> i), 0, + GetBaseFormat(fmt), GetDataType(fmt), NULL); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAX_LEVEL, 0); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + } } drv.glBindTexture(copyBindingEnum, curTex); @@ -782,27 +947,56 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com drv.glGenTextures(1, &stencilCopy); drv.glBindTexture(copyBindingEnum, stencilCopy); - if(DebugData.overlayTexSamples > 1) + if(DebugData.overlayTexSlices > 1) { - drv.glTextureStorage2DMultisampleEXT( - stencilCopy, copyBindingEnum, DebugData.overlayTexSamples, fmt, - DebugData.overlayTexWidth, DebugData.overlayTexHeight, true); + if(DebugData.overlayTexSamples > 1) + { + drv.glTextureStorage3DMultisampleEXT(stencilCopy, copyBindingEnum, + DebugData.overlayTexSamples, fmt, + DebugData.overlayTexWidth, DebugData.overlayTexHeight, + DebugData.overlayTexSlices, true); + } + else + { + drv.glTextureImage3DEXT(stencilCopy, copyBindingEnum, 0, fmt, DebugData.overlayTexWidth, + DebugData.overlayTexHeight, DebugData.overlayTexSlices, 0, + GetBaseFormat(fmt), GetDataType(fmt), NULL); + for(GLint i = 1; i < texMips; i++) + drv.glTextureImage3DEXT( + stencilCopy, copyBindingEnum, i, fmt, RDCMAX(1, DebugData.overlayTexWidth >> i), + RDCMAX(1, DebugData.overlayTexHeight >> i), DebugData.overlayTexSlices, 0, + GetBaseFormat(fmt), GetDataType(fmt), NULL); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAX_LEVEL, 0); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + } } else { - drv.glTextureImage2DEXT(stencilCopy, copyBindingEnum, 0, fmt, DebugData.overlayTexWidth, - DebugData.overlayTexHeight, 0, GetBaseFormat(fmt), GetDataType(fmt), - NULL); - for(GLint i = 1; i < texMips; i++) - drv.glTextureImage2DEXT(stencilCopy, copyBindingEnum, i, fmt, - RDCMAX(1, DebugData.overlayTexWidth >> i), - RDCMAX(1, DebugData.overlayTexHeight >> i), 0, GetBaseFormat(fmt), + if(DebugData.overlayTexSamples > 1) + { + drv.glTextureStorage2DMultisampleEXT( + stencilCopy, copyBindingEnum, DebugData.overlayTexSamples, fmt, + DebugData.overlayTexWidth, DebugData.overlayTexHeight, true); + } + else + { + drv.glTextureImage2DEXT(stencilCopy, copyBindingEnum, 0, fmt, DebugData.overlayTexWidth, + DebugData.overlayTexHeight, 0, GetBaseFormat(fmt), GetDataType(fmt), NULL); - drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAX_LEVEL, 0); - drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); - drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); - drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); - drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + for(GLint i = 1; i < texMips; i++) + drv.glTextureImage2DEXT(stencilCopy, copyBindingEnum, i, fmt, + RDCMAX(1, DebugData.overlayTexWidth >> i), + RDCMAX(1, DebugData.overlayTexHeight >> i), 0, + GetBaseFormat(fmt), GetDataType(fmt), NULL); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAX_LEVEL, 0); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + drv.glTexParameteri(copyBindingEnum, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + } } drv.glBindTexture(copyBindingEnum, curTex); @@ -811,17 +1005,17 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com // bind depth/stencil to overlay FBO (currently bound to DRAW_FRAMEBUFFER) if(curDepth != 0 && curDepth == curStencil) { - drv.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, eGL_TEXTURE_2D, - depthCopy, sub.mip); + drv.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, + copyBindingEnum, depthCopy, sub.mip); } else if(curDepth != 0) { - drv.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, eGL_TEXTURE_2D, + drv.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, copyBindingEnum, depthCopy, sub.mip); } else if(curStencil != 0) { - drv.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT, eGL_TEXTURE_2D, + drv.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT, copyBindingEnum, stencilCopy, sub.mip); } @@ -1099,8 +1293,13 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com // bind our FBO drv.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, overlayFBO); - drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texBindingEnum, - DebugData.overlayTex, sub.mip); + if(texBindingEnum == eGL_TEXTURE_2D_ARRAY || + texBindingEnum == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) + drv.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, + DebugData.overlayTex, sub.mip, sub.slice); + else + drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texBindingEnum, + DebugData.overlayTex, sub.mip); // now apply the depth texture binding if(depthObj) @@ -1554,10 +1753,20 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, const Subresource &sub, Com // modify our fbo to attach the overlay texture instead drv.glBindFramebuffer(eGL_FRAMEBUFFER, replacefbo); - drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texBindingEnum, - DebugData.overlayTex, sub.mip); - drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, texBindingEnum, - 0, 0); + if(texBindingEnum == eGL_TEXTURE_2D_ARRAY || + texBindingEnum == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) + { + drv.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, + DebugData.overlayTex, sub.mip, sub.slice); + drv.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); + } + else + { + drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, texBindingEnum, + DebugData.overlayTex, sub.mip); + drv.glFramebufferTexture2D(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, + texBindingEnum, 0, 0); + } drv.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); drv.glDisable(eGL_BLEND); diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 21164ce6a..09678a419 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -373,21 +373,6 @@ void GLReplay::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, byt drv.glBindBuffer(eGL_COPY_READ_BUFFER, oldbuf); } -bool GLReplay::IsRenderOutput(ResourceId id) -{ - for(const GLPipe::Attachment &att : m_CurPipelineState.framebuffer.drawFBO.colorAttachments) - { - if(att.resourceId == id) - return true; - } - - if(m_CurPipelineState.framebuffer.drawFBO.depthAttachment.resourceId == id || - m_CurPipelineState.framebuffer.drawFBO.stencilAttachment.resourceId == id) - return true; - - return false; -} - void GLReplay::CacheTexture(ResourceId id) { if(m_CachedTextures.find(id) != m_CachedTextures.end()) @@ -1755,11 +1740,50 @@ void GLReplay::SavePipelineState(uint32_t eventId) pipe.framebuffer.drawFBO.colorAttachments[i].resourceId = rm->GetOriginalID(id); + GLenum attachment = GLenum(eGL_COLOR_ATTACHMENT0 + i); + if(pipe.framebuffer.drawFBO.colorAttachments[i].resourceId != ResourceId() && !rbCol[i]) - GetFramebufferMipAndLayer(curDrawFBO, GLenum(eGL_COLOR_ATTACHMENT0 + i), + GetFramebufferMipAndLayer(curDrawFBO, attachment, (GLint *)&pipe.framebuffer.drawFBO.colorAttachments[i].mipLevel, (GLint *)&pipe.framebuffer.drawFBO.colorAttachments[i].slice); + pipe.framebuffer.drawFBO.colorAttachments[i].numSlices = 1; + + if(!rbCol[i] && id != ResourceId()) + { + // desktop GL allows layered attachments which attach all slices from 0 to N + if(!IsGLES) + { + GLint layered = 0; + GL.glGetNamedFramebufferAttachmentParameterivEXT( + curDrawFBO, attachment, eGL_FRAMEBUFFER_ATTACHMENT_LAYERED, &layered); + + if(layered) + { + pipe.framebuffer.drawFBO.colorAttachments[i].numSlices = m_pDriver->m_Textures[id].depth; + } + } + else + { + // on GLES there's an OVR extension that allows attaching multiple layers + if(HasExt[OVR_multiview]) + { + GLint numViews = 0, startView = 0; + GL.glGetNamedFramebufferAttachmentParameterivEXT( + curDrawFBO, attachment, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR, &numViews); + GL.glGetNamedFramebufferAttachmentParameterivEXT( + curDrawFBO, attachment, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR, + &startView); + + if(numViews > 1) + { + pipe.framebuffer.drawFBO.colorAttachments[i].numSlices = numViews; + pipe.framebuffer.drawFBO.colorAttachments[i].slice = startView; + } + } + } + } + GLenum swizzles[4] = {eGL_RED, eGL_GREEN, eGL_BLUE, eGL_ALPHA}; if(!rbCol[i] && id != ResourceId() && (HasExt[ARB_texture_swizzle] || HasExt[EXT_texture_swizzle])) @@ -1789,6 +1813,55 @@ void GLReplay::SavePipelineState(uint32_t eventId) (GLint *)&pipe.framebuffer.drawFBO.stencilAttachment.mipLevel, (GLint *)&pipe.framebuffer.drawFBO.stencilAttachment.slice); + pipe.framebuffer.drawFBO.depthAttachment.numSlices = 1; + pipe.framebuffer.drawFBO.stencilAttachment.numSlices = 1; + + ResourceId id = pipe.framebuffer.drawFBO.depthAttachment.resourceId; + if(!rbDepth && id != ResourceId()) + { + // desktop GL allows layered attachments which attach all slices from 0 to N + if(!IsGLES) + { + GLint layered = 0; + GL.glGetNamedFramebufferAttachmentParameterivEXT( + curDrawFBO, eGL_DEPTH_ATTACHMENT, eGL_FRAMEBUFFER_ATTACHMENT_LAYERED, &layered); + + if(layered) + { + pipe.framebuffer.drawFBO.depthAttachment.numSlices = m_pDriver->m_Textures[id].depth; + } + } + else + { + // on GLES there's an OVR extension that allows attaching multiple layers + if(HasExt[OVR_multiview]) + { + GLint numViews = 0, startView = 0; + GL.glGetNamedFramebufferAttachmentParameterivEXT( + curDrawFBO, eGL_DEPTH_ATTACHMENT, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR, + &numViews); + GL.glGetNamedFramebufferAttachmentParameterivEXT( + curDrawFBO, eGL_DEPTH_ATTACHMENT, + eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR, &startView); + + if(numViews > 1) + { + pipe.framebuffer.drawFBO.depthAttachment.numSlices = numViews; + pipe.framebuffer.drawFBO.depthAttachment.slice = startView; + } + } + } + + if(pipe.framebuffer.drawFBO.stencilAttachment.resourceId == + pipe.framebuffer.drawFBO.depthAttachment.resourceId) + { + pipe.framebuffer.drawFBO.stencilAttachment.slice = + pipe.framebuffer.drawFBO.depthAttachment.slice; + pipe.framebuffer.drawFBO.stencilAttachment.numSlices = + pipe.framebuffer.drawFBO.depthAttachment.numSlices; + } + } + pipe.framebuffer.drawFBO.drawBuffers.resize(numCols); for(GLint i = 0; i < numCols; i++) { diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index c5338a91a..ddfcb2ab9 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -228,9 +228,11 @@ public: uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y); - ResourceId RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents); + ResourceId RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents); + + void BindFramebufferTexture(RenderOutputSubresource &sub, GLenum texBindingEnum, GLint numSamples); + ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, CompType typeCast); @@ -242,8 +244,8 @@ public: ResourceId CreateProxyBuffer(const BufferDescription &templateBuf); void SetProxyBufferData(ResourceId bufid, byte *data, size_t dataSize); - bool IsRenderOutput(ResourceId id); - + RenderOutputSubresource GetRenderOutputSubresource(ResourceId id); + bool IsRenderOutput(ResourceId id) { return GetRenderOutputSubresource(id).mip != ~0U; } void FileChanged() {} void SetReplayData(GLWindowingData data); @@ -386,7 +388,8 @@ private: GLuint overlayTex; GLuint overlayFBO; GLuint overlayProg; - GLint overlayTexWidth, overlayTexHeight, overlayTexSamples, overlayTexMips; + GLint overlayTexWidth = 0, overlayTexHeight = 0, overlayTexSamples = 0, overlayTexMips = 0, + overlayTexSlices = 0; GLuint UBOs[3]; diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index d3d3651ca..9a63aa931 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -454,12 +454,34 @@ void VulkanDebugManager::PatchLineStripIndexBuffer(const DrawcallDescription *dr indexCount = (uint32_t)patchedIndices.size(); } -ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents) +RenderOutputSubresource VulkanReplay::GetRenderOutputSubresource(ResourceId id) +{ + id = GetResourceManager()->GetOriginalID(id); + + for(const VKPipe::Attachment &att : m_VulkanPipelineState.currentPass.framebuffer.attachments) + { + if(att.viewResourceId == id || att.imageResourceId == id) + { + return RenderOutputSubresource(att.firstMip, att.firstSlice, att.numSlices); + } + } + + return RenderOutputSubresource(~0U, ~0U, 0); +} + +ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents) { const VkDevDispatchTable *vt = ObjDisp(m_Device); + RenderOutputSubresource sub = GetRenderOutputSubresource(texid); + + if(sub.slice == ~0U) + { + RDCERR("Rendering overlay for %s couldn't find output to get subresource.", ToStr(texid).c_str()); + sub = RenderOutputSubresource(0, 0, 1); + } + VulkanShaderCache *shaderCache = m_pDriver->GetShaderCache(); VulkanCreationInfo::Image &iminfo = m_pDriver->m_CreationInfo.m_Image[texid]; @@ -486,11 +508,21 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, VkMarkerRegion::Begin(StringFormat::Fmt("RenderOverlay %d", overlay), cmd); + uint32_t multiviewMask = 0; + { + const VulkanCreationInfo::RenderPass &rp = + m_pDriver->m_CreationInfo.m_RenderPass[m_pDriver->m_RenderState.renderPass]; + + for(uint32_t v : rp.subpasses[m_pDriver->m_RenderState.subpass].multiviews) + multiviewMask |= 1U << v; + } + // if the overlay image is the wrong size, free it if(m_Overlay.Image != VK_NULL_HANDLE && (iminfo.extent.width != m_Overlay.ImageDim.width || iminfo.extent.height != m_Overlay.ImageDim.height || iminfo.samples != m_Overlay.Samples || - iminfo.mipLevels != m_Overlay.MipLevels)) + iminfo.mipLevels != m_Overlay.MipLevels || iminfo.arrayLayers != m_Overlay.ArrayLayers || + multiviewMask != m_Overlay.MultiViewMask)) { m_pDriver->vkDestroyRenderPass(m_Device, m_Overlay.NoDepthRP, NULL); m_pDriver->vkDestroyFramebuffer(m_Device, m_Overlay.NoDepthFB, NULL); @@ -503,10 +535,17 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, m_Overlay.NoDepthFB = VK_NULL_HANDLE; } - VkImageSubresourceRange subRange = {VK_IMAGE_ASPECT_COLOR_BIT, sub.mip, 1, 0, 1}; + VkImageSubresourceRange subRange = {VK_IMAGE_ASPECT_COLOR_BIT, sub.mip, 1, sub.slice, + sub.numSlices}; const VkFormat overlayFormat = VK_FORMAT_R16G16B16A16_SFLOAT; + VkRenderPassMultiviewCreateInfo multiviewRP = {VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO}; + multiviewRP.correlationMaskCount = 1; + multiviewRP.pCorrelationMasks = &multiviewMask; + multiviewRP.subpassCount = 1; + multiviewRP.pViewMasks = &multiviewMask; + // create the overlay image if we don't have one already // we go through the driver's creation functions so creation info // is saved and the resources are registered as live resources for @@ -516,7 +555,9 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, m_Overlay.ImageDim.width = iminfo.extent.width; m_Overlay.ImageDim.height = iminfo.extent.height; m_Overlay.MipLevels = iminfo.mipLevels; + m_Overlay.ArrayLayers = iminfo.arrayLayers; m_Overlay.Samples = iminfo.samples; + m_Overlay.MultiViewMask = multiviewMask; VkImageCreateInfo imInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, @@ -526,7 +567,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, overlayFormat, {m_Overlay.ImageDim.width, m_Overlay.ImageDim.height, 1}, (uint32_t)iminfo.mipLevels, - 1, + (uint32_t)iminfo.arrayLayers, iminfo.samples, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | @@ -608,16 +649,22 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, NULL, // dependencies }; + if(multiviewMask > 0) + rpinfo.pNext = &multiviewRP; + vkr = m_pDriver->vkCreateRenderPass(m_Device, &rpinfo, NULL, &m_Overlay.NoDepthRP); RDCASSERTEQUAL(vkr, VK_SUCCESS); } - if(m_Overlay.MipLevel != sub.mip || m_Overlay.ImageView == VK_NULL_HANDLE) + if(m_Overlay.ViewMip != sub.mip || m_Overlay.ViewSlice != sub.slice || + m_Overlay.ViewNumSlices != sub.numSlices || m_Overlay.ImageView == VK_NULL_HANDLE) { m_pDriver->vkDestroyFramebuffer(m_Device, m_Overlay.NoDepthFB, NULL); m_pDriver->vkDestroyImageView(m_Device, m_Overlay.ImageView, NULL); - m_Overlay.MipLevel = sub.mip; + m_Overlay.ViewMip = sub.mip; + m_Overlay.ViewSlice = sub.slice; + m_Overlay.ViewNumSlices = sub.numSlices; VkImageViewCreateInfo viewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, @@ -644,7 +691,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, &m_Overlay.ImageView, RDCMAX(1U, m_Overlay.ImageDim.width >> sub.mip), RDCMAX(1U, m_Overlay.ImageDim.height >> sub.mip), - 1, + sub.numSlices, }; vkr = m_pDriver->vkCreateFramebuffer(m_Device, &fbinfo, NULL, &m_Overlay.NoDepthFB); @@ -654,6 +701,37 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, // needs to match the depth texture type wherever our draw is. } + { + VkImageSubresourceRange fullSubRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, + 0, VK_REMAINING_ARRAY_LAYERS}; + + VkImageMemoryBarrier barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + NULL, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + Unwrap(m_Overlay.Image), + fullSubRange}; + + DoPipelineBarrier(cmd, 1, &barrier); + + float black[4] = {}; + vt->CmdClearColorImage(Unwrap(cmd), Unwrap(m_Overlay.Image), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + (VkClearColorValue *)black, 1, &fullSubRange); + + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + DoPipelineBarrier(cmd, 1, &barrier); + } + const DrawcallDescription *mainDraw = m_pDriver->GetDrawcall(eventId); // Secondary commands can't have render passes @@ -1387,6 +1465,9 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, NULL, // dependencies }; + if(multiviewMask > 0) + rpinfo.pNext = &multiviewRP; + vkr = m_pDriver->vkCreateRenderPass(m_Device, &rpinfo, NULL, &depthRP); RDCASSERTEQUAL(vkr, VK_SUCCESS); @@ -2169,6 +2250,9 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, NULL, // dependencies }; + if(multiviewMask > 0) + rpinfo.pNext = &multiviewRP; + vkr = m_pDriver->vkCreateRenderPass(m_Device, &rpinfo, NULL, &RP); RDCASSERTEQUAL(vkr, VK_SUCCESS); @@ -2187,7 +2271,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, const Subresource &sub, views, RDCMAX(1U, m_Overlay.ImageDim.width >> sub.mip), RDCMAX(1U, m_Overlay.ImageDim.height >> sub.mip), - 1, + sub.numSlices, }; vkr = m_pDriver->vkCreateFramebuffer(m_Device, &fbinfo, NULL, &FB); diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 5fdb4a314..f8328758a 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -951,17 +951,6 @@ void VulkanReplay::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, GetDebugManager()->GetBufferData(buff, offset, len, retData); } -bool VulkanReplay::IsRenderOutput(ResourceId id) -{ - for(const VKPipe::Attachment &att : m_VulkanPipelineState.currentPass.framebuffer.attachments) - { - if(att.viewResourceId == id || att.imageResourceId == id) - return true; - } - - return false; -} - void VulkanReplay::FileChanged() { } diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index c66492589..1380db8e4 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -386,9 +386,8 @@ public: uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg, uint32_t x, uint32_t y); - ResourceId RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents); + ResourceId RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents); ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub, CompType typeCast); @@ -400,8 +399,8 @@ public: ResourceId CreateProxyBuffer(const BufferDescription &templateBuf); void SetProxyBufferData(ResourceId bufid, byte *data, size_t dataSize); - bool IsRenderOutput(ResourceId id); - + RenderOutputSubresource GetRenderOutputSubresource(ResourceId id); + bool IsRenderOutput(ResourceId id) { return GetRenderOutputSubresource(id).mip != ~0U; } void FileChanged(); void InitCallstackResolver(); @@ -597,12 +596,13 @@ private: VkDeviceSize ImageMemSize = 0; VkImage Image = VK_NULL_HANDLE; VkExtent2D ImageDim = {0, 0}; - int32_t MipLevels = 0; + int32_t MipLevels = 0, ArrayLayers = 0; + uint32_t MultiViewMask = 0; VkSampleCountFlagBits Samples = VK_SAMPLE_COUNT_1_BIT; VkRenderPass NoDepthRP = VK_NULL_HANDLE; // the view and framebuffer must be recreated if the mip changes, even if the image doesn't - uint32_t MipLevel = ~0U; + uint32_t ViewMip = ~0U, ViewSlice = ~0U, ViewNumSlices = ~0U; VkImageView ImageView = VK_NULL_HANDLE; VkFramebuffer NoDepthFB = VK_NULL_HANDLE; diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 4eec78f61..dbdf8feab 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -1746,10 +1746,11 @@ void DoSerialise(SerialiserType &ser, GLPipe::Attachment &el) { SERIALISE_MEMBER(resourceId); SERIALISE_MEMBER(slice); + SERIALISE_MEMBER(numSlices); SERIALISE_MEMBER(mipLevel); SERIALISE_MEMBER(swizzle); - SIZE_CHECK(32); + SIZE_CHECK(40); } template @@ -1762,7 +1763,7 @@ void DoSerialise(SerialiserType &ser, GLPipe::FBO &el) SERIALISE_MEMBER(drawBuffers); SERIALISE_MEMBER(readBuffer); - SIZE_CHECK(128); + SIZE_CHECK(144); } template @@ -1783,7 +1784,7 @@ void DoSerialise(SerialiserType &ser, GLPipe::FrameBuffer &el) SERIALISE_MEMBER(readFBO); SERIALISE_MEMBER(blendState); - SIZE_CHECK(304); + SIZE_CHECK(336); } template @@ -1832,7 +1833,7 @@ void DoSerialise(SerialiserType &ser, GLPipe::State &el) SERIALISE_MEMBER(hints); - SIZE_CHECK(1984); + SIZE_CHECK(2016); } #pragma endregion OpenGL pipeline state diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index d97cb96c4..e44ce6b83 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -107,6 +107,16 @@ class RDCFile; class AMDRGPControl; +struct RenderOutputSubresource +{ + RenderOutputSubresource(uint32_t mip, uint32_t slice, uint32_t numSlices) + : mip(mip), slice(slice), numSlices(numSlices) + { + } + + uint32_t mip, slice, numSlices; +}; + // these two interfaces define what an API driver implementation must provide // to the replay. At minimum it must implement IRemoteDriver which contains // all of the functionality that cannot be achieved elsewhere. An IReplayDriver @@ -198,9 +208,8 @@ public: virtual rdcarray ContinueDebug(ShaderDebugger *debugger) = 0; virtual void FreeDebugger(ShaderDebugger *debugger) = 0; - virtual ResourceId RenderOverlay(ResourceId texid, const Subresource &sub, CompType typeCast, - FloatVector clearCol, DebugOverlay overlay, uint32_t eventId, - const rdcarray &passEvents) = 0; + virtual ResourceId RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay, + uint32_t eventId, const rdcarray &passEvents) = 0; virtual bool IsRenderOutput(ResourceId id) = 0; diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index c11ad9e31..96c316853 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -266,7 +266,9 @@ void ReplayOutput::RefreshOverlay() if(m_Type == ReplayOutputType::Texture && m_RenderData.texDisplay.overlay != DebugOverlay::NoOverlay) { - if(draw && m_pDevice->IsRenderOutput(m_RenderData.texDisplay.resourceId)) + ResourceId id = m_pDevice->GetLiveID(m_RenderData.texDisplay.resourceId); + + if(draw && m_pDevice->IsRenderOutput(id)) { FloatVector f = m_RenderData.texDisplay.backgroundColor; @@ -274,10 +276,8 @@ void ReplayOutput::RefreshOverlay() f.y = ConvertLinearToSRGB(f.y); f.z = ConvertLinearToSRGB(f.z); - m_OverlayResourceId = m_pDevice->RenderOverlay( - m_pDevice->GetLiveID(m_RenderData.texDisplay.resourceId), - m_RenderData.texDisplay.subresource, m_RenderData.texDisplay.typeCast, f, - m_RenderData.texDisplay.overlay, m_EventID, passEvents); + m_OverlayResourceId = + m_pDevice->RenderOverlay(id, f, m_RenderData.texDisplay.overlay, m_EventID, passEvents); m_OverlayDirty = false; } else @@ -733,9 +733,10 @@ void ReplayOutput::DisplayTex() m_pDevice->RenderTexture(texDisplay); + ResourceId id = m_pDevice->GetLiveID(m_RenderData.texDisplay.resourceId); + if(m_RenderData.texDisplay.overlay != DebugOverlay::NoOverlay && draw && - m_pDevice->IsRenderOutput(m_RenderData.texDisplay.resourceId) && - m_RenderData.texDisplay.overlay != DebugOverlay::NaN && + m_pDevice->IsRenderOutput(id) && m_RenderData.texDisplay.overlay != DebugOverlay::NaN && m_RenderData.texDisplay.overlay != DebugOverlay::Clipping && m_OverlayResourceId != ResourceId()) { texDisplay.resourceId = m_pDevice->GetLiveID(m_OverlayResourceId); diff --git a/util/test/demos/d3d12/d3d12_overlay_test.cpp b/util/test/demos/d3d12/d3d12_overlay_test.cpp index 88fc8e129..e69db1cf9 100644 --- a/util/test/demos/d3d12/d3d12_overlay_test.cpp +++ b/util/test/demos/d3d12/d3d12_overlay_test.cpp @@ -146,6 +146,7 @@ float4 main() : SV_Target0 creator.GraphicsDesc.DepthStencilState.StencilEnable = FALSE; creator.GraphicsDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS; creator.PS(whitepsblob); + creator.DSV(DXGI_FORMAT_UNKNOWN); ID3D12PipelineStatePtr whitepipe = creator; ResourceBarrier(vb, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); diff --git a/util/test/rdtest/shared/Overlay_Test.py b/util/test/rdtest/shared/Overlay_Test.py index 66d254d3d..817ffc464 100644 --- a/util/test/rdtest/shared/Overlay_Test.py +++ b/util/test/rdtest/shared/Overlay_Test.py @@ -468,7 +468,7 @@ class Overlay_Test(rdtest.TestCase): pipe: rd.PipeState = self.controller.GetPipelineState() col_tex = pipe.GetOutputTargets()[0].resourceId - sub = rd.Subresource(pipe.GetOutputTargets()[0].firstMip, 0, 0) + sub = rd.Subresource(pipe.GetOutputTargets()[0].firstMip, pipe.GetOutputTargets()[0].firstSlice, 0) for overlay in rd.DebugOverlay: if overlay == rd.DebugOverlay.NoOverlay: @@ -497,9 +497,14 @@ class Overlay_Test(rdtest.TestCase): shift = 1 # All values in mip 0 should be 0 for all overlays - self.check_pixel_value(overlay_id, 200, 150, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(0, 0, 0)) - self.check_pixel_value(overlay_id, 197, 147, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(0, 0, 0)) - self.check_pixel_value(overlay_id, 203, 153, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(0, 0, 0)) + self.check_pixel_value(overlay_id, 200 >> shift, 150 >> shift, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(0, 0, 0)) + self.check_pixel_value(overlay_id, 197 >> shift, 147 >> shift, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(0, 0, 0)) + self.check_pixel_value(overlay_id, 203 >> shift, 153 >> shift, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(0, 0, 0)) + + # Also for array slice 0 on this mip + self.check_pixel_value(overlay_id, 200 >> shift, 150 >> shift, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(mip, 0, 0)) + self.check_pixel_value(overlay_id, 197 >> shift, 147 >> shift, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(mip, 0, 0)) + self.check_pixel_value(overlay_id, 203 >> shift, 153 >> shift, [0.0, 0.0, 0.0, 0.0], sub=rd.Subresource(mip, 0, 0)) rdtest.log.success("Other mips are empty as expected for overlay {}".format(str(overlay)))