in renderdoc/driver/vulkan/vk_rendermesh.cpp [456:1276]
void VulkanReplay::RenderMesh(uint32_t eventId, const rdcarray<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.m_WindowSystem != WindowingSystem::Headless && outw.swap == VK_NULL_HANDLE)
return;
VkDevice dev = m_pDriver->GetDev();
VkCommandBuffer cmd = m_pDriver->GetNextCmd();
const VkDevDispatchTable *vt = ObjDisp(dev);
if(cmd == VK_NULL_HANDLE)
return;
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);
CheckVkResult(vkr);
VkMarkerRegion::Begin(
StringFormat::Fmt("RenderMesh with %zu secondary draws", secondaryDraws.size()), cmd);
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 axisMapMat = Matrix4f(cfg.axisMapping);
Matrix4f ModelViewProj = projMat.Mul(camMat.Mul(axisMapMat));
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);
}
if(cfg.position.flipY)
{
guessProj[5] *= -1.0f;
}
guessProjInv = guessProj.Inverse();
ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
}
// can't support secondary shading without a buffer - no pipeline will have been created
const Visualisation finalVisualisation = (cfg.visualisationMode == Visualisation::Secondary &&
cfg.second.vertexResourceId == ResourceId())
? Visualisation::NoSolid
: cfg.visualisationMode;
MeshUBOData meshUniforms = {};
meshUniforms.mvp = ModelViewProj;
meshUniforms.displayFormat = MESHDISPLAY_SOLID;
meshUniforms.homogenousInput = cfg.position.unproject;
meshUniforms.pointSpriteSize = Vec2f(0.0f, 0.0f);
meshUniforms.rawoutput = 0;
meshUniforms.vtxExploderSNorm = cfg.vtxExploderSliderSNorm;
meshUniforms.exploderScale =
(finalVisualisation == Visualisation::Explode) ? cfg.exploderScale : 0.0f;
meshUniforms.exploderCentre =
Vec3f((cfg.minBounds.x + cfg.maxBounds.x) * 0.5f, (cfg.minBounds.y + cfg.maxBounds.y) * 0.5f,
(cfg.minBounds.z + cfg.maxBounds.z) * 0.5f);
uint32_t dynOffs[2] = {};
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
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
meshUniforms.color =
Vec4f(fmt.meshColor.x, fmt.meshColor.y, fmt.meshColor.z, fmt.meshColor.w);
meshUniforms.flipY = (cfg.position.flipY == fmt.flipY) ? 0 : 1;
*data = meshUniforms;
m_MeshRender.UBO.Unmap();
mapsUsed++;
if(mapsUsed + 1 >= m_MeshRender.UBO.GetRingCount())
{
// flush and sync so we can use more maps
vt->CmdEndRenderPass(Unwrap(cmd));
vkr = vt->EndCommandBuffer(Unwrap(cmd));
CheckVkResult(vkr);
m_pDriver->SubmitCmds();
m_pDriver->FlushQ();
mapsUsed = 0;
cmd = m_pDriver->GetNextCmd();
if(cmd == VK_NULL_HANDLE)
return;
vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo);
CheckVkResult(vkr);
vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE);
vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport);
}
VKMeshDisplayPipelines secondaryCache = GetDebugManager()->CacheMeshDisplayPipelines(
m_MeshRender.PipeLayout, secondaryDraws[i], secondaryDraws[i]);
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(secondaryCache.pipes[VKMeshDisplayPipelines::ePipe_WireDepth]));
VkBuffer vb =
m_pDriver->GetResourceManager()->GetCurrentHandle<VkBuffer>(fmt.vertexResourceId);
VkDeviceSize offs = fmt.vertexByteOffset - secondaryCache.primaryStridePadding;
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;
else if(fmt.indexByteStride == 1)
idxtype = VK_INDEX_TYPE_UINT8_KHR;
if(fmt.indexResourceId != ResourceId())
{
VkBuffer ib =
m_pDriver->GetResourceManager()->GetLiveHandle<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));
CheckVkResult(vkr);
m_pDriver->SubmitCmds();
m_pDriver->FlushQ();
cmd = m_pDriver->GetNextCmd();
if(cmd == VK_NULL_HANDLE)
return;
vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo);
CheckVkResult(vkr);
vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE);
vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport);
}
}
VKMeshDisplayPipelines cache = GetDebugManager()->CacheMeshDisplayPipelines(
m_MeshRender.PipeLayout, cfg.position, cfg.second);
if(cfg.position.vertexResourceId != ResourceId())
{
VkBuffer vb =
m_pDriver->GetResourceManager()->GetCurrentHandle<VkBuffer>(cfg.position.vertexResourceId);
VkDeviceSize 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);
offs -= cache.primaryStridePadding;
vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(vb), &offs);
}
if(finalVisualisation == Visualisation::Secondary)
{
VkBuffer vb =
m_pDriver->GetResourceManager()->GetCurrentHandle<VkBuffer>(cfg.second.vertexResourceId);
VkDeviceSize 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);
offs -= cache.secondaryStridePadding;
vt->CmdBindVertexBuffers(Unwrap(cmd), 1, 1, UnwrapPtr(vb), &offs);
}
// solid render
if(finalVisualisation != Visualisation::NoSolid && cfg.position.topology < Topology::PatchList)
{
VkPipeline pipe = VK_NULL_HANDLE;
switch(finalVisualisation)
{
default:
case Visualisation::Solid:
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_SolidDepth];
break;
case Visualisation::Lit:
case Visualisation::Explode:
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_Lit];
// point list topologies don't have lighting obvious, just render them as solid
// Also, can't support lit rendering without the pipeline - maybe geometry shader wasn't supported.
if(pipe == VK_NULL_HANDLE)
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_SolidDepth];
break;
case Visualisation::Secondary:
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_Secondary];
break;
case Visualisation::Meshlet:
pipe = cache.pipes[VKMeshDisplayPipelines::ePipe_SolidDepth];
break;
}
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
if(finalVisualisation == Visualisation::Lit || finalVisualisation == Visualisation::Explode)
meshUniforms.invProj = projMat.Inverse();
meshUniforms.color = Vec4f(0.8f, 0.8f, 0.0f, 1.0f);
meshUniforms.displayFormat = VisModeToMeshDisplayFormat(finalVisualisation, cfg.second.showAlpha);
meshUniforms.flipY = 0;
if(finalVisualisation == Visualisation::Meshlet)
{
size_t numMeshlets = RDCMIN(cfg.position.meshletSizes.size(), (size_t)MAX_NUM_MESHLETS);
uint32_t *meshletCounts = (uint32_t *)m_MeshRender.MeshletSSBO.Map(
&dynOffs[1], AlignUp4(numMeshlets + 4) * sizeof(uint32_t));
if(!meshletCounts)
return;
if(cfg.position.meshletSizes.size() > MAX_NUM_MESHLETS)
RDCWARN("Too many meshlets: %zu, only colouring first %zu of them",
cfg.position.meshletSizes.size(), (size_t)MAX_NUM_MESHLETS);
meshletCounts[0] = (uint32_t)numMeshlets;
meshletCounts[1] = (uint32_t)cfg.position.meshletOffset;
meshletCounts += 4;
uint32_t prefixCount = cfg.position.meshletIndexOffset;
for(size_t i = 0; i < numMeshlets; i++)
{
prefixCount += cfg.position.meshletSizes[i].numVertices;
meshletCounts[i] = prefixCount;
}
memcpy(&meshUniforms.meshletColours[0].x, uniqueColors, sizeof(uniqueColors));
RDCCOMPILE_ASSERT(sizeof(meshUniforms.meshletColours) == sizeof(uniqueColors),
"Unique colors array is wrongly sized");
m_MeshRender.MeshletSSBO.Unmap();
}
*data = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
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;
else if(cfg.position.indexByteStride == 1)
idxtype = VK_INDEX_TYPE_UINT8_KHR;
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);
}
}
meshUniforms.displayFormat = MESHDISPLAY_SOLID;
// wireframe render
if(finalVisualisation == Visualisation::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);
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
meshUniforms.color = wireCol;
*data = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::ePipe_WireDepth]));
if(cfg.position.indexByteStride)
{
VkIndexType idxtype = VK_INDEX_TYPE_UINT16;
if(cfg.position.indexByteStride == 4)
idxtype = VK_INDEX_TYPE_UINT32;
else if(cfg.position.indexByteStride == 1)
idxtype = VK_INDEX_TYPE_UINT8_KHR;
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.allowRestart = false;
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);
meshUniforms.homogenousInput = 0;
meshUniforms.vtxExploderSNorm = 0.0f;
meshUniforms.exploderScale = 0.0f;
meshUniforms.exploderCentre = Vec3f();
// cache pipelines for use in drawing wireframe helpers
cache = GetDebugManager()->CacheMeshDisplayPipelines(m_MeshRender.PipeLayout, 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 *)m_MeshRender.BBoxVB.Map(vboffs);
if(!ptr)
return;
memcpy(ptr, bbox, sizeof(bbox));
m_MeshRender.BBoxVB.Unmap();
vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(m_MeshRender.BBoxVB.buf), &vboffs);
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
meshUniforms.color = Vec4f(0.2f, 0.2f, 1.0f, 1.0f);
*data = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::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(m_MeshRender.AxisFrustumVB.buf), &vboffs);
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
meshUniforms.color = Vec4f(1.0f, 0.0f, 0.0f, 1.0f);
*data = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::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 *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
meshUniforms.color = Vec4f(0.0f, 1.0f, 0.0f, 1.0f);
*data = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdDraw(Unwrap(cmd), 2, 1, 2, 0);
data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
meshUniforms.color = Vec4f(0.0f, 0.0f, 1.0f, 1.0f);
*data = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
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(m_MeshRender.AxisFrustumVB.buf), &vboffs);
MeshUBOData *data = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!data)
return;
meshUniforms.color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f);
*data = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::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));
CheckVkResult(vkr);
if(Vulkan_Debug_SingleSubmitFlushing())
m_pDriver->SubmitCmds();
}
m_HighlightCache.CacheHighlightingData(eventId, cfg);
{
// get a new cmdbuffer and begin it
cmd = m_pDriver->GetNextCmd();
if(cmd == VK_NULL_HANDLE)
return;
vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo);
CheckVkResult(vkr);
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)
rdcarray<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
rdcarray<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
rdcarray<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(m_MeshRender.PipeLayout, 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.Mul(axisMapMat));
meshUniforms.mvp = ModelViewProj;
meshUniforms.color = Vec4f(1.0f, 1.0f, 1.0f, 1.0f);
meshUniforms.homogenousInput = cfg.position.unproject;
MeshUBOData *ubodata = (MeshUBOData *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::ePipe_Solid]));
////////////////////////////////////////////////////////////////
// render primitives
// Draw active primitive (red)
meshUniforms.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 *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
if(activePrim.size() >= primSize)
{
VkDeviceSize vboffs = 0;
Vec4f *ptr = (Vec4f *)m_MeshRender.BBoxVB.Map(vboffs, sizeof(Vec4f) * primSize);
if(!ptr)
return;
memcpy(ptr, &activePrim[0], sizeof(Vec4f) * primSize);
m_MeshRender.BBoxVB.Unmap();
vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(m_MeshRender.BBoxVB.buf), &vboffs);
vt->CmdDraw(Unwrap(cmd), primSize, 1, 0, 0);
}
// Draw adjacent primitives (green)
meshUniforms.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 *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
if(adjacentPrimVertices.size() >= primSize && (adjacentPrimVertices.size() % primSize) == 0)
{
VkDeviceSize vboffs = 0;
Vec4f *ptr =
(Vec4f *)m_MeshRender.BBoxVB.Map(vboffs, sizeof(Vec4f) * adjacentPrimVertices.size());
if(!ptr)
return;
memcpy(ptr, &adjacentPrimVertices[0], sizeof(Vec4f) * adjacentPrimVertices.size());
m_MeshRender.BBoxVB.Unmap();
vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(m_MeshRender.BBoxVB.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);
meshUniforms.pointSpriteSize = Vec2f(scale / asp, scale);
// Draw active vertex (blue)
meshUniforms.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 *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
// vertices are drawn with tri strips
helper.topology = Topology::TriangleStrip;
cache = GetDebugManager()->CacheMeshDisplayPipelines(m_MeshRender.PipeLayout, helper, helper);
FloatVector vertSprite[4] = {
activeVertex,
activeVertex,
activeVertex,
activeVertex,
};
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(cache.pipes[VKMeshDisplayPipelines::ePipe_Solid]));
{
VkDeviceSize vboffs = 0;
Vec4f *ptr = (Vec4f *)m_MeshRender.BBoxVB.Map(vboffs, sizeof(vertSprite));
if(!ptr)
return;
memcpy(ptr, &vertSprite[0], sizeof(vertSprite));
m_MeshRender.BBoxVB.Unmap();
vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(m_MeshRender.BBoxVB.buf), &vboffs);
vt->CmdDraw(Unwrap(cmd), 4, 1, 0, 0);
}
// Draw inactive vertices (green)
meshUniforms.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 *)m_MeshRender.UBO.Map(&dynOffs[0]);
if(!ubodata)
return;
*ubodata = meshUniforms;
m_MeshRender.UBO.Unmap();
vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS,
Unwrap(m_MeshRender.PipeLayout), 0, 1,
UnwrapPtr(m_MeshRender.DescSet), 2, dynOffs);
if(!inactiveVertices.empty())
{
VkDeviceSize vboffs = 0;
FloatVector *ptr = (FloatVector *)m_MeshRender.BBoxVB.Map(vboffs, sizeof(vertSprite));
if(!ptr)
return;
for(size_t i = 0; i < inactiveVertices.size(); i++)
{
*ptr++ = inactiveVertices[i];
*ptr++ = inactiveVertices[i];
*ptr++ = inactiveVertices[i];
*ptr++ = inactiveVertices[i];
}
m_MeshRender.BBoxVB.Unmap();
for(size_t i = 0; i < inactiveVertices.size(); i++)
{
vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(m_MeshRender.BBoxVB.buf), &vboffs);
vt->CmdDraw(Unwrap(cmd), 4, 1, 0, 0);
vboffs += sizeof(FloatVector) * 4;
}
}
}
}
vt->CmdEndRenderPass(Unwrap(cmd));
VkMarkerRegion::End(cmd);
vkr = vt->EndCommandBuffer(Unwrap(cmd));
CheckVkResult(vkr);
if(Vulkan_Debug_SingleSubmitFlushing())
m_pDriver->SubmitCmds();
}