From dd9aff38907642a1efc87902f5fa7515baa8efb9 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 7 Jul 2015 10:02:36 +0200 Subject: [PATCH] Implement right click to pick vertices in the mesh viewer. Refs #139 --- renderdoc/Makefile | 1 + renderdoc/api/replay/renderdoc_replay.h | 1 + renderdoc/core/image_viewer.cpp | 2 + renderdoc/core/replay_proxy.h | 25 ++ renderdoc/data/embedded_files.h | 1 + renderdoc/data/glsl/mesh.comp | 83 +++++ renderdoc/data/hlsl/debugdisplay.hlsl | 91 ----- renderdoc/data/hlsl/mesh.hlsl | 161 +++++++++ renderdoc/data/renderdoc.rc | 2 + renderdoc/data/resource.h | 6 +- renderdoc/driver/d3d11/d3d11_analyse.cpp | 221 +++++++++++- renderdoc/driver/d3d11/d3d11_context_wrap.cpp | 6 +- renderdoc/driver/d3d11/d3d11_debug.cpp | 154 +++++---- renderdoc/driver/d3d11/d3d11_debug.h | 22 +- renderdoc/driver/d3d11/d3d11_replay.cpp | 5 + renderdoc/driver/d3d11/d3d11_replay.h | 1 + renderdoc/driver/gl/gl_debug.cpp | 325 +++++++++++++++--- renderdoc/driver/gl/gl_replay.h | 13 +- renderdoc/renderdoc.vcxproj | 2 + renderdoc/renderdoc.vcxproj.filters | 6 + renderdoc/replay/replay_driver.h | 1 + renderdoc/replay/replay_output.cpp | 20 ++ renderdoc/replay/replay_renderer.h | 1 + renderdocui/Interop/ReplayRenderer.cs | 7 + renderdocui/Windows/BufferViewer.cs | 38 ++ 25 files changed, 975 insertions(+), 220 deletions(-) create mode 100644 renderdoc/data/glsl/mesh.comp create mode 100644 renderdoc/data/hlsl/mesh.hlsl diff --git a/renderdoc/Makefile b/renderdoc/Makefile index a98903d7d..89f2933e6 100644 --- a/renderdoc/Makefile +++ b/renderdoc/Makefile @@ -50,6 +50,7 @@ data/glsl/generic.verto \ data/glsl/mesh.verto \ data/glsl/mesh.frago \ data/glsl/mesh.geomo \ +data/glsl/mesh.compo \ data/glsl/text.verto \ data/glsl/text.frago \ data/glsl/quadoverdraw.frago \ diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index f5647e7a6..3398765df 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -116,6 +116,7 @@ extern "C" RENDERDOC_API void RENDERDOC_CC ReplayOutput_DisablePixelContext(Repl extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_PickPixel(ReplayOutput *output, ResourceId texID, bool32 customShader, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *val); +extern "C" RENDERDOC_API uint32_t RENDERDOC_CC ReplayOutput_PickVertex(ReplayOutput *output, uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y); #ifdef RENDERDOC_EXPORTS struct ReplayRenderer; diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 5e5dd1bf1..41af204db 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -89,6 +89,8 @@ class ImageViewer : public IReplayDriver bool RenderTexture(TextureDisplay cfg) { return m_Proxy->RenderTexture(cfg); } void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, float pixel[4]) { m_Proxy->PickPixel(texture, x, y, sliceFace, mip, sample, pixel); } + uint32_t PickVertex(uint32_t frameID, uint32_t eventID, MeshDisplay cfg, uint32_t x, uint32_t y) + { return m_Proxy->PickVertex(frameID, eventID, cfg, x, y); } void BuildCustomShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) { m_Proxy->BuildCustomShader(source, entry, compileFlags, type, id, errors); } void FreeCustomShader(ResourceId id) { m_Proxy->FreeTargetResource(id); } diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index 7d9fbc16c..9febf997f 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -254,6 +254,31 @@ class ProxySerialiser : public IReplayDriver, Callstack::StackResolver m_Proxy->RenderMesh(frameID, eventID, secDraws, cfg); } } + + uint32_t PickVertex(uint32_t frameID, uint32_t eventID, MeshDisplay cfg, uint32_t x, uint32_t y) + { + if(m_Proxy && cfg.position.buf != ResourceId()) + { + EnsureBufCached(cfg.position.buf); + cfg.position.buf = m_ProxyBufferIds[cfg.position.buf]; + + if(cfg.second.buf != ResourceId()) + { + EnsureBufCached(cfg.second.buf); + cfg.second.buf = m_ProxyBufferIds[cfg.second.buf]; + } + + if(cfg.position.idxbuf != ResourceId()) + { + EnsureBufCached(cfg.position.idxbuf); + cfg.position.idxbuf = m_ProxyBufferIds[cfg.position.idxbuf]; + } + + return m_Proxy->PickVertex(frameID, eventID, cfg, x, y); + } + + return ~0U; + } void BuildCustomShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) { diff --git a/renderdoc/data/embedded_files.h b/renderdoc/data/embedded_files.h index 3152937fc..66e20d002 100644 --- a/renderdoc/data/embedded_files.h +++ b/renderdoc/data/embedded_files.h @@ -40,6 +40,7 @@ DECLARE_EMBED(arraymscopy_comp); DECLARE_EMBED(mesh_vert); DECLARE_EMBED(mesh_frag); DECLARE_EMBED(mesh_geom); +DECLARE_EMBED(mesh_comp); DECLARE_EMBED(generic_vert); DECLARE_EMBED(generic_frag); DECLARE_EMBED(text_frag); diff --git a/renderdoc/data/glsl/mesh.comp b/renderdoc/data/glsl/mesh.comp new file mode 100644 index 000000000..faec37d1f --- /dev/null +++ b/renderdoc/data/glsl/mesh.comp @@ -0,0 +1,83 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2015 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. + ******************************************************************************/ + +#version 420 core + +#extension GL_ARB_compute_shader : require +#extension GL_ARB_shader_storage_buffer_object : require + +layout(binding = 0) uniform atomic_uint pickresult_counter; +layout(binding = 0) writeonly buffer pickresult_buffer +{ + uvec4 results[]; +} pickresult; + +layout(binding = 1) readonly buffer vertex_data +{ + vec4 data[]; +} vb; + +layout(binding = 2) readonly buffer index_data +{ + uint data[]; +} ib; + + +uniform vec2 PickCoords; +uniform vec2 PickViewport; + +uniform mat4 PickMVP; + +uniform uint PickIdx; +uniform uint PickNumVerts; + +layout (local_size_x = 1024, local_size_y = 1) in; + +void main() +{ + uvec3 tid = gl_GlobalInvocationID; + + uint vertid = tid.x; + + if(vertid >= PickNumVerts) + return; + + uint idx = PickIdx != 0 ? ib.data[vertid] : vertid; + + vec4 pos = vb.data[idx]; + + vec4 wpos = PickMVP * pos; + + wpos.xyz /= wpos.www; + + vec2 scr = (wpos.xy*vec2(1.0f, -1.0f) + 1.0f) * 0.5f * PickViewport; + + // close to target co-ords? add to list + float len = length(scr - PickCoords); + if(len < 35.0f) + { + uint result_idx = atomicCounterIncrement(pickresult_counter); + pickresult.results[result_idx] = uvec4(vertid, idx, floatBitsToUint(len), floatBitsToUint(wpos.z)); + } +} \ No newline at end of file diff --git a/renderdoc/data/hlsl/debugdisplay.hlsl b/renderdoc/data/hlsl/debugdisplay.hlsl index c47e24372..9e5b34c8a 100644 --- a/renderdoc/data/hlsl/debugdisplay.hlsl +++ b/renderdoc/data/hlsl/debugdisplay.hlsl @@ -188,97 +188,6 @@ struct wireframeV2F float4 secondary : Secondary; }; -struct meshA2V -{ - float4 pos : pos; - float4 secondary : sec; -}; - -wireframeV2F RENDERDOC_WireframeHomogVS(meshA2V IN, uint vid : SV_VertexID) -{ - wireframeV2F OUT = (wireframeV2F)0; - OUT.pos = mul(IN.pos, ModelViewProj); - - float2 psprite[4] = - { - float2(-1.0f, -1.0f), - float2(-1.0f, 1.0f), - float2( 1.0f, -1.0f), - float2( 1.0f, 1.0f) - }; - - OUT.pos.xy += SpriteSize.xy*0.01f*psprite[vid%4]*OUT.pos.w; - OUT.secondary = IN.secondary; - - return OUT; -} - -wireframeV2F RENDERDOC_MeshVS(meshA2V IN, uint vid : SV_VertexID) -{ - wireframeV2F OUT = (wireframeV2F)0; - - OUT.pos = mul(float4(IN.pos.xyz, 1), ModelViewProj); - OUT.norm = float3(0, 0, 1); - OUT.secondary = IN.secondary; - - return OUT; -} - -[maxvertexcount(3)] -void RENDERDOC_MeshGS(triangle wireframeV2F input[3], inout TriangleStream TriStream) -{ - wireframeV2F output; - - float4 faceEdgeA = mul(input[1].pos, InvProj) - mul(input[0].pos, InvProj); - float4 faceEdgeB = mul(input[2].pos, InvProj) - mul(input[0].pos, InvProj); - float3 faceNormal = normalize( cross(faceEdgeA.xyz, faceEdgeB.xyz) ); - - for(int i=0; i<3; i++) - { - output.pos = input[i].pos; - output.norm = faceNormal; - output.secondary = input[i].secondary; - TriStream.Append(output); - } - TriStream.RestartStrip(); -} - -float4 RENDERDOC_MeshPS(wireframeV2F IN) : SV_Target0 -{ - uint type = OutputDisplayFormat; - - if(type == MESHDISPLAY_SECONDARY) - return float4(IN.secondary.xyz, 1); - else if(type == MESHDISPLAY_SECONDARY_ALPHA) - return float4(IN.secondary.www, 1); - else if(type == MESHDISPLAY_FACELIT) - { - float3 lightDir = normalize(float3(0, -0.3f, -1)); - - return float4(WireframeColour.xyz*abs(dot(lightDir, IN.norm)), 1); - } - else //if(type == MESHDISPLAY_SOLID) - return float4(WireframeColour.xyz, 1); -} - -wireframeV2F RENDERDOC_WireframeVS(float3 pos : POSITION, uint vid : SV_VertexID) -{ - wireframeV2F OUT = (wireframeV2F)0; - OUT.pos = mul(float4(pos, 1), ModelViewProj); - - float2 psprite[4] = - { - float2(-1.0f, -1.0f), - float2(-1.0f, 1.0f), - float2( 1.0f, -1.0f), - float2( 1.0f, 1.0f) - }; - - OUT.pos.xy += SpriteSize.xy*0.01f*psprite[vid%4]*OUT.pos.w; - - return OUT; -} - wireframeV2F RENDERDOC_FullscreenVS(uint id : SV_VertexID) { wireframeV2F OUT = (wireframeV2F)0; diff --git a/renderdoc/data/hlsl/mesh.hlsl b/renderdoc/data/hlsl/mesh.hlsl new file mode 100644 index 000000000..6a0f9fd2d --- /dev/null +++ b/renderdoc/data/hlsl/mesh.hlsl @@ -0,0 +1,161 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2015 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. + ******************************************************************************/ + +struct wireframeV2F +{ + float4 pos : SV_Position; + float3 norm : Normal; + float4 secondary : Secondary; +}; + +struct meshA2V +{ + float4 pos : pos; + float4 secondary : sec; +}; + +wireframeV2F RENDERDOC_WireframeHomogVS(meshA2V IN, uint vid : SV_VertexID) +{ + wireframeV2F OUT = (wireframeV2F)0; + OUT.pos = mul(IN.pos, ModelViewProj); + + float2 psprite[4] = + { + float2(-1.0f, -1.0f), + float2(-1.0f, 1.0f), + float2( 1.0f, -1.0f), + float2( 1.0f, 1.0f) + }; + + OUT.pos.xy += SpriteSize.xy*0.01f*psprite[vid%4]*OUT.pos.w; + OUT.secondary = IN.secondary; + + return OUT; +} + +wireframeV2F RENDERDOC_MeshVS(meshA2V IN, uint vid : SV_VertexID) +{ + wireframeV2F OUT = (wireframeV2F)0; + + OUT.pos = mul(float4(IN.pos.xyz, 1), ModelViewProj); + OUT.norm = float3(0, 0, 1); + OUT.secondary = IN.secondary; + + return OUT; +} + +[maxvertexcount(3)] +void RENDERDOC_MeshGS(triangle wireframeV2F input[3], inout TriangleStream TriStream) +{ + wireframeV2F output; + + float4 faceEdgeA = mul(input[1].pos, InvProj) - mul(input[0].pos, InvProj); + float4 faceEdgeB = mul(input[2].pos, InvProj) - mul(input[0].pos, InvProj); + float3 faceNormal = normalize( cross(faceEdgeA.xyz, faceEdgeB.xyz) ); + + for(int i=0; i<3; i++) + { + output.pos = input[i].pos; + output.norm = faceNormal; + output.secondary = input[i].secondary; + TriStream.Append(output); + } + TriStream.RestartStrip(); +} + +float4 RENDERDOC_MeshPS(wireframeV2F IN) : SV_Target0 +{ + uint type = OutputDisplayFormat; + + if(type == MESHDISPLAY_SECONDARY) + return float4(IN.secondary.xyz, 1); + else if(type == MESHDISPLAY_SECONDARY_ALPHA) + return float4(IN.secondary.www, 1); + else if(type == MESHDISPLAY_FACELIT) + { + float3 lightDir = normalize(float3(0, -0.3f, -1)); + + return float4(WireframeColour.xyz*abs(dot(lightDir, IN.norm)), 1); + } + else //if(type == MESHDISPLAY_SOLID) + return float4(WireframeColour.xyz, 1); +} + +wireframeV2F RENDERDOC_WireframeVS(float3 pos : POSITION, uint vid : SV_VertexID) +{ + wireframeV2F OUT = (wireframeV2F)0; + OUT.pos = mul(float4(pos, 1), ModelViewProj); + + float2 psprite[4] = + { + float2(-1.0f, -1.0f), + float2(-1.0f, 1.0f), + float2( 1.0f, -1.0f), + float2( 1.0f, 1.0f) + }; + + OUT.pos.xy += SpriteSize.xy*0.01f*psprite[vid%4]*OUT.pos.w; + + return OUT; +} + +Buffer index : register(t0); +Buffer vertex : register(t1); +AppendStructuredBuffer pickresult : register(u0); + +cbuffer MeshPickData : register(b0) +{ + float2 PickCoords; + float2 PickViewport; + + row_major float4x4 PickMVP; + + uint PickIdx; + uint PickNumVerts; + uint2 PickPadding; +}; + +[numthreads(1024, 1, 1)] +void RENDERDOC_MeshPickCS(uint3 tid : SV_DispatchThreadID) +{ + uint vertid = tid.x; + + if(vertid >= PickNumVerts) + return; + + uint idx = PickIdx ? index[vertid] : vertid; + + float4 pos = vertex[idx]; + + float4 wpos = mul(pos, PickMVP); + + wpos.xyz /= wpos.w; + + float2 scr = (wpos.xy*float2(1.0f, -1.0f) + 1.0f) * 0.5f * PickViewport; + + // close to target co-ords? add to list + float len = length(scr - PickCoords); + if(len < 25.0f) + pickresult.Append(uint4(vertid, idx, asuint(len), asuint(wpos.z))); +} \ No newline at end of file diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc index b1f5e758e..f0eb2bd71 100644 --- a/renderdoc/data/renderdoc.rc +++ b/renderdoc/data/renderdoc.rc @@ -108,6 +108,7 @@ RESOURCE_debugcommon_hlsl TYPE_EMBED "hlsl/debugcommon.hlsl" RESOURCE_histogram_hlsl TYPE_EMBED "hlsl/histogram.hlsl" RESOURCE_debugcbuffers_h TYPE_EMBED "hlsl/debugcbuffers.h" RESOURCE_multisample_hlsl TYPE_EMBED "hlsl/multisample.hlsl" +RESOURCE_mesh_hlsl TYPE_EMBED "hlsl/mesh.hlsl" RESOURCE_blit_vert TYPE_EMBED "glsl/blit.vert" RESOURCE_blit_frag TYPE_EMBED "glsl/blit.frag" @@ -123,6 +124,7 @@ RESOURCE_texsample_h TYPE_EMBED "glsl/texsample.h" RESOURCE_histogram_comp TYPE_EMBED "glsl/histogram.comp" RESOURCE_mesh_frag TYPE_EMBED "glsl/mesh.frag" RESOURCE_mesh_geom TYPE_EMBED "glsl/mesh.geom" +RESOURCE_mesh_comp TYPE_EMBED "glsl/mesh.comp" RESOURCE_arraymscopy_comp TYPE_EMBED "glsl/arraymscopy.comp" RESOURCE_quadoverdraw_frag TYPE_EMBED "glsl/quadoverdraw.frag" diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h index f25cecaa3..3dd800363 100644 --- a/renderdoc/data/resource.h +++ b/renderdoc/data/resource.h @@ -10,6 +10,7 @@ #define RESOURCE_debugcommon_hlsl 104 #define RESOURCE_histogram_hlsl 105 #define RESOURCE_multisample_hlsl 106 +#define RESOURCE_mesh_hlsl 107 #define RESOURCE_blit_vert 201 #define RESOURCE_blit_frag 202 @@ -25,8 +26,9 @@ #define RESOURCE_histogram_comp 212 #define RESOURCE_mesh_frag 213 #define RESOURCE_mesh_geom 214 -#define RESOURCE_arraymscopy_comp 215 -#define RESOURCE_quadoverdraw_frag 216 +#define RESOURCE_mesh_comp 215 +#define RESOURCE_arraymscopy_comp 216 +#define RESOURCE_quadoverdraw_frag 217 #define RESOURCE_sourcecodepro_ttf 301 diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp index b90c27871..d8ca7ea27 100644 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -24,6 +24,8 @@ #include "maths/vec.h" +#include "maths/matrix.h" +#include "maths/camera.h" #include "d3d11_manager.h" #include "d3d11_context.h" #include "d3d11_debug.h" @@ -570,7 +572,7 @@ void D3D11DebugManager::CreateShaderGlobalState(ShaderDebug::GlobalState &global { if(WrappedID3D11Buffer::IsAlloc(res)) { - global.uavs[dsti].data = GetBufferData((ID3D11Buffer *)res, 0, 0); + global.uavs[dsti].data = GetBufferData((ID3D11Buffer *)res, 0, 0, true); } else { @@ -753,7 +755,7 @@ void D3D11DebugManager::CreateShaderGlobalState(ShaderDebug::GlobalState &global { if(WrappedID3D11Buffer::IsAlloc(res)) { - global.srvs[i].data = GetBufferData((ID3D11Buffer *)res, 0, 0); + global.srvs[i].data = GetBufferData((ID3D11Buffer *)res, 0, 0, true); } } @@ -878,8 +880,8 @@ ShaderDebugTrace D3D11DebugManager::DebugVertex(uint32_t frameID, uint32_t event UINT i = *it; if(rs->IA.VBs[i]) { - vertData[i] = GetBufferData(rs->IA.VBs[i], rs->IA.Offsets[i] + rs->IA.Strides[i]*(vertOffset+idx), rs->IA.Strides[i]); - instData[i] = GetBufferData(rs->IA.VBs[i], rs->IA.Offsets[i] + rs->IA.Strides[i]*(instOffset+instid), rs->IA.Strides[i]); + vertData[i] = GetBufferData(rs->IA.VBs[i], rs->IA.Offsets[i] + rs->IA.Strides[i]*(vertOffset+idx), rs->IA.Strides[i], true); + instData[i] = GetBufferData(rs->IA.VBs[i], rs->IA.Offsets[i] + rs->IA.Strides[i]*(instOffset+instid), rs->IA.Strides[i], true); } } @@ -887,7 +889,7 @@ ShaderDebugTrace D3D11DebugManager::DebugVertex(uint32_t frameID, uint32_t event for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) if(rs->VS.ConstantBuffers[i]) - cbufData[i] = GetBufferData(rs->VS.ConstantBuffers[i], rs->VS.CBOffsets[i]*sizeof(Vec4f), 0); + cbufData[i] = GetBufferData(rs->VS.ConstantBuffers[i], rs->VS.CBOffsets[i]*sizeof(Vec4f), 0, true); ShaderDebugTrace ret; @@ -1498,7 +1500,7 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t frameID, uint32_t eventI for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) if(rs->PS.ConstantBuffers[i]) - cbufData[i] = GetBufferData(rs->PS.ConstantBuffers[i], rs->PS.CBOffsets[i]*sizeof(Vec4f), 0); + cbufData[i] = GetBufferData(rs->PS.ConstantBuffers[i], rs->PS.CBOffsets[i]*sizeof(Vec4f), 0, true); D3D11_COMPARISON_FUNC depthFunc = D3D11_COMPARISON_LESS; @@ -1757,7 +1759,7 @@ ShaderDebugTrace D3D11DebugManager::DebugThread(uint32_t frameID, uint32_t event for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++) if(rs->CS.ConstantBuffers[i]) - cbufData[i] = GetBufferData(rs->CS.ConstantBuffers[i], rs->CS.CBOffsets[i]*sizeof(Vec4f), 0); + cbufData[i] = GetBufferData(rs->CS.ConstantBuffers[i], rs->CS.CBOffsets[i]*sizeof(Vec4f), 0, true); ShaderDebugTrace ret; @@ -1790,6 +1792,211 @@ ShaderDebugTrace D3D11DebugManager::DebugThread(uint32_t frameID, uint32_t event return ret; } +uint32_t D3D11DebugManager::PickVertex(uint32_t frameID, uint32_t eventID, MeshDisplay cfg, uint32_t x, uint32_t y) +{ + D3D11RenderStateTracker tracker(m_WrappedContext); + + struct MeshPickData + { + Vec2f PickCoords; + Vec2f PickViewport; + + Matrix4f PickMVP; + + uint32_t PickIdx; + uint32_t PickNumVerts; + uint32_t PickPadding[2]; + } cbuf; + + cbuf.PickCoords = Vec2f((float)x, (float)y); + cbuf.PickViewport = Vec2f((float)GetWidth(), (float)GetHeight()); + cbuf.PickIdx = cfg.position.idxByteWidth ? 1 : 0; + cbuf.PickNumVerts = cfg.position.numVerts; + + Matrix4f projMat = Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, float(GetWidth())/float(GetHeight())); + + Camera cam; + if(cfg.arcballCamera) + cam.Arcball(Vec3f(cfg.cameraPos.x, cfg.cameraPos.y, cfg.cameraPos.z), cfg.cameraPos.w, Vec3f(cfg.cameraRot.x, cfg.cameraRot.y, cfg.cameraRot.z)); + else + cam.fpsLook(Vec3f(cfg.cameraPos.x, cfg.cameraPos.y, cfg.cameraPos.z), Vec3f(cfg.cameraRot.x, cfg.cameraRot.y, cfg.cameraRot.z)); + + Matrix4f camMat = cam.GetMatrix(); + cbuf.PickMVP = projMat.Mul(camMat); + + ResourceFormat resFmt; + resFmt.compByteWidth = cfg.position.compByteWidth; + resFmt.compCount = cfg.position.compCount; + resFmt.compType = cfg.position.compType; + resFmt.special = false; + if(cfg.position.specialFormat != eSpecial_Unknown) + { + resFmt.special = true; + resFmt.specialFormat = cfg.position.specialFormat; + } + + if(cfg.position.unproject) + { + // the derivation of the projection matrix might not be right (hell, it could be an + // orthographic projection). But it'll be close enough likely. + Matrix4f guessProj = Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect); + + if(cfg.ortho) + guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); + + cbuf.PickMVP = projMat.Mul(camMat.Mul(guessProj.Inverse())); + } + + ID3D11Buffer *vb, *ib; + DXGI_FORMAT ifmt = cfg.position.idxByteWidth == 4 ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; + + { + auto it = WrappedID3D11Buffer::m_BufferList.find(cfg.position.buf); + + if(it != WrappedID3D11Buffer::m_BufferList.end()) + vb = UNWRAP(WrappedID3D11Buffer, it->second.m_Buffer); + + it = WrappedID3D11Buffer::m_BufferList.find(cfg.position.idxbuf); + + if(it != WrappedID3D11Buffer::m_BufferList.end()) + ib = UNWRAP(WrappedID3D11Buffer, it->second.m_Buffer); + } + + // most IB/VBs will not be available as SRVs. So, we copy into our own buffers. + // In the case of VB we also tightly pack and unpack the data. IB can just be + // read as R16 or R32 via the SRV so it is just a straight copy + + if(cfg.position.idxByteWidth) + { + // resize up on demand + if(m_DebugRender.PickIBBuf == NULL || m_DebugRender.PickIBSize < cfg.position.numVerts*cfg.position.idxByteWidth) + { + SAFE_RELEASE(m_DebugRender.PickIBBuf); + SAFE_RELEASE(m_DebugRender.PickIBSRV); + + D3D11_BUFFER_DESC desc = { cfg.position.numVerts*cfg.position.idxByteWidth, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, 0 }; + + m_DebugRender.PickIBSize = cfg.position.numVerts*cfg.position.idxByteWidth; + + m_pDevice->CreateBuffer(&desc, NULL, &m_DebugRender.PickIBBuf); + + D3D11_SHADER_RESOURCE_VIEW_DESC sdesc; + sdesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + sdesc.Format = ifmt; + sdesc.Buffer.FirstElement = 0; + sdesc.Buffer.NumElements = cfg.position.numVerts; + + m_pDevice->CreateShaderResourceView(m_DebugRender.PickIBBuf, &sdesc, &m_DebugRender.PickIBSRV); + } + + // copy index data as-is, the view format will take care of the rest + + D3D11_BOX box; + box.front = 0; + box.back = 1; + box.left = cfg.position.idxoffs; + box.right = cfg.position.idxoffs + cfg.position.numVerts*cfg.position.idxByteWidth; + box.top = 0; + box.bottom = 1; + + m_pImmediateContext->CopySubresourceRegion(m_DebugRender.PickIBBuf, 0, 0, 0, 0, ib, 0, &box); + } + + if(m_DebugRender.PickVBBuf == NULL || m_DebugRender.PickVBSize < cfg.position.numVerts*sizeof(Vec4f)) + { + SAFE_RELEASE(m_DebugRender.PickVBBuf); + SAFE_RELEASE(m_DebugRender.PickVBSRV); + + D3D11_BUFFER_DESC desc = { cfg.position.numVerts*sizeof(Vec4f), D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, 0 }; + + m_DebugRender.PickVBSize = cfg.position.numVerts*sizeof(Vec4f); + + m_pDevice->CreateBuffer(&desc, NULL, &m_DebugRender.PickVBBuf); + + D3D11_SHADER_RESOURCE_VIEW_DESC sdesc; + sdesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + sdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + sdesc.Buffer.FirstElement = 0; + sdesc.Buffer.NumElements = cfg.position.numVerts; + + m_pDevice->CreateShaderResourceView(m_DebugRender.PickVBBuf, &sdesc, &m_DebugRender.PickVBSRV); + } + + // unpack and linearise the data + { + FloatVector *vbData = new FloatVector[cfg.position.numVerts]; + + vector oldData = GetBufferData(vb, cfg.position.offset, 0, false); + + byte *data = &oldData[0]; + byte *dataEnd = data + oldData.size(); + + bool valid; + + for(uint32_t i=0; i < cfg.position.numVerts; i++) + vbData[i] = InterpretVertex(data, i, cfg, dataEnd, false, valid); + + m_pImmediateContext->UpdateSubresource(m_DebugRender.PickVBBuf, 0, NULL, vbData, sizeof(Vec4f), sizeof(Vec4f)); + + delete[] vbData; + } + + ID3D11ShaderResourceView *srvs[2] = { m_DebugRender.PickIBSRV, m_DebugRender.PickVBSRV }; + + ID3D11Buffer *buf = MakeCBuffer((float *)&cbuf, sizeof(cbuf)); + + m_pImmediateContext->CSSetConstantBuffers(0, 1, &buf); + + m_pImmediateContext->CSSetShaderResources(0, 2, srvs); + + UINT reset = 0; + m_pImmediateContext->CSSetUnorderedAccessViews(0, 1, &m_DebugRender.PickResultUAV, &reset); + + m_pImmediateContext->CSSetShader(m_DebugRender.MeshPickCS, NULL, 0); + + m_pImmediateContext->Dispatch(cfg.position.numVerts/1024 + 1, 1, 1); + + m_pImmediateContext->CopyStructureCount(m_DebugRender.histogramBuff, 0, m_DebugRender.PickResultUAV); + + vector results = GetBufferData(m_DebugRender.histogramBuff, 0, 0, false); + + uint32_t numResults = *(uint32_t *)&results[0]; + + if(numResults > 0) + { + results = GetBufferData(m_DebugRender.PickResultBuf, 0, 0, false); + + struct PickResult + { + uint32_t vertid; uint32_t idx; float len; float depth; + }; + + PickResult *pickResults = (PickResult *)&results[0]; + + PickResult *closest = pickResults; + + // min with size of results buffer to protect against overflows + for(uint32_t i=1; i < RDCMIN(DebugRenderData::maxMeshPicks, numResults); i++) + { + // We need to keep the picking order consistent in the face + // of random buffer appends, when multiple vertices have the + // identical position (e.g. if UVs or normals are different). + // + // We could do something to try and disambiguate, but it's + // never going to be intuitive, it's just going to flicker + // confusingly. + if(pickResults[i].len < closest->len || + (pickResults[i].len == closest->len && pickResults[i].depth < closest->depth) || + (pickResults[i].len == closest->len && pickResults[i].depth == closest->depth && pickResults[i].vertid < closest->vertid)) + closest = pickResults+i; + } + + return closest->vertid; + } + + return ~0U; +} + void D3D11DebugManager::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, float pixel[4]) { m_pImmediateContext->OMSetRenderTargets(1, &m_DebugRender.PickPixelRT, NULL); diff --git a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp index c44cb1293..1c19075fc 100644 --- a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp @@ -3789,7 +3789,7 @@ bool WrappedID3D11DeviceContext::Serialise_DrawIndexedInstancedIndirect(ID3D11Bu { ID3D11Buffer *argBuffer = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(BufferForArgs); - vector args = m_pDevice->GetDebugManager()->GetBufferData(argBuffer, AlignedByteOffsetForArgs, 5*sizeof(uint32_t)); + vector args = m_pDevice->GetDebugManager()->GetBufferData(argBuffer, AlignedByteOffsetForArgs, 5*sizeof(uint32_t), true); uint32_t *uargs = (uint32_t *)&args[0]; name = "DrawIndexedInstancedIndirect(<" + ToStr::Get(uargs[0]) @@ -3864,7 +3864,7 @@ bool WrappedID3D11DeviceContext::Serialise_DrawInstancedIndirect(ID3D11Buffer *p { ID3D11Buffer *argBuffer = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(BufferForArgs); - vector args = m_pDevice->GetDebugManager()->GetBufferData(argBuffer, AlignedByteOffsetForArgs, 4*sizeof(uint32_t)); + vector args = m_pDevice->GetDebugManager()->GetBufferData(argBuffer, AlignedByteOffsetForArgs, 4*sizeof(uint32_t), true); uint32_t *uargs = (uint32_t *)&args[0]; name = "DrawInstancedIndirect(<" + ToStr::Get(uargs[0]) @@ -4555,7 +4555,7 @@ bool WrappedID3D11DeviceContext::Serialise_DispatchIndirect(ID3D11Buffer *pBuffe { ID3D11Buffer *argBuffer = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetLiveResource(BufferForArgs); - vector args = m_pDevice->GetDebugManager()->GetBufferData(argBuffer, AlignedByteOffsetForArgs, 5*sizeof(uint32_t)); + vector args = m_pDevice->GetDebugManager()->GetBufferData(argBuffer, AlignedByteOffsetForArgs, 5*sizeof(uint32_t), true); uint32_t *uargs = (uint32_t *)&args[0]; name = "DispatchIndirect(<" + ToStr::Get(uargs[0]) diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index e079a9b02..02f695917 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -771,6 +771,8 @@ bool D3D11DebugManager::InitDebugRendering() displayhlsl += GetEmbeddedResource(debugcommon_hlsl); displayhlsl += GetEmbeddedResource(debugdisplay_hlsl); + string meshhlsl = GetEmbeddedResource(debugcbuffers_h) + GetEmbeddedResource(mesh_hlsl); + m_DebugRender.FullscreenVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_FullscreenVS", "vs_4_0"); if(RenderDoc::Inst().IsReplayApp()) @@ -789,10 +791,10 @@ bool D3D11DebugManager::InitDebugRendering() m_DebugRender.GenericVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_DebugVS", "vs_4_0"); m_DebugRender.TexDisplayPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_TexDisplayPS", "ps_5_0"); - m_DebugRender.WireframeVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_WireframeVS", "vs_4_0", 1, &inputDesc, &m_DebugRender.GenericLayout); - m_DebugRender.MeshVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_MeshVS", "vs_4_0", 0, NULL, NULL, &bytecode); - m_DebugRender.MeshGS = MakeGShader(displayhlsl.c_str(), "RENDERDOC_MeshGS", "gs_4_0"); - m_DebugRender.MeshPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_MeshPS", "ps_4_0"); + m_DebugRender.WireframeVS = MakeVShader(meshhlsl.c_str(), "RENDERDOC_WireframeVS", "vs_4_0", 1, &inputDesc, &m_DebugRender.GenericLayout); + m_DebugRender.MeshVS = MakeVShader(meshhlsl.c_str(), "RENDERDOC_MeshVS", "vs_4_0", 0, NULL, NULL, &bytecode); + 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.MeshVSBytecode = new byte[bytecode.size()]; m_DebugRender.MeshVSBytelen = (uint32_t)bytecode.size(); @@ -816,7 +818,7 @@ bool D3D11DebugManager::InitDebugRendering() inputDescHomog[1].AlignedByteOffset = 0; inputDescHomog[1].InstanceDataStepRate = 0; - m_DebugRender.WireframeHomogVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_WireframeHomogVS", "vs_4_0", 2, inputDescHomog, &m_DebugRender.GenericHomogLayout, &bytecode); + m_DebugRender.WireframeHomogVS = MakeVShader(meshhlsl.c_str(), "RENDERDOC_WireframeHomogVS", "vs_4_0", 2, inputDescHomog, &m_DebugRender.GenericHomogLayout, &bytecode); m_DebugRender.MeshHomogVSBytecode = new byte[bytecode.size()]; m_DebugRender.MeshHomogVSBytelen = (uint32_t)bytecode.size(); @@ -833,6 +835,8 @@ bool D3D11DebugManager::InitDebugRendering() m_DebugRender.PixelHistoryCopyCS = MakeCShader(displayhlsl.c_str(), "RENDERDOC_PixelHistoryCopyPixel", "cs_5_0"); m_DebugRender.PrimitiveIDPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_PrimitiveIDPS", "ps_5_0"); + m_DebugRender.MeshPickCS = MakeCShader(meshhlsl.c_str(), "RENDERDOC_MeshPickCS", "cs_5_0"); + string histogramhlsl = GetEmbeddedResource(debugcbuffers_h); histogramhlsl += GetEmbeddedResource(debugcommon_hlsl); histogramhlsl += GetEmbeddedResource(histogram_hlsl); @@ -1215,6 +1219,34 @@ bool D3D11DebugManager::InitDebugRendering() if(FAILED(hr)) RDCERR("Failed to create result stage buff %08x", hr); + + bDesc.ByteWidth = sizeof(Vec4f)*DebugRenderData::maxMeshPicks; + bDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; + bDesc.CPUAccessFlags = 0; + bDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + bDesc.StructureByteStride = sizeof(Vec4f); + bDesc.Usage = D3D11_USAGE_DEFAULT; + + hr = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.PickResultBuf); + + if(FAILED(hr)) + RDCERR("Failed to create mesh pick result buff %08x", hr); + + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.NumElements = DebugRenderData::maxMeshPicks; + uavDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_APPEND; + + hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.PickResultBuf, &uavDesc, &m_DebugRender.PickResultUAV); + + if(FAILED(hr)) + RDCERR("Failed to create mesh pick result UAV %08x", hr); + + // created/sized on demand + m_DebugRender.PickIBBuf = m_DebugRender.PickVBBuf = NULL; + m_DebugRender.PickIBSRV = m_DebugRender.PickVBSRV = NULL; + m_DebugRender.PickIBSize = m_DebugRender.PickVBSize = 0; } if(RenderDoc::Inst().IsReplayApp()) @@ -2099,10 +2131,10 @@ vector D3D11DebugManager::GetBufferData(ResourceId buff, uint32_t offset, RDCASSERT(buffer); - return GetBufferData(buffer, offset, len); + return GetBufferData(buffer, offset, len, true); } -vector D3D11DebugManager::GetBufferData(ID3D11Buffer *buffer, uint32_t offset, uint32_t len) +vector D3D11DebugManager::GetBufferData(ID3D11Buffer *buffer, uint32_t offset, uint32_t len, bool unwrap) { D3D11_MAPPED_SUBRESOURCE mapped; @@ -2135,7 +2167,7 @@ vector D3D11DebugManager::GetBufferData(ID3D11Buffer *buffer, uint32_t off box.front = 0; box.back = 1; - ID3D11Buffer *src = UNWRAP(WrappedID3D11Buffer, buffer); + ID3D11Buffer *src = unwrap ? UNWRAP(WrappedID3D11Buffer, buffer) : buffer; while(len > 0) { @@ -3911,7 +3943,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) ID3D11Buffer *origBuf = idxBuf; - vector idxdata = GetBufferData(idxBuf, idxOffs + drawcall->indexOffset*bytesize, drawcall->numIndices*bytesize); + vector idxdata = GetBufferData(idxBuf, idxOffs + drawcall->indexOffset*bytesize, drawcall->numIndices*bytesize, true); SAFE_RELEASE(idxBuf); @@ -4454,11 +4486,11 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) } } -FloatVector D3D11DebugManager::InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool &valid) +FloatVector D3D11DebugManager::InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool useidx, bool &valid) { FloatVector ret(0.0f, 0.0f, 0.0f, 1.0f); - if(m_HighlightCache.useidx) + if(useidx && m_HighlightCache.useidx) { if(vert >= (uint32_t)m_HighlightCache.indices.size()) { @@ -4966,7 +4998,7 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec primTopo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; } - activeVertex = InterpretVertex(data, idx, cfg, dataEnd, valid); + activeVertex = InterpretVertex(data, idx, cfg, dataEnd, true, valid); // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx for // how primitive topologies are laid out @@ -4974,26 +5006,26 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec { uint32_t v = uint32_t(idx/2) * 2; // find first vert in primitive - activePrim.push_back(InterpretVertex(data, v+0, cfg, dataEnd, valid)); - activePrim.push_back(InterpretVertex(data, v+1, cfg, dataEnd, valid)); + activePrim.push_back(InterpretVertex(data, v+0, cfg, dataEnd, true, valid)); + activePrim.push_back(InterpretVertex(data, v+1, cfg, dataEnd, true, valid)); } else if(meshtopo == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST) { uint32_t v = uint32_t(idx/3) * 3; // find first vert in primitive - activePrim.push_back(InterpretVertex(data, v+0, cfg, dataEnd, valid)); - activePrim.push_back(InterpretVertex(data, v+1, cfg, dataEnd, valid)); - activePrim.push_back(InterpretVertex(data, v+2, cfg, dataEnd, valid)); + activePrim.push_back(InterpretVertex(data, v+0, cfg, dataEnd, true, valid)); + activePrim.push_back(InterpretVertex(data, v+1, cfg, dataEnd, true, valid)); + activePrim.push_back(InterpretVertex(data, v+2, cfg, dataEnd, true, valid)); } else if(meshtopo == D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ) { uint32_t v = uint32_t(idx/4) * 4; // find first vert in primitive FloatVector vs[] = { - InterpretVertex(data, v+0, cfg, dataEnd, valid), - InterpretVertex(data, v+1, cfg, dataEnd, valid), - InterpretVertex(data, v+2, cfg, dataEnd, valid), - InterpretVertex(data, v+3, cfg, dataEnd, valid), + InterpretVertex(data, v+0, cfg, dataEnd, true, valid), + InterpretVertex(data, v+1, cfg, dataEnd, true, valid), + InterpretVertex(data, v+2, cfg, dataEnd, true, valid), + InterpretVertex(data, v+3, cfg, dataEnd, true, valid), }; adjacentPrimVertices.push_back(vs[0]); @@ -5010,12 +5042,12 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec uint32_t v = uint32_t(idx/6) * 6; // find first vert in primitive FloatVector vs[] = { - InterpretVertex(data, v+0, cfg, dataEnd, valid), - InterpretVertex(data, v+1, cfg, dataEnd, valid), - InterpretVertex(data, v+2, cfg, dataEnd, valid), - InterpretVertex(data, v+3, cfg, dataEnd, valid), - InterpretVertex(data, v+4, cfg, dataEnd, valid), - InterpretVertex(data, v+5, cfg, dataEnd, valid), + InterpretVertex(data, v+0, cfg, dataEnd, true, valid), + InterpretVertex(data, v+1, cfg, dataEnd, true, valid), + InterpretVertex(data, v+2, cfg, dataEnd, true, valid), + InterpretVertex(data, v+3, cfg, dataEnd, true, valid), + InterpretVertex(data, v+4, cfg, dataEnd, true, valid), + InterpretVertex(data, v+5, cfg, dataEnd, true, valid), }; adjacentPrimVertices.push_back(vs[0]); @@ -5042,8 +5074,8 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec // primitive, and thereafter each point is in the next primitive uint32_t v = RDCMAX(idx, 1U) - 1; - activePrim.push_back(InterpretVertex(data, v+0, cfg, dataEnd, valid)); - activePrim.push_back(InterpretVertex(data, v+1, cfg, dataEnd, valid)); + activePrim.push_back(InterpretVertex(data, v+0, cfg, dataEnd, true, valid)); + activePrim.push_back(InterpretVertex(data, v+1, cfg, dataEnd, true, valid)); } else if(meshtopo == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP) { @@ -5053,9 +5085,9 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec // primitive, and thereafter each point is in the next primitive uint32_t v = RDCMAX(idx, 2U) - 2; - activePrim.push_back(InterpretVertex(data, v+0, cfg, dataEnd, valid)); - activePrim.push_back(InterpretVertex(data, v+1, cfg, dataEnd, valid)); - activePrim.push_back(InterpretVertex(data, v+2, cfg, dataEnd, valid)); + activePrim.push_back(InterpretVertex(data, v+0, cfg, dataEnd, true, valid)); + activePrim.push_back(InterpretVertex(data, v+1, cfg, dataEnd, true, valid)); + activePrim.push_back(InterpretVertex(data, v+2, cfg, dataEnd, true, valid)); } else if(meshtopo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ) { @@ -5066,10 +5098,10 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec uint32_t v = RDCMAX(idx, 3U) - 3; FloatVector vs[] = { - InterpretVertex(data, v+0, cfg, dataEnd, valid), - InterpretVertex(data, v+1, cfg, dataEnd, valid), - InterpretVertex(data, v+2, cfg, dataEnd, valid), - InterpretVertex(data, v+3, cfg, dataEnd, valid), + InterpretVertex(data, v+0, cfg, dataEnd, true, valid), + InterpretVertex(data, v+1, cfg, dataEnd, true, valid), + InterpretVertex(data, v+2, cfg, dataEnd, true, valid), + InterpretVertex(data, v+3, cfg, dataEnd, true, valid), }; adjacentPrimVertices.push_back(vs[0]); @@ -5097,18 +5129,18 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec else if(idx <= 4 || numidx <= 7) { FloatVector vs[] = { - InterpretVertex(data, 0, cfg, dataEnd, valid), - InterpretVertex(data, 1, cfg, dataEnd, valid), - InterpretVertex(data, 2, cfg, dataEnd, valid), - InterpretVertex(data, 3, cfg, dataEnd, valid), - InterpretVertex(data, 4, cfg, dataEnd, valid), + InterpretVertex(data, 0, cfg, dataEnd, true, valid), + InterpretVertex(data, 1, cfg, dataEnd, true, valid), + InterpretVertex(data, 2, cfg, dataEnd, true, valid), + InterpretVertex(data, 3, cfg, dataEnd, true, valid), + InterpretVertex(data, 4, cfg, dataEnd, true, valid), // note this one isn't used as it's adjacency for the next triangle - InterpretVertex(data, 5, cfg, dataEnd, valid), + InterpretVertex(data, 5, cfg, dataEnd, true, valid), // min() with number of indices in case this is a tiny strip // that is basically just a list - InterpretVertex(data, RDCMIN(6U, numidx-1), cfg, dataEnd, valid), + InterpretVertex(data, RDCMIN(6U, numidx-1), cfg, dataEnd, true, valid), }; // these are the triangles on the far left of the MSDN diagram above @@ -5133,18 +5165,18 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec // in diagram, numidx == 14 FloatVector vs[] = { - /*[0]=*/ InterpretVertex(data, numidx-8, cfg, dataEnd, valid), // 6 in diagram + /*[0]=*/ InterpretVertex(data, numidx-8, cfg, dataEnd, true, valid), // 6 in diagram // as above, unused since this is adjacency for 2-previous triangle - /*[1]=*/ InterpretVertex(data, numidx-7, cfg, dataEnd, valid), // 7 in diagram - /*[2]=*/ InterpretVertex(data, numidx-6, cfg, dataEnd, valid), // 8 in diagram + /*[1]=*/ InterpretVertex(data, numidx-7, cfg, dataEnd, true, valid), // 7 in diagram + /*[2]=*/ InterpretVertex(data, numidx-6, cfg, dataEnd, true, valid), // 8 in diagram // as above, unused since this is adjacency for previous triangle - /*[3]=*/ InterpretVertex(data, numidx-5, cfg, dataEnd, valid), // 9 in diagram - /*[4]=*/ InterpretVertex(data, numidx-4, cfg, dataEnd, valid), // 10 in diagram - /*[5]=*/ InterpretVertex(data, numidx-3, cfg, dataEnd, valid), // 11 in diagram - /*[6]=*/ InterpretVertex(data, numidx-2, cfg, dataEnd, valid), // 12 in diagram - /*[7]=*/ InterpretVertex(data, numidx-1, cfg, dataEnd, valid), // 13 in diagram + /*[3]=*/ InterpretVertex(data, numidx-5, cfg, dataEnd, true, valid), // 9 in diagram + /*[4]=*/ InterpretVertex(data, numidx-4, cfg, dataEnd, true, valid), // 10 in diagram + /*[5]=*/ InterpretVertex(data, numidx-3, cfg, dataEnd, true, valid), // 11 in diagram + /*[6]=*/ InterpretVertex(data, numidx-2, cfg, dataEnd, true, valid), // 12 in diagram + /*[7]=*/ InterpretVertex(data, numidx-1, cfg, dataEnd, true, valid), // 13 in diagram }; // these are the triangles on the far right of the MSDN diagram above @@ -5174,19 +5206,19 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec // these correspond to the indices in the MSDN diagram, with {2,4,6} as the // main triangle FloatVector vs[] = { - InterpretVertex(data, v+0, cfg, dataEnd, valid), + InterpretVertex(data, v+0, cfg, dataEnd, true, valid), // this one is adjacency for 2-previous triangle - InterpretVertex(data, v+1, cfg, dataEnd, valid), - InterpretVertex(data, v+2, cfg, dataEnd, valid), + InterpretVertex(data, v+1, cfg, dataEnd, true, valid), + InterpretVertex(data, v+2, cfg, dataEnd, true, valid), // this one is adjacency for previous triangle - InterpretVertex(data, v+3, cfg, dataEnd, valid), - InterpretVertex(data, v+4, cfg, dataEnd, valid), - InterpretVertex(data, v+5, cfg, dataEnd, valid), - InterpretVertex(data, v+6, cfg, dataEnd, valid), - InterpretVertex(data, v+7, cfg, dataEnd, valid), - InterpretVertex(data, v+8, cfg, dataEnd, valid), + InterpretVertex(data, v+3, cfg, dataEnd, true, valid), + InterpretVertex(data, v+4, cfg, dataEnd, true, valid), + InterpretVertex(data, v+5, cfg, dataEnd, true, valid), + InterpretVertex(data, v+6, cfg, dataEnd, true, valid), + InterpretVertex(data, v+7, cfg, dataEnd, true, valid), + InterpretVertex(data, v+8, cfg, dataEnd, true, valid), }; // these are the triangles around {2,4,6} in the MSDN diagram above @@ -5216,7 +5248,7 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec for(uint32_t v = v0; v < v0+dim; v++) { if(v != idx && valid) - inactiveVertices.push_back(InterpretVertex(data, v, cfg, dataEnd, valid)); + inactiveVertices.push_back(InterpretVertex(data, v, cfg, dataEnd, true, valid)); } } else // if(meshtopo == D3D11_PRIMITIVE_TOPOLOGY_POINTLIST) point list, or unknown/unhandled type diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index 699b6547e..3a25160eb 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -119,8 +119,8 @@ class D3D11DebugManager MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage); uint32_t GetStructCount(ID3D11UnorderedAccessView *uav); - vector GetBufferData(ID3D11Buffer *buff, uint32_t offset, uint32_t len); vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len); + vector GetBufferData(ID3D11Buffer *buff, uint32_t offset, uint32_t len, bool unwrap); byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize); @@ -171,6 +171,7 @@ class D3D11DebugManager ShaderDebugTrace DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive); ShaderDebugTrace DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]); void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, float pixel[4]); + uint32_t PickVertex(uint32_t frameID, uint32_t eventID, MeshDisplay cfg, uint32_t x, uint32_t y); ResourceId RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID, const vector &passEvents); ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip); @@ -343,7 +344,7 @@ class D3D11DebugManager ID3D11Buffer *m_FrustumHelper; ID3D11Buffer *m_TriHighlightHelper; - FloatVector InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool &valid); + FloatVector InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool useidx, bool &valid); bool InitStreamOut(); void ShutdownStreamOut(); @@ -437,6 +438,14 @@ class D3D11DebugManager SAFE_RELEASE(PixelHistoryCopyCS); SAFE_RELEASE(PrimitiveIDPS); + SAFE_RELEASE(MeshPickCS); + SAFE_RELEASE(PickIBBuf); + SAFE_RELEASE(PickVBBuf); + SAFE_RELEASE(PickIBSRV); + SAFE_RELEASE(PickVBSRV); + SAFE_RELEASE(PickResultBuf); + SAFE_RELEASE(PickResultUAV); + SAFE_RELEASE(QuadOverdrawPS); SAFE_RELEASE(QOResolvePS); @@ -501,6 +510,15 @@ class D3D11DebugManager ID3D11PixelShader *DepthCopyMSToArrayPS, *DepthCopyArrayToMSPS; ID3D11ComputeShader *PixelHistoryUnusedCS, *PixelHistoryCopyCS; ID3D11PixelShader *PrimitiveIDPS; + + static const uint32_t maxMeshPicks = 500; + + ID3D11ComputeShader *MeshPickCS; + ID3D11Buffer *PickIBBuf, *PickVBBuf; + uint32_t PickIBSize, PickVBSize; + ID3D11ShaderResourceView *PickIBSRV, *PickVBSRV; + ID3D11Buffer *PickResultBuf; + ID3D11UnorderedAccessView *PickResultUAV; ID3D11PixelShader *QuadOverdrawPS, *QOResolvePS; diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index d8a10cff0..94eccb209 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -1374,6 +1374,11 @@ ShaderDebugTrace D3D11Replay::DebugThread(uint32_t frameID, uint32_t eventID, ui return m_pDevice->GetDebugManager()->DebugThread(frameID, eventID, groupid, threadid); } +uint32_t D3D11Replay::PickVertex(uint32_t frameID, uint32_t eventID, MeshDisplay cfg, uint32_t x, uint32_t y) +{ + return m_pDevice->GetDebugManager()->PickVertex(frameID, eventID, cfg, x, y); +} + void D3D11Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, float pixel[4]) { m_pDevice->GetDebugManager()->PickPixel(texture, x, y, sliceFace, mip, sample, pixel); diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 710d85628..e112b5437 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -121,6 +121,7 @@ class D3D11Replay : public IReplayDriver ShaderDebugTrace DebugPixel(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive); ShaderDebugTrace DebugThread(uint32_t frameID, uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]); void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, float pixel[4]); + uint32_t PickVertex(uint32_t frameID, uint32_t eventID, MeshDisplay cfg, uint32_t x, uint32_t y); ResourceId RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID, const vector &passEvents); diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 18bd184ce..8d9ed28eb 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -430,6 +430,26 @@ void GLReplay::InitDebugData() DebugData.Array2MS = CreateCShaderProgram(glsl.c_str()); } + { + string glsl = GetEmbeddedResource(mesh_comp); + + DebugData.meshPickProgram = CreateCShaderProgram(glsl.c_str()); + } + + { + gl.glGenBuffers(1, &DebugData.pickResultBuf); + gl.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickResultBuf); + gl.glNamedBufferStorageEXT(DebugData.pickResultBuf, sizeof(Vec4f)*DebugRenderData::maxMeshPicks, NULL, GL_MAP_READ_BIT); + + gl.glGenBuffers(1, &DebugData.pickResultCounterBuf); + gl.glBindBuffer(eGL_ATOMIC_COUNTER_BUFFER, DebugData.pickResultCounterBuf); + gl.glNamedBufferStorageEXT(DebugData.pickResultCounterBuf, sizeof(uint32_t), NULL, GL_DYNAMIC_STORAGE_BIT); + + // sized/created on demand + DebugData.pickVBBuf = DebugData.pickIBBuf = 0; + DebugData.pickVBSize = DebugData.pickIBSize = 0; + } + gl.glGenVertexArrays(1, &DebugData.meshVAO); gl.glBindVertexArray(DebugData.meshVAO); @@ -973,6 +993,207 @@ bool GLReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, return true; } +uint32_t GLReplay::PickVertex(uint32_t frameID, uint32_t eventID, MeshDisplay cfg, uint32_t x, uint32_t y) +{ + WrappedOpenGL &gl = *m_pDriver; + + MakeCurrentReplayContext(m_DebugCtx); + + gl.glUseProgram(DebugData.meshPickProgram); + + GLint loc = gl.glGetUniformLocation(DebugData.meshPickProgram, "PickCoords"); + gl.glUniform2f(loc, (float)x, (float)y); + loc = gl.glGetUniformLocation(DebugData.meshPickProgram, "PickViewport"); + gl.glUniform2f(loc, DebugData.outWidth, DebugData.outHeight); + loc = gl.glGetUniformLocation(DebugData.meshPickProgram, "PickIdx"); + gl.glUniform1ui(loc, cfg.position.idxByteWidth ? 1U : 0U); + loc = gl.glGetUniformLocation(DebugData.meshPickProgram, "PickNumVerts"); + gl.glUniform1ui(loc, cfg.position.numVerts); + + Matrix4f projMat = Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, DebugData.outWidth/DebugData.outHeight); + + Camera cam; + if(cfg.arcballCamera) + cam.Arcball(Vec3f(cfg.cameraPos.x, cfg.cameraPos.y, cfg.cameraPos.z), cfg.cameraPos.w, Vec3f(cfg.cameraRot.x, cfg.cameraRot.y, cfg.cameraRot.z)); + else + cam.fpsLook(Vec3f(cfg.cameraPos.x, cfg.cameraPos.y, cfg.cameraPos.z), Vec3f(cfg.cameraRot.x, cfg.cameraRot.y, cfg.cameraRot.z)); + + Matrix4f camMat = cam.GetMatrix(); + Matrix4f PickMVP = projMat.Mul(camMat); + + ResourceFormat resFmt; + resFmt.compByteWidth = cfg.position.compByteWidth; + resFmt.compCount = cfg.position.compCount; + resFmt.compType = cfg.position.compType; + resFmt.special = false; + if(cfg.position.specialFormat != eSpecial_Unknown) + { + resFmt.special = true; + resFmt.specialFormat = cfg.position.specialFormat; + } + + if(cfg.position.unproject) + { + // the derivation of the projection matrix might not be right (hell, it could be an + // orthographic projection). But it'll be close enough likely. + Matrix4f guessProj = Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect); + + if(cfg.ortho) + guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); + + PickMVP = projMat.Mul(camMat.Mul(guessProj.Inverse())); + } + + loc = gl.glGetUniformLocation(DebugData.meshPickProgram, "PickMVP"); + gl.glUniformMatrix4fv(loc, 1, GL_FALSE, PickMVP.Data()); + + GLenum ifmt = cfg.position.idxByteWidth == 4 ? eGL_UNSIGNED_INT + : cfg.position.idxByteWidth == 2 ? eGL_UNSIGNED_SHORT + : eGL_UNSIGNED_BYTE; + + GLuint ib = 0; + + if(cfg.position.idxByteWidth && cfg.position.idxbuf != ResourceId()) + ib = m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.idxbuf).name; + + // We copy into our own buffers to promote to the target type (uint32) that the + // shader expects. Most IBs will be 16-bit indices, most VBs will not be float4. + + if(ib) + { + // resize up on demand + if(DebugData.pickIBBuf == 0 || DebugData.pickIBSize < cfg.position.numVerts*sizeof(uint32_t)) + { + gl.glDeleteBuffers(1, &DebugData.pickIBBuf); + + gl.glGenBuffers(1, &DebugData.pickIBBuf); + gl.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickIBBuf); + gl.glNamedBufferStorageEXT(DebugData.pickIBBuf, cfg.position.numVerts*sizeof(uint32_t), NULL, GL_DYNAMIC_STORAGE_BIT); + + DebugData.pickIBSize = cfg.position.numVerts*sizeof(uint32_t); + } + + byte *idxs = new byte[cfg.position.numVerts*cfg.position.idxByteWidth]; + uint32_t *outidxs = NULL; + + if(cfg.position.idxByteWidth < 4) + outidxs = new uint32_t[cfg.position.numVerts]; + + gl.glBindBuffer(eGL_COPY_READ_BUFFER, ib); + gl.glGetBufferSubData(eGL_COPY_READ_BUFFER, cfg.position.idxoffs, cfg.position.numVerts*cfg.position.idxByteWidth, idxs); + + uint16_t *idxs16 = (uint16_t *)idxs; + + if(cfg.position.idxByteWidth == 1) + { + for(uint32_t i=0; i < cfg.position.numVerts; i++) + outidxs[i] = idxs[i]; + + gl.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickIBBuf); + gl.glBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, cfg.position.numVerts*sizeof(uint32_t), outidxs); + } + else if(cfg.position.idxByteWidth == 2) + { + for(uint32_t i=0; i < cfg.position.numVerts; i++) + outidxs[i] = idxs16[i]; + + gl.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickIBBuf); + gl.glBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, cfg.position.numVerts*sizeof(uint32_t), outidxs); + } + else + { + gl.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickIBBuf); + gl.glBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, cfg.position.numVerts*sizeof(uint32_t), idxs); + } + + SAFE_DELETE_ARRAY(outidxs); + } + + if(DebugData.pickVBBuf == 0 || DebugData.pickVBSize < cfg.position.numVerts*sizeof(uint32_t)) + { + gl.glDeleteBuffers(1, &DebugData.pickVBBuf); + + gl.glGenBuffers(1, &DebugData.pickVBBuf); + gl.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickVBBuf); + gl.glNamedBufferStorageEXT(DebugData.pickVBBuf, cfg.position.numVerts*sizeof(Vec4f), NULL, GL_DYNAMIC_STORAGE_BIT); + + DebugData.pickVBSize = cfg.position.numVerts*sizeof(Vec4f); + } + + // unpack and linearise the data + { + FloatVector *vbData = new FloatVector[cfg.position.numVerts]; + + vector oldData = GetBufferData(cfg.position.buf, cfg.position.offset, 0); + + byte *data = &oldData[0]; + byte *dataEnd = data + oldData.size(); + + bool valid; + + for(uint32_t i=0; i < cfg.position.numVerts; i++) + vbData[i] = InterpretVertex(data, i, cfg, dataEnd, false, valid); + + gl.glBindBuffer(eGL_SHADER_STORAGE_BUFFER, DebugData.pickVBBuf); + gl.glBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, cfg.position.numVerts*sizeof(Vec4f), vbData); + + delete[] vbData; + } + + uint32_t reset = 0; + gl.glBindBufferBase(eGL_ATOMIC_COUNTER_BUFFER, 0, DebugData.pickResultCounterBuf); + gl.glBufferSubData(eGL_ATOMIC_COUNTER_BUFFER, 0, sizeof(uint32_t), &reset); + + gl.glBindBufferBase(eGL_SHADER_STORAGE_BUFFER, 0, DebugData.pickResultBuf); + gl.glBindBufferBase(eGL_SHADER_STORAGE_BUFFER, 1, DebugData.pickVBBuf); + gl.glBindBufferRange(eGL_SHADER_STORAGE_BUFFER, 2, DebugData.pickIBBuf, + cfg.position.idxoffs, cfg.position.idxoffs + cfg.position.idxByteWidth*cfg.position.numVerts); + + gl.glDispatchCompute(GLuint(cfg.position.numVerts/1024 + 1), 1, 1); + gl.glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT|GL_SHADER_STORAGE_BARRIER_BIT); + + uint32_t numResults = 0; + + gl.glBindBuffer(eGL_COPY_READ_BUFFER, DebugData.pickResultCounterBuf); + gl.glGetBufferSubData(eGL_COPY_READ_BUFFER, 0, sizeof(uint32_t), &numResults); + + if(numResults > 0) + { + struct PickResult + { + uint32_t vertid; uint32_t idx; float len; float depth; + }; + + PickResult *pickResults = (PickResult *)gl.glMapNamedBufferEXT(DebugData.pickResultBuf, eGL_READ_ONLY); + + PickResult *closest = pickResults; + + // min with size of results buffer to protect against overflows + for(uint32_t i=1; i < RDCMIN(DebugRenderData::maxMeshPicks, numResults); i++) + { + // We need to keep the picking order consistent in the face + // of random buffer appends, when multiple vertices have the + // identical position (e.g. if UVs or normals are different). + // + // We could do something to try and disambiguate, but it's + // never going to be intuitive, it's just going to flicker + // confusingly. + if(pickResults[i].len < closest->len || + (pickResults[i].len == closest->len && pickResults[i].depth < closest->depth) || + (pickResults[i].len == closest->len && pickResults[i].depth == closest->depth && pickResults[i].vertid < closest->vertid)) + closest = pickResults+i; + } + + uint32_t ret = closest->vertid; + + gl.glUnmapNamedBufferEXT(DebugData.pickResultBuf); + + return ret; + } + + return ~0U; +} + void GLReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, float pixel[4]) { WrappedOpenGL &gl = *m_pDriver; @@ -3012,11 +3233,11 @@ MeshFormat GLReplay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32 return ret; } -FloatVector GLReplay::InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool &valid) +FloatVector GLReplay::InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool useidx, bool &valid) { FloatVector ret(0.0f, 0.0f, 0.0f, 1.0f); - if(m_HighlightCache.useidx) + if(useidx && m_HighlightCache.useidx) { if(vert >= (uint32_t)m_HighlightCache.indices.size()) { @@ -3588,7 +3809,7 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector &passEvents); ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip); @@ -230,7 +231,7 @@ class GLReplay : public IReplayDriver // any objects that are shared between contexts, we just initialise // once - struct + struct DebugRenderData { float outWidth, outHeight; @@ -255,6 +256,14 @@ class GLReplay : public IReplayDriver GLuint customFBO; GLuint customTex; ResourceId CustomShaderTexID; + + static const uint32_t maxMeshPicks = 500; + + GLuint meshPickProgram; + GLuint pickIBBuf, pickVBBuf; + uint32_t pickIBSize, pickVBSize; + GLuint pickResultBuf; + GLuint pickResultCounterBuf; GLuint MS2Array, Array2MS; @@ -302,7 +311,7 @@ class GLReplay : public IReplayDriver GLuint emptyVAO; } DebugData; - FloatVector InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool &valid); + FloatVector InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool useidx, bool &valid); // simple cache for when we need buffer data for highlighting // vertices, typical use will be lots of vertices in the same diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index acd32373f..8e4b4cbf1 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -335,6 +335,7 @@ + @@ -346,6 +347,7 @@ + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index 77ad31f4d..90b83a128 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -403,6 +403,12 @@ Resources\glsl + + Resources\hlsl + + + Resources\glsl + diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index b3de342c3..858f857f2 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -147,4 +147,5 @@ class IReplayDriver : public IRemoteDriver virtual void RenderHighlightBox(float w, float h, float scale) = 0; virtual void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, float pixel[4]) = 0; + virtual uint32_t PickVertex(uint32_t frameID, uint32_t eventID, MeshDisplay cfg, uint32_t x, uint32_t y) = 0; }; diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index 89d2d471c..ffa9bf373 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -307,6 +307,23 @@ bool ReplayOutput::PickPixel(ResourceId tex, bool customShader, uint32_t x, uint return true; } +uint32_t ReplayOutput::PickVertex(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y) +{ + FetchDrawcall *draw = m_pRenderer->GetDrawcallByEID(eventID, 0); + + if(!draw) return ~0U; + if(m_RenderData.meshDisplay.type == eMeshDataStage_Unknown) return ~0U; + if((draw->flags & eDraw_Drawcall) == 0) return ~0U; + + MeshDisplay cfg = m_RenderData.meshDisplay; + cfg.position.buf = m_pDevice->GetLiveID(cfg.position.buf); + cfg.position.idxbuf = m_pDevice->GetLiveID(cfg.position.idxbuf); + cfg.second.buf = m_pDevice->GetLiveID(cfg.second.buf); + cfg.second.idxbuf = m_pDevice->GetLiveID(cfg.second.idxbuf); + + return m_pDevice->PickVertex(m_FrameID, m_EventID, cfg, x, y); +} + bool ReplayOutput::SetPixelContextLocation(uint32_t x, uint32_t y) { m_ContextX = RDCMAX((float)x, 0.0f); @@ -637,3 +654,6 @@ extern "C" RENDERDOC_API void RENDERDOC_CC ReplayOutput_DisablePixelContext(Repl extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayOutput_PickPixel(ReplayOutput *output, ResourceId texID, bool32 customShader, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *val) { return output->PickPixel(texID, customShader != 0, x, y, sliceFace, mip, sample, val); } + +extern "C" RENDERDOC_API uint32_t RENDERDOC_CC ReplayOutput_PickVertex(ReplayOutput *output, uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y) +{ return output->PickVertex(frameID, eventID, x, y); } diff --git a/renderdoc/replay/replay_renderer.h b/renderdoc/replay/replay_renderer.h index c89718ef1..c873cabc1 100644 --- a/renderdoc/replay/replay_renderer.h +++ b/renderdoc/replay/replay_renderer.h @@ -58,6 +58,7 @@ public: bool PickPixel(ResourceId texID, bool customShader, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *val); + uint32_t PickVertex(uint32_t frameID, uint32_t eventID, uint32_t x, uint32_t y); private: ReplayOutput(ReplayRenderer *parent, void *w); ~ReplayOutput(); diff --git a/renderdocui/Interop/ReplayRenderer.cs b/renderdocui/Interop/ReplayRenderer.cs index c19d85196..8f7f59814 100644 --- a/renderdocui/Interop/ReplayRenderer.cs +++ b/renderdocui/Interop/ReplayRenderer.cs @@ -102,6 +102,8 @@ namespace renderdoc [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayOutput_PickPixel(IntPtr real, ResourceId texID, bool customShader, UInt32 x, UInt32 y, UInt32 sliceFace, UInt32 mip, UInt32 sample, IntPtr outval); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern UInt32 ReplayOutput_PickVertex(IntPtr real, UInt32 frameID, UInt32 eventID, UInt32 x, UInt32 y); private IntPtr m_Real = IntPtr.Zero; @@ -163,6 +165,11 @@ namespace renderdoc return ret; } + public UInt32 PickVertex(UInt32 frameID, UInt32 eventID, UInt32 x, UInt32 y) + { + return ReplayOutput_PickVertex(m_Real, frameID, eventID, x, y); + } + }; public class ReplayRenderer diff --git a/renderdocui/Windows/BufferViewer.cs b/renderdocui/Windows/BufferViewer.cs index 1dc4e391f..381489704 100644 --- a/renderdocui/Windows/BufferViewer.cs +++ b/renderdocui/Windows/BufferViewer.cs @@ -2005,6 +2005,38 @@ namespace renderdocui.Windows } } + private void PickVert(Point p) + { + if (!m_Core.LogLoaded) + return; + + m_Core.Renderer.BeginInvoke((ReplayRenderer r) => + { + UInt32 vertSelected = m_Output.PickVertex(m_Core.CurFrame, m_Core.CurEvent, (UInt32)p.X, (UInt32)p.Y); + + if (vertSelected != UInt32.MaxValue) + { + this.BeginInvoke(new Action(() => + { + var ui = GetUIState(m_MeshDisplay.type); + + int row = (int)vertSelected; + + if (row >= 0 && row < ui.m_GridView.RowCount) + { + if (ui.m_GridView.SelectedRows.Count == 0 || ui.m_GridView.SelectedRows[0] != ui.m_GridView.Rows[row]) + { + ScrollToRow(ui.m_GridView, row); + + ui.m_GridView.ClearSelection(); + ui.m_GridView.Rows[row].Selected = true; + } + } + })); + } + }); + } + void BufferViewer_KeyUp(object sender, KeyEventArgs e) { m_CurrentCamera.KeyUp(sender, e); @@ -2023,11 +2055,17 @@ namespace renderdocui.Windows private void render_MouseMove(object sender, MouseEventArgs e) { m_CurrentCamera.MouseMove(sender, e); + + if (e.Button == MouseButtons.Right) + PickVert(e.Location); } private void render_MouseClick(object sender, MouseEventArgs e) { m_CurrentCamera.MouseClick(sender, e); + + if (e.Button == MouseButtons.Right) + PickVert(e.Location); } private void render_MouseDown(object sender, MouseEventArgs e)