diff --git a/docs/getting_started/features.rst b/docs/getting_started/features.rst index 8fc378464..54f22da28 100644 --- a/docs/getting_started/features.rst +++ b/docs/getting_started/features.rst @@ -43,7 +43,7 @@ Current Common Feature set * Tabbed view for locking a view of a particular resource over time. * Pixel value picking. * Save (in theory) any type of texture and format to various formats, dds as well as regular png/jpg. - * Several debug overlays for render targets - Wireframe, Depth pass/fail, Stencil pass/fail, Clipping (below black/above white points), NaN/-ve/INF highlight, quad overdraw. + * Several debug overlays for render targets - Wireframe, Depth pass/fail, Stencil pass/fail, Clipping (below black/above white points), NaN/-ve/INF highlight, quad overdraw, triangle size. * Custom visualisation shader support - e.g. decode custom packed formats or gbuffers. * Hot shader editing and replacement. diff --git a/docs/window/texture_viewer.rst b/docs/window/texture_viewer.rst index e5015b544..3fd164760 100644 --- a/docs/window/texture_viewer.rst +++ b/docs/window/texture_viewer.rst @@ -313,6 +313,10 @@ This is a powerful tool for quickly diagnosing issues and can be very useful for * ``Quad Overdraw (Draw)`` will show a similar visualisation to the above option, but limited only to the current drawcall. +* ``Triangle Size (Pass)`` will show a visualisation of how much pixel area triangles in the meshes are covering in the 'pass' up to the selected draw, up to 4x4 pixels (16 square px) at most. If the current API does not have the concept of a pass, it is defined as all the drawcalls with the same set of render targets. + +* ``Triangle Size (Draw)`` will show a similar visualisation to the above option, but limited only to the current drawcall. + .. note:: These overlays are all rendered after most image controls are applied. For this reason the range control, channel controls and custom shaders do not affect the overlays. diff --git a/renderdoc/CMakeLists.txt b/renderdoc/CMakeLists.txt index 637e05aeb..034ecaaa5 100644 --- a/renderdoc/CMakeLists.txt +++ b/renderdoc/CMakeLists.txt @@ -230,6 +230,8 @@ set(data data/glsl/text.vert data/glsl/array2ms.comp data/glsl/ms2array.comp + data/glsl/trisize.frag + data/glsl/trisize.geom data/sourcecodepro.ttf driver/vulkan/renderdoc.json) diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index 765790990..aa9aec4ec 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -168,6 +168,8 @@ enum TextureDisplayOverlay eTexOverlay_ClearBeforeDraw, eTexOverlay_QuadOverdrawPass, eTexOverlay_QuadOverdrawDraw, + eTexOverlay_TriangleSizePass, + eTexOverlay_TriangleSizeDraw, }; enum FileType diff --git a/renderdoc/data/embedded_files.h b/renderdoc/data/embedded_files.h index c98e54a03..cf6459379 100644 --- a/renderdoc/data/embedded_files.h +++ b/renderdoc/data/embedded_files.h @@ -39,6 +39,8 @@ DECLARE_EMBED(glsl_fixedcol_frag); DECLARE_EMBED(glsl_mesh_vert); DECLARE_EMBED(glsl_mesh_geom); DECLARE_EMBED(glsl_mesh_frag); +DECLARE_EMBED(glsl_trisize_geom); +DECLARE_EMBED(glsl_trisize_frag); DECLARE_EMBED(glsl_minmaxtile_comp); DECLARE_EMBED(glsl_minmaxresult_comp); DECLARE_EMBED(glsl_histogram_comp); diff --git a/renderdoc/data/glsl/debuguniforms.h b/renderdoc/data/glsl/debuguniforms.h index 922798e33..f624ffaaf 100644 --- a/renderdoc/data/glsl/debuguniforms.h +++ b/renderdoc/data/glsl/debuguniforms.h @@ -106,6 +106,8 @@ BINDING(0) uniform MeshUBOData uint displayFormat; uint homogenousInput; vec2 pointSpriteSize; + uint rawoutput; + vec3 padding; } INST_NAME(Mesh); diff --git a/renderdoc/data/glsl/mesh.vert b/renderdoc/data/glsl/mesh.vert index 666f17f04..6fb3e7d37 100644 --- a/renderdoc/data/glsl/mesh.vert +++ b/renderdoc/data/glsl/mesh.vert @@ -64,7 +64,10 @@ void main(void) #ifdef VULKAN // GL->VK conventions gl_Position.y = -gl_Position.y; - gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0; + if(Mesh.rawoutput == 0) + { + gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0; + } gl_PointSize = 4.0f; #endif diff --git a/renderdoc/data/glsl/trisize.frag b/renderdoc/data/glsl/trisize.frag new file mode 100644 index 000000000..afd1e6d90 --- /dev/null +++ b/renderdoc/data/glsl/trisize.frag @@ -0,0 +1,44 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2015-2016 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#define NUM_RAMP_COLOURS 128 + +layout(binding = 1) uniform OverdrawRampColors +{ + vec4 colors[NUM_RAMP_COLOURS]; +} ramp; + +layout (location = 0) in float pixarea; + +layout (location = 0) out vec4 color_out; + +void main(void) +{ + // bucket triangle area + float area = max(pixarea, 0.001f); + + int bucket = 2 + int( floor(20.0f - 20.1f * (1.0f - exp(-0.4f * area) ) ) ); + + color_out = ramp.colors[bucket]; +} diff --git a/renderdoc/data/glsl/trisize.geom b/renderdoc/data/glsl/trisize.geom new file mode 100644 index 000000000..a3a535a53 --- /dev/null +++ b/renderdoc/data/glsl/trisize.geom @@ -0,0 +1,75 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2015-2016 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +layout(triangles, invocations = 1) in; +layout(triangle_strip, max_vertices = 3) out; + +layout (location = 0) in vec4 IN_secondary[3]; +layout (location = 1) in vec4 IN_norm[3]; + +layout (location = 0) out float OUT_pixarea; + +in gl_PerVertex +{ + vec4 gl_Position; + float gl_PointSize; +} gl_in[]; + +out gl_PerVertex +{ + vec4 gl_Position; + float gl_PointSize; +}; + +layout(binding = 2) uniform ViewportSizeUBO +{ + vec4 size; +} viewport; + +void main() +{ + vec2 a = gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w; + vec2 b = gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w; + vec2 c = gl_in[2].gl_Position.xy / gl_in[2].gl_Position.w; + + a = (a * 0.5f + 0.5f) * viewport.size.xy; + b = (b * 0.5f + 0.5f) * viewport.size.xy; + c = (c * 0.5f + 0.5f) * viewport.size.xy; + + float ab = length(a - b); + float bc = length(b - c); + float ca = length(c - a); + + float s = (ab + bc + ca) / 2.0f; + + float area = sqrt( s * (s - ab) * (s - bc) * (s - ca) ); + + for(int i=0; i < 3; i++) + { + gl_Position = gl_in[i].gl_Position; + OUT_pixarea = area; + EmitVertex(); + } + EndPrimitive(); +} diff --git a/renderdoc/data/hlsl/mesh.hlsl b/renderdoc/data/hlsl/mesh.hlsl index 161db9310..4d95e9d52 100644 --- a/renderdoc/data/hlsl/mesh.hlsl +++ b/renderdoc/data/hlsl/mesh.hlsl @@ -65,6 +65,64 @@ wireframeV2F RENDERDOC_MeshVS(meshA2V IN, uint vid : SV_VertexID) return OUT; } +struct triSizeV2F +{ + float4 pos : SV_Position; + float pixarea : PixArea; +}; + +cbuffer viewportCBuf : register(b0) +{ + float4 viewport; +}; + +[maxvertexcount(3)] +void RENDERDOC_TriangleSizeGS(triangle wireframeV2F input[3], inout TriangleStream TriStream) +{ + triSizeV2F output; + + float2 a = input[0].pos.xy / input[0].pos.w; + float2 b = input[1].pos.xy / input[1].pos.w; + float2 c = input[2].pos.xy / input[2].pos.w; + + a = (a * 0.5f + 0.5f) * viewport.xy; + b = (b * 0.5f + 0.5f) * viewport.xy; + c = (c * 0.5f + 0.5f) * viewport.xy; + + float ab = length(a - b); + float bc = length(b - c); + float ca = length(c - a); + + float s = (ab + bc + ca) / 2.0f; + + float area = sqrt( s * (s - ab) * (s - bc) * (s - ca) ); + + for(int i=0; i<3; i++) + { + output.pos = input[i].pos; + output.pixarea = area; + TriStream.Append(output); + } + TriStream.RestartStrip(); +} + +#define NUM_RAMP_COLOURS 128 + +cbuffer triangleRampCBuf : register(b0) +{ + const float4 overdrawRampColours[NUM_RAMP_COLOURS]; +}; + +float4 RENDERDOC_TriangleSizePS(triSizeV2F IN) : SV_Target0 +{ + // bucket triangle area + float area = max(IN.pixarea, 0.001f); + + int bucket = 2 + int( floor(20.0f - 20.1f * (1.0f - exp(-0.4f * area) ) ) ); + + return overdrawRampColours[bucket]; +} + [maxvertexcount(3)] void RENDERDOC_MeshGS(triangle wireframeV2F input[3], inout TriangleStream TriStream) { diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc index 99a6adff7..f9dbbf535 100644 --- a/renderdoc/data/renderdoc.rc +++ b/renderdoc/data/renderdoc.rc @@ -133,6 +133,8 @@ RESOURCE_glsl_quadwrite_frag TYPE_EMBED "glsl/quadwrite.frag" RESOURCE_glsl_mesh_comp TYPE_EMBED "glsl/mesh.comp" RESOURCE_glsl_array2ms_comp TYPE_EMBED "glsl/array2ms.comp" RESOURCE_glsl_ms2array_comp TYPE_EMBED "glsl/ms2array.comp" +RESOURCE_glsl_trisize_geom TYPE_EMBED "glsl/trisize.geom" +RESOURCE_glsl_trisize_frag TYPE_EMBED "glsl/trisize.frag" #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h index 2600411ca..568e6ac8f 100644 --- a/renderdoc/data/resource.h +++ b/renderdoc/data/resource.h @@ -35,6 +35,8 @@ #define RESOURCE_glsl_mesh_comp 421 #define RESOURCE_glsl_array2ms_comp 422 #define RESOURCE_glsl_ms2array_comp 423 +#define RESOURCE_glsl_trisize_geom 424 +#define RESOURCE_glsl_trisize_frag 425 #if !defined(STRINGIZE) #define STRINGIZE2(a) #a diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp index 26ff8954f..7366a8d3c 100644 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -3854,6 +3854,167 @@ ResourceId D3D11DebugManager::RenderOverlay(ResourceId texid, FormatComponentTyp } } } + else if(overlay == eTexOverlay_TriangleSizeDraw || overlay == eTexOverlay_TriangleSizePass) + { + SCOPED_TIMER("Triangle size"); + + // ensure it will be recreated on next use + SAFE_RELEASE(m_MeshDisplayLayout); + m_PrevMeshFmt = ResourceFormat(); + + D3D11_INPUT_ELEMENT_DESC layoutdesc[2] = {}; + + layoutdesc[0].SemanticName = "pos"; + layoutdesc[0].Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + + // dummy for vertex shader + layoutdesc[1].SemanticName = "sec"; + layoutdesc[1].Format = DXGI_FORMAT_R8G8B8A8_UNORM; + layoutdesc[1].InputSlot = 1; + layoutdesc[1].InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA; + + HRESULT hr = m_pDevice->CreateInputLayout(layoutdesc, 2, m_DebugRender.MeshHomogVSBytecode, + m_DebugRender.MeshHomogVSBytelen, &m_MeshDisplayLayout); + + if(FAILED(hr)) + { + RDCERR("Failed to create m_MeshDisplayLayout %08x", hr); + m_MeshDisplayLayout = NULL; + } + + DebugVertexCBuffer vertexData = {}; + vertexData.LineStrip = 0; + vertexData.ModelViewProj = Matrix4f::Identity(); + vertexData.SpriteSize = Vec2f(); + FillCBuffer(m_DebugRender.GenericVSCBuffer, &vertexData, sizeof(DebugVertexCBuffer)); + + ID3D11Buffer *psbuf = MakeCBuffer(&overdrawRamp[0].x, sizeof(overdrawRamp)); + + Vec4f viewport = Vec4f((float)details.texWidth, (float)details.texHeight); + ID3D11Buffer *gsbuf = MakeCBuffer(&viewport.x, sizeof(viewport)); + + float overlayConsts[] = {0.0f, 0.0f, 0.0f, 0.0f}; + m_pImmediateContext->ClearRenderTargetView(rtv, overlayConsts); + + vector events = passEvents; + + if(overlay == eTexOverlay_TriangleSizeDraw) + events.clear(); + + events.push_back(eventID); + + if(overlay == eTexOverlay_TriangleSizePass) + m_WrappedDevice->ReplayLog(0, events[0], eReplay_WithoutDraw); + + events.push_back(eventID); + + for(size_t i = 0; i < events.size(); i++) + { + D3D11RenderState oldstate = *m_WrappedContext->GetCurrentPipelineState(); + + D3D11_DEPTH_STENCIL_DESC dsdesc = { + /*DepthEnable =*/TRUE, + /*DepthWriteMask =*/D3D11_DEPTH_WRITE_MASK_ALL, + /*DepthFunc =*/D3D11_COMPARISON_LESS, + /*StencilEnable =*/FALSE, + /*StencilReadMask =*/D3D11_DEFAULT_STENCIL_READ_MASK, + /*StencilWriteMask =*/D3D11_DEFAULT_STENCIL_WRITE_MASK, + /*FrontFace =*/{D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, + D3D11_COMPARISON_ALWAYS}, + /*BackFace =*/{D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, + D3D11_COMPARISON_ALWAYS}, + }; + ID3D11DepthStencilState *ds = NULL; + + if(oldstate.OM.DepthStencilState) + oldstate.OM.DepthStencilState->GetDesc(&dsdesc); + + dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + dsdesc.StencilWriteMask = 0; + + m_WrappedDevice->CreateDepthStencilState(&dsdesc, &ds); + + m_WrappedContext->OMSetDepthStencilState(ds, oldstate.OM.StencRef); + + SAFE_RELEASE(ds); + + const FetchDrawcall *draw = m_WrappedDevice->GetDrawcall(events[i]); + + for(uint32_t inst = 0; draw && inst < RDCMAX(1U, draw->numInstances); inst++) + { + MeshFormat fmt = GetPostVSBuffers(events[i], inst, eMeshDataStage_GSOut); + if(fmt.buf == ResourceId()) + fmt = GetPostVSBuffers(events[i], inst, eMeshDataStage_VSOut); + + if(fmt.buf != ResourceId()) + { + D3D11_PRIMITIVE_TOPOLOGY topo = MakeD3DPrimitiveTopology(fmt.topo); + + ID3D11Buffer *ibuf = NULL; + DXGI_FORMAT ifmt = DXGI_FORMAT_R16_UINT; + UINT ioffs = (UINT)fmt.idxoffs; + + ID3D11Buffer *vbs[2] = {NULL, NULL}; + UINT str[2] = {fmt.stride, 4}; + UINT offs[2] = {(UINT)fmt.offset, 0}; + + { + auto it = WrappedID3D11Buffer::m_BufferList.find(fmt.buf); + + if(it != WrappedID3D11Buffer::m_BufferList.end()) + vbs[0] = UNWRAP(WrappedID3D11Buffer, it->second.m_Buffer); + + it = WrappedID3D11Buffer::m_BufferList.find(fmt.idxbuf); + + if(it != WrappedID3D11Buffer::m_BufferList.end()) + ibuf = UNWRAP(WrappedID3D11Buffer, it->second.m_Buffer); + + if(fmt.idxByteWidth == 4) + ifmt = DXGI_FORMAT_R32_UINT; + } + + m_pImmediateContext->IASetVertexBuffers(0, 1, vbs, str, offs); + if(ibuf) + m_pImmediateContext->IASetIndexBuffer(ibuf, ifmt, ioffs); + else + m_pImmediateContext->IASetIndexBuffer(NULL, DXGI_FORMAT_UNKNOWN, NULL); + + m_pImmediateContext->IASetPrimitiveTopology(topo); + + m_pImmediateContext->IASetInputLayout(m_MeshDisplayLayout); + m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer); + m_pImmediateContext->PSSetConstantBuffers(0, 1, &psbuf); + m_pImmediateContext->GSSetConstantBuffers(0, 1, &gsbuf); + m_pImmediateContext->VSSetShader(m_DebugRender.WireframeHomogVS, NULL, 0); + m_pImmediateContext->GSSetShader(m_DebugRender.TriangleSizeGS, NULL, 0); + m_pImmediateContext->PSSetShader(m_DebugRender.TriangleSizePS, NULL, 0); + m_pImmediateContext->HSSetShader(NULL, NULL, 0); + m_pImmediateContext->DSSetShader(NULL, NULL, 0); + m_pImmediateContext->OMSetBlendState(NULL, NULL, 0xffffffff); + m_pImmediateContext->OMSetRenderTargets( + 1, &rtv, UNWRAP(WrappedID3D11DepthStencilView, oldstate.OM.DepthView)); + + if(ibuf) + m_pImmediateContext->DrawIndexed(fmt.numVerts, 0, fmt.baseVertex); + else + m_pImmediateContext->Draw(fmt.numVerts, 0); + } + } + + oldstate.ApplyState(m_WrappedContext); + + if(overlay == eTexOverlay_TriangleSizePass) + { + m_WrappedDevice->ReplayLog(events[i], events[i], eReplay_OnlyDraw); + + if(i + 1 < events.size()) + m_WrappedDevice->ReplayLog(events[i], events[i + 1], eReplay_WithoutDraw); + } + } + + if(overlay == eTexOverlay_TriangleSizePass) + m_WrappedDevice->ReplayLog(0, eventID, eReplay_WithoutDraw); + } else if(overlay == eTexOverlay_QuadOverdrawPass || overlay == eTexOverlay_QuadOverdrawDraw) { SCOPED_TIMER("Quad Overdraw"); diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index ff6806e4c..215932636 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -669,6 +669,11 @@ bool D3D11DebugManager::InitDebugRendering() m_DebugRender.MeshGS = MakeGShader(meshhlsl.c_str(), "RENDERDOC_MeshGS", "gs_4_0"); m_DebugRender.MeshPS = MakePShader(meshhlsl.c_str(), "RENDERDOC_MeshPS", "ps_4_0"); + m_DebugRender.TriangleSizeGS = + MakeGShader(meshhlsl.c_str(), "RENDERDOC_TriangleSizeGS", "gs_4_0"); + m_DebugRender.TriangleSizePS = + MakePShader(meshhlsl.c_str(), "RENDERDOC_TriangleSizePS", "ps_4_0"); + m_DebugRender.MeshVSBytecode = new byte[bytecode.size()]; m_DebugRender.MeshVSBytelen = (uint32_t)bytecode.size(); memcpy(m_DebugRender.MeshVSBytecode, &bytecode[0], bytecode.size()); diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index 3f2007a85..0750f1b8b 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -447,6 +447,8 @@ private: SAFE_RELEASE(MeshVS); SAFE_RELEASE(MeshGS); SAFE_RELEASE(MeshPS); + SAFE_RELEASE(TriangleSizeGS); + SAFE_RELEASE(TriangleSizePS); SAFE_RELEASE(FullscreenVS); SAFE_RELEASE(WireframeVS); SAFE_RELEASE(WireframeHomogVS); @@ -528,8 +530,9 @@ private: ID3D11Buffer *GenericPSCBuffer; ID3D11Buffer *PublicCBuffers[20]; ID3D11VertexShader *GenericVS, *WireframeVS, *MeshVS, *WireframeHomogVS, *FullscreenVS; - ID3D11GeometryShader *MeshGS; - ID3D11PixelShader *TexDisplayPS, *OverlayPS, *WireframePS, *MeshPS, *CheckerboardPS; + ID3D11GeometryShader *MeshGS, *TriangleSizeGS; + ID3D11PixelShader *TexDisplayPS, *OverlayPS, *WireframePS, *MeshPS, *CheckerboardPS, + *TriangleSizePS; ID3D11PixelShader *OutlinePS; ID3D11PixelShader *CopyMSToArrayPS, *CopyArrayToMSPS; ID3D11PixelShader *FloatCopyMSToArrayPS, *FloatCopyArrayToMSPS; diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 6953ac7f5..d6aba8186 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -319,6 +319,11 @@ void GLReplay::InitDebugData() DebugData.meshProg = CreateShaderProgram(vs, fs); DebugData.meshgsProg = CreateShaderProgram(vs, fs, gs); + GenerateGLSLShader(fs, eShaderGLSL, "", GetEmbeddedResource(glsl_trisize_frag), 420); + GenerateGLSLShader(gs, eShaderGLSL, "", GetEmbeddedResource(glsl_trisize_geom), 420); + + DebugData.trisizeProg = CreateShaderProgram(vs, fs, gs); + gl.glGenProgramPipelines(1, &DebugData.texDisplayPipe); RenderDoc::Inst().SetProgress(DebugManagerInit, 0.4f); @@ -345,10 +350,11 @@ void GLReplay::InitDebugData() for(size_t i = 0; i < ARRAY_COUNT(DebugData.UBOs); i++) { gl.glBindBuffer(eGL_UNIFORM_BUFFER, DebugData.UBOs[i]); - gl.glNamedBufferDataEXT(DebugData.UBOs[i], 512, NULL, eGL_DYNAMIC_DRAW); - RDCCOMPILE_ASSERT(sizeof(TexDisplayUBOData) < 512, "texdisplay UBO too large"); - RDCCOMPILE_ASSERT(sizeof(FontUBOData) < 512, "texdisplay UBO too large"); - RDCCOMPILE_ASSERT(sizeof(HistogramUBOData) < 512, "texdisplay UBO too large"); + gl.glNamedBufferDataEXT(DebugData.UBOs[i], 2048, NULL, eGL_DYNAMIC_DRAW); + RDCCOMPILE_ASSERT(sizeof(TexDisplayUBOData) <= 2048, "UBO too small"); + RDCCOMPILE_ASSERT(sizeof(FontUBOData) <= 2048, "UBO too small"); + RDCCOMPILE_ASSERT(sizeof(HistogramUBOData) <= 2048, "UBO too small"); + RDCCOMPILE_ASSERT(sizeof(overdrawRamp) <= 2048, "UBO too small"); } DebugData.overlayTexWidth = DebugData.overlayTexHeight = 0; @@ -610,6 +616,7 @@ void GLReplay::DeleteDebugData() gl.glDeleteProgram(DebugData.fixedcolFSProg); gl.glDeleteProgram(DebugData.meshProg); gl.glDeleteProgram(DebugData.meshgsProg); + gl.glDeleteProgram(DebugData.trisizeProg); gl.glDeleteSamplers(1, &DebugData.linearSampler); gl.glDeleteSamplers(1, &DebugData.pointSampler); @@ -2297,6 +2304,379 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FormatComponentType typeHin } } } + else if(overlay == eTexOverlay_TriangleSizeDraw || overlay == eTexOverlay_TriangleSizePass) + { + SCOPED_TIMER("Triangle Size"); + + float black[] = {0.0f, 0.0f, 0.0f, 0.0f}; + gl.glClearBufferfv(eGL_COLOR, 0, black); + + MeshUBOData uboParams = {}; + uboParams.homogenousInput = 1; + uboParams.invProj = Matrix4f::Identity(); + uboParams.mvp = Matrix4f::Identity(); + + gl.glBindBuffer(eGL_COPY_WRITE_BUFFER, DebugData.UBOs[0]); + + MeshUBOData *uboptr = + (MeshUBOData *)gl.glMapBufferRange(eGL_COPY_WRITE_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_COPY_WRITE_BUFFER); + + gl.glBindBuffer(eGL_COPY_WRITE_BUFFER, DebugData.UBOs[1]); + Vec4f *v = (Vec4f *)gl.glMapBufferRange(eGL_COPY_WRITE_BUFFER, 0, sizeof(overdrawRamp), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + memcpy(v, overdrawRamp, sizeof(overdrawRamp)); + gl.glUnmapBuffer(eGL_COPY_WRITE_BUFFER); + + gl.glBindBuffer(eGL_COPY_WRITE_BUFFER, DebugData.UBOs[2]); + v = (Vec4f *)gl.glMapBufferRange(eGL_COPY_WRITE_BUFFER, 0, sizeof(Vec4f), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *v = Vec4f((float)texDetails.width, (float)texDetails.height); + gl.glUnmapBuffer(eGL_COPY_WRITE_BUFFER); + + vector events = passEvents; + + if(overlay == eTexOverlay_QuadOverdrawDraw) + events.clear(); + + events.push_back(eventID); + + if(!events.empty()) + { + if(overlay == eTexOverlay_TriangleSizePass) + ReplayLog(events[0], eReplay_WithoutDraw); + else + rs.ApplyState(m_pDriver->GetCtx(), m_pDriver); + + // this all happens on the replay context so we need a temp FBO/VAO + GLuint overlayFBO = 0, tempVAO = 0; + gl.glGenFramebuffers(1, &overlayFBO); + gl.glGenVertexArrays(1, &tempVAO); + + for(size_t i = 0; i < events.size(); i++) + { + GLboolean blending = GL_FALSE; + GLint depthwritemask = 1; + GLint stencilfmask = 0xff, stencilbmask = 0xff; + GLuint drawFBO = 0, prevVAO = 0; + struct UBO + { + GLuint buf; + GLint64 offs; + GLint64 size; + } ubos[3]; + + // save the state we're going to mess with + { + gl.glGetIntegerv(eGL_DEPTH_WRITEMASK, &depthwritemask); + gl.glGetIntegerv(eGL_STENCIL_WRITEMASK, &stencilfmask); + gl.glGetIntegerv(eGL_STENCIL_BACK_WRITEMASK, &stencilbmask); + + gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&drawFBO); + gl.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&prevVAO); + + blending = gl.glIsEnabled(eGL_BLEND); + + for(uint32_t u = 0; u < 3; u++) + { + gl.glGetIntegeri_v(eGL_UNIFORM_BUFFER_BINDING, u, (GLint *)&ubos[u].buf); + gl.glGetInteger64i_v(eGL_UNIFORM_BUFFER_START, u, (GLint64 *)&ubos[u].offs); + gl.glGetInteger64i_v(eGL_UNIFORM_BUFFER_SIZE, u, (GLint64 *)&ubos[u].size); + } + } + + // disable depth and stencil writes + gl.glDepthMask(GL_FALSE); + gl.glStencilMask(GL_FALSE); + + // disable blending + gl.glDisable(eGL_BLEND); + + // bind our UBOs + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]); + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 1, DebugData.UBOs[1]); + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 2, DebugData.UBOs[2]); + + const GLenum att = eGL_DEPTH_ATTACHMENT; + GLuint depthObj = 0; + GLint type = 0, level = 0, layered = 0, layer = 0; + + // fetch the details of the 'real' depth attachment + gl.glGetNamedFramebufferAttachmentParameterivEXT( + drawFBO, att, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint *)&depthObj); + gl.glGetNamedFramebufferAttachmentParameterivEXT( + drawFBO, att, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type); + + if(depthObj) + { + gl.glGetNamedFramebufferAttachmentParameterivEXT( + drawFBO, att, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &level); + gl.glGetNamedFramebufferAttachmentParameterivEXT( + drawFBO, att, eGL_FRAMEBUFFER_ATTACHMENT_LAYERED, &layered); + + layered = (layered != 0); + + layer = 0; + if(layered == 0) + gl.glGetNamedFramebufferAttachmentParameterivEXT( + drawFBO, att, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER, &layer); + + if(type != eGL_RENDERBUFFER) + { + ResourceId id = m_pDriver->GetResourceManager()->GetID(TextureRes(ctx, depthObj)); + WrappedOpenGL::TextureData &details = m_pDriver->m_Textures[id]; + + if(details.curType == eGL_TEXTURE_CUBE_MAP) + { + GLenum face; + gl.glGetNamedFramebufferAttachmentParameterivEXT( + drawFBO, att, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE, (GLint *)&face); + + layer = CubeTargetIndex(face); + } + } + } + + // bind our FBO + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, overlayFBO); + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, DebugData.overlayTex, 0); + + // now apply the depth texture binding + if(depthObj) + { + if(type == eGL_RENDERBUFFER) + { + gl.glNamedFramebufferRenderbufferEXT(overlayFBO, att, eGL_RENDERBUFFER, depthObj); + } + else + { + if(!layered) + { + // we use old-style non-DSA for this because binding cubemap faces with EXT_dsa + // is completely messed up and broken + + // if obj is a cubemap use face-specific targets + ResourceId id = m_pDriver->GetResourceManager()->GetID(TextureRes(ctx, depthObj)); + WrappedOpenGL::TextureData &details = m_pDriver->m_Textures[id]; + + if(details.curType == eGL_TEXTURE_CUBE_MAP) + { + GLenum faces[] = { + eGL_TEXTURE_CUBE_MAP_POSITIVE_X, eGL_TEXTURE_CUBE_MAP_NEGATIVE_X, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Y, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + }; + + if(layer < 6) + { + gl.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, att, faces[layer], depthObj, level); + } + else + { + RDCWARN( + "Invalid layer %u used to bind cubemap to framebuffer. Binding POSITIVE_X"); + gl.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, att, faces[0], depthObj, level); + } + } + else if(details.curType == eGL_TEXTURE_CUBE_MAP_ARRAY || + details.curType == eGL_TEXTURE_1D_ARRAY || + details.curType == eGL_TEXTURE_2D_ARRAY) + { + gl.glFramebufferTextureLayer(eGL_DRAW_FRAMEBUFFER, att, depthObj, level, layer); + } + else + { + RDCASSERT(layer == 0); + gl.glNamedFramebufferTextureEXT(overlayFBO, att, depthObj, level); + } + } + else + { + gl.glNamedFramebufferTextureEXT(overlayFBO, att, depthObj, level); + } + } + } + + GLuint prog = 0, pipe = 0; + gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&prog); + gl.glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&pipe); + + gl.glUseProgram(DebugData.trisizeProg); + gl.glBindProgramPipeline(0); + + const FetchDrawcall *draw = m_pDriver->GetDrawcall(events[i]); + + for(uint32_t inst = 0; draw && inst < RDCMAX(1U, draw->numInstances); inst++) + { + MeshFormat fmt = GetPostVSBuffers(events[i], inst, eMeshDataStage_GSOut); + if(fmt.buf == ResourceId()) + fmt = GetPostVSBuffers(events[i], inst, eMeshDataStage_VSOut); + + if(fmt.buf != ResourceId()) + { + GLenum topo = MakeGLPrimitiveTopology(fmt.topo); + + gl.glBindVertexArray(tempVAO); + + { + if(fmt.specialFormat != eSpecial_Unknown) + { + if(fmt.specialFormat == eSpecial_R10G10B10A2) + { + if(fmt.compType == eCompType_UInt) + gl.glVertexAttribIFormat(0, 4, eGL_UNSIGNED_INT_2_10_10_10_REV, 0); + if(fmt.compType == eCompType_SInt) + gl.glVertexAttribIFormat(0, 4, eGL_INT_2_10_10_10_REV, 0); + } + else if(fmt.specialFormat == eSpecial_R11G11B10) + { + gl.glVertexAttribFormat(0, 4, eGL_UNSIGNED_INT_10F_11F_11F_REV, GL_FALSE, 0); + } + else + { + RDCWARN("Unsupported special vertex attribute format: %x", fmt.specialFormat); + } + } + else if(fmt.compType == eCompType_Float || fmt.compType == eCompType_UNorm || + fmt.compType == eCompType_SNorm) + { + GLenum fmttype = eGL_UNSIGNED_INT; + + if(fmt.compByteWidth == 4) + { + if(fmt.compType == eCompType_Float) + fmttype = eGL_FLOAT; + else if(fmt.compType == eCompType_UNorm) + fmttype = eGL_UNSIGNED_INT; + else if(fmt.compType == eCompType_SNorm) + fmttype = eGL_INT; + } + else if(fmt.compByteWidth == 2) + { + if(fmt.compType == eCompType_Float) + fmttype = eGL_HALF_FLOAT; + else if(fmt.compType == eCompType_UNorm) + fmttype = eGL_UNSIGNED_SHORT; + else if(fmt.compType == eCompType_SNorm) + fmttype = eGL_SHORT; + } + else if(fmt.compByteWidth == 1) + { + if(fmt.compType == eCompType_UNorm) + fmttype = eGL_UNSIGNED_BYTE; + else if(fmt.compType == eCompType_SNorm) + fmttype = eGL_BYTE; + } + + gl.glVertexAttribFormat(0, fmt.compCount, fmttype, fmt.compType != eCompType_Float, + 0); + } + else if(fmt.compType == eCompType_UInt || fmt.compType == eCompType_SInt) + { + GLenum fmttype = eGL_UNSIGNED_INT; + + if(fmt.compByteWidth == 4) + { + if(fmt.compType == eCompType_UInt) + fmttype = eGL_UNSIGNED_INT; + else if(fmt.compType == eCompType_SInt) + fmttype = eGL_INT; + } + else if(fmt.compByteWidth == 2) + { + if(fmt.compType == eCompType_UInt) + fmttype = eGL_UNSIGNED_SHORT; + else if(fmt.compType == eCompType_SInt) + fmttype = eGL_SHORT; + } + else if(fmt.compByteWidth == 1) + { + if(fmt.compType == eCompType_UInt) + fmttype = eGL_UNSIGNED_BYTE; + else if(fmt.compType == eCompType_SInt) + fmttype = eGL_BYTE; + } + + gl.glVertexAttribIFormat(0, fmt.compCount, fmttype, 0); + } + else if(fmt.compType == eCompType_Double) + { + gl.glVertexAttribLFormat(0, fmt.compCount, eGL_DOUBLE, 0); + } + + GLuint vb = m_pDriver->GetResourceManager()->GetCurrentResource(fmt.buf).name; + gl.glBindVertexBuffer(0, vb, (GLintptr)fmt.offset, fmt.stride); + } + + gl.glEnableVertexAttribArray(0); + gl.glDisableVertexAttribArray(1); + + if(fmt.idxbuf != ResourceId()) + { + GLenum idxtype = eGL_UNSIGNED_BYTE; + if(fmt.idxByteWidth == 2) + idxtype = eGL_UNSIGNED_SHORT; + else if(fmt.idxByteWidth == 4) + idxtype = eGL_UNSIGNED_INT; + + GLuint ib = m_pDriver->GetResourceManager()->GetCurrentResource(fmt.idxbuf).name; + gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); + gl.glDrawElementsBaseVertex(topo, fmt.numVerts, idxtype, + (const void *)uintptr_t(fmt.idxoffs), fmt.baseVertex); + } + else + { + gl.glDrawArrays(topo, 0, fmt.numVerts); + } + } + } + + // pop the state that we messed with + { + gl.glBindProgramPipeline(pipe); + gl.glUseProgram(prog); + + if(blending) + gl.glEnable(eGL_BLEND); + else + gl.glDisable(eGL_BLEND); + + // restore the previous FBO/VAO + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, drawFBO); + gl.glBindVertexArray(prevVAO); + + for(uint32_t u = 0; u < 3; u++) + { + if(ubos[u].buf == 0 || (ubos[u].offs == 0 && ubos[u].size == 0)) + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, u, ubos[u].buf); + else + gl.glBindBufferRange(eGL_UNIFORM_BUFFER, u, ubos[u].buf, (GLintptr)ubos[u].offs, + (GLsizeiptr)ubos[u].size); + } + + gl.glDepthMask(depthwritemask ? GL_TRUE : GL_FALSE); + gl.glStencilMaskSeparate(eGL_FRONT, (GLuint)stencilfmask); + gl.glStencilMaskSeparate(eGL_BACK, (GLuint)stencilbmask); + } + + if(overlay == eTexOverlay_TriangleSizePass) + { + m_pDriver->ReplayLog(0, events[i], eReplay_OnlyDraw); + + if(i + 1 < events.size()) + m_pDriver->ReplayLog(events[i], events[i + 1], eReplay_WithoutDraw); + } + } + + gl.glDeleteFramebuffers(1, &overlayFBO); + gl.glDeleteVertexArrays(1, &tempVAO); + + if(overlay == eTexOverlay_TriangleSizePass) + ReplayLog(eventID, eReplay_WithoutDraw); + } + } else if(overlay == eTexOverlay_QuadOverdrawDraw || overlay == eTexOverlay_QuadOverdrawPass) { if(DebugData.quadoverdraw420) diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 5ed78a0a5..87da35c1e 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -312,6 +312,7 @@ private: GLuint meshProg; GLuint meshgsProg; + GLuint trisizeProg; GLuint meshVAO; GLuint axisVAO; @@ -337,7 +338,7 @@ private: GLuint overlayPipe; GLint overlayTexWidth, overlayTexHeight; - GLuint UBOs[2]; + GLuint UBOs[3]; GLuint readFBO; diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index bb5936c17..79f888f76 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -302,6 +302,12 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) RDCEraseEl(m_QuadResolvePipeline); m_QuadSPIRV = NULL; + m_TriSizeDescSetLayout = VK_NULL_HANDLE; + m_TriSizeDescSet = VK_NULL_HANDLE; + m_TriSizePipeLayout = VK_NULL_HANDLE; + m_TriSizeGSModule = VK_NULL_HANDLE; + m_TriSizeFSModule = VK_NULL_HANDLE; + m_MeshDescSetLayout = VK_NULL_HANDLE; m_MeshPipeLayout = VK_NULL_HANDLE; m_MeshDescSet = VK_NULL_HANDLE; @@ -405,7 +411,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, NULL, 0, - 9 + ARRAY_COUNT(m_TexDisplayDescSet), + 10 + ARRAY_COUNT(m_TexDisplayDescSet), ARRAY_COUNT(replayDescPoolTypes), &replayDescPoolTypes[0], }; @@ -666,7 +672,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) }; // declare a few more misc things that are needed on both paths - VkDescriptorBufferInfo bufInfo[7]; + VkDescriptorBufferInfo bufInfo[8]; RDCEraseEl(bufInfo); vector sources; @@ -1213,6 +1219,32 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) RDCASSERTEQUAL(vkr, VK_SUCCESS); } + { + VkDescriptorSetLayoutBinding layoutBinding[] = { + { + 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, NULL, + }, + { + 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, NULL, + }, + { + 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, NULL, + }, + }; + + VkDescriptorSetLayoutCreateInfo descsetLayoutInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + NULL, + 0, + ARRAY_COUNT(layoutBinding), + &layoutBinding[0], + }; + + vkr = m_pDriver->vkCreateDescriptorSetLayout(dev, &descsetLayoutInfo, NULL, + &m_TriSizeDescSetLayout); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } + { VkDescriptorSetLayoutBinding layoutBinding[] = { { @@ -1295,6 +1327,11 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) vkr = m_pDriver->vkCreatePipelineLayout(dev, &pipeLayoutInfo, NULL, &m_QuadResolvePipeLayout); RDCASSERTEQUAL(vkr, VK_SUCCESS); + pipeLayoutInfo.pSetLayouts = &m_TriSizeDescSetLayout; + + vkr = m_pDriver->vkCreatePipelineLayout(dev, &pipeLayoutInfo, NULL, &m_TriSizePipeLayout); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + pipeLayoutInfo.pSetLayouts = &m_OutlineDescSetLayout; vkr = m_pDriver->vkCreatePipelineLayout(dev, &pipeLayoutInfo, NULL, &m_OutlinePipeLayout); @@ -1334,6 +1371,10 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) vkr = m_pDriver->vkAllocateDescriptorSets(dev, &descSetAllocInfo, &m_QuadDescSet); RDCASSERTEQUAL(vkr, VK_SUCCESS); + descSetAllocInfo.pSetLayouts = &m_TriSizeDescSetLayout; + vkr = m_pDriver->vkAllocateDescriptorSets(dev, &descSetAllocInfo, &m_TriSizeDescSet); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + descSetAllocInfo.pSetLayouts = &m_OutlineDescSetLayout; vkr = m_pDriver->vkAllocateDescriptorSets(dev, &descSetAllocInfo, &m_OutlineDescSet); RDCASSERTEQUAL(vkr, VK_SUCCESS); @@ -1390,12 +1431,13 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) GetEmbeddedResource(glsl_histogram_comp), GetEmbeddedResource(glsl_outline_frag), GetEmbeddedResource(glsl_quadresolve_frag), GetEmbeddedResource(glsl_quadwrite_frag), GetEmbeddedResource(glsl_mesh_comp), GetEmbeddedResource(glsl_ms2array_comp), + GetEmbeddedResource(glsl_trisize_geom), GetEmbeddedResource(glsl_trisize_frag), }; SPIRVShaderStage shaderStages[] = { - eSPIRVVertex, eSPIRVFragment, eSPIRVFragment, eSPIRVVertex, eSPIRVGeometry, - eSPIRVFragment, eSPIRVCompute, eSPIRVCompute, eSPIRVCompute, eSPIRVFragment, - eSPIRVFragment, eSPIRVFragment, eSPIRVCompute, eSPIRVCompute, + eSPIRVVertex, eSPIRVFragment, eSPIRVFragment, eSPIRVVertex, eSPIRVGeometry, eSPIRVFragment, + eSPIRVCompute, eSPIRVCompute, eSPIRVCompute, eSPIRVFragment, eSPIRVFragment, eSPIRVFragment, + eSPIRVCompute, eSPIRVCompute, eSPIRVGeometry, eSPIRVFragment, }; enum shaderIdx @@ -1414,6 +1456,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) QUADWRITEFS, MESHCS, MS2ARRAYCS, + TRISIZEGS, + TRISIZEFS, NUM_SHADERS, }; @@ -1733,6 +1777,14 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) { m_MeshModules[2] = module[i]; } + else if(i == TRISIZEGS) + { + m_TriSizeGSModule = module[i]; + } + else if(i == TRISIZEFS) + { + m_TriSizeFSModule = module[i]; + } else if(i == BLITVS) { m_BlitVSModule = module[i]; @@ -1919,6 +1971,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) memcpy(ramp, overdrawRamp, sizeof(overdrawRamp)); m_OverdrawRampUBO.Unmap(); + m_TriSizeUBO.Create(driver, dev, sizeof(Vec4f), 4096, 0); + // pick pixel data { // create image @@ -2115,6 +2169,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) m_MeshPickUBO.FillDescriptor(bufInfo[4]); m_MeshPickResult.FillDescriptor(bufInfo[5]); m_ArrayMSUBO.FillDescriptor(bufInfo[6]); + m_TriSizeUBO.FillDescriptor(bufInfo[7]); VkWriteDescriptorSet analysisSetWrites[] = { {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_CheckerboardDescSet), 0, 0, 1, @@ -2131,6 +2186,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, NULL, &bufInfo[5], NULL}, {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet), 2, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, NULL, &bufInfo[6], NULL}, + {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_TriSizeDescSet), 1, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, NULL, &bufInfo[3], NULL}, }; ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(analysisSetWrites), analysisSetWrites, @@ -2173,6 +2230,9 @@ VulkanDebugManager::~VulkanDebugManager() for(size_t i = 0; i < ARRAY_COUNT(m_MeshModules); i++) m_pDriver->vkDestroyShaderModule(dev, m_MeshModules[i], NULL); + m_pDriver->vkDestroyShaderModule(dev, m_TriSizeGSModule, NULL); + m_pDriver->vkDestroyShaderModule(dev, m_TriSizeFSModule, NULL); + m_pDriver->vkDestroyDescriptorPool(dev, m_DescriptorPool, NULL); m_pDriver->vkDestroySampler(dev, m_LinearSampler, NULL); @@ -2294,6 +2354,9 @@ VulkanDebugManager::~VulkanDebugManager() m_pDriver->vkDestroyImage(dev, m_OverlayImage, NULL); m_pDriver->vkFreeMemory(dev, m_OverlayImageMem, NULL); + m_pDriver->vkDestroyDescriptorSetLayout(dev, m_TriSizeDescSetLayout, NULL); + m_pDriver->vkDestroyPipelineLayout(dev, m_TriSizePipeLayout, NULL); + m_pDriver->vkDestroyDescriptorSetLayout(dev, m_QuadDescSetLayout, NULL); m_pDriver->vkDestroyPipelineLayout(dev, m_QuadResolvePipeLayout, NULL); for(size_t i = 0; i < ARRAY_COUNT(m_QuadResolvePipeline); i++) @@ -5365,6 +5428,433 @@ ResourceId VulkanDebugManager::RenderOverlay(ResourceId texid, TextureDisplayOve vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); RDCASSERTEQUAL(vkr, VK_SUCCESS); } + else if(overlay == eTexOverlay_TriangleSizePass || overlay == eTexOverlay_TriangleSizeDraw) + { + VulkanRenderState prevstate = m_pDriver->m_RenderState; + + { + SCOPED_TIMER("Triangle Size"); + + float black[] = {0.0f, 0.0f, 0.0f, 0.0f}; + + VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + NULL, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + Unwrap(m_OverlayImage), + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; + + DoPipelineBarrier(cmd, 1, &barrier); + + vt->CmdClearColorImage(Unwrap(cmd), Unwrap(m_OverlayImage), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (VkClearColorValue *)black, 1, + &subresourceRange); + + std::swap(barrier.oldLayout, barrier.newLayout); + std::swap(barrier.srcAccessMask, barrier.dstAccessMask); + barrier.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + + DoPipelineBarrier(cmd, 1, &barrier); + + // end this cmd buffer so the image is in the right state for the next part + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + +#if defined(SINGLE_FLUSH_VALIDATE) + m_pDriver->SubmitCmds(); +#endif + + vector events = passEvents; + + if(overlay == eTexOverlay_TriangleSizeDraw) + events.clear(); + + while(!events.empty()) + { + const FetchDrawcall *draw = m_pDriver->GetDrawcall(events[0]); + + // remove any non-drawcalls, like the pass boundary. + if((draw->flags & eDraw_Drawcall) == 0) + events.erase(events.begin()); + else + break; + } + + events.push_back(eventID); + + m_pDriver->ReplayLog(0, events[0], eReplay_WithoutDraw); + + VulkanRenderState &state = m_pDriver->GetRenderState(); + + uint32_t meshOffs = 0; + MeshUBOData *data = (MeshUBOData *)m_MeshUBO.Map(&meshOffs); + + data->mvp = Matrix4f::Identity(); + data->invProj = Matrix4f::Identity(); + data->color = Vec4f(); + data->homogenousInput = 1; + data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->displayFormat = 0; + data->rawoutput = 1; + data->padding = Vec3f(); + m_MeshUBO.Unmap(); + + uint32_t viewOffs = 0; + Vec4f *ubo = (Vec4f *)m_TriSizeUBO.Map(&viewOffs); + *ubo = Vec4f(state.views[0].width, state.views[0].height); + m_TriSizeUBO.Unmap(); + + uint32_t offsets[2] = {meshOffs, viewOffs}; + + VkDescriptorBufferInfo bufdesc; + m_MeshUBO.FillDescriptor(bufdesc); + + VkWriteDescriptorSet write = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + NULL, + Unwrap(m_TriSizeDescSet), + 0, + 0, + 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + NULL, + &bufdesc, + NULL}; + vt->UpdateDescriptorSets(Unwrap(m_Device), 1, &write, 0, NULL); + + m_TriSizeUBO.FillDescriptor(bufdesc); + write.dstBinding = 2; + vt->UpdateDescriptorSets(Unwrap(m_Device), 1, &write, 0, NULL); + + VkRenderPass RP = m_OverlayNoDepthRP; + VkFramebuffer FB = m_OverlayNoDepthFB; + + VulkanCreationInfo &createinfo = m_pDriver->m_CreationInfo; + + RDCASSERT(state.subpass < createinfo.m_RenderPass[state.renderPass].subpasses.size()); + int32_t dsIdx = + createinfo.m_RenderPass[state.renderPass].subpasses[state.subpass].depthstencilAttachment; + + bool depthUsed = false; + + // make a renderpass and framebuffer for rendering to overlay color and using + // depth buffer from the orignial render + if(dsIdx >= 0 && dsIdx < (int32_t)createinfo.m_Framebuffer[state.framebuffer].attachments.size()) + { + depthUsed = true; + + VkAttachmentDescription attDescs[] = { + {0, VK_FORMAT_R16G16B16A16_SFLOAT, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, + {0, VK_FORMAT_UNDEFINED, VK_SAMPLE_COUNT_1_BIT, // will patch this just below + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}, + }; + + ResourceId depthView = createinfo.m_Framebuffer[state.framebuffer].attachments[dsIdx].view; + ResourceId depthIm = createinfo.m_ImageView[depthView].image; + + attDescs[1].format = createinfo.m_Image[depthIm].format; + attDescs[0].samples = attDescs[1].samples = iminfo.samples; + + VkAttachmentReference colRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription sub = { + 0, VK_PIPELINE_BIND_POINT_GRAPHICS, + 0, NULL, // inputs + 1, &colRef, // color + NULL, // resolve + &dsRef, // depth-stencil + 0, NULL, // preserve + }; + + VkRenderPassCreateInfo rpinfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + NULL, + 0, + 2, + attDescs, + 1, + &sub, + 0, + NULL, // dependencies + }; + + vkr = m_pDriver->vkCreateRenderPass(m_Device, &rpinfo, NULL, &RP); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkImageView views[] = { + m_OverlayImageView, GetResourceManager()->GetCurrentHandle(depthView), + }; + + // Create framebuffer rendering just to overlay image, no depth + VkFramebufferCreateInfo fbinfo = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + NULL, + 0, + RP, + 2, + views, + (uint32_t)m_OverlayDim.width, + (uint32_t)m_OverlayDim.height, + 1, + }; + + vkr = m_pDriver->vkCreateFramebuffer(m_Device, &fbinfo, NULL, &FB); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } + + VkGraphicsPipelineCreateInfo pipeCreateInfo; + + MakeGraphicsPipelineInfo(pipeCreateInfo, state.graphics.pipeline); + + VkPipelineShaderStageCreateInfo stages[3] = { + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_VERTEX_BIT, + m_MeshModules[0], "main", NULL}, + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, + VK_SHADER_STAGE_FRAGMENT_BIT, m_TriSizeFSModule, "main", NULL}, + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, + VK_SHADER_STAGE_GEOMETRY_BIT, m_TriSizeGSModule, "main", NULL}, + }; + + VkPipelineInputAssemblyStateCreateInfo ia = { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; + ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkVertexInputBindingDescription binds[] = {// primary + {0, 0, VK_VERTEX_INPUT_RATE_VERTEX}, + // secondary + {1, 0, VK_VERTEX_INPUT_RATE_VERTEX}}; + + VkVertexInputAttributeDescription vertAttrs[] = { + { + 0, 0, VK_FORMAT_R32G32B32A32_SFLOAT, 0, + }, + { + 1, 0, VK_FORMAT_R32G32B32A32_SFLOAT, 0, + }, + }; + + VkPipelineVertexInputStateCreateInfo vi = { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + NULL, + 0, + 1, + binds, + 2, + vertAttrs, + }; + + VkPipelineColorBlendAttachmentState attState = { + false, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, + 0xf, + }; + + VkPipelineColorBlendStateCreateInfo cb = { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + NULL, + 0, + false, + VK_LOGIC_OP_NO_OP, + 1, + &attState, + {1.0f, 1.0f, 1.0f, 1.0f}}; + + pipeCreateInfo.stageCount = 3; + pipeCreateInfo.pStages = stages; + pipeCreateInfo.pTessellationState = NULL; + pipeCreateInfo.renderPass = RP; + pipeCreateInfo.subpass = 0; + pipeCreateInfo.layout = m_TriSizePipeLayout; + pipeCreateInfo.basePipelineHandle = VK_NULL_HANDLE; + pipeCreateInfo.basePipelineIndex = 0; + pipeCreateInfo.pInputAssemblyState = &ia; + pipeCreateInfo.pVertexInputState = &vi; + pipeCreateInfo.pColorBlendState = &cb; + + typedef std::pair PipeKey; + + map pipes; + + cmd = m_pDriver->GetNextCmd(); + + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + 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_OverlayDim}, + 1, + &clearval, + }; + vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = {0.0f, 0.0f, (float)m_OverlayDim.width, (float)m_OverlayDim.height, + 0.0f, 1.0f}; + vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); + + for(size_t i = 0; i < events.size(); i++) + { + const FetchDrawcall *draw = m_pDriver->GetDrawcall(events[i]); + + for(uint32_t inst = 0; draw && inst < RDCMAX(1U, draw->numInstances); inst++) + { + MeshFormat fmt = GetPostVSBuffers(events[i], inst, eMeshDataStage_GSOut); + if(fmt.buf == ResourceId()) + fmt = GetPostVSBuffers(events[i], inst, eMeshDataStage_VSOut); + + if(fmt.buf != ResourceId()) + { + ia.topology = MakeVkPrimitiveTopology(fmt.topo); + + binds[0].stride = binds[1].stride = fmt.stride; + + PipeKey key = std::make_pair(fmt.stride, fmt.topo); + VkPipeline pipe = pipes[key]; + + if(pipe == VK_NULL_HANDLE) + { + vkr = m_pDriver->vkCreateGraphicsPipelines(m_Device, VK_NULL_HANDLE, 1, + &pipeCreateInfo, NULL, &pipe); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } + + VkBuffer vb = m_pDriver->GetResourceManager()->GetCurrentHandle(fmt.buf); + + VkDeviceSize offs = fmt.offset; + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(vb), &offs); + + pipes[key] = pipe; + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(m_TriSizePipeLayout), 0, 1, + UnwrapPtr(m_TriSizeDescSet), 2, offsets); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(pipe)); + + const VkPipelineDynamicStateCreateInfo *dyn = pipeCreateInfo.pDynamicState; + + for(uint32_t i = 0; dyn && i < dyn->dynamicStateCount; i++) + { + VkDynamicState d = dyn->pDynamicStates[i]; + + if(!state.views.empty() && d == VK_DYNAMIC_STATE_VIEWPORT) + { + vt->CmdSetViewport(Unwrap(cmd), 0, (uint32_t)state.views.size(), &state.views[0]); + } + else if(!state.scissors.empty() && d == VK_DYNAMIC_STATE_SCISSOR) + { + vt->CmdSetScissor(Unwrap(cmd), 0, (uint32_t)state.scissors.size(), + &state.scissors[0]); + } + else if(d == VK_DYNAMIC_STATE_LINE_WIDTH) + { + vt->CmdSetLineWidth(Unwrap(cmd), state.lineWidth); + } + else if(d == VK_DYNAMIC_STATE_DEPTH_BIAS) + { + vt->CmdSetDepthBias(Unwrap(cmd), state.bias.depth, state.bias.biasclamp, + state.bias.slope); + } + else if(d == VK_DYNAMIC_STATE_BLEND_CONSTANTS) + { + vt->CmdSetBlendConstants(Unwrap(cmd), state.blendConst); + } + else if(d == VK_DYNAMIC_STATE_DEPTH_BOUNDS) + { + vt->CmdSetDepthBounds(Unwrap(cmd), state.mindepth, state.maxdepth); + } + else if(d == VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) + { + vt->CmdSetStencilCompareMask(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, + state.back.compare); + vt->CmdSetStencilCompareMask(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, + state.front.compare); + } + else if(d == VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) + { + vt->CmdSetStencilWriteMask(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, state.back.write); + vt->CmdSetStencilWriteMask(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, state.front.write); + } + else if(d == VK_DYNAMIC_STATE_STENCIL_REFERENCE) + { + vt->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_BACK_BIT, state.back.ref); + vt->CmdSetStencilReference(Unwrap(cmd), VK_STENCIL_FACE_FRONT_BIT, state.front.ref); + } + } + + if(fmt.idxByteWidth) + { + VkIndexType idxtype = VK_INDEX_TYPE_UINT16; + if(fmt.idxByteWidth == 4) + idxtype = VK_INDEX_TYPE_UINT32; + + if(fmt.idxbuf != ResourceId()) + { + VkBuffer ib = m_pDriver->GetResourceManager()->GetCurrentHandle(fmt.idxbuf); + + vt->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(ib), fmt.idxoffs, idxtype); + vt->CmdDrawIndexed(Unwrap(cmd), fmt.numVerts, 1, 0, fmt.baseVertex, 0); + } + } + else + { + vt->CmdDraw(Unwrap(cmd), fmt.numVerts, 1, 0, 0); + } + } + } + } + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + + if(depthUsed) + { + m_pDriver->vkDestroyFramebuffer(m_Device, FB, NULL); + m_pDriver->vkDestroyRenderPass(m_Device, RP, NULL); + } + + for(auto it = pipes.begin(); it != pipes.end(); ++it) + m_pDriver->vkDestroyPipeline(m_Device, it->second, NULL); + } + + // restore back to normal + m_pDriver->ReplayLog(0, eventID, eReplay_WithoutDraw); + + // restore state + m_pDriver->m_RenderState = prevstate; + + cmd = m_pDriver->GetNextCmd(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } vkr = vt->EndCommandBuffer(Unwrap(cmd)); RDCASSERTEQUAL(vkr, VK_SUCCESS); diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index b7508ff97..b04cb8f99 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -271,6 +271,13 @@ public: VkPipeline m_QuadResolvePipeline[8]; vector *m_QuadSPIRV; + GPUBuffer m_TriSizeUBO; + VkDescriptorSetLayout m_TriSizeDescSetLayout; + VkDescriptorSet m_TriSizeDescSet; + VkPipelineLayout m_TriSizePipeLayout; + VkShaderModule m_TriSizeGSModule; + VkShaderModule m_TriSizeFSModule; + VkDescriptorSetLayout m_MeshDescSetLayout; VkPipelineLayout m_MeshPipeLayout; VkDescriptorSet m_MeshDescSet; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index a3f0619f1..7c68e3c6c 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1788,6 +1788,7 @@ void VulkanReplay::RenderMesh(uint32_t eventID, const vector &second data->homogenousInput = cfg.position.unproject; data->pointSpriteSize = Vec2f(0.0f, 0.0f); data->displayFormat = MESHDISPLAY_SOLID; + data->rawoutput = 0; GetDebugManager()->m_MeshUBO.Unmap(); @@ -1918,6 +1919,7 @@ void VulkanReplay::RenderMesh(uint32_t eventID, const vector &second data->homogenousInput = cfg.position.unproject; data->pointSpriteSize = Vec2f(0.0f, 0.0f); data->displayFormat = (uint32_t)solidShadeMode; + data->rawoutput = 0; if(solidShadeMode == eShade_Secondary && cfg.second.showAlpha) data->displayFormat = MESHDISPLAY_SECONDARY_ALPHA; @@ -1965,6 +1967,7 @@ void VulkanReplay::RenderMesh(uint32_t eventID, const vector &second data->displayFormat = (uint32_t)eShade_Solid; data->homogenousInput = cfg.position.unproject; data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; GetDebugManager()->m_MeshUBO.Unmap(); @@ -2052,6 +2055,7 @@ void VulkanReplay::RenderMesh(uint32_t eventID, const vector &second data->displayFormat = (uint32_t)eShade_Solid; data->homogenousInput = 0; data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; GetDebugManager()->m_MeshUBO.Unmap(); @@ -2080,6 +2084,7 @@ void VulkanReplay::RenderMesh(uint32_t eventID, const vector &second data->displayFormat = (uint32_t)eShade_Solid; data->homogenousInput = 0; data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; GetDebugManager()->m_MeshUBO.Unmap(); @@ -2100,6 +2105,7 @@ void VulkanReplay::RenderMesh(uint32_t eventID, const vector &second data->displayFormat = (uint32_t)eShade_Solid; data->homogenousInput = 0; data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; GetDebugManager()->m_MeshUBO.Unmap(); @@ -2115,6 +2121,7 @@ void VulkanReplay::RenderMesh(uint32_t eventID, const vector &second data->displayFormat = (uint32_t)eShade_Solid; data->homogenousInput = 0; data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; GetDebugManager()->m_MeshUBO.Unmap(); @@ -2139,6 +2146,7 @@ void VulkanReplay::RenderMesh(uint32_t eventID, const vector &second data->displayFormat = (uint32_t)eShade_Solid; data->homogenousInput = 0; data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; GetDebugManager()->m_MeshUBO.Unmap(); @@ -2576,7 +2584,7 @@ void VulkanReplay::RenderMesh(uint32_t eventID, const vector &second else ModelViewProj = projMat.Mul(camMat); - MeshUBOData uniforms; + MeshUBOData uniforms = {}; uniforms.mvp = ModelViewProj; uniforms.color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f); uniforms.displayFormat = (uint32_t)eShade_Solid; diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index cb2ed7af4..bc99555a0 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -407,6 +407,8 @@ + + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index f7327dd92..179edfd34 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -511,6 +511,12 @@ Resources\glsl + + Resources\glsl + + + Resources\glsl + diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index 95968504a..6d27e208f 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -172,6 +172,40 @@ void ReplayOutput::RefreshOverlay() passEvents = m_pDevice->GetPassEvents(m_EventID); + bool postVSBuffers = false; + bool postVSWholePass = false; + + if(m_Config.m_Type == eOutputType_MeshDisplay && m_OverlayDirty) + { + postVSBuffers = true; + postVSWholePass = m_RenderData.meshDisplay.showWholePass != 0; + } + + if(m_Config.m_Type == eOutputType_TexDisplay) + { + postVSBuffers = m_RenderData.texDisplay.overlay == eTexOverlay_TriangleSizePass || + m_RenderData.texDisplay.overlay == eTexOverlay_TriangleSizeDraw; + postVSWholePass = m_RenderData.texDisplay.overlay == eTexOverlay_TriangleSizePass; + } + + if(postVSBuffers) + { + if(m_Config.m_Type == eOutputType_MeshDisplay) + m_OverlayDirty = false; + + if(draw != NULL && (draw->flags & eDraw_Drawcall)) + { + m_pDevice->InitPostVSBuffers(draw->eventID); + + if(postVSWholePass && !passEvents.empty()) + { + m_pDevice->InitPostVSBuffers(passEvents); + + m_pDevice->ReplayLog(m_EventID, eReplay_WithoutDraw); + } + } + } + if(m_Config.m_Type == eOutputType_TexDisplay && m_RenderData.texDisplay.overlay != eTexOverlay_None) { if(draw && m_pDevice->IsRenderOutput(m_RenderData.texDisplay.texid)) @@ -181,22 +215,9 @@ void ReplayOutput::RefreshOverlay() m_RenderData.texDisplay.overlay, m_EventID, passEvents); m_OverlayDirty = false; } - } - - if(m_Config.m_Type == eOutputType_MeshDisplay && m_OverlayDirty) - { - m_OverlayDirty = false; - - if(draw == NULL || (draw->flags & eDraw_Drawcall) == 0) - return; - - m_pDevice->InitPostVSBuffers(draw->eventID); - - if(m_RenderData.meshDisplay.showWholePass && !passEvents.empty()) + else { - m_pDevice->InitPostVSBuffers(passEvents); - - m_pDevice->ReplayLog(m_EventID, eReplay_WithoutDraw); + m_OverlayResourceId = ResourceId(); } } } @@ -290,7 +311,9 @@ bool ReplayOutput::PickPixel(ResourceId tex, bool customShader, uint32_t x, uint typeHint = eCompType_None; } if((m_RenderData.texDisplay.overlay == eTexOverlay_QuadOverdrawDraw || - m_RenderData.texDisplay.overlay == eTexOverlay_QuadOverdrawPass) && + m_RenderData.texDisplay.overlay == eTexOverlay_QuadOverdrawPass || + m_RenderData.texDisplay.overlay == eTexOverlay_TriangleSizeDraw || + m_RenderData.texDisplay.overlay == eTexOverlay_TriangleSizePass) && m_OverlayResourceId != ResourceId()) { decodeRamp = true; @@ -316,6 +339,21 @@ bool ReplayOutput::PickPixel(ResourceId tex, bool customShader, uint32_t x, uint break; } } + + // decode back into approximate pixel size area + if(m_RenderData.texDisplay.overlay == eTexOverlay_TriangleSizePass || + m_RenderData.texDisplay.overlay == eTexOverlay_TriangleSizeDraw) + { + float bucket = (float)ret->value_i[0]; + + // decode bucket into approximate triangle area + if(bucket <= 0.5f) + ret->value_f[0] = 0.0f; + else if(bucket < 2.0f) + ret->value_f[0] = 16.0f; + else + ret->value_f[0] = -2.5f * logf(1.0f + (bucket - 22.0f) / 20.1f); + } } return true; @@ -388,7 +426,9 @@ void ReplayOutput::DisplayContext() disp.texid = m_CustomShaderResourceId; if((m_RenderData.texDisplay.overlay == eTexOverlay_QuadOverdrawDraw || - m_RenderData.texDisplay.overlay == eTexOverlay_QuadOverdrawPass) && + m_RenderData.texDisplay.overlay == eTexOverlay_QuadOverdrawPass || + m_RenderData.texDisplay.overlay == eTexOverlay_TriangleSizeDraw || + m_RenderData.texDisplay.overlay == eTexOverlay_TriangleSizePass) && m_OverlayResourceId != ResourceId()) disp.texid = m_OverlayResourceId; diff --git a/renderdocui/Interop/Enums.cs b/renderdocui/Interop/Enums.cs index e5de14b33..1947ba3d9 100644 --- a/renderdocui/Interop/Enums.cs +++ b/renderdocui/Interop/Enums.cs @@ -171,6 +171,8 @@ namespace renderdoc ClearBeforeDraw, QuadOverdrawPass, QuadOverdrawDraw, + TriangleSizePass, + TriangleSizeDraw, }; public enum FileType diff --git a/renderdocui/Windows/TextureViewer.Designer.cs b/renderdocui/Windows/TextureViewer.Designer.cs index 46ef5af23..1a76258fb 100644 --- a/renderdocui/Windows/TextureViewer.Designer.cs +++ b/renderdocui/Windows/TextureViewer.Designer.cs @@ -592,7 +592,9 @@ "Clear Before Pass", "Clear Before Draw", "Quad Overdraw (Pass)", - "Quad Overdraw (Draw)"}); + "Quad Overdraw (Draw)", + "Triangle Size (Pass)", + "Triangle Size (Draw)"}); this.overlay.Name = "overlay"; this.overlay.Size = new System.Drawing.Size(121, 25); this.overlay.SelectedIndexChanged += new System.EventHandler(this.overlay_SelectedIndexChanged);