Files
renderdoc/renderdoc/driver/d3d12/d3d12_rendermesh.cpp
T

832 lines
30 KiB
C++

/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2018-2019 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/hlsl_cbuffers.h"
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;
if(primary.instanced)
key |= 1ULL << bit;
bit++;
if(secondary.instanced)
key |= 1ULL << bit;
bit++;
if(primary.allowRestart)
key |= 1ULL << bit;
bit++;
// only 64 bits, make sure they all fit
RDCASSERT(bit < 64);
MeshDisplayPipelines &cache = m_CachedMeshPipelines[key];
if(cache.pipes[(uint32_t)SolidShade::NoSolid] != NULL)
return cache;
cache.rootsig = m_MeshRootSig;
// 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_MeshRootSig;
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;
if(primary.allowRestart)
{
if(primary.indexByteStride == 2)
pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
else
pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF;
}
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[0].InputSlotClass = primary.instanced ? D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA
: D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
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_pDevice->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_pDevice->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_pDevice->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_pDevice->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 = secondary.instanced ? D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA
: D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
RDCASSERT(secondaryFmt != DXGI_FORMAT_UNKNOWN);
hr = m_pDevice->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_pDevice->CreateGraphicsPipelineState(
&pipeDesc, __uuidof(ID3D12PipelineState),
(void **)&cache.pipes[MeshDisplayPipelines::ePipe_Lit]);
RDCASSERTEQUAL(hr, S_OK);
}
return cache;
}
void D3D12Replay::RenderMesh(uint32_t eventId, const std::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;
D3D12MarkerRegion renderMesh(
m_pDevice->GetQueue(),
StringFormat::Fmt("RenderMesh with %zu secondary draws", secondaryDraws.size()));
OutputWindow &outw = it->second;
ID3D12GraphicsCommandList *list = m_pDevice->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);
MeshVertexCBuffer vertexData;
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();
MeshPixelCBuffer pixelData;
pixelData.MeshColour = Vec3f(0.0f, 0.0f, 0.0f);
pixelData.MeshDisplayFormat = MESHDISPLAY_SOLID;
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 =
GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData));
if(!secondaryDraws.empty())
{
ID3D12RootSignature *rootSig = NULL;
for(size_t i = 0; i < secondaryDraws.size(); i++)
{
const MeshFormat &fmt = secondaryDraws[i];
if(fmt.vertexResourceId != ResourceId())
{
MeshDisplayPipelines secondaryCache =
GetDebugManager()->CacheMeshDisplayPipelines(secondaryDraws[i], secondaryDraws[i]);
if(secondaryCache.rootsig != rootSig)
{
rootSig = secondaryCache.rootsig;
list->SetGraphicsRootSignature(rootSig);
list->SetGraphicsRootConstantBufferView(0, vsCB);
list->SetGraphicsRootConstantBufferView(1, vsCB); // geometry - dummy fill
}
pixelData.MeshColour.x = fmt.meshColor.x;
pixelData.MeshColour.y = fmt.meshColor.y;
pixelData.MeshColour.z = fmt.meshColor.z;
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 0);
list->SetPipelineState(secondaryCache.pipes[MeshDisplayPipelines::ePipe_WireDepth]);
ID3D12Resource *vb =
m_pDevice->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_pDevice->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 = GetDebugManager()->CacheMeshDisplayPipelines(cfg.position, cfg.second);
if(cfg.position.vertexResourceId != ResourceId())
{
ID3D12Resource *vb =
m_pDevice->GetResourceManager()->GetCurrentAs<ID3D12Resource>(cfg.position.vertexResourceId);
UINT64 offs = cfg.position.vertexByteOffset;
// we source all data from the first instanced value in the instanced case, so make sure we
// offset correctly here.
if(cfg.position.instanced && cfg.position.instStepRate)
offs += cfg.position.vertexByteStride * (cfg.curInstance / cfg.position.instStepRate);
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_pDevice->GetResourceManager()->GetCurrentAs<ID3D12Resource>(cfg.position.vertexResourceId);
UINT64 offs = cfg.second.vertexByteOffset;
// we source all data from the first instanced value in the instanced case, so make sure we
// offset correctly here.
if(cfg.second.instanced && cfg.second.instStepRate)
offs += cfg.second.vertexByteStride * (cfg.curInstance / cfg.second.instStepRate);
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];
// point list topologies don't have lighting obvious, just render them as solid
if(!pipe)
pipe = cache.pipes[MeshDisplayPipelines::ePipe_SolidDepth];
break;
case SolidShade::Secondary: pipe = cache.pipes[MeshDisplayPipelines::ePipe_Secondary]; break;
}
pixelData.MeshDisplayFormat = (int)cfg.solidShadeMode;
if(cfg.solidShadeMode == SolidShade::Secondary && cfg.second.showAlpha)
pixelData.MeshDisplayFormat = MESHDISPLAY_SECONDARY_ALPHA;
pixelData.MeshColour = Vec3f(0.8f, 0.8f, 0.0f);
list->SetPipelineState(pipe);
list->SetGraphicsRootSignature(cache.rootsig);
list->SetGraphicsRootConstantBufferView(0, vsCB);
if(solidShadeMode == SolidShade::Lit)
{
MeshGeometryCBuffer geomData;
geomData.InvProj = projMat.Inverse();
list->SetGraphicsRootConstantBufferView(
1, GetDebugManager()->UploadConstants(&geomData, sizeof(geomData)));
}
else
{
list->SetGraphicsRootConstantBufferView(1, vsCB); // dummy fill for geometry
}
Vec4f colour(0.8f, 0.8f, 0.0f, 1.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 0);
if(cfg.position.indexByteStride)
{
if(cfg.position.indexResourceId != ResourceId())
{
ID3D12Resource *ib = m_pDevice->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.MeshDisplayFormat = MESHDISPLAY_SOLID;
list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_WireDepth]);
list->SetGraphicsRootSignature(cache.rootsig);
list->SetGraphicsRootConstantBufferView(0, vsCB);
list->SetGraphicsRootConstantBufferView(1, vsCB);
pixelData.MeshColour.x = cfg.position.meshColor.x;
pixelData.MeshColour.y = cfg.position.meshColor.y;
pixelData.MeshColour.z = cfg.position.meshColor.z;
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 0);
if(cfg.position.indexByteStride && cfg.position.indexResourceId != ResourceId())
{
ID3D12Resource *ib =
m_pDevice->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.MeshDisplayFormat = MESHDISPLAY_SOLID;
// 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,
};
D3D12_VERTEX_BUFFER_VIEW view;
view.BufferLocation = GetDebugManager()->UploadConstants(bbox, sizeof(bbox));
view.SizeInBytes = sizeof(bbox);
view.StrideInBytes = sizeof(Vec4f);
list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST);
list->IASetVertexBuffers(0, 1, &view);
pixelData.MeshColour = Vec3f(0.2f, 0.2f, 1.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 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 = GetDebugManager()->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]);
pixelData.MeshColour = Vec3f(1.0f, 0.0f, 0.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 0);
list->DrawInstanced(2, 1, 0, 0);
pixelData.MeshColour = Vec3f(0.0f, 1.0f, 0.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 0);
list->DrawInstanced(2, 1, 2, 0);
pixelData.MeshColour = Vec3f(0.0f, 0.0f, 1.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 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 = GetDebugManager()->UploadConstants(bbox, sizeof(bbox));
view.SizeInBytes = sizeof(bbox);
view.StrideInBytes = sizeof(Vec4f);
list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST);
list->IASetVertexBuffers(0, 1, &view);
pixelData.MeshColour = Vec3f(1.0f, 1.0f, 1.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 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)
std::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
std::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
std::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)
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, GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData)));
list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Solid]);
////////////////////////////////////////////////////////////////
// render primitives
// Draw active primitive (red)
pixelData.MeshColour = Vec3f(1.0f, 0.0f, 0.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 0);
D3D12_VERTEX_BUFFER_VIEW view = {};
view.StrideInBytes = sizeof(Vec4f);
if(activePrim.size() >= primSize)
{
view.BufferLocation =
GetDebugManager()->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)
pixelData.MeshColour = Vec3f(0.0f, 1.0f, 0.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 0);
if(adjacentPrimVertices.size() >= primSize && (adjacentPrimVertices.size() % primSize) == 0)
{
view.BufferLocation = GetDebugManager()->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, GetDebugManager()->UploadConstants(&vertexData, sizeof(vertexData)));
// Draw active vertex (blue)
pixelData.MeshColour = Vec3f(0.0f, 0.0f, 1.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 0);
// vertices are drawn with tri strips
helper.topology = Topology::TriangleStrip;
cache = GetDebugManager()->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 = GetDebugManager()->UploadConstants(&vertSprite[0], sizeof(vertSprite));
view.SizeInBytes = sizeof(vertSprite);
list->IASetVertexBuffers(0, 1, &view);
list->DrawInstanced(4, 1, 0, 0);
}
// Draw inactive vertices (green)
pixelData.MeshColour = Vec3f(0.0f, 1.0f, 0.0f);
list->SetGraphicsRoot32BitConstants(2, 4, &pixelData, 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 = GetDebugManager()->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_pDevice->ExecuteLists();
m_pDevice->FlushLists();
#endif
}