diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index 828756d38..520f9b2b3 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -3562,575 +3562,6 @@ void D3D11DebugManager::RenderForPredicate() m_WrappedContext->Draw(3, 0); } -void D3D11DebugManager::RenderMesh(uint32_t eventId, const vector &secondaryDraws, - const MeshDisplay &cfg) -{ - if(cfg.position.vertexResourceId == ResourceId() || cfg.position.numIndices == 0) - return; - - DebugVertexCBuffer vertexData; - - D3D11RenderStateTracker tracker(m_WrappedContext); - - vertexData.LineStrip = 0; - - Matrix4f projMat = - Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, float(GetWidth()) / float(GetHeight())); - - Matrix4f camMat = cfg.cam ? ((Camera *)cfg.cam)->GetMatrix() : Matrix4f::Identity(); - Matrix4f guessProjInv; - - vertexData.ModelViewProj = projMat.Mul(camMat); - vertexData.SpriteSize = Vec2f(); - - DebugPixelCBufferData pixelData; - - pixelData.AlwaysZero = 0.0f; - - pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; - pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 0.0f); - FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); - - m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); - m_pImmediateContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0); - - m_pImmediateContext->HSSetShader(NULL, NULL, 0); - m_pImmediateContext->DSSetShader(NULL, NULL, 0); - m_pImmediateContext->GSSetShader(NULL, NULL, 0); - - m_pImmediateContext->OMSetDepthStencilState(NULL, 0); - m_pImmediateContext->OMSetBlendState(m_WireframeHelpersBS, NULL, 0xffffffff); - - // don't cull in wireframe mesh display - m_pImmediateContext->RSSetState(m_WireframeHelpersRS); - - const ResourceFormat &resFmt = cfg.position.format; - const ResourceFormat &resFmt2 = cfg.second.format; - - if(m_PrevMeshFmt != resFmt || m_PrevMeshFmt2 != resFmt2) - { - SAFE_RELEASE(m_MeshDisplayLayout); - - D3D11_INPUT_ELEMENT_DESC layoutdesc[2]; - - layoutdesc[0].SemanticName = "pos"; - layoutdesc[0].SemanticIndex = 0; - layoutdesc[0].Format = DXGI_FORMAT_R8G8B8A8_UNORM; - if(cfg.position.vertexResourceId != ResourceId() && (resFmt.Special() || resFmt.compCount > 0)) - layoutdesc[0].Format = MakeDXGIFormat(resFmt); - layoutdesc[0].AlignedByteOffset = 0; // offset will be handled by vertex buffer offset - layoutdesc[0].InputSlot = 0; - layoutdesc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - layoutdesc[0].InstanceDataStepRate = 0; - - layoutdesc[1].SemanticName = "sec"; - layoutdesc[1].SemanticIndex = 0; - layoutdesc[1].Format = DXGI_FORMAT_R8G8B8A8_UNORM; - if(cfg.second.vertexResourceId != ResourceId() && (resFmt2.Special() || resFmt2.compCount > 0)) - layoutdesc[1].Format = MakeDXGIFormat(resFmt2); - layoutdesc[1].AlignedByteOffset = 0; - layoutdesc[1].InputSlot = 1; - layoutdesc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - layoutdesc[1].InstanceDataStepRate = 0; - - HRESULT hr = m_pDevice->CreateInputLayout(layoutdesc, 2, m_DebugRender.MeshVSBytecode, - m_DebugRender.MeshVSBytelen, &m_MeshDisplayLayout); - - if(FAILED(hr)) - { - RDCERR("Failed to create m_MeshDisplayLayout HRESULT: %s", ToStr(hr).c_str()); - m_MeshDisplayLayout = NULL; - } - } - - m_PrevMeshFmt = resFmt; - m_PrevMeshFmt2 = resFmt2; - - RDCASSERT(cfg.position.indexByteOffset < 0xffffffff); - - ID3D11Buffer *ibuf = NULL; - DXGI_FORMAT ifmt = DXGI_FORMAT_R16_UINT; - UINT ioffs = (UINT)cfg.position.indexByteOffset; - - D3D11_PRIMITIVE_TOPOLOGY topo = MakeD3DPrimitiveTopology(cfg.position.topology); - - // render the mesh itself (solid, then wireframe) - { - 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 = - cfg.position.farPlane != FLT_MAX - ? Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, - cfg.aspect) - : Matrix4f::ReversePerspective(cfg.fov, cfg.position.nearPlane, cfg.aspect); - - if(cfg.ortho) - { - guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); - } - - guessProjInv = guessProj.Inverse(); - - vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); - } - - FillCBuffer(m_DebugRender.GenericVSCBuffer, &vertexData, sizeof(DebugVertexCBuffer)); - - m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer); - m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); - - Vec4f meshColour; - - ID3D11Buffer *meshColourBuf = MakeCBuffer(&meshColour, sizeof(Vec4f)); - - m_pImmediateContext->VSSetShader(m_DebugRender.MeshVS, NULL, 0); - m_pImmediateContext->PSSetShader(m_DebugRender.MeshPS, NULL, 0); - - // secondary draws - this is the "draw since last clear" feature. We don't have - // full flexibility, it only draws wireframe, and only the final rasterized position. - if(secondaryDraws.size() > 0) - { - m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); - - pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; - FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); - - for(size_t i = 0; i < secondaryDraws.size(); i++) - { - const MeshFormat &fmt = secondaryDraws[i]; - - if(fmt.vertexResourceId != ResourceId()) - { - meshColour = Vec4f(fmt.meshColor.x, fmt.meshColor.y, fmt.meshColor.z, 1.0f); - FillCBuffer(meshColourBuf, &meshColour, sizeof(meshColour)); - m_pImmediateContext->PSSetConstantBuffers(2, 1, &meshColourBuf); - - m_pImmediateContext->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(fmt.topology)); - - auto it = WrappedID3D11Buffer::m_BufferList.find(fmt.vertexResourceId); - - ID3D11Buffer *buf = it->second.m_Buffer; - m_pImmediateContext->IASetVertexBuffers(0, 1, &buf, (UINT *)&fmt.vertexByteStride, - (UINT *)&fmt.vertexByteOffset); - if(fmt.indexResourceId != ResourceId()) - { - RDCASSERT(fmt.indexByteOffset < 0xffffffff); - - it = WrappedID3D11Buffer::m_BufferList.find(fmt.indexResourceId); - buf = it->second.m_Buffer; - m_pImmediateContext->IASetIndexBuffer( - buf, fmt.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, - (UINT)fmt.indexByteOffset); - - m_pImmediateContext->DrawIndexed(fmt.numIndices, 0, fmt.baseVertex); - } - else - { - m_pImmediateContext->Draw(fmt.numIndices, 0); - } - } - } - } - - ID3D11InputLayout *layout = m_MeshDisplayLayout; - - if(layout == NULL) - { - RDCWARN("Couldn't get a mesh display layout"); - return; - } - - m_pImmediateContext->IASetInputLayout(layout); - - RDCASSERT(cfg.position.vertexByteOffset < 0xffffffff && cfg.second.vertexByteOffset < 0xffffffff); - - ID3D11Buffer *vbs[2] = {NULL, NULL}; - UINT str[] = {cfg.position.vertexByteStride, cfg.second.vertexByteStride}; - UINT offs[] = {(UINT)cfg.position.vertexByteOffset, (UINT)cfg.second.vertexByteOffset}; - - { - auto it = WrappedID3D11Buffer::m_BufferList.find(cfg.position.vertexResourceId); - - if(it != WrappedID3D11Buffer::m_BufferList.end()) - vbs[0] = it->second.m_Buffer; - - it = WrappedID3D11Buffer::m_BufferList.find(cfg.second.vertexResourceId); - - if(it != WrappedID3D11Buffer::m_BufferList.end()) - vbs[1] = it->second.m_Buffer; - - it = WrappedID3D11Buffer::m_BufferList.find(cfg.position.indexResourceId); - - if(it != WrappedID3D11Buffer::m_BufferList.end()) - ibuf = it->second.m_Buffer; - - if(cfg.position.indexByteStride == 4) - ifmt = DXGI_FORMAT_R32_UINT; - } - - m_pImmediateContext->IASetVertexBuffers(0, 2, vbs, str, offs); - if(cfg.position.indexByteStride) - m_pImmediateContext->IASetIndexBuffer(ibuf, ifmt, ioffs); - else - m_pImmediateContext->IASetIndexBuffer(NULL, DXGI_FORMAT_UNKNOWN, NULL); - - // draw solid shaded mode - if(cfg.solidShadeMode != SolidShade::NoSolid && cfg.position.topology < Topology::PatchList_1CPs) - { - m_pImmediateContext->RSSetState(m_DebugRender.RastState); - - m_pImmediateContext->IASetPrimitiveTopology(topo); - - pixelData.OutputDisplayFormat = (int)cfg.solidShadeMode; - if(cfg.solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha) - pixelData.OutputDisplayFormat = MESHDISPLAY_SECONDARY_ALPHA; - FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); - - meshColour = Vec4f(0.8f, 0.8f, 0.0f, 1.0f); - FillCBuffer(meshColourBuf, &meshColour, sizeof(meshColour)); - m_pImmediateContext->PSSetConstantBuffers(2, 1, &meshColourBuf); - - m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); - - if(cfg.solidShadeMode == SolidShade::Lit) - { - DebugGeometryCBuffer geomData; - - geomData.InvProj = projMat.Inverse(); - - FillCBuffer(m_DebugRender.GenericGSCBuffer, &geomData, sizeof(DebugGeometryCBuffer)); - m_pImmediateContext->GSSetConstantBuffers(0, 1, &m_DebugRender.GenericGSCBuffer); - - m_pImmediateContext->GSSetShader(m_DebugRender.MeshGS, NULL, 0); - } - - if(cfg.position.indexByteStride) - m_pImmediateContext->DrawIndexed(cfg.position.numIndices, 0, cfg.position.baseVertex); - else - m_pImmediateContext->Draw(cfg.position.numIndices, 0); - - if(cfg.solidShadeMode == SolidShade::Lit) - m_pImmediateContext->GSSetShader(NULL, NULL, 0); - } - - // draw wireframe mode - if(cfg.solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw || - cfg.position.topology >= Topology::PatchList_1CPs) - { - m_pImmediateContext->RSSetState(m_WireframeHelpersRS); - - m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.LEqualDepthState, 0); - - pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; - FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); - - meshColour = - Vec4f(cfg.position.meshColor.x, cfg.position.meshColor.y, cfg.position.meshColor.z, 1.0f); - FillCBuffer(meshColourBuf, &meshColour, sizeof(meshColour)); - m_pImmediateContext->PSSetConstantBuffers(2, 1, &meshColourBuf); - - m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); - - if(cfg.position.topology >= Topology::PatchList_1CPs) - m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); - else - m_pImmediateContext->IASetPrimitiveTopology(topo); - - if(cfg.position.indexByteStride) - m_pImmediateContext->DrawIndexed(cfg.position.numIndices, 0, cfg.position.baseVertex); - else - m_pImmediateContext->Draw(cfg.position.numIndices, 0); - } - } - - m_pImmediateContext->RSSetState(m_WireframeHelpersRS); - - // set up state for drawing helpers - { - vertexData.ModelViewProj = projMat.Mul(camMat); - FillCBuffer(m_DebugRender.GenericVSCBuffer, &vertexData, sizeof(DebugVertexCBuffer)); - - m_pImmediateContext->RSSetState(m_SolidHelpersRS); - - m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.NoDepthState, 0); - - m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer); - m_pImmediateContext->VSSetShader(m_DebugRender.MeshVS, NULL, 0); - m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); - m_pImmediateContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0); - } - - // axis markers - if(!cfg.position.unproject) - { - m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); - - UINT strides[] = {sizeof(Vec4f)}; - UINT offsets[] = {0}; - - m_pImmediateContext->IASetVertexBuffers(0, 1, &m_AxisHelper, strides, offsets); - m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); - m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); - - pixelData.WireframeColour = Vec3f(1.0f, 0.0f, 0.0f); - FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); - m_pImmediateContext->Draw(2, 0); - - pixelData.WireframeColour = Vec3f(0.0f, 1.0f, 0.0f); - FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); - m_pImmediateContext->Draw(2, 2); - - pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 1.0f); - FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); - m_pImmediateContext->Draw(2, 4); - } - - if(cfg.highlightVert != ~0U) - { - m_HighlightCache.CacheHighlightingData(eventId, cfg); - - D3D11_PRIMITIVE_TOPOLOGY meshtopo = topo; - - /////////////////////////////////////////////////////////////// - // vectors to be set from buffers, depending on topology - - // this vert (blue dot, required) - FloatVector activeVertex; - - // primitive this vert is a part of (red prim, optional) - vector activePrim; - - // 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(meshtopo == D3D11_PRIMITIVE_TOPOLOGY_LINELIST || - meshtopo == D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ || - meshtopo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP || - meshtopo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ) - { - primSize = 2; - primTopo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; - } - - bool valid = m_HighlightCache.FetchHighlightPositions(cfg, activeVertex, activePrim, - adjacentPrimVertices, inactiveVertices); - - if(valid) - { - //////////////////////////////////////////////////////////////// - // prepare rendering (for both vertices & primitives) - - // if data is from post transform, it will be in clipspace - if(cfg.position.unproject) - vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); - else - vertexData.ModelViewProj = projMat.Mul(camMat); - - m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); - - FillCBuffer(m_DebugRender.GenericVSCBuffer, &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, &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 HRESULT: %s", ToStr(hr).c_str()); - 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, &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 HRESULT: %s", ToStr(hr).c_str()); - 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, &vertexData, sizeof(DebugVertexCBuffer)); - - // Draw active vertex (blue) - pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 1.0f); - FillCBuffer(m_DebugRender.GenericPSCBuffer, &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 HRESULT: %s", ToStr(hr).c_str()); - 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, &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 HRESULT: %s", ToStr(hr).c_str()); - return; - } - - memcpy(mapped.pData, vertSprite, sizeof(vertSprite)); - m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); - - m_pImmediateContext->Draw(4, 0); - } - } - - if(cfg.position.unproject) - m_pImmediateContext->VSSetShader(m_DebugRender.MeshVS, NULL, 0); - } - - // bounding box - if(cfg.showBBox) - { - UINT strides[] = {sizeof(Vec4f)}; - UINT offsets[] = {0}; - D3D11_MAPPED_SUBRESOURCE mapped; - - vertexData.SpriteSize = Vec2f(); - vertexData.ModelViewProj = projMat.Mul(camMat); - FillCBuffer(m_DebugRender.GenericVSCBuffer, &vertexData, sizeof(DebugVertexCBuffer)); - - HRESULT hr = - m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); - RDCASSERTEQUAL(hr, S_OK); - - Vec4f a = Vec4f(cfg.minBounds.x, cfg.minBounds.y, cfg.minBounds.z, cfg.minBounds.w); - Vec4f b = Vec4f(cfg.maxBounds.x, cfg.maxBounds.y, cfg.maxBounds.z, cfg.maxBounds.w); - - Vec4f TLN = Vec4f(a.x, b.y, a.z, 1.0f); // TopLeftNear, etc... - Vec4f TRN = Vec4f(b.x, b.y, a.z, 1.0f); - Vec4f BLN = Vec4f(a.x, a.y, a.z, 1.0f); - Vec4f BRN = Vec4f(b.x, a.y, a.z, 1.0f); - - Vec4f TLF = Vec4f(a.x, b.y, b.z, 1.0f); - Vec4f TRF = Vec4f(b.x, b.y, b.z, 1.0f); - Vec4f BLF = Vec4f(a.x, a.y, b.z, 1.0f); - Vec4f BRF = Vec4f(b.x, a.y, b.z, 1.0f); - - // 12 frustum lines => 24 verts - Vec4f bbox[24] = { - TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN, - - TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF, - - TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF, - }; - - memcpy(mapped.pData, bbox, sizeof(bbox)); - - m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); - - // we want this to clip - m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.LEqualDepthState, 0); - - m_pImmediateContext->IASetVertexBuffers(0, 1, &m_TriHighlightHelper, (UINT *)&strides, - (UINT *)&offsets); - m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); - m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); - - pixelData.WireframeColour = Vec3f(0.2f, 0.2f, 1.0f); - FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); - - m_pImmediateContext->Draw(24, 0); - - m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.NoDepthState, 0); - } - - // 'fake' helper frustum - if(cfg.position.unproject) - { - UINT strides[] = {sizeof(Vec4f)}; - UINT offsets[] = {0}; - - vertexData.SpriteSize = Vec2f(); - vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); - FillCBuffer(m_DebugRender.GenericVSCBuffer, &vertexData, sizeof(DebugVertexCBuffer)); - - m_pImmediateContext->IASetVertexBuffers(0, 1, &m_FrustumHelper, (UINT *)&strides, - (UINT *)&offsets); - m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); - m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); - - pixelData.WireframeColour = Vec3f(1.0f, 1.0f, 1.0f); - FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); - - m_pImmediateContext->Draw(24, 0); - } -} - void D3D11DebugManager::FillCBufferVariables(const string &prefix, size_t &offset, bool flatten, const vector &invars, vector &outvars, const bytebuf &data) diff --git a/renderdoc/driver/d3d11/d3d11_rendermesh.cpp b/renderdoc/driver/d3d11/d3d11_rendermesh.cpp new file mode 100644 index 000000000..64f4c2fc9 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_rendermesh.cpp @@ -0,0 +1,601 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2018 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. + ******************************************************************************/ + +#include "maths/camera.h" +#include "maths/formatpacking.h" +#include "maths/matrix.h" +#include "d3d11_debug.h" +#include "d3d11_device.h" +#include "d3d11_resources.h" + +#include "data/hlsl/debugcbuffers.h" + +void D3D11DebugManager::RenderMesh(uint32_t eventId, const vector &secondaryDraws, + const MeshDisplay &cfg) +{ + if(cfg.position.vertexResourceId == ResourceId() || cfg.position.numIndices == 0) + return; + + DebugVertexCBuffer vertexData; + + D3D11RenderStateTracker tracker(m_WrappedContext); + + vertexData.LineStrip = 0; + + Matrix4f projMat = + Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, float(GetWidth()) / float(GetHeight())); + + Matrix4f camMat = cfg.cam ? ((Camera *)cfg.cam)->GetMatrix() : Matrix4f::Identity(); + Matrix4f guessProjInv; + + vertexData.ModelViewProj = projMat.Mul(camMat); + vertexData.SpriteSize = Vec2f(); + + DebugPixelCBufferData pixelData; + + pixelData.AlwaysZero = 0.0f; + + pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; + pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + m_pImmediateContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0); + + m_pImmediateContext->HSSetShader(NULL, NULL, 0); + m_pImmediateContext->DSSetShader(NULL, NULL, 0); + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + + m_pImmediateContext->OMSetDepthStencilState(NULL, 0); + m_pImmediateContext->OMSetBlendState(m_WireframeHelpersBS, NULL, 0xffffffff); + + // don't cull in wireframe mesh display + m_pImmediateContext->RSSetState(m_WireframeHelpersRS); + + const ResourceFormat &resFmt = cfg.position.format; + const ResourceFormat &resFmt2 = cfg.second.format; + + if(m_PrevMeshFmt != resFmt || m_PrevMeshFmt2 != resFmt2) + { + SAFE_RELEASE(m_MeshDisplayLayout); + + D3D11_INPUT_ELEMENT_DESC layoutdesc[2]; + + layoutdesc[0].SemanticName = "pos"; + layoutdesc[0].SemanticIndex = 0; + layoutdesc[0].Format = DXGI_FORMAT_R8G8B8A8_UNORM; + if(cfg.position.vertexResourceId != ResourceId() && (resFmt.Special() || resFmt.compCount > 0)) + layoutdesc[0].Format = MakeDXGIFormat(resFmt); + layoutdesc[0].AlignedByteOffset = 0; // offset will be handled by vertex buffer offset + layoutdesc[0].InputSlot = 0; + layoutdesc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + layoutdesc[0].InstanceDataStepRate = 0; + + layoutdesc[1].SemanticName = "sec"; + layoutdesc[1].SemanticIndex = 0; + layoutdesc[1].Format = DXGI_FORMAT_R8G8B8A8_UNORM; + if(cfg.second.vertexResourceId != ResourceId() && (resFmt2.Special() || resFmt2.compCount > 0)) + layoutdesc[1].Format = MakeDXGIFormat(resFmt2); + layoutdesc[1].AlignedByteOffset = 0; + layoutdesc[1].InputSlot = 1; + layoutdesc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + layoutdesc[1].InstanceDataStepRate = 0; + + HRESULT hr = m_pDevice->CreateInputLayout(layoutdesc, 2, m_DebugRender.MeshVSBytecode, + m_DebugRender.MeshVSBytelen, &m_MeshDisplayLayout); + + if(FAILED(hr)) + { + RDCERR("Failed to create m_MeshDisplayLayout HRESULT: %s", ToStr(hr).c_str()); + m_MeshDisplayLayout = NULL; + } + } + + m_PrevMeshFmt = resFmt; + m_PrevMeshFmt2 = resFmt2; + + RDCASSERT(cfg.position.indexByteOffset < 0xffffffff); + + ID3D11Buffer *ibuf = NULL; + DXGI_FORMAT ifmt = DXGI_FORMAT_R16_UINT; + UINT ioffs = (UINT)cfg.position.indexByteOffset; + + D3D11_PRIMITIVE_TOPOLOGY topo = MakeD3DPrimitiveTopology(cfg.position.topology); + + // render the mesh itself (solid, then wireframe) + { + 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 = + cfg.position.farPlane != FLT_MAX + ? Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, + cfg.aspect) + : Matrix4f::ReversePerspective(cfg.fov, cfg.position.nearPlane, cfg.aspect); + + if(cfg.ortho) + { + guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); + } + + guessProjInv = guessProj.Inverse(); + + vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + } + + FillCBuffer(m_DebugRender.GenericVSCBuffer, &vertexData, sizeof(DebugVertexCBuffer)); + + m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer); + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + + Vec4f meshColour; + + ID3D11Buffer *meshColourBuf = MakeCBuffer(&meshColour, sizeof(Vec4f)); + + m_pImmediateContext->VSSetShader(m_DebugRender.MeshVS, NULL, 0); + m_pImmediateContext->PSSetShader(m_DebugRender.MeshPS, NULL, 0); + + // secondary draws - this is the "draw since last clear" feature. We don't have + // full flexibility, it only draws wireframe, and only the final rasterized position. + if(secondaryDraws.size() > 0) + { + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + + pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; + FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); + + for(size_t i = 0; i < secondaryDraws.size(); i++) + { + const MeshFormat &fmt = secondaryDraws[i]; + + if(fmt.vertexResourceId != ResourceId()) + { + meshColour = Vec4f(fmt.meshColor.x, fmt.meshColor.y, fmt.meshColor.z, 1.0f); + FillCBuffer(meshColourBuf, &meshColour, sizeof(meshColour)); + m_pImmediateContext->PSSetConstantBuffers(2, 1, &meshColourBuf); + + m_pImmediateContext->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(fmt.topology)); + + auto it = WrappedID3D11Buffer::m_BufferList.find(fmt.vertexResourceId); + + ID3D11Buffer *buf = it->second.m_Buffer; + m_pImmediateContext->IASetVertexBuffers(0, 1, &buf, (UINT *)&fmt.vertexByteStride, + (UINT *)&fmt.vertexByteOffset); + if(fmt.indexResourceId != ResourceId()) + { + RDCASSERT(fmt.indexByteOffset < 0xffffffff); + + it = WrappedID3D11Buffer::m_BufferList.find(fmt.indexResourceId); + buf = it->second.m_Buffer; + m_pImmediateContext->IASetIndexBuffer( + buf, fmt.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, + (UINT)fmt.indexByteOffset); + + m_pImmediateContext->DrawIndexed(fmt.numIndices, 0, fmt.baseVertex); + } + else + { + m_pImmediateContext->Draw(fmt.numIndices, 0); + } + } + } + } + + ID3D11InputLayout *layout = m_MeshDisplayLayout; + + if(layout == NULL) + { + RDCWARN("Couldn't get a mesh display layout"); + return; + } + + m_pImmediateContext->IASetInputLayout(layout); + + RDCASSERT(cfg.position.vertexByteOffset < 0xffffffff && cfg.second.vertexByteOffset < 0xffffffff); + + ID3D11Buffer *vbs[2] = {NULL, NULL}; + UINT str[] = {cfg.position.vertexByteStride, cfg.second.vertexByteStride}; + UINT offs[] = {(UINT)cfg.position.vertexByteOffset, (UINT)cfg.second.vertexByteOffset}; + + { + auto it = WrappedID3D11Buffer::m_BufferList.find(cfg.position.vertexResourceId); + + if(it != WrappedID3D11Buffer::m_BufferList.end()) + vbs[0] = it->second.m_Buffer; + + it = WrappedID3D11Buffer::m_BufferList.find(cfg.second.vertexResourceId); + + if(it != WrappedID3D11Buffer::m_BufferList.end()) + vbs[1] = it->second.m_Buffer; + + it = WrappedID3D11Buffer::m_BufferList.find(cfg.position.indexResourceId); + + if(it != WrappedID3D11Buffer::m_BufferList.end()) + ibuf = it->second.m_Buffer; + + if(cfg.position.indexByteStride == 4) + ifmt = DXGI_FORMAT_R32_UINT; + } + + m_pImmediateContext->IASetVertexBuffers(0, 2, vbs, str, offs); + if(cfg.position.indexByteStride) + m_pImmediateContext->IASetIndexBuffer(ibuf, ifmt, ioffs); + else + m_pImmediateContext->IASetIndexBuffer(NULL, DXGI_FORMAT_UNKNOWN, NULL); + + // draw solid shaded mode + if(cfg.solidShadeMode != SolidShade::NoSolid && cfg.position.topology < Topology::PatchList_1CPs) + { + m_pImmediateContext->RSSetState(m_DebugRender.RastState); + + m_pImmediateContext->IASetPrimitiveTopology(topo); + + pixelData.OutputDisplayFormat = (int)cfg.solidShadeMode; + if(cfg.solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha) + pixelData.OutputDisplayFormat = MESHDISPLAY_SECONDARY_ALPHA; + FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); + + meshColour = Vec4f(0.8f, 0.8f, 0.0f, 1.0f); + FillCBuffer(meshColourBuf, &meshColour, sizeof(meshColour)); + m_pImmediateContext->PSSetConstantBuffers(2, 1, &meshColourBuf); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + + if(cfg.solidShadeMode == SolidShade::Lit) + { + DebugGeometryCBuffer geomData; + + geomData.InvProj = projMat.Inverse(); + + FillCBuffer(m_DebugRender.GenericGSCBuffer, &geomData, sizeof(DebugGeometryCBuffer)); + m_pImmediateContext->GSSetConstantBuffers(0, 1, &m_DebugRender.GenericGSCBuffer); + + m_pImmediateContext->GSSetShader(m_DebugRender.MeshGS, NULL, 0); + } + + if(cfg.position.indexByteStride) + m_pImmediateContext->DrawIndexed(cfg.position.numIndices, 0, cfg.position.baseVertex); + else + m_pImmediateContext->Draw(cfg.position.numIndices, 0); + + if(cfg.solidShadeMode == SolidShade::Lit) + m_pImmediateContext->GSSetShader(NULL, NULL, 0); + } + + // draw wireframe mode + if(cfg.solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw || + cfg.position.topology >= Topology::PatchList_1CPs) + { + m_pImmediateContext->RSSetState(m_WireframeHelpersRS); + + m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.LEqualDepthState, 0); + + pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; + FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); + + meshColour = + Vec4f(cfg.position.meshColor.x, cfg.position.meshColor.y, cfg.position.meshColor.z, 1.0f); + FillCBuffer(meshColourBuf, &meshColour, sizeof(meshColour)); + m_pImmediateContext->PSSetConstantBuffers(2, 1, &meshColourBuf); + + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + + if(cfg.position.topology >= Topology::PatchList_1CPs) + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + else + m_pImmediateContext->IASetPrimitiveTopology(topo); + + if(cfg.position.indexByteStride) + m_pImmediateContext->DrawIndexed(cfg.position.numIndices, 0, cfg.position.baseVertex); + else + m_pImmediateContext->Draw(cfg.position.numIndices, 0); + } + } + + m_pImmediateContext->RSSetState(m_WireframeHelpersRS); + + // set up state for drawing helpers + { + vertexData.ModelViewProj = projMat.Mul(camMat); + FillCBuffer(m_DebugRender.GenericVSCBuffer, &vertexData, sizeof(DebugVertexCBuffer)); + + m_pImmediateContext->RSSetState(m_SolidHelpersRS); + + m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.NoDepthState, 0); + + m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer); + m_pImmediateContext->VSSetShader(m_DebugRender.MeshVS, NULL, 0); + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + m_pImmediateContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0); + } + + // axis markers + if(!cfg.position.unproject) + { + m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer); + + UINT strides[] = {sizeof(Vec4f)}; + UINT offsets[] = {0}; + + m_pImmediateContext->IASetVertexBuffers(0, 1, &m_AxisHelper, strides, offsets); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + + pixelData.WireframeColour = Vec3f(1.0f, 0.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); + m_pImmediateContext->Draw(2, 0); + + pixelData.WireframeColour = Vec3f(0.0f, 1.0f, 0.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); + m_pImmediateContext->Draw(2, 2); + + pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 1.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); + m_pImmediateContext->Draw(2, 4); + } + + if(cfg.highlightVert != ~0U) + { + m_HighlightCache.CacheHighlightingData(eventId, cfg); + + D3D11_PRIMITIVE_TOPOLOGY meshtopo = topo; + + /////////////////////////////////////////////////////////////// + // vectors to be set from buffers, depending on topology + + // this vert (blue dot, required) + FloatVector activeVertex; + + // primitive this vert is a part of (red prim, optional) + vector activePrim; + + // 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(meshtopo == D3D11_PRIMITIVE_TOPOLOGY_LINELIST || + meshtopo == D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ || + meshtopo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP || + meshtopo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ) + { + primSize = 2; + primTopo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; + } + + bool valid = m_HighlightCache.FetchHighlightPositions(cfg, activeVertex, activePrim, + adjacentPrimVertices, inactiveVertices); + + if(valid) + { + //////////////////////////////////////////////////////////////// + // prepare rendering (for both vertices & primitives) + + // if data is from post transform, it will be in clipspace + if(cfg.position.unproject) + vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + else + vertexData.ModelViewProj = projMat.Mul(camMat); + + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + + FillCBuffer(m_DebugRender.GenericVSCBuffer, &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, &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 HRESULT: %s", ToStr(hr).c_str()); + 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, &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 HRESULT: %s", ToStr(hr).c_str()); + 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, &vertexData, sizeof(DebugVertexCBuffer)); + + // Draw active vertex (blue) + pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 1.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, &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 HRESULT: %s", ToStr(hr).c_str()); + 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, &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 HRESULT: %s", ToStr(hr).c_str()); + return; + } + + memcpy(mapped.pData, vertSprite, sizeof(vertSprite)); + m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); + + m_pImmediateContext->Draw(4, 0); + } + } + + if(cfg.position.unproject) + m_pImmediateContext->VSSetShader(m_DebugRender.MeshVS, NULL, 0); + } + + // bounding box + if(cfg.showBBox) + { + UINT strides[] = {sizeof(Vec4f)}; + UINT offsets[] = {0}; + D3D11_MAPPED_SUBRESOURCE mapped; + + vertexData.SpriteSize = Vec2f(); + vertexData.ModelViewProj = projMat.Mul(camMat); + FillCBuffer(m_DebugRender.GenericVSCBuffer, &vertexData, sizeof(DebugVertexCBuffer)); + + HRESULT hr = + m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + RDCASSERTEQUAL(hr, S_OK); + + Vec4f a = Vec4f(cfg.minBounds.x, cfg.minBounds.y, cfg.minBounds.z, cfg.minBounds.w); + Vec4f b = Vec4f(cfg.maxBounds.x, cfg.maxBounds.y, cfg.maxBounds.z, cfg.maxBounds.w); + + Vec4f TLN = Vec4f(a.x, b.y, a.z, 1.0f); // TopLeftNear, etc... + Vec4f TRN = Vec4f(b.x, b.y, a.z, 1.0f); + Vec4f BLN = Vec4f(a.x, a.y, a.z, 1.0f); + Vec4f BRN = Vec4f(b.x, a.y, a.z, 1.0f); + + Vec4f TLF = Vec4f(a.x, b.y, b.z, 1.0f); + Vec4f TRF = Vec4f(b.x, b.y, b.z, 1.0f); + Vec4f BLF = Vec4f(a.x, a.y, b.z, 1.0f); + Vec4f BRF = Vec4f(b.x, a.y, b.z, 1.0f); + + // 12 frustum lines => 24 verts + Vec4f bbox[24] = { + TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN, + + TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF, + + TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF, + }; + + memcpy(mapped.pData, bbox, sizeof(bbox)); + + m_pImmediateContext->Unmap(m_TriHighlightHelper, 0); + + // we want this to clip + m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.LEqualDepthState, 0); + + m_pImmediateContext->IASetVertexBuffers(0, 1, &m_TriHighlightHelper, (UINT *)&strides, + (UINT *)&offsets); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + + pixelData.WireframeColour = Vec3f(0.2f, 0.2f, 1.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); + + m_pImmediateContext->Draw(24, 0); + + m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.NoDepthState, 0); + } + + // 'fake' helper frustum + if(cfg.position.unproject) + { + UINT strides[] = {sizeof(Vec4f)}; + UINT offsets[] = {0}; + + vertexData.SpriteSize = Vec2f(); + vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + FillCBuffer(m_DebugRender.GenericVSCBuffer, &vertexData, sizeof(DebugVertexCBuffer)); + + m_pImmediateContext->IASetVertexBuffers(0, 1, &m_FrustumHelper, (UINT *)&strides, + (UINT *)&offsets); + m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); + m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout); + + pixelData.WireframeColour = Vec3f(1.0f, 1.0f, 1.0f); + FillCBuffer(m_DebugRender.GenericPSCBuffer, &pixelData, sizeof(DebugPixelCBufferData)); + + m_pImmediateContext->Draw(24, 0); + } +} diff --git a/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj b/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj index a350d9fcf..0ba160427 100644 --- a/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj +++ b/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj @@ -103,6 +103,7 @@ + diff --git a/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj.filters b/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj.filters index ac7d8478b..e5e6177b8 100644 --- a/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj.filters +++ b/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj.filters @@ -105,6 +105,9 @@ Replay + + Replay + diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index c9b1bb41b..2f9a70d91 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -3650,745 +3650,6 @@ bool D3D12DebugManager::RenderTexture(TextureDisplay cfg, bool blendAlpha) return RenderTextureInternal(m_OutputWindows[m_CurrentOutputWindow].rtv, cfg, blendAlpha); } -D3D12DebugManager::MeshDisplayPipelines D3D12DebugManager::CacheMeshDisplayPipelines( - const MeshFormat &primary, const MeshFormat &secondary) -{ - // generate a key to look up the map - uint64_t key = 0; - - uint64_t bit = 0; - - if(primary.indexByteStride == 4) - key |= 1ULL << bit; - bit++; - - RDCASSERT((uint32_t)primary.topology < 64); - key |= uint64_t((uint32_t)primary.topology & 0x3f) << bit; - bit += 6; - - DXGI_FORMAT primaryFmt = MakeDXGIFormat(primary.format); - DXGI_FORMAT secondaryFmt = secondary.vertexResourceId == ResourceId() - ? DXGI_FORMAT_UNKNOWN - : MakeDXGIFormat(secondary.format); - - key |= uint64_t((uint32_t)primaryFmt & 0xff) << bit; - bit += 8; - - key |= uint64_t((uint32_t)secondaryFmt & 0xff) << bit; - bit += 8; - - RDCASSERT(primary.vertexByteStride <= 0xffff); - key |= uint64_t((uint32_t)primary.vertexByteStride & 0xffff) << bit; - bit += 16; - - if(secondary.vertexResourceId != ResourceId()) - { - RDCASSERT(secondary.vertexByteStride <= 0xffff); - key |= uint64_t((uint32_t)secondary.vertexByteStride & 0xffff) << bit; - } - bit += 16; - - MeshDisplayPipelines &cache = m_CachedMeshPipelines[key]; - - if(cache.pipes[(uint32_t)SolidShade::NoSolid] != NULL) - return cache; - - // should we try and evict old pipelines from the cache here? - // or just keep them forever - - D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc; - RDCEraseEl(pipeDesc); - pipeDesc.pRootSignature = m_CBOnlyRootSig; - pipeDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; - pipeDesc.SampleMask = 0xFFFFFFFF; - pipeDesc.SampleDesc.Count = D3D12_MSAA_SAMPLECOUNT; - pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; - D3D_PRIMITIVE_TOPOLOGY topo = MakeD3DPrimitiveTopology(primary.topology); - - if(topo == D3D_PRIMITIVE_TOPOLOGY_POINTLIST || - topo >= D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST) - pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; - else if(topo == D3D_PRIMITIVE_TOPOLOGY_LINESTRIP || topo == D3D_PRIMITIVE_TOPOLOGY_LINELIST || - topo == D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ || topo == D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ) - pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; - else - pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - - pipeDesc.NumRenderTargets = 1; - pipeDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - pipeDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; - pipeDesc.BlendState.RenderTarget[0].BlendEnable = TRUE; - pipeDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; - pipeDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; - pipeDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; - pipeDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; - pipeDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; - pipeDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; - pipeDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; - - D3D12_INPUT_ELEMENT_DESC ia[2] = {}; - ia[0].SemanticName = "pos"; - ia[0].Format = primaryFmt; - ia[1].SemanticName = "sec"; - ia[1].InputSlot = 1; - ia[1].Format = secondaryFmt == DXGI_FORMAT_UNKNOWN ? primaryFmt : secondaryFmt; - ia[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA; - - pipeDesc.InputLayout.NumElements = 2; - pipeDesc.InputLayout.pInputElementDescs = ia; - - RDCASSERT(primaryFmt != DXGI_FORMAT_UNKNOWN); - - // wireframe pipeline - pipeDesc.VS.BytecodeLength = m_MeshVS->GetBufferSize(); - pipeDesc.VS.pShaderBytecode = m_MeshVS->GetBufferPointer(); - pipeDesc.PS.BytecodeLength = m_MeshPS->GetBufferSize(); - pipeDesc.PS.pShaderBytecode = m_MeshPS->GetBufferPointer(); - - pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME; - pipeDesc.DepthStencilState.DepthEnable = FALSE; - pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; - - HRESULT hr = S_OK; - - hr = m_WrappedDevice->CreateGraphicsPipelineState( - &pipeDesc, __uuidof(ID3D12PipelineState), - (void **)&cache.pipes[MeshDisplayPipelines::ePipe_Wire]); - RDCASSERTEQUAL(hr, S_OK); - - pipeDesc.DepthStencilState.DepthEnable = TRUE; - pipeDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; - pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; - - hr = m_WrappedDevice->CreateGraphicsPipelineState( - &pipeDesc, __uuidof(ID3D12PipelineState), - (void **)&cache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); - RDCASSERTEQUAL(hr, S_OK); - - // solid shading pipeline - pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; - pipeDesc.DepthStencilState.DepthEnable = FALSE; - pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; - - hr = m_WrappedDevice->CreateGraphicsPipelineState( - &pipeDesc, __uuidof(ID3D12PipelineState), - (void **)&cache.pipes[MeshDisplayPipelines::ePipe_Solid]); - RDCASSERTEQUAL(hr, S_OK); - - pipeDesc.DepthStencilState.DepthEnable = TRUE; - pipeDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; - pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; - - hr = m_WrappedDevice->CreateGraphicsPipelineState( - &pipeDesc, __uuidof(ID3D12PipelineState), - (void **)&cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]); - RDCASSERTEQUAL(hr, S_OK); - - if(secondary.vertexResourceId != ResourceId()) - { - // pull secondary information from second vertex buffer - ia[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - RDCASSERT(secondaryFmt != DXGI_FORMAT_UNKNOWN); - - hr = m_WrappedDevice->CreateGraphicsPipelineState( - &pipeDesc, __uuidof(ID3D12PipelineState), - (void **)&cache.pipes[MeshDisplayPipelines::ePipe_Secondary]); - RDCASSERTEQUAL(hr, S_OK); - } - - if(pipeDesc.PrimitiveTopologyType == D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE) - { - ia[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA; - - // flat lit pipeline, needs geometry shader to calculate face normals - pipeDesc.GS.BytecodeLength = m_MeshGS->GetBufferSize(); - pipeDesc.GS.pShaderBytecode = m_MeshGS->GetBufferPointer(); - - hr = m_WrappedDevice->CreateGraphicsPipelineState( - &pipeDesc, __uuidof(ID3D12PipelineState), - (void **)&cache.pipes[MeshDisplayPipelines::ePipe_Lit]); - RDCASSERTEQUAL(hr, S_OK); - } - - return cache; -} - -void D3D12DebugManager::RenderMesh(uint32_t eventId, const vector &secondaryDraws, - const MeshDisplay &cfg) -{ - if(cfg.position.vertexResourceId == ResourceId() || cfg.position.numIndices == 0) - return; - - auto it = m_OutputWindows.find(m_CurrentOutputWindow); - if(m_CurrentOutputWindow == 0 || it == m_OutputWindows.end()) - return; - - OutputWindow &outw = it->second; - - ID3D12GraphicsCommandList *list = m_WrappedDevice->GetNewList(); - - list->OMSetRenderTargets(1, &outw.rtv, TRUE, &outw.dsv); - - D3D12_VIEWPORT viewport = {0, 0, (float)outw.width, (float)outw.height, 0.0f, 1.0f}; - list->RSSetViewports(1, &viewport); - - D3D12_RECT scissor = {0, 0, outw.width, outw.height}; - list->RSSetScissorRects(1, &scissor); - - DebugVertexCBuffer vertexData; - - vertexData.LineStrip = 0; - - Matrix4f projMat = Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, viewport.Width / viewport.Height); - Matrix4f InvProj = projMat.Inverse(); - - Matrix4f camMat = cfg.cam ? ((Camera *)cfg.cam)->GetMatrix() : Matrix4f::Identity(); - - Matrix4f guessProjInv; - - vertexData.ModelViewProj = projMat.Mul(camMat); - vertexData.SpriteSize = Vec2f(); - - DebugPixelCBufferData pixelData; - - pixelData.AlwaysZero = 0.0f; - - pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; - pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 0.0f); - - 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 = - cfg.position.farPlane != FLT_MAX - ? Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect) - : Matrix4f::ReversePerspective(cfg.fov, cfg.position.nearPlane, cfg.aspect); - - if(cfg.ortho) - { - guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); - } - - guessProjInv = guessProj.Inverse(); - - vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); - } - - D3D12_GPU_VIRTUAL_ADDRESS vsCB = UploadConstants(&vertexData, sizeof(vertexData)); - - if(!secondaryDraws.empty()) - { - list->SetGraphicsRootSignature(m_CBOnlyRootSig); - - list->SetGraphicsRootConstantBufferView(0, vsCB); - list->SetGraphicsRootConstantBufferView(1, UploadConstants(&pixelData, sizeof(pixelData))); - list->SetGraphicsRootConstantBufferView(2, vsCB); - - for(size_t i = 0; i < secondaryDraws.size(); i++) - { - const MeshFormat &fmt = secondaryDraws[i]; - - DebugVertexCBuffer vdata; - - if(fmt.vertexResourceId != ResourceId()) - { - list->SetGraphicsRoot32BitConstants(3, 4, &fmt.meshColor.x, 0); - - MeshDisplayPipelines secondaryCache = - CacheMeshDisplayPipelines(secondaryDraws[i], secondaryDraws[i]); - - list->SetPipelineState(secondaryCache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); - - ID3D12Resource *vb = - m_WrappedDevice->GetResourceManager()->GetCurrentAs(fmt.vertexResourceId); - - UINT64 offs = fmt.vertexByteOffset; - D3D12_VERTEX_BUFFER_VIEW view; - view.BufferLocation = vb->GetGPUVirtualAddress() + offs; - view.StrideInBytes = fmt.vertexByteStride; - view.SizeInBytes = UINT(vb->GetDesc().Width - offs); - list->IASetVertexBuffers(0, 1, &view); - - // set it to the secondary buffer too just as dummy info - list->IASetVertexBuffers(1, 1, &view); - - list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(fmt.topology)); - - if(PatchList_Count(fmt.topology) > 0) - list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); - - if(fmt.indexByteStride) - { - if(fmt.indexResourceId != ResourceId()) - { - ID3D12Resource *ib = m_WrappedDevice->GetResourceManager()->GetCurrentAs( - fmt.indexResourceId); - - D3D12_INDEX_BUFFER_VIEW iview; - iview.BufferLocation = ib->GetGPUVirtualAddress() + fmt.indexByteOffset; - iview.SizeInBytes = UINT(ib->GetDesc().Width - fmt.indexByteOffset); - iview.Format = fmt.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; - list->IASetIndexBuffer(&iview); - - list->DrawIndexedInstanced(fmt.numIndices, 1, 0, fmt.baseVertex, 0); - } - } - else - { - list->DrawInstanced(fmt.numIndices, 1, 0, 0); - } - } - } - } - - MeshDisplayPipelines cache = CacheMeshDisplayPipelines(cfg.position, cfg.second); - - if(cfg.position.vertexResourceId != ResourceId()) - { - ID3D12Resource *vb = m_WrappedDevice->GetResourceManager()->GetCurrentAs( - cfg.position.vertexResourceId); - - UINT64 offs = cfg.position.vertexByteOffset; - D3D12_VERTEX_BUFFER_VIEW view; - view.BufferLocation = vb->GetGPUVirtualAddress() + offs; - view.StrideInBytes = cfg.position.vertexByteStride; - view.SizeInBytes = UINT(vb->GetDesc().Width - offs); - list->IASetVertexBuffers(0, 1, &view); - - // set it to the secondary buffer too just as dummy info - list->IASetVertexBuffers(1, 1, &view); - - list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(cfg.position.topology)); - - if(PatchList_Count(cfg.position.topology) > 0) - list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); - } - - SolidShade solidShadeMode = cfg.solidShadeMode; - - // can't support secondary shading without a buffer - no pipeline will have been created - if(solidShadeMode == SolidShade::Secondary && cfg.second.vertexResourceId == ResourceId()) - solidShadeMode = SolidShade::NoSolid; - - if(solidShadeMode == SolidShade::Secondary) - { - ID3D12Resource *vb = m_WrappedDevice->GetResourceManager()->GetCurrentAs( - cfg.position.vertexResourceId); - - UINT64 offs = cfg.second.vertexByteOffset; - D3D12_VERTEX_BUFFER_VIEW view; - view.BufferLocation = vb->GetGPUVirtualAddress() + offs; - view.StrideInBytes = cfg.second.vertexByteStride; - view.SizeInBytes = UINT(vb->GetDesc().Width - offs); - list->IASetVertexBuffers(1, 1, &view); - } - - // solid render - if(solidShadeMode != SolidShade::NoSolid && cfg.position.topology < Topology::PatchList) - { - ID3D12PipelineState *pipe = NULL; - switch(solidShadeMode) - { - default: - case SolidShade::Solid: pipe = cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]; break; - case SolidShade::Lit: pipe = cache.pipes[MeshDisplayPipelines::ePipe_Lit]; break; - case SolidShade::Secondary: pipe = cache.pipes[MeshDisplayPipelines::ePipe_Secondary]; break; - } - - pixelData.OutputDisplayFormat = (int)cfg.solidShadeMode; - if(cfg.solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha) - pixelData.OutputDisplayFormat = MESHDISPLAY_SECONDARY_ALPHA; - pixelData.WireframeColour = Vec3f(0.8f, 0.8f, 0.0f); - - list->SetPipelineState(pipe); - list->SetGraphicsRootSignature(m_CBOnlyRootSig); - - list->SetGraphicsRootConstantBufferView(0, vsCB); - list->SetGraphicsRootConstantBufferView(1, UploadConstants(&pixelData, sizeof(pixelData))); - - if(solidShadeMode == SolidShade::Lit) - { - DebugGeometryCBuffer geomData; - geomData.InvProj = projMat.Inverse(); - - list->SetGraphicsRootConstantBufferView(2, UploadConstants(&geomData, sizeof(geomData))); - } - else - { - list->SetGraphicsRootConstantBufferView(2, vsCB); - } - - Vec4f colour(0.8f, 0.8f, 0.0f, 1.0f); - list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); - - if(cfg.position.indexByteStride) - { - if(cfg.position.indexResourceId != ResourceId()) - { - ID3D12Resource *ib = m_WrappedDevice->GetResourceManager()->GetCurrentAs( - cfg.position.indexResourceId); - - D3D12_INDEX_BUFFER_VIEW view; - view.BufferLocation = ib->GetGPUVirtualAddress() + cfg.position.indexByteOffset; - view.SizeInBytes = UINT(ib->GetDesc().Width - cfg.position.indexByteOffset); - view.Format = cfg.position.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; - list->IASetIndexBuffer(&view); - - list->DrawIndexedInstanced(cfg.position.numIndices, 1, 0, cfg.position.baseVertex, 0); - } - } - else - { - list->DrawInstanced(cfg.position.numIndices, 1, 0, 0); - } - } - - // wireframe render - if(solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw || - cfg.position.topology >= Topology::PatchList) - { - Vec4f wireCol = - Vec4f(cfg.position.meshColor.x, cfg.position.meshColor.y, cfg.position.meshColor.z, 1.0f); - - pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; - - list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); - list->SetGraphicsRootSignature(m_CBOnlyRootSig); - - list->SetGraphicsRootConstantBufferView(0, vsCB); - list->SetGraphicsRootConstantBufferView(1, UploadConstants(&pixelData, sizeof(pixelData))); - list->SetGraphicsRootConstantBufferView(2, vsCB); - - list->SetGraphicsRoot32BitConstants(3, 4, &cfg.position.meshColor.x, 0); - - if(cfg.position.indexByteStride && cfg.position.indexResourceId != ResourceId()) - { - ID3D12Resource *ib = m_WrappedDevice->GetResourceManager()->GetCurrentAs( - cfg.position.indexResourceId); - - D3D12_INDEX_BUFFER_VIEW view; - view.BufferLocation = ib->GetGPUVirtualAddress() + cfg.position.indexByteOffset; - view.SizeInBytes = UINT(ib->GetDesc().Width - cfg.position.indexByteOffset); - view.Format = cfg.position.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; - list->IASetIndexBuffer(&view); - - list->DrawIndexedInstanced(cfg.position.numIndices, 1, 0, cfg.position.baseVertex, 0); - } - else - { - list->DrawInstanced(cfg.position.numIndices, 1, 0, 0); - } - } - - MeshFormat helper; - helper.indexByteStride = 2; - helper.topology = Topology::LineList; - - helper.format.type = ResourceFormatType::Regular; - helper.format.compByteWidth = 4; - helper.format.compCount = 4; - helper.format.compType = CompType::Float; - - helper.vertexByteStride = sizeof(Vec4f); - - pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; - - list->SetGraphicsRootConstantBufferView(1, UploadConstants(&pixelData, sizeof(pixelData))); - - // cache pipelines for use in drawing wireframe helpers - cache = CacheMeshDisplayPipelines(helper, helper); - - if(cfg.showBBox) - { - Vec4f a = Vec4f(cfg.minBounds.x, cfg.minBounds.y, cfg.minBounds.z, cfg.minBounds.w); - Vec4f b = Vec4f(cfg.maxBounds.x, cfg.maxBounds.y, cfg.maxBounds.z, cfg.maxBounds.w); - - Vec4f TLN = Vec4f(a.x, b.y, a.z, 1.0f); // TopLeftNear, etc... - Vec4f TRN = Vec4f(b.x, b.y, a.z, 1.0f); - Vec4f BLN = Vec4f(a.x, a.y, a.z, 1.0f); - Vec4f BRN = Vec4f(b.x, a.y, a.z, 1.0f); - - Vec4f TLF = Vec4f(a.x, b.y, b.z, 1.0f); - Vec4f TRF = Vec4f(b.x, b.y, b.z, 1.0f); - Vec4f BLF = Vec4f(a.x, a.y, b.z, 1.0f); - Vec4f BRF = Vec4f(b.x, a.y, b.z, 1.0f); - - // 12 frustum lines => 24 verts - Vec4f bbox[24] = { - TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN, - - TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF, - - TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF, - }; - - D3D12_VERTEX_BUFFER_VIEW view; - view.BufferLocation = UploadConstants(bbox, sizeof(bbox)); - view.SizeInBytes = sizeof(bbox); - view.StrideInBytes = sizeof(Vec4f); - - list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST); - - list->IASetVertexBuffers(0, 1, &view); - - Vec4f colour(0.2f, 0.2f, 1.0f, 1.0f); - list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); - - list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); - - list->DrawInstanced(24, 1, 0, 0); - } - - // draw axis helpers - if(!cfg.position.unproject) - { - Vec4f axismarker[6] = { - Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), - Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), - }; - - D3D12_VERTEX_BUFFER_VIEW view; - view.BufferLocation = UploadConstants(axismarker, sizeof(axismarker)); - view.SizeInBytes = sizeof(axismarker); - view.StrideInBytes = sizeof(Vec4f); - - list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST); - - list->IASetVertexBuffers(0, 1, &view); - - list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Wire]); - - Vec4f colour(1.0f, 0.0f, 0.0f, 1.0f); - list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); - list->DrawInstanced(2, 1, 0, 0); - - colour = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); - list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); - list->DrawInstanced(2, 1, 2, 0); - - colour = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); - list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); - list->DrawInstanced(2, 1, 4, 0); - } - - // 'fake' helper frustum - if(cfg.position.unproject) - { - Vec4f TLN = Vec4f(-1.0f, 1.0f, 0.0f, 1.0f); // TopLeftNear, etc... - Vec4f TRN = Vec4f(1.0f, 1.0f, 0.0f, 1.0f); - Vec4f BLN = Vec4f(-1.0f, -1.0f, 0.0f, 1.0f); - Vec4f BRN = Vec4f(1.0f, -1.0f, 0.0f, 1.0f); - - Vec4f TLF = Vec4f(-1.0f, 1.0f, 1.0f, 1.0f); - Vec4f TRF = Vec4f(1.0f, 1.0f, 1.0f, 1.0f); - Vec4f BLF = Vec4f(-1.0f, -1.0f, 1.0f, 1.0f); - Vec4f BRF = Vec4f(1.0f, -1.0f, 1.0f, 1.0f); - - // 12 frustum lines => 24 verts - Vec4f bbox[24] = { - TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN, - - TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF, - - TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF, - }; - - D3D12_VERTEX_BUFFER_VIEW view; - view.BufferLocation = UploadConstants(bbox, sizeof(bbox)); - view.SizeInBytes = sizeof(bbox); - view.StrideInBytes = sizeof(Vec4f); - - list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST); - - list->IASetVertexBuffers(0, 1, &view); - - Vec4f colour(1.0f, 1.0f, 1.0f, 1.0f); - list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); - - list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Wire]); - - list->DrawInstanced(24, 1, 0, 0); - } - - // show highlighted vertex - if(cfg.highlightVert != ~0U) - { - m_HighlightCache.CacheHighlightingData(eventId, cfg); - - Topology meshtopo = cfg.position.topology; - - /////////////////////////////////////////////////////////////// - // vectors to be set from buffers, depending on topology - - // this vert (blue dot, required) - FloatVector activeVertex; - - // primitive this vert is a part of (red prim, optional) - vector activePrim; - - // 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; - - helper.topology = Topology::TriangleList; - uint32_t primSize = 3; // number of verts per primitive - - if(meshtopo == Topology::LineList || meshtopo == Topology::LineStrip || - meshtopo == Topology::LineList_Adj || meshtopo == Topology::LineStrip_Adj) - { - primSize = 2; - helper.topology = Topology::LineList; - } - else - { - // update the cache, as it's currently linelist - helper.topology = Topology::TriangleList; - cache = CacheMeshDisplayPipelines(helper, helper); - } - - bool valid = m_HighlightCache.FetchHighlightPositions(cfg, activeVertex, activePrim, - adjacentPrimVertices, inactiveVertices); - - if(valid) - { - //////////////////////////////////////////////////////////////// - // prepare rendering (for both vertices & primitives) - - // if data is from post transform, it will be in clipspace - if(cfg.position.unproject) - vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); - else - vertexData.ModelViewProj = projMat.Mul(camMat); - - list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(helper.topology)); - - if(PatchList_Count(helper.topology) > 0) - list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); - - list->SetGraphicsRootConstantBufferView(0, UploadConstants(&vertexData, sizeof(vertexData))); - - list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Solid]); - - //////////////////////////////////////////////////////////////// - // render primitives - - // Draw active primitive (red) - Vec4f colour(1.0f, 0.0f, 0.0f, 1.0f); - list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); - - D3D12_VERTEX_BUFFER_VIEW view = {}; - view.StrideInBytes = sizeof(Vec4f); - - if(activePrim.size() >= primSize) - { - view.BufferLocation = UploadConstants(&activePrim[0], sizeof(Vec4f) * primSize); - view.SizeInBytes = sizeof(Vec4f) * primSize; - - list->IASetVertexBuffers(0, 1, &view); - - list->DrawInstanced(primSize, 1, 0, 0); - } - - // Draw adjacent primitives (green) - colour = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); - list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); - - if(adjacentPrimVertices.size() >= primSize && (adjacentPrimVertices.size() % primSize) == 0) - { - view.BufferLocation = - UploadConstants(&activePrim[0], sizeof(Vec4f) * adjacentPrimVertices.size()); - view.SizeInBytes = UINT(sizeof(Vec4f) * adjacentPrimVertices.size()); - - list->IASetVertexBuffers(0, 1, &view); - - list->DrawInstanced((UINT)adjacentPrimVertices.size(), 1, 0, 0); - } - - //////////////////////////////////////////////////////////////// - // prepare to render dots - - float scale = 800.0f / viewport.Height; - float asp = viewport.Width / viewport.Height; - - vertexData.SpriteSize = Vec2f(scale / asp, scale); - - list->SetGraphicsRootConstantBufferView(0, UploadConstants(&vertexData, sizeof(vertexData))); - - // Draw active vertex (blue) - colour = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); - list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); - - // vertices are drawn with tri strips - helper.topology = Topology::TriangleStrip; - cache = CacheMeshDisplayPipelines(helper, helper); - - FloatVector vertSprite[4] = { - activeVertex, activeVertex, activeVertex, activeVertex, - }; - - list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(helper.topology)); - - if(PatchList_Count(helper.topology) > 0) - list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); - - list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Solid]); - - { - view.BufferLocation = UploadConstants(&vertSprite[0], sizeof(vertSprite)); - view.SizeInBytes = sizeof(vertSprite); - - list->IASetVertexBuffers(0, 1, &view); - - list->DrawInstanced(4, 1, 0, 0); - } - - // Draw inactive vertices (green) - colour = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); - list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); - - if(!inactiveVertices.empty()) - { - std::vector inactiveVB; - inactiveVB.reserve(inactiveVertices.size() * 4); - - for(size_t i = 0; i < inactiveVertices.size(); i++) - { - inactiveVB.push_back(inactiveVertices[i]); - inactiveVB.push_back(inactiveVertices[i]); - inactiveVB.push_back(inactiveVertices[i]); - inactiveVB.push_back(inactiveVertices[i]); - } - - view.BufferLocation = - UploadConstants(&inactiveVB[0], sizeof(vertSprite) * inactiveVertices.size()); - view.SizeInBytes = UINT(sizeof(vertSprite) * inactiveVertices.size()); - - for(size_t i = 0; i < inactiveVertices.size(); i++) - { - list->IASetVertexBuffers(0, 1, &view); - - list->DrawInstanced(4, 1, 0, 0); - - view.BufferLocation += sizeof(FloatVector) * 4; - } - } - } - } - - list->Close(); - -#if ENABLED(SINGLE_FLUSH_VALIDATE) - m_WrappedDevice->ExecuteLists(); - m_WrappedDevice->FlushLists(); -#endif -} - void D3D12DebugManager::PrepareTextureSampling(ID3D12Resource *resource, CompType typeHint, int &resType, vector &barriers) { diff --git a/renderdoc/driver/d3d12/d3d12_rendermesh.cpp b/renderdoc/driver/d3d12/d3d12_rendermesh.cpp new file mode 100644 index 000000000..d7ece0b06 --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_rendermesh.cpp @@ -0,0 +1,774 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2018 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. + ******************************************************************************/ + +#include "driver/dxgi/dxgi_common.h" +#include "maths/camera.h" +#include "maths/formatpacking.h" +#include "maths/matrix.h" +#include "maths/vec.h" +#include "d3d12_command_list.h" +#include "d3d12_command_queue.h" +#include "d3d12_debug.h" +#include "d3d12_device.h" + +#include "data/hlsl/debugcbuffers.h" + +D3D12DebugManager::MeshDisplayPipelines D3D12DebugManager::CacheMeshDisplayPipelines( + const MeshFormat &primary, const MeshFormat &secondary) +{ + // generate a key to look up the map + uint64_t key = 0; + + uint64_t bit = 0; + + if(primary.indexByteStride == 4) + key |= 1ULL << bit; + bit++; + + RDCASSERT((uint32_t)primary.topology < 64); + key |= uint64_t((uint32_t)primary.topology & 0x3f) << bit; + bit += 6; + + DXGI_FORMAT primaryFmt = MakeDXGIFormat(primary.format); + DXGI_FORMAT secondaryFmt = secondary.vertexResourceId == ResourceId() + ? DXGI_FORMAT_UNKNOWN + : MakeDXGIFormat(secondary.format); + + key |= uint64_t((uint32_t)primaryFmt & 0xff) << bit; + bit += 8; + + key |= uint64_t((uint32_t)secondaryFmt & 0xff) << bit; + bit += 8; + + RDCASSERT(primary.vertexByteStride <= 0xffff); + key |= uint64_t((uint32_t)primary.vertexByteStride & 0xffff) << bit; + bit += 16; + + if(secondary.vertexResourceId != ResourceId()) + { + RDCASSERT(secondary.vertexByteStride <= 0xffff); + key |= uint64_t((uint32_t)secondary.vertexByteStride & 0xffff) << bit; + } + bit += 16; + + MeshDisplayPipelines &cache = m_CachedMeshPipelines[key]; + + if(cache.pipes[(uint32_t)SolidShade::NoSolid] != NULL) + return cache; + + // should we try and evict old pipelines from the cache here? + // or just keep them forever + + D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc; + RDCEraseEl(pipeDesc); + pipeDesc.pRootSignature = m_CBOnlyRootSig; + pipeDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; + pipeDesc.SampleMask = 0xFFFFFFFF; + pipeDesc.SampleDesc.Count = D3D12_MSAA_SAMPLECOUNT; + pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + D3D_PRIMITIVE_TOPOLOGY topo = MakeD3DPrimitiveTopology(primary.topology); + + if(topo == D3D_PRIMITIVE_TOPOLOGY_POINTLIST || + topo >= D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST) + pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; + else if(topo == D3D_PRIMITIVE_TOPOLOGY_LINESTRIP || topo == D3D_PRIMITIVE_TOPOLOGY_LINELIST || + topo == D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ || topo == D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ) + pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + else + pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + + pipeDesc.NumRenderTargets = 1; + pipeDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + pipeDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; + pipeDesc.BlendState.RenderTarget[0].BlendEnable = TRUE; + pipeDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + pipeDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + pipeDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + + D3D12_INPUT_ELEMENT_DESC ia[2] = {}; + ia[0].SemanticName = "pos"; + ia[0].Format = primaryFmt; + ia[1].SemanticName = "sec"; + ia[1].InputSlot = 1; + ia[1].Format = secondaryFmt == DXGI_FORMAT_UNKNOWN ? primaryFmt : secondaryFmt; + ia[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA; + + pipeDesc.InputLayout.NumElements = 2; + pipeDesc.InputLayout.pInputElementDescs = ia; + + RDCASSERT(primaryFmt != DXGI_FORMAT_UNKNOWN); + + // wireframe pipeline + pipeDesc.VS.BytecodeLength = m_MeshVS->GetBufferSize(); + pipeDesc.VS.pShaderBytecode = m_MeshVS->GetBufferPointer(); + pipeDesc.PS.BytecodeLength = m_MeshPS->GetBufferSize(); + pipeDesc.PS.pShaderBytecode = m_MeshPS->GetBufferPointer(); + + pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME; + pipeDesc.DepthStencilState.DepthEnable = FALSE; + pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + + HRESULT hr = S_OK; + + hr = m_WrappedDevice->CreateGraphicsPipelineState( + &pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&cache.pipes[MeshDisplayPipelines::ePipe_Wire]); + RDCASSERTEQUAL(hr, S_OK); + + pipeDesc.DepthStencilState.DepthEnable = TRUE; + pipeDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; + pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + + hr = m_WrappedDevice->CreateGraphicsPipelineState( + &pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&cache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); + RDCASSERTEQUAL(hr, S_OK); + + // solid shading pipeline + pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; + pipeDesc.DepthStencilState.DepthEnable = FALSE; + pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + + hr = m_WrappedDevice->CreateGraphicsPipelineState( + &pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&cache.pipes[MeshDisplayPipelines::ePipe_Solid]); + RDCASSERTEQUAL(hr, S_OK); + + pipeDesc.DepthStencilState.DepthEnable = TRUE; + pipeDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; + pipeDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + + hr = m_WrappedDevice->CreateGraphicsPipelineState( + &pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]); + RDCASSERTEQUAL(hr, S_OK); + + if(secondary.vertexResourceId != ResourceId()) + { + // pull secondary information from second vertex buffer + ia[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; + RDCASSERT(secondaryFmt != DXGI_FORMAT_UNKNOWN); + + hr = m_WrappedDevice->CreateGraphicsPipelineState( + &pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&cache.pipes[MeshDisplayPipelines::ePipe_Secondary]); + RDCASSERTEQUAL(hr, S_OK); + } + + if(pipeDesc.PrimitiveTopologyType == D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE) + { + ia[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA; + + // flat lit pipeline, needs geometry shader to calculate face normals + pipeDesc.GS.BytecodeLength = m_MeshGS->GetBufferSize(); + pipeDesc.GS.pShaderBytecode = m_MeshGS->GetBufferPointer(); + + hr = m_WrappedDevice->CreateGraphicsPipelineState( + &pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&cache.pipes[MeshDisplayPipelines::ePipe_Lit]); + RDCASSERTEQUAL(hr, S_OK); + } + + return cache; +} + +void D3D12DebugManager::RenderMesh(uint32_t eventId, const vector &secondaryDraws, + const MeshDisplay &cfg) +{ + if(cfg.position.vertexResourceId == ResourceId() || cfg.position.numIndices == 0) + return; + + auto it = m_OutputWindows.find(m_CurrentOutputWindow); + if(m_CurrentOutputWindow == 0 || it == m_OutputWindows.end()) + return; + + OutputWindow &outw = it->second; + + ID3D12GraphicsCommandList *list = m_WrappedDevice->GetNewList(); + + list->OMSetRenderTargets(1, &outw.rtv, TRUE, &outw.dsv); + + D3D12_VIEWPORT viewport = {0, 0, (float)outw.width, (float)outw.height, 0.0f, 1.0f}; + list->RSSetViewports(1, &viewport); + + D3D12_RECT scissor = {0, 0, outw.width, outw.height}; + list->RSSetScissorRects(1, &scissor); + + DebugVertexCBuffer vertexData; + + vertexData.LineStrip = 0; + + Matrix4f projMat = Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, viewport.Width / viewport.Height); + Matrix4f InvProj = projMat.Inverse(); + + Matrix4f camMat = cfg.cam ? ((Camera *)cfg.cam)->GetMatrix() : Matrix4f::Identity(); + + Matrix4f guessProjInv; + + vertexData.ModelViewProj = projMat.Mul(camMat); + vertexData.SpriteSize = Vec2f(); + + DebugPixelCBufferData pixelData; + + pixelData.AlwaysZero = 0.0f; + + pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; + pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 0.0f); + + 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 = + cfg.position.farPlane != FLT_MAX + ? Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect) + : Matrix4f::ReversePerspective(cfg.fov, cfg.position.nearPlane, cfg.aspect); + + if(cfg.ortho) + { + guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); + } + + guessProjInv = guessProj.Inverse(); + + vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + } + + D3D12_GPU_VIRTUAL_ADDRESS vsCB = UploadConstants(&vertexData, sizeof(vertexData)); + + if(!secondaryDraws.empty()) + { + list->SetGraphicsRootSignature(m_CBOnlyRootSig); + + list->SetGraphicsRootConstantBufferView(0, vsCB); + list->SetGraphicsRootConstantBufferView(1, UploadConstants(&pixelData, sizeof(pixelData))); + list->SetGraphicsRootConstantBufferView(2, vsCB); + + for(size_t i = 0; i < secondaryDraws.size(); i++) + { + const MeshFormat &fmt = secondaryDraws[i]; + + DebugVertexCBuffer vdata; + + if(fmt.vertexResourceId != ResourceId()) + { + list->SetGraphicsRoot32BitConstants(3, 4, &fmt.meshColor.x, 0); + + MeshDisplayPipelines secondaryCache = + CacheMeshDisplayPipelines(secondaryDraws[i], secondaryDraws[i]); + + list->SetPipelineState(secondaryCache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); + + ID3D12Resource *vb = + m_WrappedDevice->GetResourceManager()->GetCurrentAs(fmt.vertexResourceId); + + UINT64 offs = fmt.vertexByteOffset; + D3D12_VERTEX_BUFFER_VIEW view; + view.BufferLocation = vb->GetGPUVirtualAddress() + offs; + view.StrideInBytes = fmt.vertexByteStride; + view.SizeInBytes = UINT(vb->GetDesc().Width - offs); + list->IASetVertexBuffers(0, 1, &view); + + // set it to the secondary buffer too just as dummy info + list->IASetVertexBuffers(1, 1, &view); + + list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(fmt.topology)); + + if(PatchList_Count(fmt.topology) > 0) + list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); + + if(fmt.indexByteStride) + { + if(fmt.indexResourceId != ResourceId()) + { + ID3D12Resource *ib = m_WrappedDevice->GetResourceManager()->GetCurrentAs( + fmt.indexResourceId); + + D3D12_INDEX_BUFFER_VIEW iview; + iview.BufferLocation = ib->GetGPUVirtualAddress() + fmt.indexByteOffset; + iview.SizeInBytes = UINT(ib->GetDesc().Width - fmt.indexByteOffset); + iview.Format = fmt.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; + list->IASetIndexBuffer(&iview); + + list->DrawIndexedInstanced(fmt.numIndices, 1, 0, fmt.baseVertex, 0); + } + } + else + { + list->DrawInstanced(fmt.numIndices, 1, 0, 0); + } + } + } + } + + MeshDisplayPipelines cache = CacheMeshDisplayPipelines(cfg.position, cfg.second); + + if(cfg.position.vertexResourceId != ResourceId()) + { + ID3D12Resource *vb = m_WrappedDevice->GetResourceManager()->GetCurrentAs( + cfg.position.vertexResourceId); + + UINT64 offs = cfg.position.vertexByteOffset; + D3D12_VERTEX_BUFFER_VIEW view; + view.BufferLocation = vb->GetGPUVirtualAddress() + offs; + view.StrideInBytes = cfg.position.vertexByteStride; + view.SizeInBytes = UINT(vb->GetDesc().Width - offs); + list->IASetVertexBuffers(0, 1, &view); + + // set it to the secondary buffer too just as dummy info + list->IASetVertexBuffers(1, 1, &view); + + list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(cfg.position.topology)); + + if(PatchList_Count(cfg.position.topology) > 0) + list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); + } + + SolidShade solidShadeMode = cfg.solidShadeMode; + + // can't support secondary shading without a buffer - no pipeline will have been created + if(solidShadeMode == SolidShade::Secondary && cfg.second.vertexResourceId == ResourceId()) + solidShadeMode = SolidShade::NoSolid; + + if(solidShadeMode == SolidShade::Secondary) + { + ID3D12Resource *vb = m_WrappedDevice->GetResourceManager()->GetCurrentAs( + cfg.position.vertexResourceId); + + UINT64 offs = cfg.second.vertexByteOffset; + D3D12_VERTEX_BUFFER_VIEW view; + view.BufferLocation = vb->GetGPUVirtualAddress() + offs; + view.StrideInBytes = cfg.second.vertexByteStride; + view.SizeInBytes = UINT(vb->GetDesc().Width - offs); + list->IASetVertexBuffers(1, 1, &view); + } + + // solid render + if(solidShadeMode != SolidShade::NoSolid && cfg.position.topology < Topology::PatchList) + { + ID3D12PipelineState *pipe = NULL; + switch(solidShadeMode) + { + default: + case SolidShade::Solid: pipe = cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]; break; + case SolidShade::Lit: pipe = cache.pipes[MeshDisplayPipelines::ePipe_Lit]; break; + case SolidShade::Secondary: pipe = cache.pipes[MeshDisplayPipelines::ePipe_Secondary]; break; + } + + pixelData.OutputDisplayFormat = (int)cfg.solidShadeMode; + if(cfg.solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha) + pixelData.OutputDisplayFormat = MESHDISPLAY_SECONDARY_ALPHA; + pixelData.WireframeColour = Vec3f(0.8f, 0.8f, 0.0f); + + list->SetPipelineState(pipe); + list->SetGraphicsRootSignature(m_CBOnlyRootSig); + + list->SetGraphicsRootConstantBufferView(0, vsCB); + list->SetGraphicsRootConstantBufferView(1, UploadConstants(&pixelData, sizeof(pixelData))); + + if(solidShadeMode == SolidShade::Lit) + { + DebugGeometryCBuffer geomData; + geomData.InvProj = projMat.Inverse(); + + list->SetGraphicsRootConstantBufferView(2, UploadConstants(&geomData, sizeof(geomData))); + } + else + { + list->SetGraphicsRootConstantBufferView(2, vsCB); + } + + Vec4f colour(0.8f, 0.8f, 0.0f, 1.0f); + list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); + + if(cfg.position.indexByteStride) + { + if(cfg.position.indexResourceId != ResourceId()) + { + ID3D12Resource *ib = m_WrappedDevice->GetResourceManager()->GetCurrentAs( + cfg.position.indexResourceId); + + D3D12_INDEX_BUFFER_VIEW view; + view.BufferLocation = ib->GetGPUVirtualAddress() + cfg.position.indexByteOffset; + view.SizeInBytes = UINT(ib->GetDesc().Width - cfg.position.indexByteOffset); + view.Format = cfg.position.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; + list->IASetIndexBuffer(&view); + + list->DrawIndexedInstanced(cfg.position.numIndices, 1, 0, cfg.position.baseVertex, 0); + } + } + else + { + list->DrawInstanced(cfg.position.numIndices, 1, 0, 0); + } + } + + // wireframe render + if(solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw || + cfg.position.topology >= Topology::PatchList) + { + Vec4f wireCol = + Vec4f(cfg.position.meshColor.x, cfg.position.meshColor.y, cfg.position.meshColor.z, 1.0f); + + pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; + + list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); + list->SetGraphicsRootSignature(m_CBOnlyRootSig); + + list->SetGraphicsRootConstantBufferView(0, vsCB); + list->SetGraphicsRootConstantBufferView(1, UploadConstants(&pixelData, sizeof(pixelData))); + list->SetGraphicsRootConstantBufferView(2, vsCB); + + list->SetGraphicsRoot32BitConstants(3, 4, &cfg.position.meshColor.x, 0); + + if(cfg.position.indexByteStride && cfg.position.indexResourceId != ResourceId()) + { + ID3D12Resource *ib = m_WrappedDevice->GetResourceManager()->GetCurrentAs( + cfg.position.indexResourceId); + + D3D12_INDEX_BUFFER_VIEW view; + view.BufferLocation = ib->GetGPUVirtualAddress() + cfg.position.indexByteOffset; + view.SizeInBytes = UINT(ib->GetDesc().Width - cfg.position.indexByteOffset); + view.Format = cfg.position.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; + list->IASetIndexBuffer(&view); + + list->DrawIndexedInstanced(cfg.position.numIndices, 1, 0, cfg.position.baseVertex, 0); + } + else + { + list->DrawInstanced(cfg.position.numIndices, 1, 0, 0); + } + } + + MeshFormat helper; + helper.indexByteStride = 2; + helper.topology = Topology::LineList; + + helper.format.type = ResourceFormatType::Regular; + helper.format.compByteWidth = 4; + helper.format.compCount = 4; + helper.format.compType = CompType::Float; + + helper.vertexByteStride = sizeof(Vec4f); + + pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID; + + list->SetGraphicsRootConstantBufferView(1, UploadConstants(&pixelData, sizeof(pixelData))); + + // cache pipelines for use in drawing wireframe helpers + cache = CacheMeshDisplayPipelines(helper, helper); + + if(cfg.showBBox) + { + Vec4f a = Vec4f(cfg.minBounds.x, cfg.minBounds.y, cfg.minBounds.z, cfg.minBounds.w); + Vec4f b = Vec4f(cfg.maxBounds.x, cfg.maxBounds.y, cfg.maxBounds.z, cfg.maxBounds.w); + + Vec4f TLN = Vec4f(a.x, b.y, a.z, 1.0f); // TopLeftNear, etc... + Vec4f TRN = Vec4f(b.x, b.y, a.z, 1.0f); + Vec4f BLN = Vec4f(a.x, a.y, a.z, 1.0f); + Vec4f BRN = Vec4f(b.x, a.y, a.z, 1.0f); + + Vec4f TLF = Vec4f(a.x, b.y, b.z, 1.0f); + Vec4f TRF = Vec4f(b.x, b.y, b.z, 1.0f); + Vec4f BLF = Vec4f(a.x, a.y, b.z, 1.0f); + Vec4f BRF = Vec4f(b.x, a.y, b.z, 1.0f); + + // 12 frustum lines => 24 verts + Vec4f bbox[24] = { + TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN, + + TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF, + + TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF, + }; + + D3D12_VERTEX_BUFFER_VIEW view; + view.BufferLocation = UploadConstants(bbox, sizeof(bbox)); + view.SizeInBytes = sizeof(bbox); + view.StrideInBytes = sizeof(Vec4f); + + list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST); + + list->IASetVertexBuffers(0, 1, &view); + + Vec4f colour(0.2f, 0.2f, 1.0f, 1.0f); + list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); + + list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); + + list->DrawInstanced(24, 1, 0, 0); + } + + // draw axis helpers + if(!cfg.position.unproject) + { + Vec4f axismarker[6] = { + Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), + Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), + }; + + D3D12_VERTEX_BUFFER_VIEW view; + view.BufferLocation = UploadConstants(axismarker, sizeof(axismarker)); + view.SizeInBytes = sizeof(axismarker); + view.StrideInBytes = sizeof(Vec4f); + + list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST); + + list->IASetVertexBuffers(0, 1, &view); + + list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Wire]); + + Vec4f colour(1.0f, 0.0f, 0.0f, 1.0f); + list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); + list->DrawInstanced(2, 1, 0, 0); + + colour = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); + list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); + list->DrawInstanced(2, 1, 2, 0); + + colour = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); + list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); + list->DrawInstanced(2, 1, 4, 0); + } + + // 'fake' helper frustum + if(cfg.position.unproject) + { + Vec4f TLN = Vec4f(-1.0f, 1.0f, 0.0f, 1.0f); // TopLeftNear, etc... + Vec4f TRN = Vec4f(1.0f, 1.0f, 0.0f, 1.0f); + Vec4f BLN = Vec4f(-1.0f, -1.0f, 0.0f, 1.0f); + Vec4f BRN = Vec4f(1.0f, -1.0f, 0.0f, 1.0f); + + Vec4f TLF = Vec4f(-1.0f, 1.0f, 1.0f, 1.0f); + Vec4f TRF = Vec4f(1.0f, 1.0f, 1.0f, 1.0f); + Vec4f BLF = Vec4f(-1.0f, -1.0f, 1.0f, 1.0f); + Vec4f BRF = Vec4f(1.0f, -1.0f, 1.0f, 1.0f); + + // 12 frustum lines => 24 verts + Vec4f bbox[24] = { + TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN, + + TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF, + + TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF, + }; + + D3D12_VERTEX_BUFFER_VIEW view; + view.BufferLocation = UploadConstants(bbox, sizeof(bbox)); + view.SizeInBytes = sizeof(bbox); + view.StrideInBytes = sizeof(Vec4f); + + list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST); + + list->IASetVertexBuffers(0, 1, &view); + + Vec4f colour(1.0f, 1.0f, 1.0f, 1.0f); + list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); + + list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Wire]); + + list->DrawInstanced(24, 1, 0, 0); + } + + // show highlighted vertex + if(cfg.highlightVert != ~0U) + { + m_HighlightCache.CacheHighlightingData(eventId, cfg); + + Topology meshtopo = cfg.position.topology; + + /////////////////////////////////////////////////////////////// + // vectors to be set from buffers, depending on topology + + // this vert (blue dot, required) + FloatVector activeVertex; + + // primitive this vert is a part of (red prim, optional) + vector activePrim; + + // 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; + + helper.topology = Topology::TriangleList; + uint32_t primSize = 3; // number of verts per primitive + + if(meshtopo == Topology::LineList || meshtopo == Topology::LineStrip || + meshtopo == Topology::LineList_Adj || meshtopo == Topology::LineStrip_Adj) + { + primSize = 2; + helper.topology = Topology::LineList; + } + else + { + // update the cache, as it's currently linelist + helper.topology = Topology::TriangleList; + cache = CacheMeshDisplayPipelines(helper, helper); + } + + bool valid = m_HighlightCache.FetchHighlightPositions(cfg, activeVertex, activePrim, + adjacentPrimVertices, inactiveVertices); + + if(valid) + { + //////////////////////////////////////////////////////////////// + // prepare rendering (for both vertices & primitives) + + // if data is from post transform, it will be in clipspace + if(cfg.position.unproject) + vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + else + vertexData.ModelViewProj = projMat.Mul(camMat); + + list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(helper.topology)); + + if(PatchList_Count(helper.topology) > 0) + list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); + + list->SetGraphicsRootConstantBufferView(0, UploadConstants(&vertexData, sizeof(vertexData))); + + list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Solid]); + + //////////////////////////////////////////////////////////////// + // render primitives + + // Draw active primitive (red) + Vec4f colour(1.0f, 0.0f, 0.0f, 1.0f); + list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); + + D3D12_VERTEX_BUFFER_VIEW view = {}; + view.StrideInBytes = sizeof(Vec4f); + + if(activePrim.size() >= primSize) + { + view.BufferLocation = UploadConstants(&activePrim[0], sizeof(Vec4f) * primSize); + view.SizeInBytes = sizeof(Vec4f) * primSize; + + list->IASetVertexBuffers(0, 1, &view); + + list->DrawInstanced(primSize, 1, 0, 0); + } + + // Draw adjacent primitives (green) + colour = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); + list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); + + if(adjacentPrimVertices.size() >= primSize && (adjacentPrimVertices.size() % primSize) == 0) + { + view.BufferLocation = + UploadConstants(&activePrim[0], sizeof(Vec4f) * adjacentPrimVertices.size()); + view.SizeInBytes = UINT(sizeof(Vec4f) * adjacentPrimVertices.size()); + + list->IASetVertexBuffers(0, 1, &view); + + list->DrawInstanced((UINT)adjacentPrimVertices.size(), 1, 0, 0); + } + + //////////////////////////////////////////////////////////////// + // prepare to render dots + + float scale = 800.0f / viewport.Height; + float asp = viewport.Width / viewport.Height; + + vertexData.SpriteSize = Vec2f(scale / asp, scale); + + list->SetGraphicsRootConstantBufferView(0, UploadConstants(&vertexData, sizeof(vertexData))); + + // Draw active vertex (blue) + colour = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); + list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); + + // vertices are drawn with tri strips + helper.topology = Topology::TriangleStrip; + cache = CacheMeshDisplayPipelines(helper, helper); + + FloatVector vertSprite[4] = { + activeVertex, activeVertex, activeVertex, activeVertex, + }; + + list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(helper.topology)); + + if(PatchList_Count(helper.topology) > 0) + list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); + + list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Solid]); + + { + view.BufferLocation = UploadConstants(&vertSprite[0], sizeof(vertSprite)); + view.SizeInBytes = sizeof(vertSprite); + + list->IASetVertexBuffers(0, 1, &view); + + list->DrawInstanced(4, 1, 0, 0); + } + + // Draw inactive vertices (green) + colour = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); + list->SetGraphicsRoot32BitConstants(3, 4, &colour.x, 0); + + if(!inactiveVertices.empty()) + { + std::vector inactiveVB; + inactiveVB.reserve(inactiveVertices.size() * 4); + + for(size_t i = 0; i < inactiveVertices.size(); i++) + { + inactiveVB.push_back(inactiveVertices[i]); + inactiveVB.push_back(inactiveVertices[i]); + inactiveVB.push_back(inactiveVertices[i]); + inactiveVB.push_back(inactiveVertices[i]); + } + + view.BufferLocation = + UploadConstants(&inactiveVB[0], sizeof(vertSprite) * inactiveVertices.size()); + view.SizeInBytes = UINT(sizeof(vertSprite) * inactiveVertices.size()); + + for(size_t i = 0; i < inactiveVertices.size(); i++) + { + list->IASetVertexBuffers(0, 1, &view); + + list->DrawInstanced(4, 1, 0, 0); + + view.BufferLocation += sizeof(FloatVector) * 4; + } + } + } + } + + list->Close(); + +#if ENABLED(SINGLE_FLUSH_VALIDATE) + m_WrappedDevice->ExecuteLists(); + m_WrappedDevice->FlushLists(); +#endif +} diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj index c34cb1264..0c3f70c01 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj @@ -112,6 +112,7 @@ + diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters index f60c67f7c..44a33c6f0 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters @@ -125,5 +125,8 @@ Replay + + Replay + \ No newline at end of file diff --git a/renderdoc/driver/gl/CMakeLists.txt b/renderdoc/driver/gl/CMakeLists.txt index 2d910a276..d3a2f6376 100644 --- a/renderdoc/driver/gl/CMakeLists.txt +++ b/renderdoc/driver/gl/CMakeLists.txt @@ -6,6 +6,7 @@ set(sources gl_postvs.cpp gl_overlay.cpp gl_outputwindow.cpp + gl_rendermesh.cpp gl_driver.cpp gl_driver.h gl_enum.h diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 1c9523082..7349027be 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -2148,562 +2148,3 @@ void GLReplay::RenderHighlightBox(float w, float h, float scale) gl.glDisable(eGL_SCISSOR_TEST); } - -void GLReplay::RenderMesh(uint32_t eventId, const vector &secondaryDraws, - const MeshDisplay &cfg) -{ - WrappedOpenGL &gl = *m_pDriver; - - if(cfg.position.vertexResourceId == ResourceId()) - return; - - MakeCurrentReplayContext(m_DebugCtx); - - Matrix4f projMat = - Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, DebugData.outWidth / DebugData.outHeight); - - Matrix4f camMat = cfg.cam ? ((Camera *)cfg.cam)->GetMatrix() : Matrix4f::Identity(); - - Matrix4f ModelViewProj = projMat.Mul(camMat); - Matrix4f guessProjInv; - - gl.glBindVertexArray(DebugData.meshVAO); - - const MeshFormat *meshData[2] = {&cfg.position, &cfg.second}; - - GLenum topo = MakeGLPrimitiveTopology(cfg.position.topology); - - GLuint prog = DebugData.meshProg; - - MeshUBOData uboParams = {}; - MeshUBOData *uboptr = NULL; - - gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]); - - gl.glUseProgram(prog); - - gl.glEnable(eGL_FRAMEBUFFER_SRGB); - - 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 = - cfg.position.farPlane != FLT_MAX - ? Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect) - : Matrix4f::ReversePerspective(cfg.fov, cfg.position.nearPlane, cfg.aspect); - - if(cfg.ortho) - { - guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); - } - - guessProjInv = guessProj.Inverse(); - - ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); - } - - uboParams.mvp = ModelViewProj; - uboParams.homogenousInput = cfg.position.unproject; - uboParams.pointSpriteSize = Vec2f(0.0f, 0.0f); - - if(!secondaryDraws.empty()) - { - uboParams.displayFormat = MESHDISPLAY_SOLID; - - if(!IsGLES) - gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_LINE); - - // secondary draws have to come from gl_Position which is float4 - gl.glVertexAttribFormat(0, 4, eGL_FLOAT, GL_FALSE, 0); - gl.glEnableVertexAttribArray(0); - gl.glDisableVertexAttribArray(1); - - for(size_t i = 0; i < secondaryDraws.size(); i++) - { - const MeshFormat &fmt = secondaryDraws[i]; - - if(fmt.vertexResourceId != ResourceId()) - { - uboParams.color = Vec4f(fmt.meshColor.x, fmt.meshColor.y, fmt.meshColor.z, fmt.meshColor.w); - - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - GLuint vb = m_pDriver->GetResourceManager()->GetCurrentResource(fmt.vertexResourceId).name; - gl.glBindVertexBuffer(0, vb, (GLintptr)fmt.vertexByteOffset, fmt.vertexByteStride); - - GLenum secondarytopo = MakeGLPrimitiveTopology(fmt.topology); - - if(fmt.indexByteStride) - { - GLuint ib = m_pDriver->GetResourceManager()->GetCurrentResource(fmt.indexResourceId).name; - gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); - - GLenum idxtype = eGL_UNSIGNED_BYTE; - if(fmt.indexByteStride == 2) - idxtype = eGL_UNSIGNED_SHORT; - else if(fmt.indexByteStride == 4) - idxtype = eGL_UNSIGNED_INT; - - gl.glDrawElementsBaseVertex(secondarytopo, fmt.numIndices, idxtype, - (const void *)uintptr_t(fmt.indexByteOffset), fmt.baseVertex); - } - else - { - gl.glDrawArrays(secondarytopo, 0, fmt.numIndices); - } - } - } - } - - for(uint32_t i = 0; i < 2; i++) - { - if(meshData[i]->vertexResourceId == ResourceId()) - continue; - - if(meshData[i]->format.Special()) - { - if(meshData[i]->format.type == ResourceFormatType::R10G10B10A2) - { - if(meshData[i]->format.compType == CompType::UInt) - gl.glVertexAttribIFormat(i, 4, eGL_UNSIGNED_INT_2_10_10_10_REV, 0); - if(meshData[i]->format.compType == CompType::SInt) - gl.glVertexAttribIFormat(i, 4, eGL_INT_2_10_10_10_REV, 0); - } - else if(meshData[i]->format.type == ResourceFormatType::R11G11B10) - { - gl.glVertexAttribFormat(i, 4, eGL_UNSIGNED_INT_10F_11F_11F_REV, GL_FALSE, 0); - } - else - { - RDCWARN("Unsupported vertex attribute format: %x", meshData[i]->format.type); - } - } - else if(meshData[i]->format.compType == CompType::Float || - meshData[i]->format.compType == CompType::UNorm || - meshData[i]->format.compType == CompType::SNorm) - { - GLenum fmttype = eGL_UNSIGNED_INT; - - if(meshData[i]->format.compByteWidth == 4) - { - if(meshData[i]->format.compType == CompType::Float) - fmttype = eGL_FLOAT; - else if(meshData[i]->format.compType == CompType::UNorm) - fmttype = eGL_UNSIGNED_INT; - else if(meshData[i]->format.compType == CompType::SNorm) - fmttype = eGL_INT; - } - else if(meshData[i]->format.compByteWidth == 2) - { - if(meshData[i]->format.compType == CompType::Float) - fmttype = eGL_HALF_FLOAT; - else if(meshData[i]->format.compType == CompType::UNorm) - fmttype = eGL_UNSIGNED_SHORT; - else if(meshData[i]->format.compType == CompType::SNorm) - fmttype = eGL_SHORT; - } - else if(meshData[i]->format.compByteWidth == 1) - { - if(meshData[i]->format.compType == CompType::UNorm) - fmttype = eGL_UNSIGNED_BYTE; - else if(meshData[i]->format.compType == CompType::SNorm) - fmttype = eGL_BYTE; - } - - gl.glVertexAttribFormat(i, meshData[i]->format.compCount, fmttype, - meshData[i]->format.compType != CompType::Float, 0); - } - else if(meshData[i]->format.compType == CompType::UInt || - meshData[i]->format.compType == CompType::SInt) - { - GLenum fmttype = eGL_UNSIGNED_INT; - - if(meshData[i]->format.compByteWidth == 4) - { - if(meshData[i]->format.compType == CompType::UInt) - fmttype = eGL_UNSIGNED_INT; - else if(meshData[i]->format.compType == CompType::SInt) - fmttype = eGL_INT; - } - else if(meshData[i]->format.compByteWidth == 2) - { - if(meshData[i]->format.compType == CompType::UInt) - fmttype = eGL_UNSIGNED_SHORT; - else if(meshData[i]->format.compType == CompType::SInt) - fmttype = eGL_SHORT; - } - else if(meshData[i]->format.compByteWidth == 1) - { - if(meshData[i]->format.compType == CompType::UInt) - fmttype = eGL_UNSIGNED_BYTE; - else if(meshData[i]->format.compType == CompType::SInt) - fmttype = eGL_BYTE; - } - - gl.glVertexAttribIFormat(i, meshData[i]->format.compCount, fmttype, 0); - } - else if(meshData[i]->format.compType == CompType::Double) - { - gl.glVertexAttribLFormat(i, meshData[i]->format.compCount, eGL_DOUBLE, 0); - } - - GLuint vb = - m_pDriver->GetResourceManager()->GetCurrentResource(meshData[i]->vertexResourceId).name; - gl.glBindVertexBuffer(i, vb, (GLintptr)meshData[i]->vertexByteOffset, - meshData[i]->vertexByteStride); - } - - // enable position attribute - gl.glEnableVertexAttribArray(0); - gl.glDisableVertexAttribArray(1); - - gl.glEnable(eGL_DEPTH_TEST); - - // solid render - if(cfg.solidShadeMode != SolidShade::NoSolid && topo != eGL_PATCHES) - { - gl.glDepthFunc(eGL_LESS); - - GLuint solidProg = prog; - - if(cfg.solidShadeMode == SolidShade::Lit && DebugData.meshgsProg) - { - // pick program with GS for per-face lighting - solidProg = DebugData.meshgsProg; - - ClearGLErrors(gl.GetHookset()); - gl.glUseProgram(solidProg); - GLenum err = gl.glGetError(); - - err = eGL_NONE; - } - - MeshUBOData *soliddata = (MeshUBOData *)gl.glMapBufferRange( - eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - - soliddata->mvp = ModelViewProj; - soliddata->pointSpriteSize = Vec2f(0.0f, 0.0f); - soliddata->homogenousInput = cfg.position.unproject; - - soliddata->color = Vec4f(0.8f, 0.8f, 0.0f, 1.0f); - - uint32_t OutputDisplayFormat = (uint32_t)cfg.solidShadeMode; - if(cfg.solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha) - OutputDisplayFormat = MESHDISPLAY_SECONDARY_ALPHA; - soliddata->displayFormat = OutputDisplayFormat; - - if(cfg.solidShadeMode == SolidShade::Lit) - soliddata->invProj = projMat.Inverse(); - - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - if(cfg.second.vertexResourceId != ResourceId()) - gl.glEnableVertexAttribArray(1); - - if(!IsGLES) - gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); - - if(cfg.position.indexByteStride) - { - GLenum idxtype = eGL_UNSIGNED_BYTE; - if(cfg.position.indexByteStride == 2) - idxtype = eGL_UNSIGNED_SHORT; - else if(cfg.position.indexByteStride == 4) - idxtype = eGL_UNSIGNED_INT; - - if(cfg.position.indexResourceId != ResourceId()) - { - GLuint ib = - m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.indexResourceId).name; - gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); - } - gl.glDrawElementsBaseVertex(topo, cfg.position.numIndices, idxtype, - (const void *)uintptr_t(cfg.position.indexByteOffset), - cfg.position.baseVertex); - } - else - { - gl.glDrawArrays(topo, 0, cfg.position.numIndices); - } - - gl.glDisableVertexAttribArray(1); - - gl.glUseProgram(prog); - } - - gl.glDepthFunc(eGL_ALWAYS); - - // wireframe render - if(cfg.solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw || topo == eGL_PATCHES) - { - uboParams.color = Vec4f(cfg.position.meshColor.x, cfg.position.meshColor.y, - cfg.position.meshColor.z, cfg.position.meshColor.w); - - uboParams.displayFormat = MESHDISPLAY_SOLID; - - if(!IsGLES) - gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_LINE); - - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - if(cfg.position.indexByteStride) - { - GLenum idxtype = eGL_UNSIGNED_BYTE; - if(cfg.position.indexByteStride == 2) - idxtype = eGL_UNSIGNED_SHORT; - else if(cfg.position.indexByteStride == 4) - idxtype = eGL_UNSIGNED_INT; - - if(cfg.position.indexResourceId != ResourceId()) - { - GLuint ib = - m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.indexResourceId).name; - gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); - - gl.glDrawElementsBaseVertex(topo != eGL_PATCHES ? topo : eGL_POINTS, cfg.position.numIndices, - idxtype, (const void *)uintptr_t(cfg.position.indexByteOffset), - cfg.position.baseVertex); - } - } - else - { - gl.glDrawArrays(topo != eGL_PATCHES ? topo : eGL_POINTS, 0, cfg.position.numIndices); - } - } - - if(cfg.showBBox) - { - Vec4f a = Vec4f(cfg.minBounds.x, cfg.minBounds.y, cfg.minBounds.z, cfg.minBounds.w); - Vec4f b = Vec4f(cfg.maxBounds.x, cfg.maxBounds.y, cfg.maxBounds.z, cfg.maxBounds.w); - - Vec4f TLN = Vec4f(a.x, b.y, a.z, 1.0f); // TopLeftNear, etc... - Vec4f TRN = Vec4f(b.x, b.y, a.z, 1.0f); - Vec4f BLN = Vec4f(a.x, a.y, a.z, 1.0f); - Vec4f BRN = Vec4f(b.x, a.y, a.z, 1.0f); - - Vec4f TLF = Vec4f(a.x, b.y, b.z, 1.0f); - Vec4f TRF = Vec4f(b.x, b.y, b.z, 1.0f); - Vec4f BLF = Vec4f(a.x, a.y, b.z, 1.0f); - Vec4f BRF = Vec4f(b.x, a.y, b.z, 1.0f); - - // 12 frustum lines => 24 verts - Vec4f bbox[24] = { - TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN, - - TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF, - - TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF, - }; - - gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.triHighlightBuffer); - gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(bbox), &bbox[0]); - - gl.glBindVertexArray(DebugData.triHighlightVAO); - - uboParams.color = Vec4f(0.2f, 0.2f, 1.0f, 1.0f); - - Matrix4f mvpMat = projMat.Mul(camMat); - - uboParams.mvp = mvpMat; - - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - // we want this to clip - gl.glDepthFunc(eGL_LESS); - - gl.glDrawArrays(eGL_LINES, 0, 24); - - gl.glDepthFunc(eGL_ALWAYS); - } - - // draw axis helpers - if(!cfg.position.unproject) - { - gl.glBindVertexArray(DebugData.axisVAO); - - uboParams.color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f); - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - gl.glDrawArrays(eGL_LINES, 0, 2); - - uboParams.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - gl.glDrawArrays(eGL_LINES, 2, 2); - - uboParams.color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - gl.glDrawArrays(eGL_LINES, 4, 2); - } - - // 'fake' helper frustum - if(cfg.position.unproject) - { - gl.glBindVertexArray(DebugData.frustumVAO); - - uboParams.color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f); - uboParams.mvp = ModelViewProj; - - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - gl.glDrawArrays(eGL_LINES, 0, 24); - } - - if(!IsGLES) - gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); - - // show highlighted vertex - if(cfg.highlightVert != ~0U) - { - m_HighlightCache.CacheHighlightingData(eventId, cfg); - - GLenum meshtopo = topo; - - /////////////////////////////////////////////////////////////// - // vectors to be set from buffers, depending on topology - - // this vert (blue dot, required) - FloatVector activeVertex; - - // primitive this vert is a part of (red prim, optional) - vector activePrim; - - // 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; - - GLenum primTopo = eGL_TRIANGLES; - uint32_t primSize = 3; // number of verts per primitive - - if(meshtopo == eGL_LINES || meshtopo == eGL_LINES_ADJACENCY || meshtopo == eGL_LINE_STRIP || - meshtopo == eGL_LINE_STRIP_ADJACENCY) - { - primSize = 2; - primTopo = eGL_LINES; - } - - bool valid = m_HighlightCache.FetchHighlightPositions(cfg, activeVertex, activePrim, - adjacentPrimVertices, inactiveVertices); - - if(valid) - { - //////////////////////////////////////////////////////////////// - // prepare rendering (for both vertices & primitives) - - // if data is from post transform, it will be in clipspace - if(cfg.position.unproject) - ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); - else - ModelViewProj = projMat.Mul(camMat); - - uboParams.homogenousInput = cfg.position.unproject; - - uboParams.mvp = ModelViewProj; - - gl.glBindVertexArray(DebugData.triHighlightVAO); - - //////////////////////////////////////////////////////////////// - // render primitives - - // Draw active primitive (red) - uboParams.color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f); - - if(activePrim.size() >= primSize) - { - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.triHighlightBuffer); - gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(Vec4f) * primSize, &activePrim[0]); - - gl.glDrawArrays(primTopo, 0, primSize); - } - - // Draw adjacent primitives (green) - uboParams.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); - - if(adjacentPrimVertices.size() >= primSize && (adjacentPrimVertices.size() % primSize) == 0) - { - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.triHighlightBuffer); - gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(Vec4f) * adjacentPrimVertices.size(), - &adjacentPrimVertices[0]); - - gl.glDrawArrays(primTopo, 0, (GLsizei)adjacentPrimVertices.size()); - } - - //////////////////////////////////////////////////////////////// - // prepare to render dots - float scale = 800.0f / float(DebugData.outHeight); - float asp = float(DebugData.outWidth) / float(DebugData.outHeight); - - uboParams.pointSpriteSize = Vec2f(scale / asp, scale); - - // Draw active vertex (blue) - uboParams.color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); - - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - FloatVector vertSprite[4] = { - activeVertex, activeVertex, activeVertex, activeVertex, - }; - - gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.triHighlightBuffer); - gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(vertSprite), &vertSprite[0]); - - gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); - - // Draw inactive vertices (green) - uboParams.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); - - uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), - GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - *uboptr = uboParams; - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - for(size_t i = 0; i < inactiveVertices.size(); i++) - { - vertSprite[0] = vertSprite[1] = vertSprite[2] = vertSprite[3] = inactiveVertices[i]; - - gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(vertSprite), &vertSprite[0]); - - gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); - } - } - } -} diff --git a/renderdoc/driver/gl/gl_rendermesh.cpp b/renderdoc/driver/gl/gl_rendermesh.cpp new file mode 100644 index 000000000..b8cee4923 --- /dev/null +++ b/renderdoc/driver/gl/gl_rendermesh.cpp @@ -0,0 +1,593 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2018 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. + ******************************************************************************/ + +#include +#include "maths/camera.h" +#include "maths/formatpacking.h" +#include "maths/matrix.h" +#include "gl_driver.h" +#include "gl_replay.h" +#include "gl_resources.h" + +#define OPENGL 1 +#include "data/glsl/debuguniforms.h" + +void GLReplay::RenderMesh(uint32_t eventId, const vector &secondaryDraws, + const MeshDisplay &cfg) +{ + WrappedOpenGL &gl = *m_pDriver; + + if(cfg.position.vertexResourceId == ResourceId()) + return; + + MakeCurrentReplayContext(m_DebugCtx); + + Matrix4f projMat = + Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, DebugData.outWidth / DebugData.outHeight); + + Matrix4f camMat = cfg.cam ? ((Camera *)cfg.cam)->GetMatrix() : Matrix4f::Identity(); + + Matrix4f ModelViewProj = projMat.Mul(camMat); + Matrix4f guessProjInv; + + gl.glBindVertexArray(DebugData.meshVAO); + + const MeshFormat *meshData[2] = {&cfg.position, &cfg.second}; + + GLenum topo = MakeGLPrimitiveTopology(cfg.position.topology); + + GLuint prog = DebugData.meshProg; + + MeshUBOData uboParams = {}; + MeshUBOData *uboptr = NULL; + + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]); + + gl.glUseProgram(prog); + + gl.glEnable(eGL_FRAMEBUFFER_SRGB); + + 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 = + cfg.position.farPlane != FLT_MAX + ? Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect) + : Matrix4f::ReversePerspective(cfg.fov, cfg.position.nearPlane, cfg.aspect); + + if(cfg.ortho) + { + guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); + } + + guessProjInv = guessProj.Inverse(); + + ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + } + + uboParams.mvp = ModelViewProj; + uboParams.homogenousInput = cfg.position.unproject; + uboParams.pointSpriteSize = Vec2f(0.0f, 0.0f); + + if(!secondaryDraws.empty()) + { + uboParams.displayFormat = MESHDISPLAY_SOLID; + + if(!IsGLES) + gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_LINE); + + // secondary draws have to come from gl_Position which is float4 + gl.glVertexAttribFormat(0, 4, eGL_FLOAT, GL_FALSE, 0); + gl.glEnableVertexAttribArray(0); + gl.glDisableVertexAttribArray(1); + + for(size_t i = 0; i < secondaryDraws.size(); i++) + { + const MeshFormat &fmt = secondaryDraws[i]; + + if(fmt.vertexResourceId != ResourceId()) + { + uboParams.color = Vec4f(fmt.meshColor.x, fmt.meshColor.y, fmt.meshColor.z, fmt.meshColor.w); + + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + GLuint vb = m_pDriver->GetResourceManager()->GetCurrentResource(fmt.vertexResourceId).name; + gl.glBindVertexBuffer(0, vb, (GLintptr)fmt.vertexByteOffset, fmt.vertexByteStride); + + GLenum secondarytopo = MakeGLPrimitiveTopology(fmt.topology); + + if(fmt.indexByteStride) + { + GLuint ib = m_pDriver->GetResourceManager()->GetCurrentResource(fmt.indexResourceId).name; + gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); + + GLenum idxtype = eGL_UNSIGNED_BYTE; + if(fmt.indexByteStride == 2) + idxtype = eGL_UNSIGNED_SHORT; + else if(fmt.indexByteStride == 4) + idxtype = eGL_UNSIGNED_INT; + + gl.glDrawElementsBaseVertex(secondarytopo, fmt.numIndices, idxtype, + (const void *)uintptr_t(fmt.indexByteOffset), fmt.baseVertex); + } + else + { + gl.glDrawArrays(secondarytopo, 0, fmt.numIndices); + } + } + } + } + + for(uint32_t i = 0; i < 2; i++) + { + if(meshData[i]->vertexResourceId == ResourceId()) + continue; + + if(meshData[i]->format.Special()) + { + if(meshData[i]->format.type == ResourceFormatType::R10G10B10A2) + { + if(meshData[i]->format.compType == CompType::UInt) + gl.glVertexAttribIFormat(i, 4, eGL_UNSIGNED_INT_2_10_10_10_REV, 0); + if(meshData[i]->format.compType == CompType::SInt) + gl.glVertexAttribIFormat(i, 4, eGL_INT_2_10_10_10_REV, 0); + } + else if(meshData[i]->format.type == ResourceFormatType::R11G11B10) + { + gl.glVertexAttribFormat(i, 4, eGL_UNSIGNED_INT_10F_11F_11F_REV, GL_FALSE, 0); + } + else + { + RDCWARN("Unsupported vertex attribute format: %x", meshData[i]->format.type); + } + } + else if(meshData[i]->format.compType == CompType::Float || + meshData[i]->format.compType == CompType::UNorm || + meshData[i]->format.compType == CompType::SNorm) + { + GLenum fmttype = eGL_UNSIGNED_INT; + + if(meshData[i]->format.compByteWidth == 4) + { + if(meshData[i]->format.compType == CompType::Float) + fmttype = eGL_FLOAT; + else if(meshData[i]->format.compType == CompType::UNorm) + fmttype = eGL_UNSIGNED_INT; + else if(meshData[i]->format.compType == CompType::SNorm) + fmttype = eGL_INT; + } + else if(meshData[i]->format.compByteWidth == 2) + { + if(meshData[i]->format.compType == CompType::Float) + fmttype = eGL_HALF_FLOAT; + else if(meshData[i]->format.compType == CompType::UNorm) + fmttype = eGL_UNSIGNED_SHORT; + else if(meshData[i]->format.compType == CompType::SNorm) + fmttype = eGL_SHORT; + } + else if(meshData[i]->format.compByteWidth == 1) + { + if(meshData[i]->format.compType == CompType::UNorm) + fmttype = eGL_UNSIGNED_BYTE; + else if(meshData[i]->format.compType == CompType::SNorm) + fmttype = eGL_BYTE; + } + + gl.glVertexAttribFormat(i, meshData[i]->format.compCount, fmttype, + meshData[i]->format.compType != CompType::Float, 0); + } + else if(meshData[i]->format.compType == CompType::UInt || + meshData[i]->format.compType == CompType::SInt) + { + GLenum fmttype = eGL_UNSIGNED_INT; + + if(meshData[i]->format.compByteWidth == 4) + { + if(meshData[i]->format.compType == CompType::UInt) + fmttype = eGL_UNSIGNED_INT; + else if(meshData[i]->format.compType == CompType::SInt) + fmttype = eGL_INT; + } + else if(meshData[i]->format.compByteWidth == 2) + { + if(meshData[i]->format.compType == CompType::UInt) + fmttype = eGL_UNSIGNED_SHORT; + else if(meshData[i]->format.compType == CompType::SInt) + fmttype = eGL_SHORT; + } + else if(meshData[i]->format.compByteWidth == 1) + { + if(meshData[i]->format.compType == CompType::UInt) + fmttype = eGL_UNSIGNED_BYTE; + else if(meshData[i]->format.compType == CompType::SInt) + fmttype = eGL_BYTE; + } + + gl.glVertexAttribIFormat(i, meshData[i]->format.compCount, fmttype, 0); + } + else if(meshData[i]->format.compType == CompType::Double) + { + gl.glVertexAttribLFormat(i, meshData[i]->format.compCount, eGL_DOUBLE, 0); + } + + GLuint vb = + m_pDriver->GetResourceManager()->GetCurrentResource(meshData[i]->vertexResourceId).name; + gl.glBindVertexBuffer(i, vb, (GLintptr)meshData[i]->vertexByteOffset, + meshData[i]->vertexByteStride); + } + + // enable position attribute + gl.glEnableVertexAttribArray(0); + gl.glDisableVertexAttribArray(1); + + gl.glEnable(eGL_DEPTH_TEST); + + // solid render + if(cfg.solidShadeMode != SolidShade::NoSolid && topo != eGL_PATCHES) + { + gl.glDepthFunc(eGL_LESS); + + GLuint solidProg = prog; + + if(cfg.solidShadeMode == SolidShade::Lit && DebugData.meshgsProg) + { + // pick program with GS for per-face lighting + solidProg = DebugData.meshgsProg; + + ClearGLErrors(gl.GetHookset()); + gl.glUseProgram(solidProg); + GLenum err = gl.glGetError(); + + err = eGL_NONE; + } + + MeshUBOData *soliddata = (MeshUBOData *)gl.glMapBufferRange( + eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + + soliddata->mvp = ModelViewProj; + soliddata->pointSpriteSize = Vec2f(0.0f, 0.0f); + soliddata->homogenousInput = cfg.position.unproject; + + soliddata->color = Vec4f(0.8f, 0.8f, 0.0f, 1.0f); + + uint32_t OutputDisplayFormat = (uint32_t)cfg.solidShadeMode; + if(cfg.solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha) + OutputDisplayFormat = MESHDISPLAY_SECONDARY_ALPHA; + soliddata->displayFormat = OutputDisplayFormat; + + if(cfg.solidShadeMode == SolidShade::Lit) + soliddata->invProj = projMat.Inverse(); + + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + if(cfg.second.vertexResourceId != ResourceId()) + gl.glEnableVertexAttribArray(1); + + if(!IsGLES) + gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); + + if(cfg.position.indexByteStride) + { + GLenum idxtype = eGL_UNSIGNED_BYTE; + if(cfg.position.indexByteStride == 2) + idxtype = eGL_UNSIGNED_SHORT; + else if(cfg.position.indexByteStride == 4) + idxtype = eGL_UNSIGNED_INT; + + if(cfg.position.indexResourceId != ResourceId()) + { + GLuint ib = + m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.indexResourceId).name; + gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); + } + gl.glDrawElementsBaseVertex(topo, cfg.position.numIndices, idxtype, + (const void *)uintptr_t(cfg.position.indexByteOffset), + cfg.position.baseVertex); + } + else + { + gl.glDrawArrays(topo, 0, cfg.position.numIndices); + } + + gl.glDisableVertexAttribArray(1); + + gl.glUseProgram(prog); + } + + gl.glDepthFunc(eGL_ALWAYS); + + // wireframe render + if(cfg.solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw || topo == eGL_PATCHES) + { + uboParams.color = Vec4f(cfg.position.meshColor.x, cfg.position.meshColor.y, + cfg.position.meshColor.z, cfg.position.meshColor.w); + + uboParams.displayFormat = MESHDISPLAY_SOLID; + + if(!IsGLES) + gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_LINE); + + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + if(cfg.position.indexByteStride) + { + GLenum idxtype = eGL_UNSIGNED_BYTE; + if(cfg.position.indexByteStride == 2) + idxtype = eGL_UNSIGNED_SHORT; + else if(cfg.position.indexByteStride == 4) + idxtype = eGL_UNSIGNED_INT; + + if(cfg.position.indexResourceId != ResourceId()) + { + GLuint ib = + m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.indexResourceId).name; + gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); + + gl.glDrawElementsBaseVertex(topo != eGL_PATCHES ? topo : eGL_POINTS, cfg.position.numIndices, + idxtype, (const void *)uintptr_t(cfg.position.indexByteOffset), + cfg.position.baseVertex); + } + } + else + { + gl.glDrawArrays(topo != eGL_PATCHES ? topo : eGL_POINTS, 0, cfg.position.numIndices); + } + } + + if(cfg.showBBox) + { + Vec4f a = Vec4f(cfg.minBounds.x, cfg.minBounds.y, cfg.minBounds.z, cfg.minBounds.w); + Vec4f b = Vec4f(cfg.maxBounds.x, cfg.maxBounds.y, cfg.maxBounds.z, cfg.maxBounds.w); + + Vec4f TLN = Vec4f(a.x, b.y, a.z, 1.0f); // TopLeftNear, etc... + Vec4f TRN = Vec4f(b.x, b.y, a.z, 1.0f); + Vec4f BLN = Vec4f(a.x, a.y, a.z, 1.0f); + Vec4f BRN = Vec4f(b.x, a.y, a.z, 1.0f); + + Vec4f TLF = Vec4f(a.x, b.y, b.z, 1.0f); + Vec4f TRF = Vec4f(b.x, b.y, b.z, 1.0f); + Vec4f BLF = Vec4f(a.x, a.y, b.z, 1.0f); + Vec4f BRF = Vec4f(b.x, a.y, b.z, 1.0f); + + // 12 frustum lines => 24 verts + Vec4f bbox[24] = { + TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN, + + TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF, + + TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF, + }; + + gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.triHighlightBuffer); + gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(bbox), &bbox[0]); + + gl.glBindVertexArray(DebugData.triHighlightVAO); + + uboParams.color = Vec4f(0.2f, 0.2f, 1.0f, 1.0f); + + Matrix4f mvpMat = projMat.Mul(camMat); + + uboParams.mvp = mvpMat; + + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + // we want this to clip + gl.glDepthFunc(eGL_LESS); + + gl.glDrawArrays(eGL_LINES, 0, 24); + + gl.glDepthFunc(eGL_ALWAYS); + } + + // draw axis helpers + if(!cfg.position.unproject) + { + gl.glBindVertexArray(DebugData.axisVAO); + + uboParams.color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f); + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + gl.glDrawArrays(eGL_LINES, 0, 2); + + uboParams.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + gl.glDrawArrays(eGL_LINES, 2, 2); + + uboParams.color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + gl.glDrawArrays(eGL_LINES, 4, 2); + } + + // 'fake' helper frustum + if(cfg.position.unproject) + { + gl.glBindVertexArray(DebugData.frustumVAO); + + uboParams.color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f); + uboParams.mvp = ModelViewProj; + + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + gl.glDrawArrays(eGL_LINES, 0, 24); + } + + if(!IsGLES) + gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); + + // show highlighted vertex + if(cfg.highlightVert != ~0U) + { + m_HighlightCache.CacheHighlightingData(eventId, cfg); + + GLenum meshtopo = topo; + + /////////////////////////////////////////////////////////////// + // vectors to be set from buffers, depending on topology + + // this vert (blue dot, required) + FloatVector activeVertex; + + // primitive this vert is a part of (red prim, optional) + vector activePrim; + + // 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; + + GLenum primTopo = eGL_TRIANGLES; + uint32_t primSize = 3; // number of verts per primitive + + if(meshtopo == eGL_LINES || meshtopo == eGL_LINES_ADJACENCY || meshtopo == eGL_LINE_STRIP || + meshtopo == eGL_LINE_STRIP_ADJACENCY) + { + primSize = 2; + primTopo = eGL_LINES; + } + + bool valid = m_HighlightCache.FetchHighlightPositions(cfg, activeVertex, activePrim, + adjacentPrimVertices, inactiveVertices); + + if(valid) + { + //////////////////////////////////////////////////////////////// + // prepare rendering (for both vertices & primitives) + + // if data is from post transform, it will be in clipspace + if(cfg.position.unproject) + ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + else + ModelViewProj = projMat.Mul(camMat); + + uboParams.homogenousInput = cfg.position.unproject; + + uboParams.mvp = ModelViewProj; + + gl.glBindVertexArray(DebugData.triHighlightVAO); + + //////////////////////////////////////////////////////////////// + // render primitives + + // Draw active primitive (red) + uboParams.color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f); + + if(activePrim.size() >= primSize) + { + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.triHighlightBuffer); + gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(Vec4f) * primSize, &activePrim[0]); + + gl.glDrawArrays(primTopo, 0, primSize); + } + + // Draw adjacent primitives (green) + uboParams.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); + + if(adjacentPrimVertices.size() >= primSize && (adjacentPrimVertices.size() % primSize) == 0) + { + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.triHighlightBuffer); + gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(Vec4f) * adjacentPrimVertices.size(), + &adjacentPrimVertices[0]); + + gl.glDrawArrays(primTopo, 0, (GLsizei)adjacentPrimVertices.size()); + } + + //////////////////////////////////////////////////////////////// + // prepare to render dots + float scale = 800.0f / float(DebugData.outHeight); + float asp = float(DebugData.outWidth) / float(DebugData.outHeight); + + uboParams.pointSpriteSize = Vec2f(scale / asp, scale); + + // Draw active vertex (blue) + uboParams.color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); + + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + FloatVector vertSprite[4] = { + activeVertex, activeVertex, activeVertex, activeVertex, + }; + + gl.glBindBuffer(eGL_ARRAY_BUFFER, DebugData.triHighlightBuffer); + gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(vertSprite), &vertSprite[0]); + + gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); + + // Draw inactive vertices (green) + uboParams.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); + + uboptr = (MeshUBOData *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(MeshUBOData), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + *uboptr = uboParams; + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + for(size_t i = 0; i < inactiveVertices.size(); i++) + { + vertSprite[0] = vertSprite[1] = vertSprite[2] = vertSprite[3] = inactiveVertices[i]; + + gl.glBufferSubData(eGL_ARRAY_BUFFER, 0, sizeof(vertSprite), &vertSprite[0]); + + gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); + } + } + } +} diff --git a/renderdoc/driver/gl/renderdoc_gl.vcxproj b/renderdoc/driver/gl/renderdoc_gl.vcxproj index 871e44b1c..74bd2ac1c 100644 --- a/renderdoc/driver/gl/renderdoc_gl.vcxproj +++ b/renderdoc/driver/gl/renderdoc_gl.vcxproj @@ -154,6 +154,7 @@ + diff --git a/renderdoc/driver/gl/renderdoc_gl.vcxproj.filters b/renderdoc/driver/gl/renderdoc_gl.vcxproj.filters index bddc78b70..609ddddac 100644 --- a/renderdoc/driver/gl/renderdoc_gl.vcxproj.filters +++ b/renderdoc/driver/gl/renderdoc_gl.vcxproj.filters @@ -236,5 +236,8 @@ Replay + + Replay + \ No newline at end of file diff --git a/renderdoc/driver/vulkan/CMakeLists.txt b/renderdoc/driver/vulkan/CMakeLists.txt index b3104eaf0..24d920eb4 100644 --- a/renderdoc/driver/vulkan/CMakeLists.txt +++ b/renderdoc/driver/vulkan/CMakeLists.txt @@ -9,6 +9,7 @@ set(sources vk_postvs.cpp vk_overlay.cpp vk_outputwindow.cpp + vk_rendermesh.cpp vk_dispatchtables.cpp vk_dispatchtables.h vk_hookset_defs.h diff --git a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj index a589ed29b..cf0c99f6e 100644 --- a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj +++ b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj @@ -107,6 +107,7 @@ + diff --git a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters index c64514389..4ce490c9b 100644 --- a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters +++ b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters @@ -115,6 +115,9 @@ Replay + + Replay + diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index d96d36249..c94979b9c 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -4768,308 +4768,3 @@ void VulkanDebugManager::MakeComputePipelineInfo(VkComputePipelineCreateInfo &pi pipeCreateInfo = ret; } - -MeshDisplayPipelines VulkanDebugManager::CacheMeshDisplayPipelines(const MeshFormat &primary, - const MeshFormat &secondary) -{ - // generate a key to look up the map - uint64_t key = 0; - - uint64_t bit = 0; - - if(primary.indexByteStride == 4) - key |= 1ULL << bit; - bit++; - - RDCASSERT((uint32_t)primary.topology < 64); - key |= uint64_t((uint32_t)primary.topology & 0x3f) << bit; - bit += 6; - - VkFormat primaryFmt = MakeVkFormat(primary.format); - VkFormat secondaryFmt = secondary.vertexResourceId == ResourceId() - ? VK_FORMAT_UNDEFINED - : MakeVkFormat(secondary.format); - - RDCCOMPILE_ASSERT(VK_FORMAT_RANGE_SIZE <= 255, - "Mesh pipeline cache key needs an extra bit for format"); - - key |= uint64_t((uint32_t)primaryFmt & 0xff) << bit; - bit += 8; - - key |= uint64_t((uint32_t)secondaryFmt & 0xff) << bit; - bit += 8; - - RDCASSERT(primary.vertexByteStride <= 0xffff); - key |= uint64_t((uint32_t)primary.vertexByteStride & 0xffff) << bit; - bit += 16; - - if(secondary.vertexResourceId != ResourceId()) - { - RDCASSERT(secondary.vertexByteStride <= 0xffff); - key |= uint64_t((uint32_t)secondary.vertexByteStride & 0xffff) << bit; - } - bit += 16; - - MeshDisplayPipelines &cache = m_CachedMeshPipelines[key]; - - if(cache.pipes[(uint32_t)SolidShade::NoSolid] != VK_NULL_HANDLE) - return cache; - - const VkLayerDispatchTable *vt = ObjDisp(m_Device); - VkResult vkr = VK_SUCCESS; - - // should we try and evict old pipelines from the cache here? - // or just keep them forever - - VkVertexInputBindingDescription binds[] = { - // primary - {0, primary.vertexByteStride, VK_VERTEX_INPUT_RATE_VERTEX}, - // secondary - {1, secondary.vertexByteStride, VK_VERTEX_INPUT_RATE_VERTEX}}; - - RDCASSERT(primaryFmt != VK_FORMAT_UNDEFINED); - - VkVertexInputAttributeDescription vertAttrs[] = { - // primary - { - 0, 0, primaryFmt, 0, - }, - // secondary - { - 1, 0, primaryFmt, 0, - }, - }; - - VkPipelineVertexInputStateCreateInfo vi = { - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, NULL, 0, 1, binds, 2, vertAttrs, - }; - - VkPipelineShaderStageCreateInfo stages[3] = { - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_ALL_GRAPHICS, - VK_NULL_HANDLE, "main", NULL}, - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_ALL_GRAPHICS, - VK_NULL_HANDLE, "main", NULL}, - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_ALL_GRAPHICS, - VK_NULL_HANDLE, "main", NULL}, - }; - - VkPipelineInputAssemblyStateCreateInfo ia = { - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, NULL, 0, - primary.topology >= Topology::PatchList ? VK_PRIMITIVE_TOPOLOGY_POINT_LIST - : MakeVkPrimitiveTopology(primary.topology), - false, - }; - - VkRect2D scissor = {{0, 0}, {16384, 16384}}; - - VkPipelineViewportStateCreateInfo vp = { - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, NULL, 0, 1, NULL, 1, &scissor}; - - VkPipelineRasterizationStateCreateInfo rs = { - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - NULL, - 0, - false, - false, - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_NONE, - VK_FRONT_FACE_CLOCKWISE, - false, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }; - - VkPipelineMultisampleStateCreateInfo msaa = { - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - NULL, - 0, - VULKAN_MESH_VIEW_SAMPLES, - false, - 0.0f, - NULL, - false, - false}; - - VkPipelineDepthStencilStateCreateInfo ds = { - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, - NULL, - 0, - true, - true, - VK_COMPARE_OP_LESS_OR_EQUAL, - false, - false, - {VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0, 0, 0}, - {VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0, 0, 0}, - 0.0f, - 1.0f, - }; - - VkPipelineColorBlendAttachmentState attState = { - false, - VK_BLEND_FACTOR_ONE, - VK_BLEND_FACTOR_ZERO, - VK_BLEND_OP_ADD, - VK_BLEND_FACTOR_ONE, - VK_BLEND_FACTOR_ZERO, - VK_BLEND_OP_ADD, - 0xf, - }; - - VkPipelineColorBlendStateCreateInfo cb = { - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - NULL, - 0, - false, - VK_LOGIC_OP_NO_OP, - 1, - &attState, - {1.0f, 1.0f, 1.0f, 1.0f}}; - - VkDynamicState dynstates[] = {VK_DYNAMIC_STATE_VIEWPORT}; - - VkPipelineDynamicStateCreateInfo dyn = { - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - NULL, - 0, - ARRAY_COUNT(dynstates), - dynstates, - }; - - VkRenderPass rp; // compatible render pass - - { - VkAttachmentDescription attDesc[] = { - {0, VK_FORMAT_R8G8B8A8_SRGB, VULKAN_MESH_VIEW_SAMPLES, VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - {0, VK_FORMAT_D32_SFLOAT, VULKAN_MESH_VIEW_SAMPLES, VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - }; - - VkAttachmentReference attRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription sub = { - 0, VK_PIPELINE_BIND_POINT_GRAPHICS, - 0, NULL, // inputs - 1, &attRef, // color - NULL, // resolve - &dsRef, // depth-stencil - 0, NULL, // preserve - }; - - VkRenderPassCreateInfo rpinfo = { - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - NULL, - 0, - 2, - attDesc, - 1, - &sub, - 0, - NULL, // dependencies - }; - - vt->CreateRenderPass(Unwrap(m_Device), &rpinfo, NULL, &rp); - } - - VkGraphicsPipelineCreateInfo pipeInfo = { - VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - NULL, - 0, - 2, - stages, - &vi, - &ia, - NULL, // tess - &vp, - &rs, - &msaa, - &ds, - &cb, - &dyn, - Unwrap(m_MeshPipeLayout), - rp, - 0, // sub pass - VK_NULL_HANDLE, // base pipeline handle - 0, // base pipeline index - }; - - // wireframe pipeline - stages[0].module = Unwrap(m_MeshModules[0]); - stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - stages[1].module = Unwrap(m_MeshModules[2]); - stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - - rs.polygonMode = VK_POLYGON_MODE_LINE; - rs.lineWidth = 1.0f; - ds.depthTestEnable = false; - - vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, - &cache.pipes[MeshDisplayPipelines::ePipe_Wire]); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - ds.depthTestEnable = true; - - vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, - &cache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - // solid shading pipeline - rs.polygonMode = VK_POLYGON_MODE_FILL; - ds.depthTestEnable = false; - - vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, - &cache.pipes[MeshDisplayPipelines::ePipe_Solid]); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - ds.depthTestEnable = true; - - vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, - &cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - if(secondary.vertexResourceId != ResourceId()) - { - // pull secondary information from second vertex buffer - vertAttrs[1].binding = 1; - vertAttrs[1].format = secondaryFmt; - RDCASSERT(secondaryFmt != VK_FORMAT_UNDEFINED); - - vi.vertexBindingDescriptionCount = 2; - - vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, - &cache.pipes[MeshDisplayPipelines::ePipe_Secondary]); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - } - - vertAttrs[1].binding = 0; - vi.vertexBindingDescriptionCount = 1; - - // flat lit pipeline, needs geometry shader to calculate face normals - stages[0].module = Unwrap(m_MeshModules[0]); - stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - stages[1].module = Unwrap(m_MeshModules[1]); - stages[1].stage = VK_SHADER_STAGE_GEOMETRY_BIT; - stages[2].module = Unwrap(m_MeshModules[2]); - stages[2].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - pipeInfo.stageCount = 3; - - vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, - &cache.pipes[MeshDisplayPipelines::ePipe_Lit]); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - for(uint32_t i = 0; i < MeshDisplayPipelines::ePipe_Count; i++) - if(cache.pipes[i] != VK_NULL_HANDLE) - GetResourceManager()->WrapResource(Unwrap(m_Device), cache.pipes[i]); - - vt->DestroyRenderPass(Unwrap(m_Device), rp, NULL); - - return cache; -} diff --git a/renderdoc/driver/vulkan/vk_rendermesh.cpp b/renderdoc/driver/vulkan/vk_rendermesh.cpp new file mode 100644 index 000000000..a3769a806 --- /dev/null +++ b/renderdoc/driver/vulkan/vk_rendermesh.cpp @@ -0,0 +1,1055 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2018 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. + ******************************************************************************/ + +#include +#include "maths/camera.h" +#include "maths/formatpacking.h" +#include "maths/matrix.h" +#include "vk_core.h" +#include "vk_debug.h" + +#define VULKAN 1 +#include "data/glsl/debuguniforms.h" + +MeshDisplayPipelines VulkanDebugManager::CacheMeshDisplayPipelines(const MeshFormat &primary, + const MeshFormat &secondary) +{ + // generate a key to look up the map + uint64_t key = 0; + + uint64_t bit = 0; + + if(primary.indexByteStride == 4) + key |= 1ULL << bit; + bit++; + + RDCASSERT((uint32_t)primary.topology < 64); + key |= uint64_t((uint32_t)primary.topology & 0x3f) << bit; + bit += 6; + + VkFormat primaryFmt = MakeVkFormat(primary.format); + VkFormat secondaryFmt = secondary.vertexResourceId == ResourceId() + ? VK_FORMAT_UNDEFINED + : MakeVkFormat(secondary.format); + + RDCCOMPILE_ASSERT(VK_FORMAT_RANGE_SIZE <= 255, + "Mesh pipeline cache key needs an extra bit for format"); + + key |= uint64_t((uint32_t)primaryFmt & 0xff) << bit; + bit += 8; + + key |= uint64_t((uint32_t)secondaryFmt & 0xff) << bit; + bit += 8; + + RDCASSERT(primary.vertexByteStride <= 0xffff); + key |= uint64_t((uint32_t)primary.vertexByteStride & 0xffff) << bit; + bit += 16; + + if(secondary.vertexResourceId != ResourceId()) + { + RDCASSERT(secondary.vertexByteStride <= 0xffff); + key |= uint64_t((uint32_t)secondary.vertexByteStride & 0xffff) << bit; + } + bit += 16; + + MeshDisplayPipelines &cache = m_CachedMeshPipelines[key]; + + if(cache.pipes[(uint32_t)SolidShade::NoSolid] != VK_NULL_HANDLE) + return cache; + + const VkLayerDispatchTable *vt = ObjDisp(m_Device); + VkResult vkr = VK_SUCCESS; + + // should we try and evict old pipelines from the cache here? + // or just keep them forever + + VkVertexInputBindingDescription binds[] = { + // primary + {0, primary.vertexByteStride, VK_VERTEX_INPUT_RATE_VERTEX}, + // secondary + {1, secondary.vertexByteStride, VK_VERTEX_INPUT_RATE_VERTEX}}; + + RDCASSERT(primaryFmt != VK_FORMAT_UNDEFINED); + + VkVertexInputAttributeDescription vertAttrs[] = { + // primary + { + 0, 0, primaryFmt, 0, + }, + // secondary + { + 1, 0, primaryFmt, 0, + }, + }; + + VkPipelineVertexInputStateCreateInfo vi = { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, NULL, 0, 1, binds, 2, vertAttrs, + }; + + VkPipelineShaderStageCreateInfo stages[3] = { + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_ALL_GRAPHICS, + VK_NULL_HANDLE, "main", NULL}, + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_ALL_GRAPHICS, + VK_NULL_HANDLE, "main", NULL}, + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, 0, VK_SHADER_STAGE_ALL_GRAPHICS, + VK_NULL_HANDLE, "main", NULL}, + }; + + VkPipelineInputAssemblyStateCreateInfo ia = { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, NULL, 0, + primary.topology >= Topology::PatchList ? VK_PRIMITIVE_TOPOLOGY_POINT_LIST + : MakeVkPrimitiveTopology(primary.topology), + false, + }; + + VkRect2D scissor = {{0, 0}, {16384, 16384}}; + + VkPipelineViewportStateCreateInfo vp = { + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, NULL, 0, 1, NULL, 1, &scissor}; + + VkPipelineRasterizationStateCreateInfo rs = { + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + NULL, + 0, + false, + false, + VK_POLYGON_MODE_FILL, + VK_CULL_MODE_NONE, + VK_FRONT_FACE_CLOCKWISE, + false, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }; + + VkPipelineMultisampleStateCreateInfo msaa = { + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + NULL, + 0, + VULKAN_MESH_VIEW_SAMPLES, + false, + 0.0f, + NULL, + false, + false}; + + VkPipelineDepthStencilStateCreateInfo ds = { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + NULL, + 0, + true, + true, + VK_COMPARE_OP_LESS_OR_EQUAL, + false, + false, + {VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0, 0, 0}, + {VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0, 0, 0}, + 0.0f, + 1.0f, + }; + + VkPipelineColorBlendAttachmentState attState = { + false, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, + 0xf, + }; + + VkPipelineColorBlendStateCreateInfo cb = { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + NULL, + 0, + false, + VK_LOGIC_OP_NO_OP, + 1, + &attState, + {1.0f, 1.0f, 1.0f, 1.0f}}; + + VkDynamicState dynstates[] = {VK_DYNAMIC_STATE_VIEWPORT}; + + VkPipelineDynamicStateCreateInfo dyn = { + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + NULL, + 0, + ARRAY_COUNT(dynstates), + dynstates, + }; + + VkRenderPass rp; // compatible render pass + + { + VkAttachmentDescription attDesc[] = { + {0, VK_FORMAT_R8G8B8A8_SRGB, VULKAN_MESH_VIEW_SAMPLES, VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, + {0, VK_FORMAT_D32_SFLOAT, VULKAN_MESH_VIEW_SAMPLES, VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, + }; + + VkAttachmentReference attRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription sub = { + 0, VK_PIPELINE_BIND_POINT_GRAPHICS, + 0, NULL, // inputs + 1, &attRef, // color + NULL, // resolve + &dsRef, // depth-stencil + 0, NULL, // preserve + }; + + VkRenderPassCreateInfo rpinfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + NULL, + 0, + 2, + attDesc, + 1, + &sub, + 0, + NULL, // dependencies + }; + + vt->CreateRenderPass(Unwrap(m_Device), &rpinfo, NULL, &rp); + } + + VkGraphicsPipelineCreateInfo pipeInfo = { + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + NULL, + 0, + 2, + stages, + &vi, + &ia, + NULL, // tess + &vp, + &rs, + &msaa, + &ds, + &cb, + &dyn, + Unwrap(m_MeshPipeLayout), + rp, + 0, // sub pass + VK_NULL_HANDLE, // base pipeline handle + 0, // base pipeline index + }; + + // wireframe pipeline + stages[0].module = Unwrap(m_MeshModules[0]); + stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + stages[1].module = Unwrap(m_MeshModules[2]); + stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + + rs.polygonMode = VK_POLYGON_MODE_LINE; + rs.lineWidth = 1.0f; + ds.depthTestEnable = false; + + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, + &cache.pipes[MeshDisplayPipelines::ePipe_Wire]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + ds.depthTestEnable = true; + + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, + &cache.pipes[MeshDisplayPipelines::ePipe_WireDepth]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + // solid shading pipeline + rs.polygonMode = VK_POLYGON_MODE_FILL; + ds.depthTestEnable = false; + + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, + &cache.pipes[MeshDisplayPipelines::ePipe_Solid]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + ds.depthTestEnable = true; + + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, + &cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + if(secondary.vertexResourceId != ResourceId()) + { + // pull secondary information from second vertex buffer + vertAttrs[1].binding = 1; + vertAttrs[1].format = secondaryFmt; + RDCASSERT(secondaryFmt != VK_FORMAT_UNDEFINED); + + vi.vertexBindingDescriptionCount = 2; + + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, + &cache.pipes[MeshDisplayPipelines::ePipe_Secondary]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } + + vertAttrs[1].binding = 0; + vi.vertexBindingDescriptionCount = 1; + + // flat lit pipeline, needs geometry shader to calculate face normals + stages[0].module = Unwrap(m_MeshModules[0]); + stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + stages[1].module = Unwrap(m_MeshModules[1]); + stages[1].stage = VK_SHADER_STAGE_GEOMETRY_BIT; + stages[2].module = Unwrap(m_MeshModules[2]); + stages[2].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + pipeInfo.stageCount = 3; + + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, NULL, + &cache.pipes[MeshDisplayPipelines::ePipe_Lit]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + for(uint32_t i = 0; i < MeshDisplayPipelines::ePipe_Count; i++) + if(cache.pipes[i] != VK_NULL_HANDLE) + GetResourceManager()->WrapResource(Unwrap(m_Device), cache.pipes[i]); + + vt->DestroyRenderPass(Unwrap(m_Device), rp, NULL); + + return cache; +} + +void VulkanReplay::RenderMesh(uint32_t eventId, const vector &secondaryDraws, + const MeshDisplay &cfg) +{ + if(cfg.position.vertexResourceId == ResourceId() || cfg.position.numIndices == 0) + return; + + auto it = m_OutputWindows.find(m_ActiveWinID); + if(m_ActiveWinID == 0 || it == m_OutputWindows.end()) + return; + + OutputWindow &outw = it->second; + + // if the swapchain failed to create, do nothing. We will try to recreate it + // again in CheckResizeOutputWindow (once per render 'frame') + if(outw.swap == VK_NULL_HANDLE) + return; + + VkDevice dev = m_pDriver->GetDev(); + VkCommandBuffer cmd = m_pDriver->GetNextCmd(); + const VkLayerDispatchTable *vt = ObjDisp(dev); + + VkResult vkr = VK_SUCCESS; + + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkRenderPassBeginInfo rpbegin = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + NULL, + Unwrap(outw.rpdepth), + Unwrap(outw.fbdepth), + {{ + 0, 0, + }, + {m_DebugWidth, m_DebugHeight}}, + 0, + NULL, + }; + vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); + + VkViewport viewport = {0.0f, 0.0f, (float)m_DebugWidth, (float)m_DebugHeight, 0.0f, 1.0f}; + vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); + + Matrix4f projMat = + Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, float(m_DebugWidth) / float(m_DebugHeight)); + Matrix4f InvProj = projMat.Inverse(); + + Matrix4f camMat = cfg.cam ? ((Camera *)cfg.cam)->GetMatrix() : Matrix4f::Identity(); + + Matrix4f ModelViewProj = projMat.Mul(camMat); + Matrix4f guessProjInv; + + 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 = + cfg.position.farPlane != FLT_MAX + ? Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect) + : Matrix4f::ReversePerspective(cfg.fov, cfg.position.nearPlane, cfg.aspect); + + if(cfg.ortho) + { + guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); + } + + guessProjInv = guessProj.Inverse(); + + ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + } + + if(!secondaryDraws.empty()) + { + size_t mapsUsed = 0; + + for(size_t i = 0; i < secondaryDraws.size(); i++) + { + const MeshFormat &fmt = secondaryDraws[i]; + + if(fmt.vertexResourceId != ResourceId()) + { + // TODO should move the color to a push constant so we don't have to map all the time + uint32_t uboOffs = 0; + MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + + data->mvp = ModelViewProj; + data->color = Vec4f(fmt.meshColor.x, fmt.meshColor.y, fmt.meshColor.z, fmt.meshColor.w); + data->homogenousInput = cfg.position.unproject; + data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->displayFormat = MESHDISPLAY_SOLID; + data->rawoutput = 0; + + GetDebugManager()->m_MeshUBO.Unmap(); + + mapsUsed++; + + if(mapsUsed + 1 >= GetDebugManager()->m_MeshUBO.GetRingCount()) + { + // flush and sync so we can use more maps + vt->CmdEndRenderPass(Unwrap(cmd)); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + + mapsUsed = 0; + + cmd = m_pDriver->GetNextCmd(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); + + vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); + } + + MeshDisplayPipelines secondaryCache = + GetDebugManager()->CacheMeshDisplayPipelines(secondaryDraws[i], secondaryDraws[i]); + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(secondaryCache.pipes[MeshDisplayPipelines::ePipe_WireDepth])); + + VkBuffer vb = + m_pDriver->GetResourceManager()->GetCurrentHandle(fmt.vertexResourceId); + + VkDeviceSize offs = fmt.vertexByteOffset; + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(vb), &offs); + + if(fmt.indexByteStride) + { + VkIndexType idxtype = VK_INDEX_TYPE_UINT16; + if(fmt.indexByteStride == 4) + idxtype = VK_INDEX_TYPE_UINT32; + + if(fmt.indexResourceId != ResourceId()) + { + VkBuffer ib = + m_pDriver->GetResourceManager()->GetCurrentHandle(fmt.indexResourceId); + + vt->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(ib), fmt.indexByteOffset, idxtype); + } + vt->CmdDrawIndexed(Unwrap(cmd), fmt.numIndices, 1, 0, fmt.baseVertex, 0); + } + else + { + vt->CmdDraw(Unwrap(cmd), fmt.numIndices, 1, 0, 0); + } + } + } + + { + // flush and sync so we can use more maps + vt->CmdEndRenderPass(Unwrap(cmd)); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + + cmd = m_pDriver->GetNextCmd(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); + + vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); + } + } + + MeshDisplayPipelines cache = GetDebugManager()->CacheMeshDisplayPipelines(cfg.position, cfg.second); + + if(cfg.position.vertexResourceId != ResourceId()) + { + VkBuffer vb = + m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.position.vertexResourceId); + + VkDeviceSize offs = cfg.position.vertexByteOffset; + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(vb), &offs); + } + + SolidShade solidShadeMode = cfg.solidShadeMode; + + // can't support secondary shading without a buffer - no pipeline will have been created + if(solidShadeMode == SolidShade::Secondary && cfg.second.vertexResourceId == ResourceId()) + solidShadeMode = SolidShade::NoSolid; + + if(solidShadeMode == SolidShade::Secondary) + { + VkBuffer vb = + m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.second.vertexResourceId); + + VkDeviceSize offs = cfg.second.vertexByteOffset; + vt->CmdBindVertexBuffers(Unwrap(cmd), 1, 1, UnwrapPtr(vb), &offs); + } + + // solid render + if(solidShadeMode != SolidShade::NoSolid && cfg.position.topology < Topology::PatchList) + { + VkPipeline pipe = VK_NULL_HANDLE; + switch(solidShadeMode) + { + default: + case SolidShade::Solid: pipe = cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]; break; + case SolidShade::Lit: pipe = cache.pipes[MeshDisplayPipelines::ePipe_Lit]; break; + case SolidShade::Secondary: pipe = cache.pipes[MeshDisplayPipelines::ePipe_Secondary]; break; + } + + uint32_t uboOffs = 0; + MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + + if(solidShadeMode == SolidShade::Lit) + data->invProj = projMat.Inverse(); + + data->mvp = ModelViewProj; + data->color = Vec4f(0.8f, 0.8f, 0.0f, 1.0f); + data->homogenousInput = cfg.position.unproject; + data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->displayFormat = (uint32_t)solidShadeMode; + data->rawoutput = 0; + + if(solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha) + data->displayFormat = MESHDISPLAY_SECONDARY_ALPHA; + + GetDebugManager()->m_MeshUBO.Unmap(); + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(pipe)); + + if(cfg.position.indexByteStride) + { + VkIndexType idxtype = VK_INDEX_TYPE_UINT16; + if(cfg.position.indexByteStride == 4) + idxtype = VK_INDEX_TYPE_UINT32; + + if(cfg.position.indexResourceId != ResourceId()) + { + VkBuffer ib = + m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.position.indexResourceId); + + vt->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(ib), cfg.position.indexByteOffset, idxtype); + } + vt->CmdDrawIndexed(Unwrap(cmd), cfg.position.numIndices, 1, 0, cfg.position.baseVertex, 0); + } + else + { + vt->CmdDraw(Unwrap(cmd), cfg.position.numIndices, 1, 0, 0); + } + } + + // wireframe render + if(solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw || + cfg.position.topology >= Topology::PatchList) + { + Vec4f wireCol = + Vec4f(cfg.position.meshColor.x, cfg.position.meshColor.y, cfg.position.meshColor.z, 1.0f); + + uint32_t uboOffs = 0; + MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + + data->mvp = ModelViewProj; + data->color = wireCol; + data->displayFormat = (uint32_t)SolidShade::Solid; + data->homogenousInput = cfg.position.unproject; + data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; + + GetDebugManager()->m_MeshUBO.Unmap(); + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_WireDepth])); + + if(cfg.position.indexByteStride) + { + VkIndexType idxtype = VK_INDEX_TYPE_UINT16; + if(cfg.position.indexByteStride == 4) + idxtype = VK_INDEX_TYPE_UINT32; + + if(cfg.position.indexResourceId != ResourceId()) + { + VkBuffer ib = + m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.position.indexResourceId); + + vt->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(ib), cfg.position.indexByteOffset, idxtype); + } + vt->CmdDrawIndexed(Unwrap(cmd), cfg.position.numIndices, 1, 0, cfg.position.baseVertex, 0); + } + else + { + vt->CmdDraw(Unwrap(cmd), cfg.position.numIndices, 1, 0, 0); + } + } + + MeshFormat helper; + helper.indexByteStride = 2; + helper.topology = Topology::LineList; + + helper.format.type = ResourceFormatType::Regular; + helper.format.compByteWidth = 4; + helper.format.compCount = 4; + helper.format.compType = CompType::Float; + + helper.vertexByteStride = sizeof(Vec4f); + + // cache pipelines for use in drawing wireframe helpers + cache = GetDebugManager()->CacheMeshDisplayPipelines(helper, helper); + + if(cfg.showBBox) + { + Vec4f a = Vec4f(cfg.minBounds.x, cfg.minBounds.y, cfg.minBounds.z, cfg.minBounds.w); + Vec4f b = Vec4f(cfg.maxBounds.x, cfg.maxBounds.y, cfg.maxBounds.z, cfg.maxBounds.w); + + Vec4f TLN = Vec4f(a.x, b.y, a.z, 1.0f); // TopLeftNear, etc... + Vec4f TRN = Vec4f(b.x, b.y, a.z, 1.0f); + Vec4f BLN = Vec4f(a.x, a.y, a.z, 1.0f); + Vec4f BRN = Vec4f(b.x, a.y, a.z, 1.0f); + + Vec4f TLF = Vec4f(a.x, b.y, b.z, 1.0f); + Vec4f TRF = Vec4f(b.x, b.y, b.z, 1.0f); + Vec4f BLF = Vec4f(a.x, a.y, b.z, 1.0f); + Vec4f BRF = Vec4f(b.x, a.y, b.z, 1.0f); + + // 12 frustum lines => 24 verts + Vec4f bbox[24] = { + TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN, + + TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF, + + TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF, + }; + + VkDeviceSize vboffs = 0; + Vec4f *ptr = (Vec4f *)GetDebugManager()->m_MeshBBoxVB.Map(vboffs); + + memcpy(ptr, bbox, sizeof(bbox)); + + GetDebugManager()->m_MeshBBoxVB.Unmap(); + + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(GetDebugManager()->m_MeshBBoxVB.buf), + &vboffs); + + uint32_t uboOffs = 0; + MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + + data->mvp = ModelViewProj; + data->color = Vec4f(0.2f, 0.2f, 1.0f, 1.0f); + data->displayFormat = (uint32_t)SolidShade::Solid; + data->homogenousInput = 0; + data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; + + GetDebugManager()->m_MeshUBO.Unmap(); + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_WireDepth])); + + vt->CmdDraw(Unwrap(cmd), 24, 1, 0, 0); + } + + // draw axis helpers + if(!cfg.position.unproject) + { + VkDeviceSize vboffs = 0; + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshAxisFrustumVB.buf), &vboffs); + + uint32_t uboOffs = 0; + MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + + data->mvp = ModelViewProj; + data->color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f); + data->displayFormat = (uint32_t)SolidShade::Solid; + data->homogenousInput = 0; + data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; + + GetDebugManager()->m_MeshUBO.Unmap(); + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_Wire])); + + vt->CmdDraw(Unwrap(cmd), 2, 1, 0, 0); + + // poke the color (this would be a good candidate for a push constant) + data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + + data->mvp = ModelViewProj; + data->color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); + data->displayFormat = (uint32_t)SolidShade::Solid; + data->homogenousInput = 0; + data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; + + GetDebugManager()->m_MeshUBO.Unmap(); + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + vt->CmdDraw(Unwrap(cmd), 2, 1, 2, 0); + + data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + + data->mvp = ModelViewProj; + data->color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); + data->displayFormat = (uint32_t)SolidShade::Solid; + data->homogenousInput = 0; + data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; + + GetDebugManager()->m_MeshUBO.Unmap(); + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + vt->CmdDraw(Unwrap(cmd), 2, 1, 4, 0); + } + + // 'fake' helper frustum + if(cfg.position.unproject) + { + VkDeviceSize vboffs = sizeof(Vec4f) * 6; // skim the axis helpers + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshAxisFrustumVB.buf), &vboffs); + + uint32_t uboOffs = 0; + MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + + data->mvp = ModelViewProj; + data->color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f); + data->displayFormat = (uint32_t)SolidShade::Solid; + data->homogenousInput = 0; + data->pointSpriteSize = Vec2f(0.0f, 0.0f); + data->rawoutput = 0; + + GetDebugManager()->m_MeshUBO.Unmap(); + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_Wire])); + + vt->CmdDraw(Unwrap(cmd), 24, 1, 0, 0); + } + + // show highlighted vertex + if(cfg.highlightVert != ~0U) + { + { + // need to end our cmd buffer, it might be submitted in GetBufferData when caching highlight + // data + vt->CmdEndRenderPass(Unwrap(cmd)); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + +#if ENABLED(SINGLE_FLUSH_VALIDATE) + m_pDriver->SubmitCmds(); +#endif + } + + m_HighlightCache.CacheHighlightingData(eventId, cfg); + + { + // get a new cmdbuffer and begin it + cmd = m_pDriver->GetNextCmd(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); + + vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); + } + + Topology meshtopo = cfg.position.topology; + + /////////////////////////////////////////////////////////////// + // vectors to be set from buffers, depending on topology + + // this vert (blue dot, required) + FloatVector activeVertex; + + // primitive this vert is a part of (red prim, optional) + vector activePrim; + + // 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; + + helper.topology = Topology::TriangleList; + uint32_t primSize = 3; // number of verts per primitive + + if(meshtopo == Topology::LineList || meshtopo == Topology::LineStrip || + meshtopo == Topology::LineList_Adj || meshtopo == Topology::LineStrip_Adj) + { + primSize = 2; + helper.topology = Topology::LineList; + } + else + { + // update the cache, as it's currently linelist + helper.topology = Topology::TriangleList; + cache = GetDebugManager()->CacheMeshDisplayPipelines(helper, helper); + } + + bool valid = m_HighlightCache.FetchHighlightPositions(cfg, activeVertex, activePrim, + adjacentPrimVertices, inactiveVertices); + + if(valid) + { + //////////////////////////////////////////////////////////////// + // prepare rendering (for both vertices & primitives) + + // if data is from post transform, it will be in clipspace + if(cfg.position.unproject) + ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + else + ModelViewProj = projMat.Mul(camMat); + + MeshUBOData uniforms = {}; + uniforms.mvp = ModelViewProj; + uniforms.color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f); + uniforms.displayFormat = (uint32_t)SolidShade::Solid; + uniforms.homogenousInput = cfg.position.unproject; + uniforms.pointSpriteSize = Vec2f(0.0f, 0.0f); + + uint32_t uboOffs = 0; + MeshUBOData *ubodata = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + *ubodata = uniforms; + GetDebugManager()->m_MeshUBO.Unmap(); + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_Solid])); + + //////////////////////////////////////////////////////////////// + // render primitives + + // Draw active primitive (red) + uniforms.color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f); + // poke the color (this would be a good candidate for a push constant) + ubodata = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + *ubodata = uniforms; + GetDebugManager()->m_MeshUBO.Unmap(); + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + if(activePrim.size() >= primSize) + { + VkDeviceSize vboffs = 0; + Vec4f *ptr = (Vec4f *)GetDebugManager()->m_MeshBBoxVB.Map(vboffs, sizeof(Vec4f) * primSize); + + memcpy(ptr, &activePrim[0], sizeof(Vec4f) * primSize); + + GetDebugManager()->m_MeshBBoxVB.Unmap(); + + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(GetDebugManager()->m_MeshBBoxVB.buf), + &vboffs); + + vt->CmdDraw(Unwrap(cmd), primSize, 1, 0, 0); + } + + // Draw adjacent primitives (green) + uniforms.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); + // poke the color (this would be a good candidate for a push constant) + ubodata = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + *ubodata = uniforms; + GetDebugManager()->m_MeshUBO.Unmap(); + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + if(adjacentPrimVertices.size() >= primSize && (adjacentPrimVertices.size() % primSize) == 0) + { + VkDeviceSize vboffs = 0; + Vec4f *ptr = (Vec4f *)GetDebugManager()->m_MeshBBoxVB.Map( + vboffs, sizeof(Vec4f) * adjacentPrimVertices.size()); + + memcpy(ptr, &adjacentPrimVertices[0], sizeof(Vec4f) * adjacentPrimVertices.size()); + + GetDebugManager()->m_MeshBBoxVB.Unmap(); + + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(GetDebugManager()->m_MeshBBoxVB.buf), + &vboffs); + + vt->CmdDraw(Unwrap(cmd), (uint32_t)adjacentPrimVertices.size(), 1, 0, 0); + } + + //////////////////////////////////////////////////////////////// + // prepare to render dots + float scale = 800.0f / float(m_DebugHeight); + float asp = float(m_DebugWidth) / float(m_DebugHeight); + + uniforms.pointSpriteSize = Vec2f(scale / asp, scale); + + // Draw active vertex (blue) + uniforms.color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); + // poke the color (this would be a good candidate for a push constant) + ubodata = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + *ubodata = uniforms; + GetDebugManager()->m_MeshUBO.Unmap(); + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + // vertices are drawn with tri strips + helper.topology = Topology::TriangleStrip; + cache = GetDebugManager()->CacheMeshDisplayPipelines(helper, helper); + + FloatVector vertSprite[4] = { + activeVertex, activeVertex, activeVertex, activeVertex, + }; + + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_Solid])); + + { + VkDeviceSize vboffs = 0; + Vec4f *ptr = (Vec4f *)GetDebugManager()->m_MeshBBoxVB.Map(vboffs, sizeof(vertSprite)); + + memcpy(ptr, &vertSprite[0], sizeof(vertSprite)); + + GetDebugManager()->m_MeshBBoxVB.Unmap(); + + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(GetDebugManager()->m_MeshBBoxVB.buf), + &vboffs); + + vt->CmdDraw(Unwrap(cmd), 4, 1, 0, 0); + } + + // Draw inactive vertices (green) + uniforms.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); + // poke the color (this would be a good candidate for a push constant) + ubodata = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); + *ubodata = uniforms; + GetDebugManager()->m_MeshUBO.Unmap(); + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); + + if(!inactiveVertices.empty()) + { + VkDeviceSize vboffs = 0; + FloatVector *ptr = + (FloatVector *)GetDebugManager()->m_MeshBBoxVB.Map(vboffs, sizeof(vertSprite)); + + for(size_t i = 0; i < inactiveVertices.size(); i++) + { + *ptr++ = inactiveVertices[i]; + *ptr++ = inactiveVertices[i]; + *ptr++ = inactiveVertices[i]; + *ptr++ = inactiveVertices[i]; + } + + GetDebugManager()->m_MeshBBoxVB.Unmap(); + + for(size_t i = 0; i < inactiveVertices.size(); i++) + { + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, + UnwrapPtr(GetDebugManager()->m_MeshBBoxVB.buf), &vboffs); + + vt->CmdDraw(Unwrap(cmd), 4, 1, 0, 0); + + vboffs += sizeof(FloatVector) * 4; + } + } + } + } + + vt->CmdEndRenderPass(Unwrap(cmd)); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + +#if ENABLED(SINGLE_FLUSH_VALIDATE) + m_pDriver->SubmitCmds(); +#endif +} diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 6f3e638dd..5a330e08f 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1213,723 +1213,6 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Debu return GetDebugManager()->RenderOverlay(texid, overlay, eventId, passEvents); } -void VulkanReplay::RenderMesh(uint32_t eventId, const vector &secondaryDraws, - const MeshDisplay &cfg) -{ - if(cfg.position.vertexResourceId == ResourceId() || cfg.position.numIndices == 0) - return; - - auto it = m_OutputWindows.find(m_ActiveWinID); - if(m_ActiveWinID == 0 || it == m_OutputWindows.end()) - return; - - OutputWindow &outw = it->second; - - // if the swapchain failed to create, do nothing. We will try to recreate it - // again in CheckResizeOutputWindow (once per render 'frame') - if(outw.swap == VK_NULL_HANDLE) - return; - - VkDevice dev = m_pDriver->GetDev(); - VkCommandBuffer cmd = m_pDriver->GetNextCmd(); - const VkLayerDispatchTable *vt = ObjDisp(dev); - - VkResult vkr = VK_SUCCESS; - - VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; - - vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - VkRenderPassBeginInfo rpbegin = { - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - NULL, - Unwrap(outw.rpdepth), - Unwrap(outw.fbdepth), - {{ - 0, 0, - }, - {m_DebugWidth, m_DebugHeight}}, - 0, - NULL, - }; - vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); - - VkViewport viewport = {0.0f, 0.0f, (float)m_DebugWidth, (float)m_DebugHeight, 0.0f, 1.0f}; - vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); - - Matrix4f projMat = - Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, float(m_DebugWidth) / float(m_DebugHeight)); - Matrix4f InvProj = projMat.Inverse(); - - Matrix4f camMat = cfg.cam ? ((Camera *)cfg.cam)->GetMatrix() : Matrix4f::Identity(); - - Matrix4f ModelViewProj = projMat.Mul(camMat); - Matrix4f guessProjInv; - - 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 = - cfg.position.farPlane != FLT_MAX - ? Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect) - : Matrix4f::ReversePerspective(cfg.fov, cfg.position.nearPlane, cfg.aspect); - - if(cfg.ortho) - { - guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); - } - - guessProjInv = guessProj.Inverse(); - - ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); - } - - if(!secondaryDraws.empty()) - { - size_t mapsUsed = 0; - - for(size_t i = 0; i < secondaryDraws.size(); i++) - { - const MeshFormat &fmt = secondaryDraws[i]; - - if(fmt.vertexResourceId != ResourceId()) - { - // TODO should move the color to a push constant so we don't have to map all the time - uint32_t uboOffs = 0; - MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - - data->mvp = ModelViewProj; - data->color = Vec4f(fmt.meshColor.x, fmt.meshColor.y, fmt.meshColor.z, fmt.meshColor.w); - data->homogenousInput = cfg.position.unproject; - data->pointSpriteSize = Vec2f(0.0f, 0.0f); - data->displayFormat = MESHDISPLAY_SOLID; - data->rawoutput = 0; - - GetDebugManager()->m_MeshUBO.Unmap(); - - mapsUsed++; - - if(mapsUsed + 1 >= GetDebugManager()->m_MeshUBO.GetRingCount()) - { - // flush and sync so we can use more maps - vt->CmdEndRenderPass(Unwrap(cmd)); - - vkr = vt->EndCommandBuffer(Unwrap(cmd)); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - m_pDriver->SubmitCmds(); - m_pDriver->FlushQ(); - - mapsUsed = 0; - - cmd = m_pDriver->GetNextCmd(); - - vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); - - vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); - } - - MeshDisplayPipelines secondaryCache = - GetDebugManager()->CacheMeshDisplayPipelines(secondaryDraws[i], secondaryDraws[i]); - - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(secondaryCache.pipes[MeshDisplayPipelines::ePipe_WireDepth])); - - VkBuffer vb = - m_pDriver->GetResourceManager()->GetCurrentHandle(fmt.vertexResourceId); - - VkDeviceSize offs = fmt.vertexByteOffset; - vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(vb), &offs); - - if(fmt.indexByteStride) - { - VkIndexType idxtype = VK_INDEX_TYPE_UINT16; - if(fmt.indexByteStride == 4) - idxtype = VK_INDEX_TYPE_UINT32; - - if(fmt.indexResourceId != ResourceId()) - { - VkBuffer ib = - m_pDriver->GetResourceManager()->GetCurrentHandle(fmt.indexResourceId); - - vt->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(ib), fmt.indexByteOffset, idxtype); - } - vt->CmdDrawIndexed(Unwrap(cmd), fmt.numIndices, 1, 0, fmt.baseVertex, 0); - } - else - { - vt->CmdDraw(Unwrap(cmd), fmt.numIndices, 1, 0, 0); - } - } - } - - { - // flush and sync so we can use more maps - vt->CmdEndRenderPass(Unwrap(cmd)); - - vkr = vt->EndCommandBuffer(Unwrap(cmd)); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - - m_pDriver->SubmitCmds(); - m_pDriver->FlushQ(); - - cmd = m_pDriver->GetNextCmd(); - - vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); - - vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); - } - } - - MeshDisplayPipelines cache = GetDebugManager()->CacheMeshDisplayPipelines(cfg.position, cfg.second); - - if(cfg.position.vertexResourceId != ResourceId()) - { - VkBuffer vb = - m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.position.vertexResourceId); - - VkDeviceSize offs = cfg.position.vertexByteOffset; - vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(vb), &offs); - } - - SolidShade solidShadeMode = cfg.solidShadeMode; - - // can't support secondary shading without a buffer - no pipeline will have been created - if(solidShadeMode == SolidShade::Secondary && cfg.second.vertexResourceId == ResourceId()) - solidShadeMode = SolidShade::NoSolid; - - if(solidShadeMode == SolidShade::Secondary) - { - VkBuffer vb = - m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.second.vertexResourceId); - - VkDeviceSize offs = cfg.second.vertexByteOffset; - vt->CmdBindVertexBuffers(Unwrap(cmd), 1, 1, UnwrapPtr(vb), &offs); - } - - // solid render - if(solidShadeMode != SolidShade::NoSolid && cfg.position.topology < Topology::PatchList) - { - VkPipeline pipe = VK_NULL_HANDLE; - switch(solidShadeMode) - { - default: - case SolidShade::Solid: pipe = cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth]; break; - case SolidShade::Lit: pipe = cache.pipes[MeshDisplayPipelines::ePipe_Lit]; break; - case SolidShade::Secondary: pipe = cache.pipes[MeshDisplayPipelines::ePipe_Secondary]; break; - } - - uint32_t uboOffs = 0; - MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - - if(solidShadeMode == SolidShade::Lit) - data->invProj = projMat.Inverse(); - - data->mvp = ModelViewProj; - data->color = Vec4f(0.8f, 0.8f, 0.0f, 1.0f); - data->homogenousInput = cfg.position.unproject; - data->pointSpriteSize = Vec2f(0.0f, 0.0f); - data->displayFormat = (uint32_t)solidShadeMode; - data->rawoutput = 0; - - if(solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha) - data->displayFormat = MESHDISPLAY_SECONDARY_ALPHA; - - GetDebugManager()->m_MeshUBO.Unmap(); - - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(pipe)); - - if(cfg.position.indexByteStride) - { - VkIndexType idxtype = VK_INDEX_TYPE_UINT16; - if(cfg.position.indexByteStride == 4) - idxtype = VK_INDEX_TYPE_UINT32; - - if(cfg.position.indexResourceId != ResourceId()) - { - VkBuffer ib = - m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.position.indexResourceId); - - vt->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(ib), cfg.position.indexByteOffset, idxtype); - } - vt->CmdDrawIndexed(Unwrap(cmd), cfg.position.numIndices, 1, 0, cfg.position.baseVertex, 0); - } - else - { - vt->CmdDraw(Unwrap(cmd), cfg.position.numIndices, 1, 0, 0); - } - } - - // wireframe render - if(solidShadeMode == SolidShade::NoSolid || cfg.wireframeDraw || - cfg.position.topology >= Topology::PatchList) - { - Vec4f wireCol = - Vec4f(cfg.position.meshColor.x, cfg.position.meshColor.y, cfg.position.meshColor.z, 1.0f); - - uint32_t uboOffs = 0; - MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - - data->mvp = ModelViewProj; - data->color = wireCol; - data->displayFormat = (uint32_t)SolidShade::Solid; - data->homogenousInput = cfg.position.unproject; - data->pointSpriteSize = Vec2f(0.0f, 0.0f); - data->rawoutput = 0; - - GetDebugManager()->m_MeshUBO.Unmap(); - - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_WireDepth])); - - if(cfg.position.indexByteStride) - { - VkIndexType idxtype = VK_INDEX_TYPE_UINT16; - if(cfg.position.indexByteStride == 4) - idxtype = VK_INDEX_TYPE_UINT32; - - if(cfg.position.indexResourceId != ResourceId()) - { - VkBuffer ib = - m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.position.indexResourceId); - - vt->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(ib), cfg.position.indexByteOffset, idxtype); - } - vt->CmdDrawIndexed(Unwrap(cmd), cfg.position.numIndices, 1, 0, cfg.position.baseVertex, 0); - } - else - { - vt->CmdDraw(Unwrap(cmd), cfg.position.numIndices, 1, 0, 0); - } - } - - MeshFormat helper; - helper.indexByteStride = 2; - helper.topology = Topology::LineList; - - helper.format.type = ResourceFormatType::Regular; - helper.format.compByteWidth = 4; - helper.format.compCount = 4; - helper.format.compType = CompType::Float; - - helper.vertexByteStride = sizeof(Vec4f); - - // cache pipelines for use in drawing wireframe helpers - cache = GetDebugManager()->CacheMeshDisplayPipelines(helper, helper); - - if(cfg.showBBox) - { - Vec4f a = Vec4f(cfg.minBounds.x, cfg.minBounds.y, cfg.minBounds.z, cfg.minBounds.w); - Vec4f b = Vec4f(cfg.maxBounds.x, cfg.maxBounds.y, cfg.maxBounds.z, cfg.maxBounds.w); - - Vec4f TLN = Vec4f(a.x, b.y, a.z, 1.0f); // TopLeftNear, etc... - Vec4f TRN = Vec4f(b.x, b.y, a.z, 1.0f); - Vec4f BLN = Vec4f(a.x, a.y, a.z, 1.0f); - Vec4f BRN = Vec4f(b.x, a.y, a.z, 1.0f); - - Vec4f TLF = Vec4f(a.x, b.y, b.z, 1.0f); - Vec4f TRF = Vec4f(b.x, b.y, b.z, 1.0f); - Vec4f BLF = Vec4f(a.x, a.y, b.z, 1.0f); - Vec4f BRF = Vec4f(b.x, a.y, b.z, 1.0f); - - // 12 frustum lines => 24 verts - Vec4f bbox[24] = { - TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN, - - TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF, - - TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF, - }; - - VkDeviceSize vboffs = 0; - Vec4f *ptr = (Vec4f *)GetDebugManager()->m_MeshBBoxVB.Map(vboffs); - - memcpy(ptr, bbox, sizeof(bbox)); - - GetDebugManager()->m_MeshBBoxVB.Unmap(); - - vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(GetDebugManager()->m_MeshBBoxVB.buf), - &vboffs); - - uint32_t uboOffs = 0; - MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - - data->mvp = ModelViewProj; - data->color = Vec4f(0.2f, 0.2f, 1.0f, 1.0f); - data->displayFormat = (uint32_t)SolidShade::Solid; - data->homogenousInput = 0; - data->pointSpriteSize = Vec2f(0.0f, 0.0f); - data->rawoutput = 0; - - GetDebugManager()->m_MeshUBO.Unmap(); - - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_WireDepth])); - - vt->CmdDraw(Unwrap(cmd), 24, 1, 0, 0); - } - - // draw axis helpers - if(!cfg.position.unproject) - { - VkDeviceSize vboffs = 0; - vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshAxisFrustumVB.buf), &vboffs); - - uint32_t uboOffs = 0; - MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - - data->mvp = ModelViewProj; - data->color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f); - data->displayFormat = (uint32_t)SolidShade::Solid; - data->homogenousInput = 0; - data->pointSpriteSize = Vec2f(0.0f, 0.0f); - data->rawoutput = 0; - - GetDebugManager()->m_MeshUBO.Unmap(); - - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_Wire])); - - vt->CmdDraw(Unwrap(cmd), 2, 1, 0, 0); - - // poke the color (this would be a good candidate for a push constant) - data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - - data->mvp = ModelViewProj; - data->color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); - data->displayFormat = (uint32_t)SolidShade::Solid; - data->homogenousInput = 0; - data->pointSpriteSize = Vec2f(0.0f, 0.0f); - data->rawoutput = 0; - - GetDebugManager()->m_MeshUBO.Unmap(); - - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - vt->CmdDraw(Unwrap(cmd), 2, 1, 2, 0); - - data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - - data->mvp = ModelViewProj; - data->color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); - data->displayFormat = (uint32_t)SolidShade::Solid; - data->homogenousInput = 0; - data->pointSpriteSize = Vec2f(0.0f, 0.0f); - data->rawoutput = 0; - - GetDebugManager()->m_MeshUBO.Unmap(); - - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - vt->CmdDraw(Unwrap(cmd), 2, 1, 4, 0); - } - - // 'fake' helper frustum - if(cfg.position.unproject) - { - VkDeviceSize vboffs = sizeof(Vec4f) * 6; // skim the axis helpers - vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshAxisFrustumVB.buf), &vboffs); - - uint32_t uboOffs = 0; - MeshUBOData *data = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - - data->mvp = ModelViewProj; - data->color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f); - data->displayFormat = (uint32_t)SolidShade::Solid; - data->homogenousInput = 0; - data->pointSpriteSize = Vec2f(0.0f, 0.0f); - data->rawoutput = 0; - - GetDebugManager()->m_MeshUBO.Unmap(); - - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_Wire])); - - vt->CmdDraw(Unwrap(cmd), 24, 1, 0, 0); - } - - // show highlighted vertex - if(cfg.highlightVert != ~0U) - { - { - // need to end our cmd buffer, it might be submitted in GetBufferData when caching highlight - // data - vt->CmdEndRenderPass(Unwrap(cmd)); - - vkr = vt->EndCommandBuffer(Unwrap(cmd)); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - -#if ENABLED(SINGLE_FLUSH_VALIDATE) - m_pDriver->SubmitCmds(); -#endif - } - - m_HighlightCache.CacheHighlightingData(eventId, cfg); - - { - // get a new cmdbuffer and begin it - cmd = m_pDriver->GetNextCmd(); - - vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); - - vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); - } - - Topology meshtopo = cfg.position.topology; - - /////////////////////////////////////////////////////////////// - // vectors to be set from buffers, depending on topology - - // this vert (blue dot, required) - FloatVector activeVertex; - - // primitive this vert is a part of (red prim, optional) - vector activePrim; - - // 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; - - helper.topology = Topology::TriangleList; - uint32_t primSize = 3; // number of verts per primitive - - if(meshtopo == Topology::LineList || meshtopo == Topology::LineStrip || - meshtopo == Topology::LineList_Adj || meshtopo == Topology::LineStrip_Adj) - { - primSize = 2; - helper.topology = Topology::LineList; - } - else - { - // update the cache, as it's currently linelist - helper.topology = Topology::TriangleList; - cache = GetDebugManager()->CacheMeshDisplayPipelines(helper, helper); - } - - bool valid = m_HighlightCache.FetchHighlightPositions(cfg, activeVertex, activePrim, - adjacentPrimVertices, inactiveVertices); - - if(valid) - { - //////////////////////////////////////////////////////////////// - // prepare rendering (for both vertices & primitives) - - // if data is from post transform, it will be in clipspace - if(cfg.position.unproject) - ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); - else - ModelViewProj = projMat.Mul(camMat); - - MeshUBOData uniforms = {}; - uniforms.mvp = ModelViewProj; - uniforms.color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f); - uniforms.displayFormat = (uint32_t)SolidShade::Solid; - uniforms.homogenousInput = cfg.position.unproject; - uniforms.pointSpriteSize = Vec2f(0.0f, 0.0f); - - uint32_t uboOffs = 0; - MeshUBOData *ubodata = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - *ubodata = uniforms; - GetDebugManager()->m_MeshUBO.Unmap(); - - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_Solid])); - - //////////////////////////////////////////////////////////////// - // render primitives - - // Draw active primitive (red) - uniforms.color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f); - // poke the color (this would be a good candidate for a push constant) - ubodata = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - *ubodata = uniforms; - GetDebugManager()->m_MeshUBO.Unmap(); - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - if(activePrim.size() >= primSize) - { - VkDeviceSize vboffs = 0; - Vec4f *ptr = (Vec4f *)GetDebugManager()->m_MeshBBoxVB.Map(vboffs, sizeof(Vec4f) * primSize); - - memcpy(ptr, &activePrim[0], sizeof(Vec4f) * primSize); - - GetDebugManager()->m_MeshBBoxVB.Unmap(); - - vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(GetDebugManager()->m_MeshBBoxVB.buf), - &vboffs); - - vt->CmdDraw(Unwrap(cmd), primSize, 1, 0, 0); - } - - // Draw adjacent primitives (green) - uniforms.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); - // poke the color (this would be a good candidate for a push constant) - ubodata = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - *ubodata = uniforms; - GetDebugManager()->m_MeshUBO.Unmap(); - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - if(adjacentPrimVertices.size() >= primSize && (adjacentPrimVertices.size() % primSize) == 0) - { - VkDeviceSize vboffs = 0; - Vec4f *ptr = (Vec4f *)GetDebugManager()->m_MeshBBoxVB.Map( - vboffs, sizeof(Vec4f) * adjacentPrimVertices.size()); - - memcpy(ptr, &adjacentPrimVertices[0], sizeof(Vec4f) * adjacentPrimVertices.size()); - - GetDebugManager()->m_MeshBBoxVB.Unmap(); - - vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(GetDebugManager()->m_MeshBBoxVB.buf), - &vboffs); - - vt->CmdDraw(Unwrap(cmd), (uint32_t)adjacentPrimVertices.size(), 1, 0, 0); - } - - //////////////////////////////////////////////////////////////// - // prepare to render dots - float scale = 800.0f / float(m_DebugHeight); - float asp = float(m_DebugWidth) / float(m_DebugHeight); - - uniforms.pointSpriteSize = Vec2f(scale / asp, scale); - - // Draw active vertex (blue) - uniforms.color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f); - // poke the color (this would be a good candidate for a push constant) - ubodata = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - *ubodata = uniforms; - GetDebugManager()->m_MeshUBO.Unmap(); - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - // vertices are drawn with tri strips - helper.topology = Topology::TriangleStrip; - cache = GetDebugManager()->CacheMeshDisplayPipelines(helper, helper); - - FloatVector vertSprite[4] = { - activeVertex, activeVertex, activeVertex, activeVertex, - }; - - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(cache.pipes[MeshDisplayPipelines::ePipe_Solid])); - - { - VkDeviceSize vboffs = 0; - Vec4f *ptr = (Vec4f *)GetDebugManager()->m_MeshBBoxVB.Map(vboffs, sizeof(vertSprite)); - - memcpy(ptr, &vertSprite[0], sizeof(vertSprite)); - - GetDebugManager()->m_MeshBBoxVB.Unmap(); - - vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(GetDebugManager()->m_MeshBBoxVB.buf), - &vboffs); - - vt->CmdDraw(Unwrap(cmd), 4, 1, 0, 0); - } - - // Draw inactive vertices (green) - uniforms.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f); - // poke the color (this would be a good candidate for a push constant) - ubodata = (MeshUBOData *)GetDebugManager()->m_MeshUBO.Map(&uboOffs); - *ubodata = uniforms; - GetDebugManager()->m_MeshUBO.Unmap(); - vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, - Unwrap(GetDebugManager()->m_MeshPipeLayout), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshDescSet), 1, &uboOffs); - - if(!inactiveVertices.empty()) - { - VkDeviceSize vboffs = 0; - FloatVector *ptr = - (FloatVector *)GetDebugManager()->m_MeshBBoxVB.Map(vboffs, sizeof(vertSprite)); - - for(size_t i = 0; i < inactiveVertices.size(); i++) - { - *ptr++ = inactiveVertices[i]; - *ptr++ = inactiveVertices[i]; - *ptr++ = inactiveVertices[i]; - *ptr++ = inactiveVertices[i]; - } - - GetDebugManager()->m_MeshBBoxVB.Unmap(); - - for(size_t i = 0; i < inactiveVertices.size(); i++) - { - vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, - UnwrapPtr(GetDebugManager()->m_MeshBBoxVB.buf), &vboffs); - - vt->CmdDraw(Unwrap(cmd), 4, 1, 0, 0); - - vboffs += sizeof(FloatVector) * 4; - } - } - } - } - - vt->CmdEndRenderPass(Unwrap(cmd)); - - vkr = vt->EndCommandBuffer(Unwrap(cmd)); - RDCASSERTEQUAL(vkr, VK_SUCCESS); - -#if ENABLED(SINGLE_FLUSH_VALIDATE) - m_pDriver->SubmitCmds(); -#endif -} - void VulkanReplay::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &retData) { GetDebugManager()->GetBufferData(buff, offset, len, retData);