From 485f7d21fca7dfe37c36688a1b4a7008e8c14a10 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 17 Jul 2020 13:02:33 +0100 Subject: [PATCH] Make overlays interact consistently with viewport/scissor * We also add a red/green display to the viewport and scissor overlay to show pixels that fail the scissor test. --- renderdoc/driver/d3d11/d3d11_overlay.cpp | 122 +++++--- renderdoc/driver/d3d12/d3d12_overlay.cpp | 195 +++++++++--- renderdoc/driver/gl/gl_overlay.cpp | 178 ++++++++++- renderdoc/driver/vulkan/vk_overlay.cpp | 299 +++++++++++++------ util/test/demos/d3d11/d3d11_overlay_test.cpp | 11 + util/test/demos/d3d12/d3d12_overlay_test.cpp | 13 + util/test/demos/gl/gl_overlay_test.cpp | 14 + util/test/demos/vk/vk_overlay_test.cpp | 21 +- util/test/rdtest/shared/Overlay_Test.py | 139 ++++++++- util/test/rdtest/testcase.py | 3 + 10 files changed, 798 insertions(+), 197 deletions(-) diff --git a/renderdoc/driver/d3d11/d3d11_overlay.cpp b/renderdoc/driver/d3d11/d3d11_overlay.cpp index 0c8e47b57..4fea4a79b 100644 --- a/renderdoc/driver/d3d11/d3d11_overlay.cpp +++ b/renderdoc/driver/d3d11/d3d11_overlay.cpp @@ -357,6 +357,7 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De { origdesc.CullMode = D3D11_CULL_BACK; origdesc.FrontCounterClockwise = FALSE; + origdesc.ScissorEnable = FALSE; } SAFE_RELEASE(rs); @@ -372,7 +373,7 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De rdesc.DepthBiasClamp = D3D11_DEFAULT_DEPTH_BIAS_CLAMP; rdesc.SlopeScaledDepthBias = D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; rdesc.DepthClipEnable = FALSE; - rdesc.ScissorEnable = FALSE; + rdesc.ScissorEnable = origdesc.ScissorEnable; rdesc.MultisampleEnable = FALSE; rdesc.AntialiasedLineEnable = FALSE; @@ -422,27 +423,22 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De } else if(overlay == DebugOverlay::ViewportScissor) { - m_pImmediateContext->VSSetShader(m_Overlay.FullscreenVS, NULL, 0); - m_pImmediateContext->HSSetShader(NULL, NULL, 0); - m_pImmediateContext->DSSetShader(NULL, NULL, 0); - m_pImmediateContext->GSSetShader(NULL, NULL, 0); - m_pImmediateContext->PSSetShader(m_General.CheckerboardPS, NULL, 0); - m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - m_pImmediateContext->IASetInputLayout(NULL); + m_pImmediateContext->OMSetBlendState(NULL, NULL, 0xffffffff); + m_pImmediateContext->PSSetShader(m_General.FixedColPS, NULL, 0); - D3D11_RASTERIZER_DESC origdesc; + D3D11_RASTERIZER_DESC origdesc = {}; { - ID3D11RasterizerState *rs = NULL; + ID3D11RasterizerState *origRS = NULL; - m_pImmediateContext->RSGetState(&rs); + m_pImmediateContext->RSGetState(&origRS); - if(rs) - rs->GetDesc(&origdesc); + if(origRS) + origRS->GetDesc(&origdesc); else origdesc.ScissorEnable = FALSE; - SAFE_RELEASE(rs); + SAFE_RELEASE(origRS); } dsDesc.DepthEnable = FALSE; @@ -456,8 +452,71 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De return m_Overlay.resourceId; } + ID3D11RasterizerState *rs = NULL; + ID3D11RasterizerState *rsScissorOn = NULL; + { + D3D11_RASTERIZER_DESC rdesc; + + rdesc.FillMode = D3D11_FILL_SOLID; + rdesc.CullMode = D3D11_CULL_NONE; + rdesc.FrontCounterClockwise = FALSE; + rdesc.DepthBias = D3D11_DEFAULT_DEPTH_BIAS; + rdesc.DepthBiasClamp = D3D11_DEFAULT_DEPTH_BIAS_CLAMP; + rdesc.SlopeScaledDepthBias = D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; + rdesc.DepthClipEnable = FALSE; + rdesc.ScissorEnable = FALSE; + rdesc.MultisampleEnable = FALSE; + rdesc.AntialiasedLineEnable = FALSE; + + hr = m_pDevice->CreateRasterizerState(&rdesc, &rs); + if(FAILED(hr)) + { + RDCERR("Failed to create drawcall rast state HRESULT: %s", ToStr(hr).c_str()); + return m_Overlay.resourceId; + } + + rdesc.ScissorEnable = TRUE; + + hr = m_pDevice->CreateRasterizerState(&rdesc, &rsScissorOn); + if(FAILED(hr)) + { + RDCERR("Failed to create drawcall rast state HRESULT: %s", ToStr(hr).c_str()); + return m_Overlay.resourceId; + } + } + + float clearColour[] = {0.0f, 0.0f, 0.0f, 0.0f}; + m_pImmediateContext->ClearRenderTargetView(rtv, clearColour); + + m_pImmediateContext->RSSetState(rs); m_pImmediateContext->OMSetDepthStencilState(os, 0); + float overlayConsts[] = {1.0f, 0.0f, 0.0f, 1.0f}; + ID3D11Buffer *buf = GetDebugManager()->MakeCBuffer(overlayConsts, sizeof(overlayConsts)); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &buf); + + m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); + + overlayConsts[0] = 0.0f; + overlayConsts[1] = 1.0f; + + buf = GetDebugManager()->MakeCBuffer(overlayConsts, sizeof(overlayConsts)); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &buf); + + m_pImmediateContext->RSSetState(rsScissorOn); + + m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); + + m_pImmediateContext->VSSetShader(m_Overlay.FullscreenVS, NULL, 0); + m_pImmediateContext->HSSetShader(NULL, NULL, 0); + m_pImmediateContext->DSSetShader(NULL, NULL, 0); + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + m_pImmediateContext->IASetInputLayout(NULL); + m_pImmediateContext->PSSetShader(m_General.CheckerboardPS, NULL, 0); + D3D11_BLEND_DESC blendDesc; RDCEraseEl(blendDesc); @@ -478,32 +537,6 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De float blendwhite[] = {1.0f, 1.0f, 1.0f, 1.0f}; m_pImmediateContext->OMSetBlendState(bs, blendwhite, 0xffffffff); - ID3D11RasterizerState *rs = NULL; - { - D3D11_RASTERIZER_DESC rdesc; - - rdesc.FillMode = D3D11_FILL_SOLID; - rdesc.CullMode = D3D11_CULL_NONE; - rdesc.FrontCounterClockwise = FALSE; - rdesc.DepthBias = D3D11_DEFAULT_DEPTH_BIAS; - rdesc.DepthBiasClamp = D3D11_DEFAULT_DEPTH_BIAS_CLAMP; - rdesc.SlopeScaledDepthBias = D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; - rdesc.DepthClipEnable = FALSE; - rdesc.ScissorEnable = FALSE; - rdesc.MultisampleEnable = FALSE; - rdesc.AntialiasedLineEnable = FALSE; - - hr = m_pDevice->CreateRasterizerState(&rdesc, &rs); - if(FAILED(hr)) - { - RDCERR("Failed to create drawcall rast state HRESULT: %s", ToStr(hr).c_str()); - return m_Overlay.resourceId; - } - } - - float clearColour[] = {0.0f, 0.0f, 0.0f, 0.0f}; - m_pImmediateContext->ClearRenderTargetView(rtv, clearColour); - m_pImmediateContext->RSSetState(rs); CheckerboardCBuffer pixelData = {0}; @@ -517,13 +550,13 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De // set primary/secondary to the same to 'disable' checkerboard pixelData.PrimaryColor = pixelData.SecondaryColor = Vec4f(0.1f, 0.1f, 0.1f, 1.0f); - pixelData.InnerColor = Vec4f(0.2f, 0.2f, 0.9f, 0.7f); + pixelData.InnerColor = Vec4f(0.2f, 0.2f, 0.9f, 0.4f); // set viewport rect pixelData.RectPosition = Vec2f(views[0].TopLeftX, views[0].TopLeftY); pixelData.RectSize = Vec2f(views[0].Width, views[0].Height); - ID3D11Buffer *buf = GetDebugManager()->MakeCBuffer(&pixelData, sizeof(pixelData)); + buf = GetDebugManager()->MakeCBuffer(&pixelData, sizeof(pixelData)); m_pImmediateContext->PSSetConstantBuffers(0, 1, &buf); @@ -565,6 +598,7 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De SAFE_RELEASE(os); SAFE_RELEASE(rs); + SAFE_RELEASE(rsScissorOn); SAFE_RELEASE(bs); } else if(overlay == DebugOverlay::Wireframe) @@ -1116,6 +1150,10 @@ ResourceId D3D11Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De m_pImmediateContext->OMSetBlendState(NULL, NULL, 0xffffffff); m_pImmediateContext->RSSetState(m_General.RasterState); + D3D11_VIEWPORT view = {0.0f, 0.0f, (float)realTexDesc.Width, (float)realTexDesc.Height, + 0.0f, 1.0f}; + m_pImmediateContext->RSSetViewports(1, &view); + float clearColour[] = {0.0f, 0.0f, 0.0f, 0.0f}; m_pImmediateContext->ClearRenderTargetView(rtv, clearColour); diff --git a/renderdoc/driver/d3d12/d3d12_overlay.cpp b/renderdoc/driver/d3d12/d3d12_overlay.cpp index ddd97bc2d..a004dda9b 100644 --- a/renderdoc/driver/d3d12/d3d12_overlay.cpp +++ b/renderdoc/driver/d3d12/d3d12_overlay.cpp @@ -442,7 +442,7 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De D3D12_RENDER_TARGET_VIEW_DESC rtDesc = {}; rtDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - ID3D12GraphicsCommandList *list = m_pDevice->GetNewList(); + ID3D12GraphicsCommandListX *list = m_pDevice->GetNewList(); // clear all mips and all slices first for(UINT mip = 0; mip < overlayTexDesc.MipLevels; mip++) @@ -563,6 +563,9 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De rs.rts[0] = *GetWrapped(rtv); RDCEraseEl(rs.dsv); + for(D3D12_RECT &r : rs.scissors) + r = {0, 0, 32768, 32768}; + m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); rs = prev; @@ -844,12 +847,102 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De { if(pipe && pipe->IsGraphics() && !rs.views.empty()) { + D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC psoDesc; + pipe->Fill(psoDesc); + + bool dxil = + DXBC::DXBCContainer::CheckForDXIL(psoDesc.VS.pShaderBytecode, psoDesc.VS.BytecodeLength); + + ID3DBlob *red = m_pDevice->GetShaderCache()->MakeFixedColShader(D3D12ShaderCache::RED, dxil); + ID3DBlob *green = + m_pDevice->GetShaderCache()->MakeFixedColShader(D3D12ShaderCache::GREEN, dxil); + + psoDesc.DepthStencilState.DepthEnable = FALSE; + psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + psoDesc.DepthStencilState.StencilEnable = FALSE; + + psoDesc.BlendState.AlphaToCoverageEnable = FALSE; + psoDesc.BlendState.IndependentBlendEnable = FALSE; + psoDesc.BlendState.RenderTarget[0].BlendEnable = FALSE; + psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0xf; + psoDesc.BlendState.RenderTarget[0].LogicOpEnable = FALSE; + RDCEraseEl(psoDesc.RTVFormats.RTFormats); + psoDesc.RTVFormats.RTFormats[0] = DXGI_FORMAT_R16G16B16A16_FLOAT; + psoDesc.RTVFormats.NumRenderTargets = 1; + psoDesc.SampleMask = ~0U; + psoDesc.SampleDesc.Count = RDCMAX(1U, psoDesc.SampleDesc.Count); + psoDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; + + psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; + psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; + psoDesc.RasterizerState.FrontCounterClockwise = FALSE; + psoDesc.RasterizerState.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; + psoDesc.RasterizerState.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; + psoDesc.RasterizerState.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; + psoDesc.RasterizerState.DepthClipEnable = FALSE; + psoDesc.RasterizerState.MultisampleEnable = FALSE; + psoDesc.RasterizerState.AntialiasedLineEnable = FALSE; + + psoDesc.PS.pShaderBytecode = red->GetBufferPointer(); + psoDesc.PS.BytecodeLength = red->GetBufferSize(); + + ID3D12PipelineState *redPSO = NULL; + HRESULT hr = m_pDevice->CreatePipeState(psoDesc, &redPSO); + if(FAILED(hr)) + { + RDCERR("Failed to create overlay pso HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(red); + SAFE_RELEASE(redPSO); + SAFE_RELEASE(green); + return m_Overlay.resourceId; + } + + psoDesc.PS.pShaderBytecode = green->GetBufferPointer(); + psoDesc.PS.BytecodeLength = green->GetBufferSize(); + + ID3D12PipelineState *greenPSO = NULL; + hr = m_pDevice->CreatePipeState(psoDesc, &greenPSO); + if(FAILED(hr)) + { + RDCERR("Failed to create overlay pso HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(red); + SAFE_RELEASE(redPSO); + SAFE_RELEASE(green); + SAFE_RELEASE(greenPSO); + return m_Overlay.resourceId; + } + + list->Close(); + list = NULL; + + D3D12_RECT scissor = {0, 0, 16384, 16384}; + + D3D12RenderState prev = rs; + + rs.rts = {*GetWrapped(rtv)}; + + for(D3D12_RECT &s : rs.scissors) + s = scissor; + + rs.pipe = GetResID(redPSO); + m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); + + rs.scissors = prev.scissors; + + rs.pipe = GetResID(greenPSO); + m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); + + rs = prev; + + list = m_pDevice->GetNewList(); + + rs.ApplyState(m_pDevice, list); + list->OMSetRenderTargets(1, &rtv, TRUE, NULL); D3D12_VIEWPORT viewport = rs.views[0]; list->RSSetViewports(1, &viewport); - D3D12_RECT scissor = {0, 0, 16384, 16384}; list->RSSetScissorRects(1, &scissor); list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); @@ -866,7 +959,7 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De // set primary/secondary to the same to 'disable' checkerboard pixelData.PrimaryColor = pixelData.SecondaryColor = Vec4f(0.1f, 0.1f, 0.1f, 1.0f); - pixelData.InnerColor = Vec4f(0.2f, 0.2f, 0.9f, 0.7f); + pixelData.InnerColor = Vec4f(0.2f, 0.2f, 0.9f, 0.4f); // set viewport rect pixelData.RectPosition = Vec2f(viewport.TopLeftX, viewport.TopLeftY); @@ -905,6 +998,17 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De list->SetGraphicsRootConstantBufferView(0, scissorCB); list->DrawInstanced(3, 1, 0, 0); + + list->Close(); + list = NULL; + + m_pDevice->ExecuteLists(); + m_pDevice->FlushLists(); + + SAFE_RELEASE(red); + SAFE_RELEASE(redPSO); + SAFE_RELEASE(green); + SAFE_RELEASE(greenPSO); } } else if(overlay == DebugOverlay::TriangleSizeDraw || overlay == DebugOverlay::TriangleSizePass) @@ -937,8 +1041,6 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De list = NULL; m_pDevice->ReplayLog(0, events[0], eReplay_WithoutDraw); - - list = m_pDevice->GetNewList(); } pipe = m_pDevice->GetResourceManager()->GetCurrentAs(rs.pipe); @@ -996,40 +1098,40 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De vertexData.ModelViewProj = Matrix4f::Identity(); vertexData.SpriteSize = Vec2f(); - Vec4f viewport; - - if(!rs.views.empty()) - viewport = Vec4f(rs.views[0].Width, rs.views[0].Height); - - if(rs.dsv.GetResResourceId() != ResourceId()) - { - D3D12_CPU_DESCRIPTOR_HANDLE tmpdsv = GetDebugManager()->GetTempDescriptor(rs.dsv); - list->OMSetRenderTargets(1, &rtv, TRUE, &tmpdsv); - } - else - { - list->OMSetRenderTargets(1, &rtv, TRUE, NULL); - } - - if(!rs.views.empty()) - list->RSSetViewports(1, &rs.views[0]); - - D3D12_RECT scissor = {0, 0, 16384, 16384}; - list->RSSetScissorRects(1, &scissor); - - list->OMSetStencilRef(rs.stencilRef); - list->OMSetBlendFactor(rs.blendFactor); - - list->SetGraphicsRootSignature(GetDebugManager()->GetMeshRootSig()); - - list->SetGraphicsRootConstantBufferView( - 0, GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData))); - list->SetGraphicsRootConstantBufferView( - 1, GetDebugManager()->UploadConstants(&viewport, sizeof(viewport))); - list->SetGraphicsRoot32BitConstants(2, 4, &viewport.x, 0); + D3D12RenderState::SignatureElement vertexElem(eRootCBV, ResourceId(), 0); + WrappedID3D12Resource1::GetResIDFromAddr( + GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData)), vertexElem.id, + vertexElem.offset); for(size_t i = 0; i < events.size(); i++) { + D3D12RenderState prevState = rs; + + Vec4f viewport; + + if(!rs.views.empty()) + viewport = Vec4f(rs.views[0].Width, rs.views[0].Height); + + D3D12RenderState::SignatureElement viewportElem(eRootCBV, ResourceId(), 0); + WrappedID3D12Resource1::GetResIDFromAddr( + GetDebugManager()->UploadConstants(&viewport, sizeof(viewport)), viewportElem.id, + viewportElem.offset); + + D3D12RenderState::SignatureElement viewportConstElem(eRootConst, ResourceId(), 0); + viewportConstElem.SetConstants(4, &viewport, 0); + + rs.graphics.rootsig = GetResID(GetDebugManager()->GetMeshRootSig()); + rs.graphics.sigelems = { + vertexElem, viewportElem, viewportConstElem, + }; + + rs.rts = {*(D3D12Descriptor *)rtv.ptr}; + + if(list == NULL) + list = m_pDevice->GetNewList(); + + rs.ApplyState(m_pDevice, list); + const DrawcallDescription *draw = m_pDevice->GetDrawcall(events[i]); for(uint32_t inst = 0; draw && inst < RDCMAX(1U, draw->numInstances); inst++) @@ -1097,10 +1199,20 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De } } } - } - list->Close(); - list = NULL; + list->Close(); + list = NULL; + + rs = prevState; + + if(overlay == DebugOverlay::TriangleSizePass) + { + m_pDevice->ReplayLog(events[i], events[i], eReplay_OnlyDraw); + + if(i + 1 < events.size()) + m_pDevice->ReplayLog(events[i], events[i + 1], eReplay_WithoutDraw); + } + } m_pDevice->ExecuteLists(); m_pDevice->FlushLists(); @@ -1220,8 +1332,9 @@ ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FloatVector clearCol, De list->OMSetRenderTargets(1, &rtv, TRUE, NULL); - if(!rs.views.empty()) - list->RSSetViewports(1, &rs.views[0]); + D3D12_VIEWPORT view = {0.0f, 0.0f, (float)resourceDesc.Width, (float)resourceDesc.Height, + 0.0f, 1.0f}; + list->RSSetViewports(1, &view); D3D12_RECT scissor = {0, 0, 16384, 16384}; list->RSSetScissorRects(1, &scissor); diff --git a/renderdoc/driver/gl/gl_overlay.cpp b/renderdoc/driver/gl/gl_overlay.cpp index fadf486bc..34b015b4f 100644 --- a/renderdoc/driver/gl/gl_overlay.cpp +++ b/renderdoc/driver/gl/gl_overlay.cpp @@ -548,7 +548,6 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug // clear all mips first drv.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); drv.glDisable(eGL_BLEND); - drv.glDisable(eGL_SCISSOR_TEST); drv.glDepthMask(GL_FALSE); drv.glDisable(eGL_CULL_FACE); drv.glDisable(eGL_DEPTH_TEST); @@ -563,6 +562,8 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug drv.glBindFramebuffer(eGL_FRAMEBUFFER, DebugData.overlayFBO); + drv.glDisable(eGL_SCISSOR_TEST); + // clear the overlay texture to black { GLfloat black[4] = {}; @@ -597,7 +598,6 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug // the program's state. drv.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); drv.glDisable(eGL_BLEND); - drv.glDisable(eGL_SCISSOR_TEST); drv.glDepthMask(GL_FALSE); drv.glDisable(eGL_CULL_FACE); drv.glDisable(eGL_DEPTH_TEST); @@ -609,6 +609,24 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug drv.glEnable(eGL_DEPTH_CLAMP); } + if(HasExt[ARB_viewport_array]) + { + for(size_t s = 0; s < ARRAY_COUNT(rs.Scissors); s++) + { + if(rs.Scissors[s].enabled) + drv.glEnablei(eGL_SCISSOR_TEST, (GLuint)s); + else + drv.glDisablei(eGL_SCISSOR_TEST, (GLuint)s); + } + } + else + { + if(rs.Scissors[0].enabled) + drv.glEnable(eGL_SCISSOR_TEST); + else + drv.glDisable(eGL_SCISSOR_TEST); + } + if(overlay == DebugOverlay::NaN || overlay == DebugOverlay::Clipping) { // just need the basic texture @@ -617,6 +635,11 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug } else if(overlay == DebugOverlay::Drawcall) { + if(HasExt[ARB_viewport_array]) + drv.glDisablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisable(eGL_SCISSOR_TEST); + float black[] = {0.0f, 0.0f, 0.0f, 0.5f}; drv.glClearBufferfv(eGL_COLOR, 0, black); @@ -727,6 +750,41 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug float col[] = {0.0f, 0.0f, 0.0f, 0.0f}; drv.glClearBufferfv(eGL_COLOR, 0, col); + if(HasExt[ARB_viewport_array]) + drv.glDisablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisable(eGL_SCISSOR_TEST); + + col[0] = 1.0f; + col[1] = 0.0f; + col[3] = 1.0f; + + drv.glProgramUniform4fv(DebugData.overlayProg, overlayFixedColLocation, 1, col); + + ReplayLog(eventId, eReplay_OnlyDraw); + + if(HasExt[ARB_viewport_array]) + { + if(rs.Scissors[0].enabled) + drv.glEnablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisablei(eGL_SCISSOR_TEST, 0); + } + else + { + if(rs.Scissors[0].enabled) + drv.glEnable(eGL_SCISSOR_TEST); + else + drv.glDisable(eGL_SCISSOR_TEST); + } + + col[0] = 0.0f; + col[1] = 1.0f; + + drv.glProgramUniform4fv(DebugData.overlayProg, overlayFixedColLocation, 1, col); + + ReplayLog(eventId, eReplay_OnlyDraw); + // don't need to use the existing program at all! drv.glUseProgram(DebugData.checkerProg); drv.glBindProgramPipeline(0); @@ -775,7 +833,7 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug // set primary/secondary to the same to 'disable' checkerboard cdata->PrimaryColor = cdata->SecondaryColor = Vec4f(0.1f, 0.1f, 0.1f, 1.0f); - cdata->InnerColor = Vec4f(0.2f, 0.2f, 0.9f, 0.7f); + cdata->InnerColor = Vec4f(0.2f, 0.2f, 0.9f, 0.4f); // set viewport rect cdata->RectPosition = Vec2f(rs.Viewports[0].x, rs.Viewports[0].y); @@ -820,9 +878,29 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug } else if(overlay == DebugOverlay::Depth || overlay == DebugOverlay::Stencil) { + if(HasExt[ARB_viewport_array]) + drv.glDisablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisable(eGL_SCISSOR_TEST); + float backCol[] = {0.0f, 1.0f, 0.0f, 0.0f}; drv.glClearBufferfv(eGL_COLOR, 0, backCol); + if(HasExt[ARB_viewport_array]) + { + if(rs.Scissors[0].enabled) + drv.glEnablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisablei(eGL_SCISSOR_TEST, 0); + } + else + { + if(rs.Scissors[0].enabled) + drv.glEnable(eGL_SCISSOR_TEST); + else + drv.glDisable(eGL_SCISSOR_TEST); + } + float red[] = {1.0f, 0.0f, 0.0f, 1.0f}; drv.glProgramUniform4fv(DebugData.overlayProg, overlayFixedColLocation, 1, red); @@ -1091,9 +1169,29 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug } else if(overlay == DebugOverlay::BackfaceCull) { + if(HasExt[ARB_viewport_array]) + drv.glDisablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisable(eGL_SCISSOR_TEST); + float col[] = {0.0f, 1.0f, 0.0f, 0.0f}; drv.glClearBufferfv(eGL_COLOR, 0, col); + if(HasExt[ARB_viewport_array]) + { + if(rs.Scissors[0].enabled) + drv.glEnablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisablei(eGL_SCISSOR_TEST, 0); + } + else + { + if(rs.Scissors[0].enabled) + drv.glEnable(eGL_SCISSOR_TEST); + else + drv.glDisable(eGL_SCISSOR_TEST); + } + col[0] = 1.0f; col[1] = 0.0f; col[3] = 1.0f; @@ -1116,9 +1214,32 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug } else if(overlay == DebugOverlay::ClearBeforeDraw || overlay == DebugOverlay::ClearBeforePass) { + if(HasExt[ARB_viewport_array]) + drv.glDisablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisable(eGL_SCISSOR_TEST); + float col[] = {0.0f, 0.0f, 0.0f, 0.0f}; drv.glClearBufferfv(eGL_COLOR, 0, col); + if(HasExt[ARB_viewport_array]) + { + for(size_t s = 0; s < ARRAY_COUNT(rs.Scissors); s++) + { + if(rs.Scissors[s].enabled) + drv.glEnablei(eGL_SCISSOR_TEST, (GLuint)s); + else + drv.glDisablei(eGL_SCISSOR_TEST, (GLuint)s); + } + } + else + { + if(rs.Scissors[0].enabled) + drv.glEnable(eGL_SCISSOR_TEST); + else + drv.glDisable(eGL_SCISSOR_TEST); + } + rdcarray events = passEvents; if(overlay == DebugOverlay::ClearBeforeDraw) @@ -1138,9 +1259,32 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug rs.ApplyState(&drv); } + GLboolean scissor = HasExt[ARB_viewport_array] ? GL.glIsEnabledi(eGL_SCISSOR_TEST, 0) + : GL.glIsEnabled(eGL_SCISSOR_TEST); + + if(HasExt[ARB_viewport_array]) + drv.glDisablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisable(eGL_SCISSOR_TEST); + for(int i = 0; i < 8; i++) drv.glClearBufferfv(eGL_COLOR, i, &clearCol.x); + if(HasExt[ARB_viewport_array]) + { + if(scissor == GL_TRUE) + drv.glEnablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisablei(eGL_SCISSOR_TEST, 0); + } + else + { + if(scissor == GL_TRUE) + drv.glEnable(eGL_SCISSOR_TEST); + else + drv.glDisable(eGL_SCISSOR_TEST); + } + // Try to clear depth as well, to help debug shadow rendering if(IsDepthStencilFormat(texDetails.internalFormat)) { @@ -1172,9 +1316,32 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug { SCOPED_TIMER("Triangle Size"); + if(HasExt[ARB_viewport_array]) + drv.glDisablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisable(eGL_SCISSOR_TEST); + float black[] = {0.0f, 0.0f, 0.0f, 0.0f}; drv.glClearBufferfv(eGL_COLOR, 0, black); + if(HasExt[ARB_viewport_array]) + { + for(size_t s = 0; s < ARRAY_COUNT(rs.Scissors); s++) + { + if(rs.Scissors[s].enabled) + drv.glEnablei(eGL_SCISSOR_TEST, (GLuint)s); + else + drv.glDisablei(eGL_SCISSOR_TEST, (GLuint)s); + } + } + else + { + if(rs.Scissors[0].enabled) + drv.glEnable(eGL_SCISSOR_TEST); + else + drv.glDisable(eGL_SCISSOR_TEST); + } + MeshUBOData uboParams = {}; uboParams.homogenousInput = 1; uboParams.invProj = Matrix4f::Identity(); @@ -1568,6 +1735,11 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug { SCOPED_TIMER("Quad Overdraw"); + if(HasExt[ARB_viewport_array]) + drv.glDisablei(eGL_SCISSOR_TEST, 0); + else + drv.glDisable(eGL_SCISSOR_TEST); + float black[] = {0.0f, 0.0f, 0.0f, 0.0f}; drv.glClearBufferfv(eGL_COLOR, 0, black); diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index efd2dddd3..8f3b59184 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -935,14 +935,17 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D att->colorWriteMask = 0xf; } - // set scissors to max - for(size_t i = 0; i < pipeCreateInfo.pViewportState->scissorCount; i++) + // set scissors to max for drawcall + if(overlay == DebugOverlay::Drawcall) { - VkRect2D &sc = (VkRect2D &)pipeCreateInfo.pViewportState->pScissors[i]; - sc.offset.x = 0; - sc.offset.y = 0; - sc.extent.width = 16384; - sc.extent.height = 16384; + for(size_t i = 0; i < pipeCreateInfo.pViewportState->scissorCount; i++) + { + VkRect2D &sc = (VkRect2D &)pipeCreateInfo.pViewportState->pScissors[i]; + sc.offset.x = 0; + sc.offset.y = 0; + sc.extent.width = 16384; + sc.extent.height = 16384; + } } // set our renderpass and shader @@ -992,12 +995,15 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D m_pDriver->m_RenderState.graphics.pipeline = GetResID(pipe); // set dynamic scissors in case pipeline was using them - for(size_t i = 0; i < m_pDriver->m_RenderState.scissors.size(); i++) + if(overlay == DebugOverlay::Drawcall) { - m_pDriver->m_RenderState.scissors[i].offset.x = 0; - m_pDriver->m_RenderState.scissors[i].offset.x = 0; - m_pDriver->m_RenderState.scissors[i].extent.width = 16384; - m_pDriver->m_RenderState.scissors[i].extent.height = 16384; + for(size_t i = 0; i < m_pDriver->m_RenderState.scissors.size(); i++) + { + m_pDriver->m_RenderState.scissors[i].offset.x = 0; + m_pDriver->m_RenderState.scissors[i].offset.y = 0; + m_pDriver->m_RenderState.scissors[i].extent.width = 16384; + m_pDriver->m_RenderState.scissors[i].extent.height = 16384; + } } if(overlay == DebugOverlay::Wireframe) @@ -1051,7 +1057,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D { // clear the whole image to opaque black. We'll overwite the render area with transparent black // before rendering the viewport/scissors - float black[] = {0.0f, 0.0f, 0.0f, 1.0f}; + float black[] = {0.0f, 0.0f, 0.0f, 0.0f}; VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, NULL, @@ -1077,6 +1083,138 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D black[3] = 0.0f; + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + float highlightCol[] = {1.0f, 0.0f, 0.0f, 1.0f}; + + // backup state + VulkanRenderState prevstate = m_pDriver->m_RenderState; + + // make patched shader + VkShaderModule mod[2] = {0}; + VkPipeline pipe[2] = {0}; + + // first shader, no culling, writes red + GetDebugManager()->PatchFixedColShader(mod[0], highlightCol); + + highlightCol[0] = 0.0f; + highlightCol[1] = 1.0f; + + // second shader, normal culling, writes green + GetDebugManager()->PatchFixedColShader(mod[1], highlightCol); + + // make patched pipeline + VkGraphicsPipelineCreateInfo pipeCreateInfo; + + m_pDriver->GetShaderCache()->MakeGraphicsPipelineInfo(pipeCreateInfo, + prevstate.graphics.pipeline); + + // disable all tests possible + VkPipelineDepthStencilStateCreateInfo *ds = + (VkPipelineDepthStencilStateCreateInfo *)pipeCreateInfo.pDepthStencilState; + ds->depthTestEnable = false; + ds->depthWriteEnable = false; + ds->stencilTestEnable = false; + ds->depthBoundsTestEnable = false; + + VkPipelineRasterizationStateCreateInfo *rs = + (VkPipelineRasterizationStateCreateInfo *)pipeCreateInfo.pRasterizationState; + rs->cullMode = VK_CULL_MODE_NONE; // first render without any culling + rs->rasterizerDiscardEnable = false; + + if(m_pDriver->GetDeviceEnabledFeatures().depthClamp) + rs->depthClampEnable = true; + + VkPipelineColorBlendStateCreateInfo *cb = + (VkPipelineColorBlendStateCreateInfo *)pipeCreateInfo.pColorBlendState; + cb->logicOpEnable = false; + cb->attachmentCount = 1; // only one colour attachment + for(uint32_t i = 0; i < cb->attachmentCount; i++) + { + VkPipelineColorBlendAttachmentState *att = + (VkPipelineColorBlendAttachmentState *)&cb->pAttachments[i]; + att->blendEnable = false; + att->colorWriteMask = 0xf; + } + + // set our renderpass and shader + pipeCreateInfo.renderPass = m_Overlay.NoDepthRP; + pipeCreateInfo.subpass = 0; + + VkPipelineShaderStageCreateInfo *fragShader = NULL; + + for(uint32_t i = 0; i < pipeCreateInfo.stageCount; i++) + { + VkPipelineShaderStageCreateInfo &sh = + (VkPipelineShaderStageCreateInfo &)pipeCreateInfo.pStages[i]; + if(sh.stage == VK_SHADER_STAGE_FRAGMENT_BIT) + { + sh.module = mod[0]; + sh.pName = "main"; + fragShader = &sh; + break; + } + } + + if(fragShader == NULL) + { + // we know this is safe because it's pointing to a static array that's + // big enough for all shaders + + VkPipelineShaderStageCreateInfo &sh = + (VkPipelineShaderStageCreateInfo &)pipeCreateInfo.pStages[pipeCreateInfo.stageCount++]; + sh.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + sh.pNext = NULL; + sh.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + sh.module = mod[0]; + sh.pName = "main"; + sh.pSpecializationInfo = NULL; + + fragShader = &sh; + } + + vkr = m_pDriver->vkCreateGraphicsPipelines(m_Device, VK_NULL_HANDLE, 1, &pipeCreateInfo, NULL, + &pipe[0]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + fragShader->module = mod[1]; + + vkr = m_pDriver->vkCreateGraphicsPipelines(m_Device, VK_NULL_HANDLE, 1, &pipeCreateInfo, NULL, + &pipe[1]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + // modify state + m_pDriver->m_RenderState.renderPass = GetResID(m_Overlay.NoDepthRP); + m_pDriver->m_RenderState.subpass = 0; + m_pDriver->m_RenderState.SetFramebuffer(m_pDriver, GetResID(m_Overlay.NoDepthFB)); + + m_pDriver->m_RenderState.graphics.pipeline = GetResID(pipe[0]); + m_pDriver->m_RenderState.scissors = prevstate.scissors; + + for(VkRect2D &sc : m_pDriver->m_RenderState.scissors) + { + sc.offset.x = 0; + sc.offset.y = 0; + sc.extent.width = 16384; + sc.extent.height = 16384; + } + + m_pDriver->ReplayLog(0, eventId, eReplay_OnlyDraw); + + m_pDriver->m_RenderState.graphics.pipeline = GetResID(pipe[1]); + m_pDriver->m_RenderState.scissors = prevstate.scissors; + + m_pDriver->ReplayLog(0, eventId, eReplay_OnlyDraw); + + // restore state + m_pDriver->m_RenderState = prevstate; + + cmd = m_pDriver->GetNextCmd(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + { VkClearValue clearval = {}; VkRenderPassBeginInfo rpbegin = { @@ -1090,23 +1228,6 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D }; vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); - VkClearRect rect = { - { - { - m_pDriver->m_RenderState.renderArea.offset.x, - m_pDriver->m_RenderState.renderArea.offset.y, - }, - { - m_pDriver->m_RenderState.renderArea.extent.width, - m_pDriver->m_RenderState.renderArea.extent.height, - }, - }, - 0, - 1, - }; - VkClearAttachment blackclear = {VK_IMAGE_ASPECT_COLOR_BIT, 0, {}}; - vt->CmdClearAttachments(Unwrap(cmd), 1, &blackclear, 1, &rect); - VkViewport viewport = m_pDriver->m_RenderState.views[0]; vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); @@ -1119,7 +1240,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D // set primary/secondary to the same to 'disable' checkerboard ubo->PrimaryColor = ubo->SecondaryColor = Vec4f(0.1f, 0.1f, 0.1f, 1.0f); - ubo->InnerColor = Vec4f(0.2f, 0.2f, 0.9f, 0.7f); + ubo->InnerColor = Vec4f(0.2f, 0.2f, 0.9f, 0.4f); // set viewport rect ubo->RectPosition = Vec2f(viewport.x, viewport.y); @@ -1185,6 +1306,24 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D vt->CmdEndRenderPass(Unwrap(cmd)); } + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + // submit & flush so that we don't have to keep pipeline around for a while + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + + cmd = m_pDriver->GetNextCmd(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + for(int i = 0; i < 2; i++) + { + m_pDriver->vkDestroyPipeline(m_Device, pipe[i], NULL); + m_pDriver->vkDestroyShaderModule(m_Device, mod[i], NULL); + } } else if(overlay == DebugOverlay::BackfaceCull) { @@ -1267,16 +1406,6 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D att->colorWriteMask = 0xf; } - // set scissors to max - for(size_t i = 0; i < pipeCreateInfo.pViewportState->scissorCount; i++) - { - VkRect2D &sc = (VkRect2D &)pipeCreateInfo.pViewportState->pScissors[i]; - sc.offset.x = 0; - sc.offset.y = 0; - sc.extent.width = 16384; - sc.extent.height = 16384; - } - // set our renderpass and shader pipeCreateInfo.renderPass = m_Overlay.NoDepthRP; pipeCreateInfo.subpass = 0; @@ -1334,15 +1463,6 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D m_pDriver->m_RenderState.graphics.pipeline = GetResID(pipe[0]); - // set dynamic scissors in case pipeline was using them - for(size_t i = 0; i < m_pDriver->m_RenderState.scissors.size(); i++) - { - m_pDriver->m_RenderState.scissors[i].offset.x = 0; - m_pDriver->m_RenderState.scissors[i].offset.x = 0; - m_pDriver->m_RenderState.scissors[i].extent.width = 16384; - m_pDriver->m_RenderState.scissors[i].extent.height = 16384; - } - m_pDriver->ReplayLog(0, eventId, eReplay_OnlyDraw); m_pDriver->m_RenderState.graphics.pipeline = GetResID(pipe[1]); @@ -1544,16 +1664,6 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D att->colorWriteMask = 0xf; } - // set scissors to max - for(size_t i = 0; i < pipeCreateInfo.pViewportState->scissorCount; i++) - { - VkRect2D &sc = (VkRect2D &)pipeCreateInfo.pViewportState->pScissors[i]; - sc.offset.x = 0; - sc.offset.y = 0; - sc.extent.width = 16384; - sc.extent.height = 16384; - } - // subpass 0 in either render pass pipeCreateInfo.subpass = 0; @@ -1631,15 +1741,6 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D m_pDriver->m_RenderState.graphics.pipeline = GetResID(failpipe); - // set dynamic scissors in case pipeline was using them - for(size_t i = 0; i < m_pDriver->m_RenderState.scissors.size(); i++) - { - m_pDriver->m_RenderState.scissors[i].offset.x = 0; - m_pDriver->m_RenderState.scissors[i].offset.x = 0; - m_pDriver->m_RenderState.scissors[i].extent.width = 16384; - m_pDriver->m_RenderState.scissors[i].extent.height = 16384; - } - vkr = vt->EndCommandBuffer(Unwrap(cmd)); RDCASSERTEQUAL(vkr, VK_SUCCESS); @@ -2372,33 +2473,25 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D std::map pipes; - cmd = m_pDriver->GetNextCmd(); - - vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - VkClearValue clearval = {}; - VkRenderPassBeginInfo rpbegin = { - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - NULL, - Unwrap(RP), - Unwrap(FB), - {{0, 0}, m_Overlay.ImageDim}, - 1, - &clearval, - }; - vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); - - VkViewport viewport = {0.0f, - 0.0f, - (float)RDCMAX(1U, m_Overlay.ImageDim.width >> sub.mip), - (float)RDCMAX(1U, m_Overlay.ImageDim.height >> sub.mip), - 0.0f, - 1.0f}; - vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); - for(size_t i = 0; i < events.size(); i++) { + cmd = m_pDriver->GetNextCmd(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkClearValue clearval = {}; + VkRenderPassBeginInfo rpbegin = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + NULL, + Unwrap(RP), + Unwrap(FB), + {{0, 0}, m_Overlay.ImageDim}, + 1, + &clearval, + }; + vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); + const DrawcallDescription *draw = m_pDriver->GetDrawcall(events[i]); for(uint32_t inst = 0; draw && inst < RDCMAX(1U, draw->numInstances); inst++) @@ -2567,13 +2660,21 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D } } } + + vt->CmdEndRenderPass(Unwrap(cmd)); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + if(overlay == DebugOverlay::TriangleSizePass) + { + m_pDriver->ReplayLog(events[i], events[i], eReplay_OnlyDraw); + + if(i + 1 < events.size()) + m_pDriver->ReplayLog(events[i], events[i + 1], eReplay_WithoutDraw); + } } - vt->CmdEndRenderPass(Unwrap(cmd)); - - vkr = vt->EndCommandBuffer(Unwrap(cmd)); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - m_pDriver->SubmitCmds(); m_pDriver->FlushQ(); diff --git a/util/test/demos/d3d11/d3d11_overlay_test.cpp b/util/test/demos/d3d11/d3d11_overlay_test.cpp index e3fe28b6a..f35643962 100644 --- a/util/test/demos/d3d11/d3d11_overlay_test.cpp +++ b/util/test/demos/d3d11/d3d11_overlay_test.cpp @@ -110,6 +110,12 @@ float4 main() : SV_Target0 {Vec3f(0.0f, 0.7f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)}, {Vec3f(0.0f, 0.725f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)}, {Vec3f(0.025f, 0.7f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + // this triangle deliberately goes out of the viewport, it will test viewport & scissor + // clipping + {Vec3f(-1.3f, -1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.0f, 1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(1.3f, -1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(1.0f, 0.0f)}, }; ID3D11BufferPtr vb = MakeBuffer().Vertex().Data(VBData); @@ -188,6 +194,11 @@ float4 main() : SV_Target0 depth.DepthFunc = D3D11_COMPARISON_ALWAYS; SetDepthState(depth); + setMarker("Viewport Test"); + RSSetViewport({10.0f, 10.0f, 80.0f, 80.0f, 0.0f, 1.0f}); + RSSetScissor({24, 24, 76, 76}); + ctx->Draw(3, 33); + ctx->PSSetShader(whiteps, NULL, 0); RSSetViewport({5.0f, 5.0f, float(screenWidth) / 4.0f - 10.0f, diff --git a/util/test/demos/d3d12/d3d12_overlay_test.cpp b/util/test/demos/d3d12/d3d12_overlay_test.cpp index e69db1cf9..469ba40b8 100644 --- a/util/test/demos/d3d12/d3d12_overlay_test.cpp +++ b/util/test/demos/d3d12/d3d12_overlay_test.cpp @@ -105,6 +105,12 @@ float4 main() : SV_Target0 {Vec3f(0.0f, 0.7f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)}, {Vec3f(0.0f, 0.725f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)}, {Vec3f(0.025f, 0.7f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + // this triangle deliberately goes out of the viewport, it will test viewport & scissor + // clipping + {Vec3f(-1.3f, -1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.0f, 1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(1.3f, -1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(1.0f, 0.0f)}, }; ID3D12ResourcePtr vb = MakeBuffer().Data(VBData); @@ -204,6 +210,13 @@ float4 main() : SV_Target0 cmd->SetPipelineState(pipe); cmd->DrawInstanced(24, 1, 9, 0); + setMarker(cmd, "Viewport Test"); + + RSSetViewport(cmd, {10.0f, 10.0f, 80.0f, 80.0f, 0.0f, 1.0f}); + RSSetScissorRect(cmd, {24, 24, 76, 76}); + cmd->SetPipelineState(backgroundPipe); + cmd->DrawInstanced(3, 1, 33, 0); + D3D12_CPU_DESCRIPTOR_HANDLE subrtv = MakeRTV(subtex) .Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) .FirstSlice(2) diff --git a/util/test/demos/gl/gl_overlay_test.cpp b/util/test/demos/gl/gl_overlay_test.cpp index 197069ae4..33df6213c 100644 --- a/util/test/demos/gl/gl_overlay_test.cpp +++ b/util/test/demos/gl/gl_overlay_test.cpp @@ -153,6 +153,12 @@ void main() {Vec3f(0.0f, 0.7f, 0.0f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)}, {Vec3f(0.0f, 0.725f, 0.0f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)}, {Vec3f(0.025f, 0.7f, 0.0f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + // this triangle deliberately goes out of the viewport, it will test viewport & scissor + // clipping + {Vec3f(-1.3f, -1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.0f, 1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(1.3f, -1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(1.0f, 0.0f)}, }; GLuint vb = MakeBuffer(); @@ -256,6 +262,14 @@ void main() glStencilFunc(GL_GREATER, 0x55, 0xff); glDrawArrays(GL_TRIANGLES, 9, 24); + setMarker("Viewport Test"); + glDisable(GL_STENCIL_TEST); + glViewport(10, screenHeight - 90, 80, 80); + glScissor(24, screenHeight - 76, 52, 52); + glDrawArrays(GL_TRIANGLES, 33, 3); + + glScissor(0, 0, screenWidth, screenHeight); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, diff --git a/util/test/demos/vk/vk_overlay_test.cpp b/util/test/demos/vk/vk_overlay_test.cpp index 6e53dc8a1..4f1812400 100644 --- a/util/test/demos/vk/vk_overlay_test.cpp +++ b/util/test/demos/vk/vk_overlay_test.cpp @@ -157,6 +157,12 @@ void main() {Vec3f(0.0f, -0.7f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)}, {Vec3f(0.0f, -0.725f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)}, {Vec3f(0.025f, -0.7f, 0.5f), Vec4f(1.0f, 0.5f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + // this triangle deliberately goes out of the viewport, it will test viewport & scissor + // clipping + {Vec3f(-1.3f, 1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.0f, -1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(1.3f, 1.3f, 0.95f), Vec4f(0.1f, 0.1f, 0.5f, 1.0f), Vec2f(1.0f, 0.0f)}, }; // negate y if we're using negative viewport height @@ -336,6 +342,19 @@ void main() vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); vkCmdDraw(cmd, 24, 1, 9, 0); + setMarker(cmd, "Viewport Test"); + v = {10.0f, 10.0f, 80.0f, 80.0f, 0.0f, 1.0f}; + if(KHR_maintenance1) + { + v.y += v.height; + v.height = -v.height; + } + VkRect2D s = {{24, 24}, {52, 52}}; + vkCmdSetViewport(cmd, 0, 1, &v); + vkCmdSetScissor(cmd, 0, 1, &s); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, backgroundPipe); + vkCmdDraw(cmd, 3, 1, 33, 0); + vkCmdEndRenderPass(cmd); v = mainWindow->viewport; @@ -352,7 +371,7 @@ void main() v.height = -v.height; } - VkRect2D s = mainWindow->scissor; + s = mainWindow->scissor; s.extent.width /= 4; s.extent.height /= 4; diff --git a/util/test/rdtest/shared/Overlay_Test.py b/util/test/rdtest/shared/Overlay_Test.py index de5e4df72..68c01e85f 100644 --- a/util/test/rdtest/shared/Overlay_Test.py +++ b/util/test/rdtest/shared/Overlay_Test.py @@ -224,10 +224,14 @@ class Overlay_Test(rdtest.TestCase): self.check_pixel_value(overlay_id, 200, 93, [0.0, 1.0, 0.0, 1.0], eps=eps) elif overlay == rd.DebugOverlay.ViewportScissor: # Inside viewport - self.check_pixel_value(overlay_id, 50, 50, [0.2*0.7, 0.2*0.7, 0.9*0.7, 0.7*0.7], eps=eps) - self.check_pixel_value(overlay_id, 350, 50, [0.2*0.7, 0.2*0.7, 0.9*0.7, 0.7*0.7], eps=eps) - self.check_pixel_value(overlay_id, 50, 250, [0.2*0.7, 0.2*0.7, 0.9*0.7, 0.7*0.7], eps=eps) - self.check_pixel_value(overlay_id, 350, 250, [0.2*0.7, 0.2*0.7, 0.9*0.7, 0.7*0.7], eps=eps) + self.check_pixel_value(overlay_id, 50, 50, [0.2 * 0.4, 0.2 * 0.4, 0.9 * 0.4, 0.4 * 0.4], eps=eps) + self.check_pixel_value(overlay_id, 350, 50, [0.2 * 0.4, 0.2 * 0.4, 0.9 * 0.4, 0.4 * 0.4], eps=eps) + self.check_pixel_value(overlay_id, 50, 250, [0.2 * 0.4, 0.2 * 0.4, 0.9 * 0.4, 0.4 * 0.4], eps=eps) + self.check_pixel_value(overlay_id, 350, 250, [0.2 * 0.4, 0.2 * 0.4, 0.9 * 0.4, 0.4 * 0.4], eps=eps) + + # Passing triangle inside the viewport + self.check_pixel_value(overlay_id, 200, 150, + [0.2 * 0.4, 1.0 * 0.6 + 0.2 * 0.4, 0.9 * 0.4, 1.0 * 0.6 + 0.4 * 0.4], eps=eps) # Viewport border self.check_pixel_value(overlay_id, 12, 12, [0.1, 0.1, 0.1, 1.0], eps=eps) @@ -364,7 +368,116 @@ class Overlay_Test(rdtest.TestCase): rdtest.log.success("All normal overlays are as expected") + # Check the viewport overlay especially + view_marker: rd.DrawcallDescription = self.find_draw("Viewport Test") + + self.controller.SetFrameEvent(view_marker.next.eventId, True) + + for overlay in rd.DebugOverlay: + if overlay == rd.DebugOverlay.NoOverlay: + continue + + # These overlays are just displaymodes really, not actually separate overlays + if overlay == rd.DebugOverlay.NaN or overlay == rd.DebugOverlay.Clipping: + continue + + # We'll test the clear-before-X overlays seperately, for both colour and depth + if overlay == rd.DebugOverlay.ClearBeforeDraw or overlay == rd.DebugOverlay.ClearBeforePass: + continue + + rdtest.log.print("Checking overlay {} in viewport draw".format(str(overlay))) + + tex.overlay = overlay + out.SetTextureDisplay(tex) + + out.Display() + + eps = 1.0 / 256.0 + + overlay_id: rd.ResourceId = out.GetDebugOverlayTexID() + + if overlay == rd.DebugOverlay.Drawcall: + # The drawcall overlay will show up outside the scissor region + self.check_pixel_value(overlay_id, 50, 85, [0.8, 0.1, 0.8, 1.0], eps=eps) + self.check_pixel_value(overlay_id, 50, 50, [0.8, 0.1, 0.8, 1.0], eps=eps) + self.check_pixel_value(overlay_id, 50, 10, [0.8, 0.1, 0.8, 1.0], eps=eps) + self.check_pixel_value(overlay_id, 85, 85, [0.8, 0.1, 0.8, 1.0], eps=eps) + + self.check_pixel_value(overlay_id, 50, 5, [0.0, 0.0, 0.0, 0.5], eps=eps) + self.check_pixel_value(overlay_id, 95, 85, [0.0, 0.0, 0.0, 0.5], eps=eps) + self.check_pixel_value(overlay_id, 80, 30, [0.0, 0.0, 0.0, 0.5], eps=eps) + elif overlay == rd.DebugOverlay.Wireframe: + # Wireframe we only test a limited set to avoid hitting implementation variations of line raster + # We also have to fudge a little because the lines might land on adjacent pixels + + found = False + + for delta in range(0, 5): + try: + self.check_pixel_value(overlay_id, 30 + delta, 32, [200.0 / 255.0, 1.0, 0.0, 1.0], eps=eps) + found = True + break + except rdtest.TestFailureException: + pass + + if not found: + raise rdtest.TestFailureException("Couldn't find wireframe within scissor") + + found = False + + for delta in range(0, 5): + try: + self.check_pixel_value(overlay_id, 34 + delta, 22, [200.0 / 255.0, 1.0, 0.0, 1.0], eps=eps) + found = True + break + except rdtest.TestFailureException: + pass + + if found: + raise rdtest.TestFailureException("Found wireframe outside of scissor") + elif overlay == rd.DebugOverlay.Depth or overlay == rd.DebugOverlay.Stencil or overlay == rd.DebugOverlay.BackfaceCull: + self.check_pixel_value(overlay_id, 50, 25, [0.0, 1.0, 0.0, 1.0], eps=eps) + self.check_pixel_value(overlay_id, 50, 75, [0.0, 1.0, 0.0, 1.0], eps=eps) + + self.check_pixel_value(overlay_id, 50, 20, [0.0, 1.0, 0.0, 0.0], eps=eps) + self.check_pixel_value(overlay_id, 50, 80, [0.0, 1.0, 0.0, 0.0], eps=eps) + elif overlay == rd.DebugOverlay.ViewportScissor: + # Inside viewport and scissor, passing triangle + self.check_pixel_value(overlay_id, 50, 50, + [0.2 * 0.4, 1.0 * 0.6 + 0.2 * 0.4, 0.9 * 0.4, 1.0 * 0.6 + 0.4 * 0.4], eps=eps) + + # Inside viewport and outside scissor + self.check_pixel_value(overlay_id, 50, 80, + [1.0 * 0.6 + 0.2 * 0.4, 0.2 * 0.4, 0.9 * 0.4, 1.0 * 0.6 + 0.4 * 0.4], eps=eps) + elif overlay == rd.DebugOverlay.QuadOverdrawDraw: + self.check_pixel_value(overlay_id, 50, 50, [1.0, 1.0, 1.0, 1.0], eps=eps) + self.check_pixel_value(overlay_id, 50, 15, [0.0, 0.0, 0.0, 0.0], eps=eps) + elif overlay == rd.DebugOverlay.QuadOverdrawPass: + self.check_pixel_value(overlay_id, 50, 50, [1.0, 1.0, 1.0, 1.0], eps=eps) + self.check_pixel_value(overlay_id, 50, 15, [0.0, 0.0, 0.0, 0.0], eps=eps) + + self.check_pixel_value(overlay_id, 200, 270, [1.0, 1.0, 1.0, 1.0], eps=eps) + self.check_pixel_value(overlay_id, 200, 280, [0.0, 0.0, 0.0, 0.0], eps=eps) + elif overlay == rd.DebugOverlay.TriangleSizeDraw: + eps = 1.0 + + self.check_pixel_value(overlay_id, 50, 50, [5408.0, 5408.0, 5408.0, 1.0], eps=eps) + self.check_pixel_value(overlay_id, 50, 15, [0.0, 0.0, 0.0, 0.0], eps=eps) + elif overlay == rd.DebugOverlay.TriangleSizePass: + eps = 1.0 + + self.check_pixel_value(overlay_id, 50, 50, [5408.0, 5408.0, 5408.0, 1.0], eps=eps) + self.check_pixel_value(overlay_id, 50, 15, [0.0, 0.0, 0.0, 0.0], eps=eps) + + self.check_pixel_value(overlay_id, 200, 270, [43072.0, 43072.0, 43072.0, 1.0], eps=eps) + self.check_pixel_value(overlay_id, 200, 280, [0.0, 0.0, 0.0, 0.0], eps=eps) + + rdtest.log.success("Picked pixels are as expected for {}".format(str(overlay))) + + rdtest.log.success("Overlays are as expected around viewport/scissor behaviour") + # Now check clear-before-X by hand, for colour and for depth + self.controller.SetFrameEvent(test_marker.next.eventId, True) depth_tex: rd.ResourceId = pipe.GetDepthTarget().resourceId @@ -535,14 +648,18 @@ class Overlay_Test(rdtest.TestCase): self.check_pixel_value(overlay_id, 70 >> shift, 34 >> shift, [1.0, 0.0, 0.0, 1.0], sub=sub) self.check_pixel_value(overlay_id, 70 >> shift, 20 >> shift, [0.0, 1.0, 0.0, 0.0], sub=sub) elif overlay == rd.DebugOverlay.ViewportScissor: + self.check_pixel_value(overlay_id, 20 >> shift, 15 >> shift, + [0.2 * 0.4, 0.2 * 0.4, 0.9 * 0.4, 0.4 * 0.4], sub=sub, eps=eps) + self.check_pixel_value(overlay_id, 80 >> shift, 15 >> shift, + [0.2 * 0.4, 0.2 * 0.4, 0.9 * 0.4, 0.4 * 0.4], sub=sub, eps=eps) + self.check_pixel_value(overlay_id, 20 >> shift, 60 >> shift, + [0.2 * 0.4, 0.2 * 0.4, 0.9 * 0.4, 0.4 * 0.4], sub=sub, eps=eps) + self.check_pixel_value(overlay_id, 80 >> shift, 60 >> shift, + [0.2 * 0.4, 0.2 * 0.4, 0.9 * 0.4, 0.4 * 0.4], sub=sub, eps=eps) + self.check_pixel_value(overlay_id, 50 >> shift, 36 >> shift, - [0.2 * 0.7, 0.2 * 0.7, 0.9 * 0.7, 0.7 * 0.7], sub=sub, eps=eps) - self.check_pixel_value(overlay_id, 30 >> shift, 36 >> shift, - [0.2 * 0.7, 0.2 * 0.7, 0.9 * 0.7, 0.7 * 0.7], sub=sub, eps=eps) - self.check_pixel_value(overlay_id, 70 >> shift, 34 >> shift, - [0.2 * 0.7, 0.2 * 0.7, 0.9 * 0.7, 0.7 * 0.7], sub=sub, eps=eps) - self.check_pixel_value(overlay_id, 70 >> shift, 20 >> shift, - [0.2 * 0.7, 0.2 * 0.7, 0.9 * 0.7, 0.7 * 0.7], sub=sub, eps=eps) + [0.2 * 0.4, 1.0 * 0.6 + 0.2 * 0.4, 0.9 * 0.4, 1.0 * 0.6 + 0.4 * 0.4], + sub=sub, eps=eps) if mip == 2: self.check_pixel_value(overlay_id, 6, 6, [0.1, 0.1, 0.1, 1.0], sub=sub, eps=eps) diff --git a/util/test/rdtest/testcase.py b/util/test/rdtest/testcase.py index 4c53df320..34423d21b 100644 --- a/util/test/rdtest/testcase.py +++ b/util/test/rdtest/testcase.py @@ -382,6 +382,9 @@ class TestCase: save_data = rd.TextureSave() save_data.resourceId = tex save_data.destType = rd.FileType.PNG + save_data.slice.sliceIndex = sub.slice + save_data.mip = sub.mip + save_data.sample.sampleIndex = sub.sample img_path = util.get_tmp_path('output.png')