From faeb047211a1ce6439d0f56ea45cce357441de45 Mon Sep 17 00:00:00 2001 From: baldurk Date: Sun, 28 Sep 2014 02:24:57 +0100 Subject: [PATCH] Handle vtx highlights outside UI, for complex topologies. Refs #85 --- renderdoc/api/replay/control_types.h | 10 +- renderdoc/driver/d3d11/d3d11_debug.cpp | 643 ++++++++++++++++++++++--- renderdoc/driver/d3d11/d3d11_debug.h | 17 + renderdoc/maths/formatpacking.h | 3 + renderdoc/replay/replay_output.cpp | 5 +- renderdoc/replay/replay_renderer.cpp | 2 +- renderdocui/Interop/FetchInfo.cs | 19 +- renderdocui/Windows/BufferViewer.cs | 124 ++--- 8 files changed, 663 insertions(+), 160 deletions(-) diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index 3ef69b056..b7fca6ec6 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -42,8 +42,14 @@ struct MeshDisplay bool32 thisDrawOnly; - bool32 showVerts; - FloatVector hilightVerts[3]; + uint32_t highlightVert; + ResourceId positionBuf; + uint32_t positionOffset; + uint32_t positionStride; + uint32_t positionCompCount; + uint32_t positionCompByteWidth; + FormatComponentType positionCompType; + SpecialFormat positionFormat; FloatVector prevMeshColour; FloatVector currentMeshColour; diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index b194d2513..7ebedbd4c 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -31,6 +31,7 @@ #include "maths/camera.h" #include "data/resource.h" #include "common/string_utils.h" +#include "maths/formatpacking.h" #include "driver/d3d11/d3d11_resources.h" @@ -1480,7 +1481,7 @@ bool D3D11DebugManager::InitStreamOut() D3D11_BUFFER_DESC bdesc; bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - bdesc.ByteWidth = sizeof(Vec4f)*4; + bdesc.ByteWidth = sizeof(Vec4f)*16; bdesc.MiscFlags = 0; bdesc.Usage = D3D11_USAGE_DYNAMIC; @@ -2172,15 +2173,16 @@ vector D3D11DebugManager::GetBufferData(ID3D11Buffer *buffer, uint32_t off D3D11_BUFFER_DESC desc; buffer->GetDesc(&desc); + if(len == 0) + { + len = desc.ByteWidth-offset; + } + if(len > 0 && offset+len > desc.ByteWidth) { RDCWARN("Attempting to read off the end of the array. Will be clamped"); len = RDCMIN(len, desc.ByteWidth-offset); } - else if(len == 0) - { - len = desc.ByteWidth; - } uint32_t outOffs = 0; @@ -3870,7 +3872,8 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // force to 4 components, as we need it, and store its offset if(a.find("SV_POSITION") != string::npos || sign.systemValue == eAttr_Position || posoffset == ~0U) { - decl.ComponentCount = 4; + if(a.find("SV_POSITION") != string::npos || sign.systemValue == eAttr_Position) + decl.ComponentCount = 4; posoffset = stride; numPosComponents = decl.ComponentCount; @@ -4027,6 +4030,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) if(numPrims.NumPrimitivesWritten == 0) { m_PostVSData[idx] = PostVSData(); + SAFE_RELEASE(idxBuf); return; } @@ -4036,6 +4040,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) if(FAILED(hr)) { RDCERR("Failed to map sobuffer %08x", hr); + SAFE_RELEASE(idxBuf); return; } @@ -4054,6 +4059,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) RDCERR("Generated output data too large: %08x", bufferDesc.ByteWidth); m_pImmediateContext->Unmap(m_SOStagingBuffer, 0); + SAFE_RELEASE(idxBuf); return; } @@ -4073,6 +4079,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) RDCERR("Failed to create postvs pos buffer %08x", hr); m_pImmediateContext->Unmap(m_SOStagingBuffer, 0); + SAFE_RELEASE(idxBuf); return; } @@ -4193,7 +4200,8 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // force to 4 components, as we need it, and store its offset if(a.find("SV_POSITION") != string::npos || sign.systemValue == eAttr_Position || posoffset == ~0U) { - decl.ComponentCount = 4; + if(a.find("SV_POSITION") != string::npos || sign.systemValue == eAttr_Position) + decl.ComponentCount = 4; posoffset = stride; numPosComponents = decl.ComponentCount; @@ -4410,6 +4418,99 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) } } +FloatVector D3D11DebugManager::InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool &valid) +{ + FloatVector ret(0.0f, 0.0f, 0.0f, 1.0f); + + if(m_HighlightCache.useidx) + { + if(vert >= (uint32_t)m_HighlightCache.indices.size()) + { + valid = false; + return ret; + } + + vert = m_HighlightCache.indices[vert]; + } + + data += vert*cfg.positionStride; + + float *out = &ret.x; + + ResourceFormat fmt; + fmt.compByteWidth = cfg.positionCompByteWidth; + fmt.compCount = cfg.positionCompCount; + fmt.compType = cfg.positionCompType; + + if(cfg.positionFormat == eSpecial_R10G10B10A2) + { + if(data+4 >= end) + { + valid = false; + return ret; + } + + Vec4f v = ConvertFromR10G10B10A2(*(uint32_t *)data); + ret.x = v.x; + ret.y = v.y; + ret.z = v.z; + ret.w = v.w; + return ret; + } + else if(cfg.positionFormat == eSpecial_R11G11B10) + { + if(data+4 >= end) + { + valid = false; + return ret; + } + + Vec3f v = ConvertFromR11G11B10(*(uint32_t *)data); + ret.x = v.x; + ret.y = v.y; + ret.z = v.z; + return ret; + } + else if(cfg.positionFormat == eSpecial_B8G8R8A8) + { + if(data+4 >= end) + { + valid = false; + return ret; + } + + fmt.compByteWidth = 1; + fmt.compCount = 4; + fmt.compType = eCompType_UNorm; + } + + if(data + cfg.positionCompCount*cfg.positionCompByteWidth >= end) + { + valid = false; + return ret; + } + + for(uint32_t i=0; i < cfg.positionCompCount; i++) + { + *out = ConvertComponent(fmt, data); + + data += cfg.positionCompByteWidth; + out++; + } + + if(cfg.positionFormat == eSpecial_B8G8R8A8) + { + FloatVector reversed; + reversed.x = ret.x; + reversed.y = ret.y; + reversed.z = ret.z; + reversed.w = ret.w; + return reversed; + } + + return ret; +} + void D3D11DebugManager::RenderMesh(uint32_t frameID, const vector &events, MeshDisplay cfg) { DebugVertexCBuffer vertexData; @@ -4823,79 +4924,489 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, const vector &eve m_pImmediateContext->Draw(2, 4); } - if(cfg.showVerts) - { - // if data is from post transform, it will be in clipspace - if((cfg.type != eMeshDataStage_VSIn && pipeState.m_HS.Shader == ResourceId()) || - (cfg.type == eMeshDataStage_GSOut && pipeState.m_HS.Shader != ResourceId())) + if(cfg.highlightVert != ~0U) + { + const FetchDrawcall *drawcall = m_WrappedDevice->GetDrawcall(frameID, events.back()); + + MeshDataStage stage = cfg.type; + + if(cfg.type == eMeshDataStage_VSOut && pipeState.m_HS.Shader != ResourceId()) + stage = eMeshDataStage_VSIn; + + if(m_HighlightCache.EID != events.back() || m_HighlightCache.buf != cfg.positionBuf || stage != m_HighlightCache.stage) { - vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); - m_pImmediateContext->VSSetShader(m_DebugRender.WireframeHomogVS, NULL, 0); - m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericHomogLayout); - } - else - { - vertexData.ModelViewProj = projMat.Mul(camMat); - m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + m_HighlightCache.EID = events.back(); + m_HighlightCache.buf = cfg.positionBuf; + m_HighlightCache.stage = stage; + + if(cfg.type == eMeshDataStage_VSIn) + { + m_HighlightCache.data = GetBufferData(cfg.positionBuf, 0, 0); + } + else + { + PostVSMeshData postvs = GetPostVSBuffers(frameID, events.back(), stage); + m_HighlightCache.data.resize(postvs.buf.count); + memcpy(&m_HighlightCache.data[0], postvs.buf.elems, postvs.buf.count); + } + + if((drawcall->flags & eDraw_UseIBuffer) == 0) + { + m_HighlightCache.indices.clear(); + m_HighlightCache.useidx = false; + } + else + { + m_HighlightCache.useidx = true; + + ID3D11Buffer *idxBuf = curRS->IA.IndexBuffer; + DXGI_FORMAT idxFmt = curRS->IA.IndexFormat; + UINT idxOffs = curRS->IA.IndexOffset; + + bool index16 = (idxFmt == DXGI_FORMAT_R16_UINT); + UINT bytesize = index16 ? 2 : 4; + + vector idxdata = GetBufferData(idxBuf, idxOffs + drawcall->indexOffset*bytesize, drawcall->numIndices*bytesize); + + uint16_t *idx16 = (uint16_t *)&idxdata[0]; + uint32_t *idx32 = (uint32_t *)&idxdata[0]; + + uint32_t numIndices = RDCMIN(drawcall->numIndices, uint32_t(idxdata.size()/bytesize)); + + m_HighlightCache.indices.resize(numIndices); + + for(uint32_t i=0; i < numIndices; i++) + m_HighlightCache.indices[i] = index16 ? uint32_t(idx16[i]) : idx32[i]; + } } - FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + uint32_t idx = cfg.highlightVert; - pixelData.WireframeColour = Vec3f(1.0f, 0.0f, 0.0f); - FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + byte *data = &m_HighlightCache.data[0]; // buffer start + byte *dataEnd = data + m_HighlightCache.data.size(); - D3D11_MAPPED_SUBRESOURCE mapped; + data += cfg.positionOffset; // to start of position data + data += drawcall->vertexOffset*cfg.positionStride; // to first vertex + + /////////////////////////////////////////////////////////////// + // vectors to be set from buffers, depending on topology - HRESULT hr = S_OK; + bool valid = true; - hr = m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + // this vert (blue dot, required) + FloatVector activeVertex; + + // primitive this vert is a part of (red prim, optional) + vector activePrim; - if(FAILED(hr)) + // for patch lists, to show other verts in patch (green dots, optional) + // for non-patch lists, we use the activePrim and adjacentPrimVertices + // to show what other verts are related + vector inactiveVertices; + + // adjacency (line or tri, strips or lists) (green prims, optional) + // will be N*M long, N adjacent prims of M verts each. M = primSize below + vector adjacentPrimVertices; + + D3D11_PRIMITIVE_TOPOLOGY primTopo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; // tri or line list + uint32_t primSize = 3; // number of verts per primitive + + if(pipeState.m_IA.Topology == eTopology_LineList || + pipeState.m_IA.Topology == eTopology_LineList_Adj || + pipeState.m_IA.Topology == eTopology_LineStrip || + pipeState.m_IA.Topology == eTopology_LineStrip_Adj) { - RDCERR("Failde to map m_TriHighlightHelper %08x", hr); - return; + primSize = 2; + primTopo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; + } + + activeVertex = InterpretVertex(data, idx, cfg, dataEnd, valid); + + // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx for + // how primitive topologies are laid out + if(pipeState.m_IA.Topology == eTopology_LineList) + { + 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)); + } + else if(pipeState.m_IA.Topology == eTopology_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)); + } + else if(pipeState.m_IA.Topology == eTopology_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), + }; + + adjacentPrimVertices.push_back(vs[0]); + adjacentPrimVertices.push_back(vs[1]); + + adjacentPrimVertices.push_back(vs[2]); + adjacentPrimVertices.push_back(vs[3]); + + activePrim.push_back(vs[1]); + activePrim.push_back(vs[2]); + } + else if(pipeState.m_IA.Topology == eTopology_TriangleList_Adj) + { + 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), + }; + + adjacentPrimVertices.push_back(vs[0]); + adjacentPrimVertices.push_back(vs[1]); + adjacentPrimVertices.push_back(vs[2]); + + adjacentPrimVertices.push_back(vs[2]); + adjacentPrimVertices.push_back(vs[3]); + adjacentPrimVertices.push_back(vs[4]); + + adjacentPrimVertices.push_back(vs[4]); + adjacentPrimVertices.push_back(vs[5]); + adjacentPrimVertices.push_back(vs[0]); + + activePrim.push_back(vs[0]); + activePrim.push_back(vs[2]); + activePrim.push_back(vs[4]); + } + else if(pipeState.m_IA.Topology == eTopology_LineStrip) + { + // find first vert in primitive. In strips a vert isn't + // in only one primitive, so we pick the first primitive + // it's in. This means the first N points are in the first + // 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)); + } + else if(pipeState.m_IA.Topology == eTopology_TriangleStrip) + { + // find first vert in primitive. In strips a vert isn't + // in only one primitive, so we pick the first primitive + // it's in. This means the first N points are in the first + // 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)); + } + else if(pipeState.m_IA.Topology == eTopology_LineStrip_Adj) + { + // find first vert in primitive. In strips a vert isn't + // in only one primitive, so we pick the first primitive + // it's in. This means the first N points are in the first + // primitive, and thereafter each point is in the next primitive + 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), + }; + + adjacentPrimVertices.push_back(vs[0]); + adjacentPrimVertices.push_back(vs[1]); + + adjacentPrimVertices.push_back(vs[2]); + adjacentPrimVertices.push_back(vs[3]); + + activePrim.push_back(vs[1]); + activePrim.push_back(vs[2]); + } + else if(pipeState.m_IA.Topology == eTopology_TriangleStrip_Adj) + { + // Triangle strip with adjacency is the most complex topology, as + // we need to handle the ends separately where the pattern breaks. + + uint32_t numidx = drawcall->numIndices; + + if(numidx < 6) + { + // not enough indices provided, bail to make sure logic below doesn't + // need to have tons of edge case detection + valid = false; + } + 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), + + // note this one isn't used as it's adjacency for the next triangle + InterpretVertex(data, 5, cfg, dataEnd, 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), + }; + + // these are the triangles on the far left of the MSDN diagram above + adjacentPrimVertices.push_back(vs[0]); + adjacentPrimVertices.push_back(vs[1]); + adjacentPrimVertices.push_back(vs[2]); + + adjacentPrimVertices.push_back(vs[4]); + adjacentPrimVertices.push_back(vs[3]); + adjacentPrimVertices.push_back(vs[0]); + + adjacentPrimVertices.push_back(vs[4]); + adjacentPrimVertices.push_back(vs[2]); + adjacentPrimVertices.push_back(vs[6]); + + activePrim.push_back(vs[0]); + activePrim.push_back(vs[2]); + activePrim.push_back(vs[4]); + } + else if(idx > numidx-4) + { + // in diagram, numidx == 14 + + FloatVector vs[] = { + /*[0]=*/ InterpretVertex(data, numidx-8, cfg, dataEnd, 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 + + // 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 + }; + + // these are the triangles on the far right of the MSDN diagram above + adjacentPrimVertices.push_back(vs[2]); // 8 in diagram + adjacentPrimVertices.push_back(vs[0]); // 6 in diagram + adjacentPrimVertices.push_back(vs[4]); // 10 in diagram + + adjacentPrimVertices.push_back(vs[4]); // 10 in diagram + adjacentPrimVertices.push_back(vs[7]); // 13 in diagram + adjacentPrimVertices.push_back(vs[6]); // 12 in diagram + + adjacentPrimVertices.push_back(vs[6]); // 12 in diagram + adjacentPrimVertices.push_back(vs[5]); // 11 in diagram + adjacentPrimVertices.push_back(vs[2]); // 8 in diagram + + activePrim.push_back(vs[2]); // 8 in diagram + activePrim.push_back(vs[4]); // 10 in diagram + activePrim.push_back(vs[6]); // 12 in diagram + } + else + { + // we're in the middle somewhere. Each primitive has two vertices for it + // so our step rate is 2. The first 'middle' primitive starts at indices 5&6 + // and uses indices all the way back to 0 + uint32_t v = RDCMAX( ( (idx+1) / 2) * 2, 6U) - 6; + + // 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), + + // this one is adjacency for 2-previous triangle + InterpretVertex(data, v+1, cfg, dataEnd, valid), + InterpretVertex(data, v+2, cfg, dataEnd, 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), + }; + + // these are the triangles around {2,4,6} in the MSDN diagram above + adjacentPrimVertices.push_back(vs[0]); + adjacentPrimVertices.push_back(vs[2]); + adjacentPrimVertices.push_back(vs[4]); + + adjacentPrimVertices.push_back(vs[2]); + adjacentPrimVertices.push_back(vs[5]); + adjacentPrimVertices.push_back(vs[6]); + + adjacentPrimVertices.push_back(vs[6]); + adjacentPrimVertices.push_back(vs[8]); + adjacentPrimVertices.push_back(vs[4]); + + activePrim.push_back(vs[2]); + activePrim.push_back(vs[4]); + activePrim.push_back(vs[6]); + } + } + else if(pipeState.m_IA.Topology >= eTopology_PatchList_1CPs) + { + uint32_t dim = (pipeState.m_IA.Topology-eTopology_PatchList_1CPs) + 1; + + uint32_t v0 = uint32_t(idx/dim) * dim; + + for(uint32_t v = v0; v < v0+dim; v++) + { + if(v != idx && valid) + inactiveVertices.push_back(InterpretVertex(data, v, cfg, dataEnd, valid)); + } + } + else // if(pipeState.m_IA.Topology == eTopology_PointList) point list, or unknown/unhandled type + { + // no adjacency, inactive verts or active primitive } - memcpy(mapped.pData, cfg.hilightVerts, sizeof(Vec4f)*3); - m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); - - UINT strides[] = { sizeof(Vec4f) }; - UINT offsets[] = { 0 }; - - m_pImmediateContext->IASetVertexBuffers(0, 1, &m_TriHighlightHelper, (UINT *)&strides, (UINT *)&offsets); - m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - m_pImmediateContext->Draw(3, 0); - - FloatVector vertSprite[4] = { - cfg.hilightVerts[0], - cfg.hilightVerts[0], - cfg.hilightVerts[0], - cfg.hilightVerts[0] - }; - - hr = m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); - - if(FAILED(hr)) + if(valid) { - RDCERR("Failde to map m_TriHighlightHelper %08x", hr); - return; + //////////////////////////////////////////////////////////////// + // prepare rendering (for both vertices & primitives) + + // if data is from post transform, it will be in clipspace + if((cfg.type != eMeshDataStage_VSIn && pipeState.m_HS.Shader == ResourceId()) || + (cfg.type == eMeshDataStage_GSOut && pipeState.m_HS.Shader != ResourceId())) + { + vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + m_pImmediateContext->VSSetShader(m_DebugRender.WireframeHomogVS, NULL, 0); + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericHomogLayout); + } + else + { + vertexData.ModelViewProj = projMat.Mul(camMat); + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + } + + FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + + D3D11_MAPPED_SUBRESOURCE mapped; + HRESULT hr = S_OK; + UINT strides[] = { sizeof(Vec4f) }; + UINT offsets[] = { 0 }; + m_pImmediateContext->IASetVertexBuffers(0, 1, &m_TriHighlightHelper, (UINT *)&strides, (UINT *)&offsets); + + //////////////////////////////////////////////////////////////// + // render primitives + + m_pImmediateContext->IASetPrimitiveTopology(primTopo); + + // Draw active primitive (red) + pixelData.WireframeColour = Vec3f(1.0f, 0.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + if(activePrim.size() >= primSize) + { + hr = m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failde to map m_TriHighlightHelper %08x", hr); + return; + } + + memcpy(mapped.pData, &activePrim[0], sizeof(Vec4f)*primSize); + m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); + + m_pImmediateContext->Draw(primSize, 0); + } + + // Draw adjacent primitives (green) + pixelData.WireframeColour = Vec3f(0.0f, 1.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + if(adjacentPrimVertices.size() >= primSize && (adjacentPrimVertices.size() % primSize) == 0) + { + hr = m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failde to map m_TriHighlightHelper %08x", hr); + return; + } + + memcpy(mapped.pData, &adjacentPrimVertices[0], sizeof(Vec4f)*adjacentPrimVertices.size()); + m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); + + m_pImmediateContext->Draw((UINT)adjacentPrimVertices.size(), 0); + } + + //////////////////////////////////////////////////////////////// + // prepare to render dots (set new VS params and topology) + float scale = 800.0f/float(GetHeight()); + float asp = float(GetWidth())/float(GetHeight()); + + vertexData.SpriteSize = Vec2f(scale/asp, scale); + FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); + + // Draw active vertex (blue) + pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 1.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + FloatVector vertSprite[4] = { + activeVertex, + activeVertex, + activeVertex, + activeVertex, + }; + + hr = m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failde to map m_TriHighlightHelper %08x", hr); + return; + } + + memcpy(mapped.pData, vertSprite, sizeof(vertSprite)); + m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); + + m_pImmediateContext->Draw(4, 0); + + // Draw inactive vertices (green) + pixelData.WireframeColour = Vec3f(0.0f, 1.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); + + for(size_t i=0; i < inactiveVertices.size(); i++) + { + vertSprite[0] = vertSprite[1] = vertSprite[2] = vertSprite[3] = inactiveVertices[i]; + + hr = m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failde to map m_TriHighlightHelper %08x", hr); + return; + } + + memcpy(mapped.pData, vertSprite, sizeof(vertSprite)); + m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); + + m_pImmediateContext->Draw(4, 0); + } } - memcpy(mapped.pData, vertSprite, sizeof(vertSprite)); - m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); - - float scale = 800.0f/float(GetHeight()); - float asp = float(GetWidth())/float(GetHeight()); - - pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 1.0f); - vertexData.SpriteSize = Vec2f(scale/asp, scale); - FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer)); - FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData)); - - m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - m_pImmediateContext->Draw(4, 0); - if(cfg.type != eMeshDataStage_VSIn) m_pImmediateContext->VSSetShader(m_DebugRender.WireframeVS, NULL, 0); } diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index ae709fc52..f113616a1 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -292,6 +292,21 @@ class D3D11DebugManager // -> data map, PostVSData> m_PostVSData; + // simple cache for when we need buffer data for highlighting + // vertices, typical use will be lots of vertices in the same + // mesh, not jumping back and forth much between meshes. + struct HighlightCache + { + HighlightCache() : EID(0), buf(), stage(eMeshDataStage_Unknown), useidx(false) {} + uint32_t EID; + ResourceId buf; + MeshDataStage stage; + bool useidx; + + vector data; + vector indices; + } m_HighlightCache; + ID3D11Texture2D *m_OverlayRenderTex; ResourceId m_OverlayResourceId; @@ -314,6 +329,8 @@ class D3D11DebugManager ID3D11Buffer *m_FrustumHelper; ID3D11Buffer *m_TriHighlightHelper; + FloatVector InterpretVertex(byte *data, uint32_t vert, MeshDisplay cfg, byte *end, bool &valid); + bool InitStreamOut(); void ShutdownStreamOut(); diff --git a/renderdoc/maths/formatpacking.h b/renderdoc/maths/formatpacking.h index feb2344bb..c79913849 100644 --- a/renderdoc/maths/formatpacking.h +++ b/renderdoc/maths/formatpacking.h @@ -102,4 +102,7 @@ inline float ConvertFromSRGB8(uint8_t comp) return SRGB8_lookuptable[comp]; } +struct ResourceFormat; +float ConvertComponent(ResourceFormat fmt, byte *data); + #include "half_convert.h" diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index 93762485b..f48372561 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -564,7 +564,10 @@ void ReplayOutput::DisplayMesh() m_pDevice->ClearOutputWindowDepth(m_MainOutput.outputID, 1.0f, 0); - m_pDevice->RenderMesh(m_FrameID, events, m_RenderData.meshDisplay); + MeshDisplay mesh = m_RenderData.meshDisplay; + mesh.positionBuf = m_pDevice->GetLiveID(mesh.positionBuf); + + m_pDevice->RenderMesh(m_FrameID, events, mesh); } diff --git a/renderdoc/replay/replay_renderer.cpp b/renderdoc/replay/replay_renderer.cpp index 96220d4dc..636285075 100644 --- a/renderdoc/replay/replay_renderer.cpp +++ b/renderdoc/replay/replay_renderer.cpp @@ -40,7 +40,7 @@ #include "stb/stb_image_write.h" #include "common/dds_readwrite.h" -static inline float ConvertComponent(ResourceFormat fmt, byte *data) +float ConvertComponent(ResourceFormat fmt, byte *data) { if(fmt.compByteWidth == 4) { diff --git a/renderdocui/Interop/FetchInfo.cs b/renderdocui/Interop/FetchInfo.cs index d5c3bc8f3..2f5a53f4c 100644 --- a/renderdocui/Interop/FetchInfo.cs +++ b/renderdocui/Interop/FetchInfo.cs @@ -355,17 +355,14 @@ namespace renderdoc public bool thisDrawOnly = true; - public bool showVerts; - - [StructLayout(LayoutKind.Sequential)] - public struct HighlightVerts - { - public FloatVector v0; - public FloatVector v1; - public FloatVector v2; - }; - [CustomMarshalAs(CustomUnmanagedType.CustomClass)] - public HighlightVerts highlight = new HighlightVerts(); + public UInt32 highlightVert; + public ResourceId positionBuf; + public UInt32 positionOffset; + public UInt32 positionStride; + public UInt32 positionCompCount; + public UInt32 positionCompByteWidth; + public FormatComponentType positionCompType; + public SpecialFormat positionFormat; public FloatVector prevMeshColour = new FloatVector(); public FloatVector currentMeshColour = new FloatVector(); diff --git a/renderdocui/Windows/BufferViewer.cs b/renderdocui/Windows/BufferViewer.cs index b3d778f6e..0e935e005 100644 --- a/renderdocui/Windows/BufferViewer.cs +++ b/renderdocui/Windows/BufferViewer.cs @@ -443,6 +443,8 @@ namespace renderdocui.Windows var contentsVSOut = RT_FetchBufferContents(MeshDataStage.VSOut, r, m_VSOut.m_Input); var contentsGSOut = RT_FetchBufferContents(MeshDataStage.GSOut, r, m_GSOut.m_Input); + UpdateMeshPositionBuffer(); + if (curReq != m_ReqID) return; @@ -520,6 +522,9 @@ namespace renderdocui.Windows var contentsVSOut = RT_FetchBufferContents(MeshDataStage.VSOut, r, m_VSOut.m_Input); var contentsGSOut = RT_FetchBufferContents(MeshDataStage.GSOut, r, m_GSOut.m_Input); + if (MeshView) + UpdateMeshPositionBuffer(); + if (curReq != m_ReqID) return; @@ -1792,7 +1797,7 @@ namespace renderdocui.Windows } } - ClearHighlightVerts(); + UpdateHighlightVerts(GetUIState(m_MeshDisplay.type)); m_CurrentCamera.Apply(); m_Core.Renderer.BeginInvoke(RT_UpdateRenderOutput); @@ -1950,11 +1955,48 @@ namespace renderdocui.Windows controlType.SelectedIndex = 1; } + UpdateMeshPositionBuffer(); + enableCameraControls(); controlType_SelectedIndexChanged(sender, e); } + private void UpdateMeshPositionBuffer() + { + var ui = GetUIState(m_MeshDisplay.type); + + FormatElement pos = null; + + if (ui.m_Input.BufferFormats != null) + { + foreach (var el in ui.m_Input.BufferFormats) + { + // prioritise SV_Position over general POSITION + if (el.name.ToUpper() == "SV_POSITION") + pos = el; + if (el.name.ToUpper() == "POSITION" && pos == null) + pos = el; + } + } + + if (pos == null) + { + m_MeshDisplay.positionBuf = ResourceId.Null; + } + else + { + m_MeshDisplay.positionBuf = m_VSIn.m_Input.Buffers[pos.buffer]; + m_MeshDisplay.positionOffset = pos.offset + ui.m_Input.Offsets[pos.buffer]; + m_MeshDisplay.positionStride = ui.m_Input.Strides[pos.buffer]; + + m_MeshDisplay.positionCompByteWidth = pos.format.compByteWidth; + m_MeshDisplay.positionCompCount = pos.format.compCount; + m_MeshDisplay.positionCompType = pos.format.compType; + m_MeshDisplay.positionFormat = pos.format.special ? pos.format.specialFormat : SpecialFormat.Unknown; + } + } + private void camGuess_PropChanged() { m_MeshDisplay.ortho = matrixType.SelectedIndex == 1; @@ -2397,7 +2439,7 @@ namespace renderdocui.Windows private void ClearHighlightVerts() { - m_MeshDisplay.showVerts = false; + m_MeshDisplay.highlightVert = ~0U; m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { RT_UpdateRenderOutput(r); if (m_Output != null) m_Output.Display(); }); } @@ -2407,83 +2449,7 @@ namespace renderdocui.Windows if (ui.m_GridView.SelectedRows.Count == 0) return; if (!MeshView) return; - int v0 = (ui.m_GridView.SelectedRows[0].Index / 3) * 3; - - if (ui == m_VSIn && ui.m_Data.Topology == PrimitiveTopology.TriangleStrip) - { - int idx = ui.m_GridView.SelectedRows[0].Index; - v0 = Math.Min(ui.m_GridView.RowCount - 3, idx); - - if ((ui.m_Input.Drawcall.flags & DrawcallFlags.UseIBuffer) != 0) - { - // handle tristrip reset values by clamping where possible. - if (GetIndex(ui, v0 + 2) == uint.MaxValue && v0 > 0) - { - if (v0 > 0) - { - v0 -= 1; - } - else - { - // reset value before we've done a full tri. Don't show highlight - ClearHighlightVerts(); - return; - } - } - else if (GetIndex(ui, v0 + 1) == uint.MaxValue && v0 > 1) - { - if (v0 > 1) - { - v0 -= 2; - } - else - { - // reset value before we've done a full tri. Don't show highlight - ClearHighlightVerts(); - return; - } - } - - if (GetIndex(ui, v0 + 0) == uint.MaxValue || - GetIndex(ui, v0 + 1) == uint.MaxValue || - GetIndex(ui, v0 + 2) == uint.MaxValue) - { - // selected a reset value, or shifted back into a reset value thus degenerate triangle, - // don't show anything - ClearHighlightVerts(); - return; - } - } - } - - if (ui.m_GridView.SelectedRows[0].Index == v0 + 0) - { - m_MeshDisplay.highlight.v0 = GetPosition(ui, v0 + 0); - m_MeshDisplay.highlight.v1 = GetPosition(ui, v0 + 1); - m_MeshDisplay.highlight.v2 = GetPosition(ui, v0 + 2); - m_MeshDisplay.showVerts = true; - } - if (ui.m_GridView.SelectedRows[0].Index == v0 + 1) - { - m_MeshDisplay.highlight.v0 = GetPosition(ui, v0 + 1); - m_MeshDisplay.highlight.v1 = GetPosition(ui, v0 + 0); - m_MeshDisplay.highlight.v2 = GetPosition(ui, v0 + 2); - m_MeshDisplay.showVerts = true; - } - if (ui.m_GridView.SelectedRows[0].Index == v0 + 2) - { - m_MeshDisplay.highlight.v0 = GetPosition(ui, v0 + 2); - m_MeshDisplay.highlight.v1 = GetPosition(ui, v0 + 1); - m_MeshDisplay.highlight.v2 = GetPosition(ui, v0 + 0); - m_MeshDisplay.showVerts = true; - } - - if (ui.m_Data.Topology == PrimitiveTopology.PointList) - m_MeshDisplay.highlight.v2 = m_MeshDisplay.highlight.v1 = m_MeshDisplay.highlight.v0; - - if (ui.m_Data.Topology == PrimitiveTopology.LineList || - ui.m_Data.Topology == PrimitiveTopology.LineStrip) - m_MeshDisplay.highlight.v2 = m_MeshDisplay.highlight.v1; + m_MeshDisplay.highlightVert = (uint)ui.m_GridView.SelectedRows[0].Index; m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { RT_UpdateRenderOutput(r); if (m_Output != null) m_Output.Display(); }); }