mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 10:00:40 +00:00
Split out mesh rendering to separate files
This commit is contained in:
@@ -3562,575 +3562,6 @@ void D3D11DebugManager::RenderForPredicate()
|
||||
m_WrappedContext->Draw(3, 0);
|
||||
}
|
||||
|
||||
void D3D11DebugManager::RenderMesh(uint32_t eventId, const vector<MeshFormat> &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<FloatVector> 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<FloatVector> 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<FloatVector> 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<DXBC::CBufferVariable> &invars,
|
||||
vector<ShaderVariable> &outvars, const bytebuf &data)
|
||||
|
||||
@@ -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<MeshFormat> &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<FloatVector> 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<FloatVector> 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<FloatVector> 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);
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,7 @@
|
||||
<ClCompile Include="d3d11_overlay.cpp" />
|
||||
<ClCompile Include="d3d11_pixelhistory.cpp" />
|
||||
<ClCompile Include="d3d11_postvs.cpp" />
|
||||
<ClCompile Include="d3d11_rendermesh.cpp" />
|
||||
<ClCompile Include="d3d11_serialise.cpp" />
|
||||
<ClCompile Include="d3d11_context.cpp" />
|
||||
<ClCompile Include="d3d11_context1_wrap.cpp" />
|
||||
|
||||
@@ -105,6 +105,9 @@
|
||||
<ClCompile Include="d3d11_outputwindow.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="d3d11_rendermesh.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="d3d11_replay.h">
|
||||
|
||||
@@ -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<MeshFormat> &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<ID3D12Resource>(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<ID3D12Resource>(
|
||||
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<ID3D12Resource>(
|
||||
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<ID3D12Resource>(
|
||||
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<ID3D12Resource>(
|
||||
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<ID3D12Resource>(
|
||||
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<FloatVector> 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<FloatVector> 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<FloatVector> 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<FloatVector> 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<D3D12_RESOURCE_BARRIER> &barriers)
|
||||
{
|
||||
|
||||
@@ -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<MeshFormat> &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<ID3D12Resource>(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<ID3D12Resource>(
|
||||
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<ID3D12Resource>(
|
||||
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<ID3D12Resource>(
|
||||
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<ID3D12Resource>(
|
||||
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<ID3D12Resource>(
|
||||
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<FloatVector> 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<FloatVector> 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<FloatVector> 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<FloatVector> 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
|
||||
}
|
||||
@@ -112,6 +112,7 @@
|
||||
<ClCompile Include="d3d12_outputwindow.cpp" />
|
||||
<ClCompile Include="d3d12_overlay.cpp" />
|
||||
<ClCompile Include="d3d12_postvs.cpp" />
|
||||
<ClCompile Include="d3d12_rendermesh.cpp" />
|
||||
<ClCompile Include="d3d12_replay.cpp" />
|
||||
<ClCompile Include="d3d12_resources.cpp" />
|
||||
<ClCompile Include="d3d12_serialise.cpp" />
|
||||
|
||||
@@ -125,5 +125,8 @@
|
||||
<ClCompile Include="d3d12_outputwindow.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="d3d12_rendermesh.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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
|
||||
|
||||
@@ -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<MeshFormat> &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<FloatVector> 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<FloatVector> 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<FloatVector> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <float.h>
|
||||
#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<MeshFormat> &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<FloatVector> 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<FloatVector> 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<FloatVector> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,6 +154,7 @@
|
||||
<ClCompile Include="gl_overlay.cpp" />
|
||||
<ClCompile Include="gl_postvs.cpp" />
|
||||
<ClCompile Include="gl_program_iterate.cpp" />
|
||||
<ClCompile Include="gl_rendermesh.cpp" />
|
||||
<ClCompile Include="gl_renderstate.cpp" />
|
||||
<ClCompile Include="gl_replay.cpp" />
|
||||
<ClCompile Include="gl_replay_egl.cpp">
|
||||
|
||||
@@ -236,5 +236,8 @@
|
||||
<ClCompile Include="gl_outputwindow.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gl_rendermesh.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
<ClCompile Include="vk_outputwindow.cpp" />
|
||||
<ClCompile Include="vk_overlay.cpp" />
|
||||
<ClCompile Include="vk_postvs.cpp" />
|
||||
<ClCompile Include="vk_rendermesh.cpp" />
|
||||
<ClCompile Include="vk_serialise.cpp" />
|
||||
<ClCompile Include="vk_sparse_initstate.cpp" />
|
||||
<ClCompile Include="vk_stringise.cpp" />
|
||||
|
||||
@@ -115,6 +115,9 @@
|
||||
<ClCompile Include="vk_outputwindow.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vk_rendermesh.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="vk_replay.h">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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<MeshFormat> &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<VkBuffer>(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<VkBuffer>(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<VkBuffer>(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<VkBuffer>(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<VkBuffer>(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<VkBuffer>(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<FloatVector> 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<FloatVector> 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<FloatVector> 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);
|
||||
|
||||
Reference in New Issue
Block a user