From 879df2585024979e7e2d9a0c859eec09f3b87341 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 13 Nov 2015 19:56:02 +0100 Subject: [PATCH] Implement mesh rendering (wireframe and solid) --- renderdoc/driver/vulkan/vk_debug.cpp | 355 +++++++++++++++++++++++++- renderdoc/driver/vulkan/vk_debug.h | 16 +- renderdoc/driver/vulkan/vk_replay.cpp | 199 ++++++++++++++- renderdocui/Windows/BufferViewer.cs | 2 +- 4 files changed, 565 insertions(+), 7 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 85de1ca87..f44ad1ce2 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -24,6 +24,7 @@ #include "vk_debug.h" #include "vk_core.h" +#include "maths/matrix.h" #include "stb/stb_truetype.h" @@ -88,6 +89,16 @@ struct stringdata uint32_t str[256][4]; }; +struct meshuniforms +{ + Matrix4f mvp; + Matrix4f invProj; + Vec4f color; + uint32_t displayFormat; + uint32_t homogenousInput; + Vec2f pointSpriteSize; +}; + void VulkanDebugManager::GPUBuffer::Create(WrappedVulkan *driver, VkDevice dev, VkDeviceSize size, uint32_t ringSize, uint32_t flags) { const VkLayerDispatchTable *vt = ObjDisp(dev); @@ -296,6 +307,12 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) RDCASSERT(vkr == VK_SUCCESS); GetResourceManager()->WrapResource(Unwrap(dev), m_GenericDescSetLayout); + + // identical layout + vkr = vt->CreateDescriptorSetLayout(Unwrap(dev), &descsetLayoutInfo, &m_MeshDescSetLayout); + RDCASSERT(vkr == VK_SUCCESS); + + GetResourceManager()->WrapResource(Unwrap(dev), m_MeshDescSetLayout); } { @@ -366,6 +383,13 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) GetResourceManager()->WrapResource(Unwrap(dev), m_GenericPipeLayout); + pipeLayoutInfo.pSetLayouts = UnwrapPtr(m_MeshDescSetLayout); + + vkr = vt->CreatePipelineLayout(Unwrap(dev), &pipeLayoutInfo, &m_MeshPipeLayout); + RDCASSERT(vkr == VK_SUCCESS); + + GetResourceManager()->WrapResource(Unwrap(dev), m_MeshPipeLayout); + VkDescriptorTypeCount descPoolTypes[] = { { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1024, }, { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1024, }, @@ -374,7 +398,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) VkDescriptorPoolCreateInfo descpoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, NULL, - VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 3+ARRAY_COUNT(m_TexDisplayDescSet), + VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 4+ARRAY_COUNT(m_TexDisplayDescSet), ARRAY_COUNT(descPoolTypes), &descPoolTypes[0], }; @@ -409,6 +433,12 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) RDCASSERT(vkr == VK_SUCCESS); GetResourceManager()->WrapResource(Unwrap(dev), m_GenericDescSet); + + vkr = vt->AllocDescriptorSets(Unwrap(dev), Unwrap(m_DescriptorPool), VK_DESCRIPTOR_SET_USAGE_STATIC, 1, + UnwrapPtr(m_MeshDescSetLayout), &m_MeshDescSet); + RDCASSERT(vkr == VK_SUCCESS); + + GetResourceManager()->WrapResource(Unwrap(dev), m_MeshDescSet); m_GenericUBO.Create(driver, dev, 128, 10, 0); RDCCOMPILE_ASSERT(sizeof(genericuniforms) <= 128, "outline strip VBO size"); @@ -1008,7 +1038,9 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) m_PickPixelReadbackBuffer.Create(driver, dev, sizeof(float)*4, 1, GPUBuffer::eGPUBufferReadback); } - VkDescriptorInfo desc[6]; + m_MeshUBO.Create(driver, dev, sizeof(meshuniforms), 16, 0); + + VkDescriptorInfo desc[7]; RDCEraseEl(desc); // checkerboard @@ -1027,6 +1059,9 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) // generic m_GenericUBO.FillDescriptor(desc[5]); + // mesh + m_MeshUBO.FillDescriptor(desc[6]); + VkWriteDescriptorSet writeSet[] = { { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, @@ -1052,6 +1087,10 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev) VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_GenericDescSet), 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &desc[5] }, + { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, + Unwrap(m_MeshDescSet), 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &desc[6] + }, }; vt->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(writeSet), writeSet, 0, NULL); @@ -1070,6 +1109,17 @@ VulkanDebugManager::~VulkanDebugManager() // pool here won't remove the descriptor sets, so we need to free our own // tracking data (not the API objects) for descriptor sets. + for(auto it=m_CachedMeshPipelines.begin(); it != m_CachedMeshPipelines.end(); ++it) + { + for(uint32_t i=0; i < eShade_Count; i++) + { + if(it->second.pipes[i] == VK_NULL_HANDLE) continue; + + vt->DestroyPipeline(Unwrap(dev), Unwrap(it->second.pipes[i])); + GetResourceManager()->ReleaseWrappedResource(it->second.pipes[i]); + } + } + for(size_t i=0; i < ARRAY_COUNT(m_MeshModules); i++) { vt->DestroyShader(Unwrap(dev), Unwrap(m_MeshShaders[i])); @@ -1082,6 +1132,7 @@ VulkanDebugManager::~VulkanDebugManager() GetResourceManager()->ReleaseWrappedResource(m_CheckerboardDescSet); GetResourceManager()->ReleaseWrappedResource(m_GenericDescSet); GetResourceManager()->ReleaseWrappedResource(m_TextDescSet); + GetResourceManager()->ReleaseWrappedResource(m_MeshDescSet); for(size_t i=0; i < ARRAY_COUNT(m_TexDisplayDescSet); i++) GetResourceManager()->ReleaseWrappedResource(m_TexDisplayDescSet[i]); @@ -1226,7 +1277,21 @@ VulkanDebugManager::~VulkanDebugManager() vt->FreeMemory(Unwrap(dev), Unwrap(m_TextAtlasMem)); GetResourceManager()->ReleaseWrappedResource(m_TextAtlasMem); } - + + if(m_MeshDescSetLayout != VK_NULL_HANDLE) + { + vt->DestroyDescriptorSetLayout(Unwrap(dev), Unwrap(m_MeshDescSetLayout)); + GetResourceManager()->ReleaseWrappedResource(m_MeshDescSetLayout); + } + + if(m_MeshPipeLayout != VK_NULL_HANDLE) + { + vt->DestroyPipelineLayout(Unwrap(dev), Unwrap(m_MeshPipeLayout)); + GetResourceManager()->ReleaseWrappedResource(m_MeshPipeLayout); + } + + m_MeshUBO.Destroy(vt, dev); + if(m_GenericDescSetLayout != VK_NULL_HANDLE) { vt->DestroyDescriptorSetLayout(Unwrap(dev), Unwrap(m_GenericDescSetLayout)); @@ -1881,3 +1946,287 @@ ResourceId VulkanDebugManager::RenderOverlay(ResourceId texid, TextureDisplayOve return GetResID(m_OverlayImage); } + +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.idxByteWidth == 4) key |= 1ULL << bit; + bit++; + + RDCASSERT((uint32_t)primary.topo < 64); + key |= ((uint32_t)primary.topo & 0x3f) << bit; + bit += 6; + + ResourceFormat fmt; + fmt.special = primary.specialFormat != eSpecial_Unknown; + fmt.specialFormat = primary.specialFormat; + fmt.compByteWidth = primary.compByteWidth; + fmt.compCount = primary.compCount; + fmt.compType = primary.compType; + + VkFormat primaryFmt = MakeVkFormat(fmt); + + fmt.special = secondary.specialFormat != eSpecial_Unknown; + fmt.specialFormat = secondary.specialFormat; + fmt.compByteWidth = secondary.compByteWidth; + fmt.compCount = secondary.compCount; + fmt.compType = secondary.compType; + + VkFormat secondaryFmt = secondary.buf == ResourceId() ? VK_FORMAT_UNDEFINED : MakeVkFormat(fmt); + + RDCCOMPILE_ASSERT(VK_FORMAT_NUM <= 255, "Mesh pipeline cache key needs an extra bit for format"); + + key |= ((uint32_t)primaryFmt & 0xff) << bit; + bit += 8; + + key |= ((uint32_t)secondaryFmt & 0xff) << bit; + bit += 8; + + RDCASSERT(primary.stride <= 0xffff); + key |= ((uint32_t)primary.stride & 0xffff) << bit; + bit += 16; + + if(secondary.buf != ResourceId()) + { + RDCASSERT(secondary.stride <= 0xffff); + key |= ((uint32_t)secondary.stride & 0xffff) << bit; + } + bit += 16; + + MeshDisplayPipelines &cache = m_CachedMeshPipelines[key]; + + if(cache.pipes[eShade_None] != 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.stride, + VK_VERTEX_INPUT_STEP_RATE_VERTEX + }, + // secondary + { + 1, + secondary.stride, + VK_VERTEX_INPUT_STEP_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, + 1, binds, + 2, vertAttrs, + }; + + VkPipelineShaderStageCreateInfo stages[3] = { + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, VK_SHADER_STAGE_MAX_ENUM, VK_NULL_HANDLE, NULL }, + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, VK_SHADER_STAGE_MAX_ENUM, VK_NULL_HANDLE, NULL }, + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, VK_SHADER_STAGE_MAX_ENUM, VK_NULL_HANDLE, NULL }, + }; + + VkPipelineInputAssemblyStateCreateInfo ia = { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, NULL, + primary.topo >= eTopology_PatchList ? VK_PRIMITIVE_TOPOLOGY_POINT_LIST : MakeVkPrimitiveTopology(primary.topo), false, + }; + + VkRect2D scissor = { { 0, 0 }, { 4096, 4096 } }; + + VkPipelineViewportStateCreateInfo vp = { + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, NULL, + 1, NULL, + 1, &scissor + }; + + VkPipelineRasterStateCreateInfo rs = { + VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO, NULL, + true, false, VK_FILL_MODE_SOLID, VK_CULL_MODE_NONE, VK_FRONT_FACE_CW, + false, 0.0f, 0.0f, 0.0f, 1.0f, + }; + + VkPipelineMultisampleStateCreateInfo msaa = { + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, NULL, + 1, false, 0.0f, NULL, + }; + + VkPipelineDepthStencilStateCreateInfo ds = { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, NULL, + true, true, VK_COMPARE_OP_LESS, 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_ONE, VK_BLEND_ZERO, VK_BLEND_OP_ADD, + VK_BLEND_ONE, VK_BLEND_ZERO, VK_BLEND_OP_ADD, + 0xf, + }; + + VkPipelineColorBlendStateCreateInfo cb = { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, NULL, + false, false, false, VK_LOGIC_OP_NOOP, + 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, + ARRAY_COUNT(dynstates), dynstates, + }; + + VkRenderPass rp; // compatible render pass + + { + VkAttachmentDescription attDesc[] = { + { + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, NULL, + VK_FORMAT_R8G8B8A8_UNORM, 1, + 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 + }, + { + VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, NULL, + VK_FORMAT_D32_SFLOAT, 1, + 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 }; + + VkSubpassDescription sub = { + VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION, NULL, + VK_PIPELINE_BIND_POINT_GRAPHICS, 0, + 0, NULL, // inputs + 1, &attRef, // color + NULL, // resolve + { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }, // depth-stencil + 0, NULL, // preserve + }; + + VkRenderPassCreateInfo rpinfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, NULL, + 2, attDesc, + 1, &sub, + 0, NULL, // dependencies + }; + + vt->CreateRenderPass(Unwrap(m_Device), &rpinfo, &rp); + } + + VkGraphicsPipelineCreateInfo pipeInfo = { + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, NULL, + 2, stages, + &vi, + &ia, + NULL, // tess + &vp, + &rs, + &msaa, + &ds, + &cb, + &dyn, + 0, // flags + Unwrap(m_MeshPipeLayout), + rp, + 0, // sub pass + VK_NULL_HANDLE, // base pipeline handle + 0, // base pipeline index + }; + + // wireframe pipeline + stages[0].shader = Unwrap(m_MeshShaders[0]); + stages[0].stage = VK_SHADER_STAGE_VERTEX; + stages[1].shader = Unwrap(m_MeshShaders[2]); + stages[1].stage = VK_SHADER_STAGE_FRAGMENT; + + rs.fillMode = VK_FILL_MODE_WIREFRAME; + rs.lineWidth = 1.0f; + ds.depthTestEnable = false; + + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, &cache.pipes[eShade_None]); + RDCASSERT(vkr == VK_SUCCESS); + + // solid shading pipeline + rs.fillMode = VK_FILL_MODE_SOLID; + ds.depthTestEnable = true; + + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, &cache.pipes[eShade_Solid]); + RDCASSERT(vkr == VK_SUCCESS); + + if(secondary.buf != ResourceId()) + { + // pull secondary information from second vertex buffer + vertAttrs[1].binding = 1; + vertAttrs[1].format = secondaryFmt; + RDCASSERT(secondaryFmt != VK_FORMAT_UNDEFINED); + + vi.bindingCount = 2; + + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, &cache.pipes[eShade_Secondary]); + RDCASSERT(vkr == VK_SUCCESS); + } + + // seems to not be working at the moment, just make a solid-shaded pipeline + vertAttrs[1].binding = 0; + vi.bindingCount = 1; + +#if 1 + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, &cache.pipes[eShade_Lit]); + RDCASSERT(vkr == VK_SUCCESS); +#else + // flat lit pipeline, needs geometry shader to calculate face normals + stages[0].shader = Unwrap(m_MeshShaders[0]); + stages[0].stage = VK_SHADER_STAGE_VERTEX; + stages[1].shader = Unwrap(m_MeshShaders[1]); + stages[1].stage = VK_SHADER_STAGE_GEOMETRY; + stages[2].shader = Unwrap(m_MeshShaders[2]); + stages[2].stage = VK_SHADER_STAGE_FRAGMENT; + + vkr = vt->CreateGraphicsPipelines(Unwrap(m_Device), VK_NULL_HANDLE, 1, &pipeInfo, &cache.pipes[eShade_Lit]); + RDCASSERT(vkr == VK_SUCCESS); +#endif + + for(uint32_t i=0; i < eShade_Count; i++) + if(cache.pipes[i] != VK_NULL_HANDLE) + GetResourceManager()->WrapResource(Unwrap(m_Device), cache.pipes[i]); + + vt->DestroyRenderPass(Unwrap(m_Device), rp); + + return cache; +} diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index 3d5a99008..efd2480da 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -38,6 +38,11 @@ struct TextPrintState int32_t w, h; }; +struct MeshDisplayPipelines +{ + VkPipeline pipes[eShade_Count]; +}; + class VulkanResourceManager; class VulkanDebugManager @@ -137,9 +142,16 @@ class VulkanDebugManager VkRenderPass m_OverlayNoDepthRP; VkExtent2D m_OverlayDim; VkDeviceSize m_OverlayMemSize; + + VkDescriptorSetLayout m_MeshDescSetLayout; + VkPipelineLayout m_MeshPipeLayout; + VkDescriptorSet m_MeshDescSet; + GPUBuffer m_MeshUBO; VkShader m_MeshShaders[3]; VkShaderModule m_MeshModules[3]; + MeshDisplayPipelines CacheMeshDisplayPipelines(const MeshFormat &primary, const MeshFormat &secondary); + private: void InitDebugData(); void ShutdownDebugData(); @@ -149,12 +161,14 @@ class VulkanDebugManager void PatchFixedColShader(VkShaderModule &mod, VkShader &shad, float col[4]); void RenderTextInternal(const TextPrintState &textstate, float x, float y, const char *text); - void MakeGraphicsPipelineInfo( VkGraphicsPipelineCreateInfo &pipeCreateInfo, ResourceId pipeline ); + void MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &pipeCreateInfo, ResourceId pipeline); static const int FONT_TEX_WIDTH = 256; static const int FONT_TEX_HEIGHT = 128; float m_FontCharAspect; float m_FontCharSize; + + map m_CachedMeshPipelines; WrappedVulkan *m_pDriver; VulkanResourceManager *m_ResourceManager; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 6a255a930..e2ef78266 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -26,6 +26,9 @@ #include "vk_core.h" #include "vk_debug.h" #include "vk_resources.h" +#include "maths/matrix.h" +#include "maths/camera.h" +#include "maths/formatpacking.h" #include "serialise/string_utils.h" @@ -62,6 +65,21 @@ struct genericuniforms Vec4f Color; }; +struct meshuniforms +{ + Matrix4f mvp; + Matrix4f invProj; + Vec4f color; + uint32_t displayFormat; + uint32_t homogenousInput; + Vec2f pointSpriteSize; +}; + +#define MESHDISPLAY_SOLID 0x1 +#define MESHDISPLAY_FACELIT 0x2 +#define MESHDISPLAY_SECONDARY 0x3 +#define MESHDISPLAY_SECONDARY_ALPHA 0x4 + VulkanReplay::OutputWindow::OutputWindow() : wnd(NULL_WND_HANDLE), width(0), height(0), dsimg(VK_NULL_HANDLE), dsmem(VK_NULL_HANDLE) { @@ -1217,10 +1235,187 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay o { return GetDebugManager()->RenderOverlay(texid, overlay, frameID, eventID, passEvents); } - + void VulkanReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector &secondaryDraws, MeshDisplay cfg) { - VULKANNOTIMP("RenderMesh"); + if(cfg.position.buf == ResourceId()) + return; + + auto it = m_OutputWindows.find(m_ActiveWinID); + if(m_ActiveWinID == 0 || it == m_OutputWindows.end()) + return; + + OutputWindow &outw = it->second; + + VkDevice dev = m_pDriver->GetDev(); + VkCmdBuffer cmd = m_pDriver->GetNextCmd(); + const VkLayerDispatchTable *vt = ObjDisp(dev); + + VkResult vkr = VK_SUCCESS; + + VkCmdBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, NULL, VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT }; + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERT(vkr == VK_SUCCESS); + + VkClearValue clearval = {0}; + VkRenderPassBeginInfo rpbegin = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, NULL, + Unwrap(outw.rpdepth), Unwrap(outw.fbdepth), + { { 0, 0, }, { m_DebugWidth, m_DebugHeight } }, + 1, &clearval, + }; + vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_RENDER_PASS_CONTENTS_INLINE); + + VkViewport viewport = { 0.0f, 0.0f, (float)m_DebugWidth, (float)m_DebugHeight, 0.0f, 1.0f }; + vt->CmdSetViewport(Unwrap(cmd), 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 ? 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 = Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect); + + if(cfg.ortho) + { + guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); + } + + guessProjInv = guessProj.Inverse(); + + ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv)); + } + + RDCASSERT(secondaryDraws.empty()); + + MeshDisplayPipelines cache = GetDebugManager()->CacheMeshDisplayPipelines(cfg.position, cfg.second); + + if(cfg.position.buf != ResourceId()) + { + VkBuffer vb = m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.position.buf); + + VkDeviceSize offs = cfg.position.offset; + vt->CmdBindVertexBuffers(Unwrap(cmd), 0, 1, UnwrapPtr(vb), &offs); + } + + if(cfg.second.buf != ResourceId()) + { + VkBuffer vb = m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.second.buf); + + VkDeviceSize offs = cfg.second.offset; + vt->CmdBindVertexBuffers(Unwrap(cmd), 1, 1, UnwrapPtr(vb), &offs); + } + + // can't support secondary shading without a buffer - no pipeline will have been created + if(cfg.solidShadeMode == eShade_Secondary && cfg.second.buf == ResourceId()) + cfg.solidShadeMode = eShade_None; + + // solid render + if(cfg.solidShadeMode != eShade_None && cfg.position.topo < eTopology_PatchList) + { + VkPipeline pipe = cache.pipes[cfg.solidShadeMode]; + + uint32_t uboOffs = 0; + meshuniforms *data = (meshuniforms *)GetDebugManager()->m_MeshUBO.Map(vt, dev, &uboOffs); + + if(cfg.solidShadeMode == eShade_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)cfg.solidShadeMode; + + if(cfg.solidShadeMode == eShade_Secondary && cfg.second.showAlpha) + data->displayFormat = MESHDISPLAY_SECONDARY_ALPHA; + + GetDebugManager()->m_MeshUBO.Unmap(vt, dev); + + 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.idxByteWidth) + { + VkIndexType idxtype = VK_INDEX_TYPE_UINT16; + if(cfg.position.idxByteWidth == 4) + idxtype = VK_INDEX_TYPE_UINT32; + + if(cfg.position.idxbuf != ResourceId()) + { + VkBuffer ib = m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.position.idxbuf); + + vt->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(ib), cfg.position.idxoffs, idxtype); + } + vt->CmdDrawIndexed(Unwrap(cmd), cfg.position.numVerts, 1, 0, 0, 0); + } + else + { + vt->CmdDraw(Unwrap(cmd), cfg.position.numVerts, 1, 0, 0); + } + } + + // wireframe render + if(cfg.solidShadeMode == eShade_None || cfg.wireframeDraw || cfg.position.topo >= eTopology_PatchList) + { + Vec4f wireCol = Vec4f(0.0f, 0.0f, 0.0f, 1.0f); + if(!secondaryDraws.empty()) + { + wireCol.x = cfg.currentMeshColour.x; + wireCol.y = cfg.currentMeshColour.y; + wireCol.z = cfg.currentMeshColour.z; + } + + uint32_t uboOffs = 0; + meshuniforms *data = (meshuniforms *)GetDebugManager()->m_MeshUBO.Map(vt, dev, &uboOffs); + + data->mvp = ModelViewProj; + data->color = wireCol; + data->displayFormat = (uint32_t)eShade_Solid; + data->homogenousInput = cfg.position.unproject; + data->pointSpriteSize = Vec2f(0.0f, 0.0f); + + GetDebugManager()->m_MeshUBO.Unmap(vt, dev); + + 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[eShade_None])); + + if(cfg.position.idxByteWidth) + { + VkIndexType idxtype = VK_INDEX_TYPE_UINT16; + if(cfg.position.idxByteWidth == 4) + idxtype = VK_INDEX_TYPE_UINT32; + + if(cfg.position.idxbuf != ResourceId()) + { + VkBuffer ib = m_pDriver->GetResourceManager()->GetCurrentHandle(cfg.position.idxbuf); + + vt->CmdBindIndexBuffer(Unwrap(cmd), Unwrap(ib), cfg.position.idxoffs, idxtype); + } + vt->CmdDrawIndexed(Unwrap(cmd), cfg.position.numVerts, 1, 0, 0, 0); + } + else + { + vt->CmdDraw(Unwrap(cmd), cfg.position.numVerts, 1, 0, 0); + } + } + + vt->CmdEndRenderPass(Unwrap(cmd)); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + RDCASSERT(vkr == VK_SUCCESS); } bool VulkanReplay::CheckResizeOutputWindow(uint64_t id) diff --git a/renderdocui/Windows/BufferViewer.cs b/renderdocui/Windows/BufferViewer.cs index caa79142d..e6834e07d 100644 --- a/renderdocui/Windows/BufferViewer.cs +++ b/renderdocui/Windows/BufferViewer.cs @@ -2177,7 +2177,7 @@ namespace renderdocui.Windows private void render_Paint(object sender, PaintEventArgs e) { - if (m_Core.CurVulkanPipelineState != null || m_Output == null || m_Core.Renderer == null) + if (m_Output == null || m_Core.Renderer == null) { e.Graphics.Clear(Color.Black); return;