Split out mesh rendering to separate files

This commit is contained in:
baldurk
2018-01-02 18:52:59 +00:00
parent 635a58280e
commit 013457ab5f
19 changed files with 3041 additions and 2889 deletions
-569
View File
@@ -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)
+601
View File
@@ -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">
-739
View File
@@ -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)
{
+774
View File
@@ -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>
+1
View File
@@ -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
-559
View File
@@ -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);
}
}
}
}
+593
View File
@@ -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);
}
}
}
}
+1
View File
@@ -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>
+1
View File
@@ -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">
-305
View File
@@ -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
-717
View File
@@ -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);