diff --git a/ReleaseNotes.md b/ReleaseNotes.md index b448ff3a7..4b3f89da1 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -12,27 +12,34 @@ If you have any questions you can contact myself (baldurk@baldurk.org) or LunarG Current Support ======== -* A single VkInstance/VkQueue/VkDevice triple is supported -* Capture and replay of a single frame at a time +* A single VkInstance/VkQueue/VkDevice triple is supported. +* Capture and replay of a single frame at a time. * On replay you can step into each vkQueueSubmit call to see the command buffers submitted, and step into them to browse through the commands. * The pipeline state will be displayed at each command, roughly showing the data contained in each member of the pipeline createinfo struct, as well as dynamic state. * Simple disassembly/reflection of SPIR-V to determine which descriptors to read for read-only resources and uniform buffers. The uniform buffers will be listed separately and the member variables filled out. -* Simple display of most 2D textures in the texture viewer +* Simple display of most 2D textures in the texture viewer. Known Issues ======== +On capture: + * Multiple VkQueues are untested and may likely not work. * Some API functions are not currently hooked and will crash if called by the application to be debugged (see note 1). +* Subpasses aren't supported. +* Push constants aren't supported. +* Memory/image barriers are as yet unverified, potentially could lead to bad capture or replay. +* Sparse resources are not supported. +* Memory maps are not intercepted, so any modifications are saved by reading back from the mapped pointer, even if it is uncached/write combined. +* Image contents are saved out by copying aliasing their backing memory to a buffer, so will not be GPU-portable. +* Captures will not be GPU-portable where memory indices etc change. + +On replay: + * Only 2D non-array non-integer textures can currently be displayed, and only the first mip. * Pixel values aren't fetched. * Auto texture range-fit or histogram display is not implemented. * Debug overlays aren't implemented. -* Subpasses are completely untested. -* Memory/image barriers are as yet unverified, potentially could lead to bad capture or replay. -* Image contents are saved out by copying aliasing their backing memory to a buffer, so will not be GPU-portable. -* Memory maps are not intercepted, so any modifications are saved by reading back from the mapped pointer, even if it is uncached/write combined. -* Sparse resources are not supported. * The display pipeline is not yet gamma correct. * Saving textures is not supported. * Queue-level API events are not properly listed. API calls between draw-type vkCmd... are listed. @@ -57,17 +64,12 @@ Note 1, unsupported entry points: * vkResetFences * vkWaitForFences + * vkCreateEvent * vkDestroyEvent * vkGetEventStatus * vkSetEvent * vkResetEvent -* vkCmdFillBuffer * vkCmdSetEvent * vkCmdResetEvent * vkCmdWaitEvents -* vkCmdWriteTimestamp -* vkCmdCopyQueryPoolResults -* vkCmdPushConstants -* vkCmdNextSubpass -* vkCmdExecuteCommands diff --git a/renderdoc/driver/vulkan/vk_common.cpp b/renderdoc/driver/vulkan/vk_common.cpp index 5d2fcbcab..3eba2762b 100644 --- a/renderdoc/driver/vulkan/vk_common.cpp +++ b/renderdoc/driver/vulkan/vk_common.cpp @@ -967,6 +967,25 @@ string ToStrHelper::Get(const VkQueryControlFlagB return ret; } +template<> +string ToStrHelper::Get(const VkQueryResultFlagBits &el) +{ + string ret; + + if(el == VK_QUERY_RESULT_DEFAULT) + return "VK_QUERY_RESULT_DEFAULT"; + + if(el & VK_QUERY_RESULT_64_BIT) ret += " | VK_QUERY_RESULT_64_BIT"; + if(el & VK_QUERY_RESULT_WAIT_BIT) ret += " | VK_QUERY_RESULT_WAIT_BIT"; + if(el & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) ret += " | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT"; + if(el & VK_QUERY_RESULT_PARTIAL_BIT) ret += " | VK_QUERY_RESULT_PARTIAL_BIT"; + + if(!ret.empty()) + ret = ret.substr(3); + + return ret; +} + template<> string ToStrHelper::Get(const VkShaderStageFlagBits &el) { diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index e6d1f927e..e427b69f4 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -208,6 +208,8 @@ enum VulkanChunkType BIND_IMAGE_MEM, BEGIN_RENDERPASS, + NEXT_SUBPASS, + EXEC_CMDS, END_RENDERPASS, BIND_PIPELINE, @@ -232,6 +234,8 @@ enum VulkanChunkType BLIT_IMG, RESOLVE_IMG, UPDATE_BUF, + FILL_BUF, + PUSH_CONST, CLEAR_COLOR, CLEAR_DEPTHSTENCIL, @@ -240,6 +244,7 @@ enum VulkanChunkType PIPELINE_BARRIER, WRITE_TIMESTAMP, + COPY_QUERY_RESULTS, BEGIN_QUERY, END_QUERY, RESET_QUERY_POOL, diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 478d845a8..57c968a4b 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -99,6 +99,8 @@ const char *VkChunkNames[] = "vkBindImageMemory", "vkCmdBeginRenderPass", + "vkCmdNextSubpass", + "vkCmdExecuteCommands", "vkCmdEndRenderPass", "vkCmdBindPipeline", @@ -123,6 +125,8 @@ const char *VkChunkNames[] = "vkCmdBlitImage", "vkCmdResolveImage", "vkCmdUpdateBuffer", + "vkCmdFillBuffer", + "vkCmdPushConstants", "vkCmdClearColorImage", "vkCmdClearDepthStencilImage", @@ -131,6 +135,7 @@ const char *VkChunkNames[] = "vkCmdPipelineBarrier", "vkCmdWriteTimestamp", + "vkCmdCopyQueryPoolResults", "vkCmdBeginQuery", "vkCmdEndQuery", "vkCmdResetQueryPool", @@ -1053,6 +1058,12 @@ void WrappedVulkan::ProcessChunk(uint64_t offset, VulkanChunkType context) case BEGIN_RENDERPASS: Serialise_vkCmdBeginRenderPass(GetMainSerialiser(), VK_NULL_HANDLE, NULL, VK_RENDER_PASS_CONTENTS_MAX_ENUM); break; + case NEXT_SUBPASS: + Serialise_vkCmdNextSubpass(GetMainSerialiser(), VK_NULL_HANDLE, VK_RENDER_PASS_CONTENTS_MAX_ENUM); + break; + case EXEC_CMDS: + Serialise_vkCmdExecuteCommands(GetMainSerialiser(), VK_NULL_HANDLE, 0, NULL); + break; case END_RENDERPASS: Serialise_vkCmdEndRenderPass(GetMainSerialiser(), VK_NULL_HANDLE); break; @@ -1117,6 +1128,12 @@ void WrappedVulkan::ProcessChunk(uint64_t offset, VulkanChunkType context) case UPDATE_BUF: Serialise_vkCmdUpdateBuffer(GetMainSerialiser(), VK_NULL_HANDLE, VK_NULL_HANDLE, 0, 0, NULL); break; + case FILL_BUF: + Serialise_vkCmdFillBuffer(GetMainSerialiser(), VK_NULL_HANDLE, VK_NULL_HANDLE, 0, 0, 0); + break; + case PUSH_CONST: + Serialise_vkCmdPushConstants(GetMainSerialiser(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_SHADER_STAGE_ALL, 0, 0, NULL); + break; case CLEAR_COLOR: Serialise_vkCmdClearColorImage(GetMainSerialiser(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_MAX_ENUM, NULL, 0, NULL); break; @@ -1133,8 +1150,10 @@ void WrappedVulkan::ProcessChunk(uint64_t offset, VulkanChunkType context) Serialise_vkCmdPipelineBarrier(GetMainSerialiser(), VK_NULL_HANDLE, 0, 0, VK_FALSE, 0, NULL); break; case WRITE_TIMESTAMP: - //VKTODOMED: - //Serialise_vkCmdWriteTimestamp(GetMainSerialiser(), VK_NULL_HANDLE, VK_TIMESTAMP_TYPE_MAX_ENUM, VK_NULL_HANDLE, 0); + Serialise_vkCmdWriteTimestamp(GetMainSerialiser(), VK_NULL_HANDLE, VK_TIMESTAMP_TYPE_MAX_ENUM, VK_NULL_HANDLE, 0); + break; + case COPY_QUERY_RESULTS: + Serialise_vkCmdCopyQueryPoolResults(GetMainSerialiser(), VK_NULL_HANDLE, VK_NULL_HANDLE, 0, 0, VK_NULL_HANDLE, 0, 0, VK_QUERY_RESULT_DEFAULT); break; case BEGIN_QUERY: Serialise_vkCmdBeginQuery(GetMainSerialiser(), VK_NULL_HANDLE, VK_NULL_HANDLE, 0, 0); diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index f4f2a128c..6f222383c 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -1127,6 +1127,21 @@ public: VkDeviceSize destOffset, VkDeviceSize dataSize, const uint32_t* pData); + + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdFillBuffer, + VkCmdBuffer cmdBuffer, + VkBuffer destBuffer, + VkDeviceSize destOffset, + VkDeviceSize fillSize, + uint32_t data); + + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdPushConstants, + VkCmdBuffer cmdBuffer, + VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t start, + uint32_t length, + const void* values); IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdClearColorImage, VkCmdBuffer cmdBuffer, @@ -1167,6 +1182,22 @@ public: VkBool32 byRegion, uint32_t memBarrierCount, const void* const* ppMemBarriers); + + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdWriteTimestamp, + VkCmdBuffer cmdBuffer, + VkTimestampType timestampType, + VkBuffer destBuffer, + VkDeviceSize destOffset); + + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdCopyQueryPoolResults, + VkCmdBuffer cmdBuffer, + VkQueryPool queryPool, + uint32_t startQuery, + uint32_t queryCount, + VkBuffer destBuffer, + VkDeviceSize destOffset, + VkDeviceSize destStride, + VkQueryResultFlags flags); IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdBeginQuery, VkCmdBuffer cmdBuffer, @@ -1207,6 +1238,15 @@ public: VkCmdBuffer cmdBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, VkRenderPassContents contents); + + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdNextSubpass, + VkCmdBuffer cmdBuffer, + VkRenderPassContents contents); + + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdExecuteCommands, + VkCmdBuffer cmdBuffer, + uint32_t cmdBuffersCount, + const VkCmdBuffer* pCmdBuffers); IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdEndRenderPass, VkCmdBuffer cmdBuffer); diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index 736456277..de3c31d24 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -138,11 +138,15 @@ HookInit(CmdBlitImage); \ HookInit(CmdResolveImage); \ HookInit(CmdUpdateBuffer); \ + HookInit(CmdFillBuffer); \ + HookInit(CmdPushConstants); \ HookInit(CmdClearColorImage); \ HookInit(CmdClearDepthStencilImage); \ HookInit(CmdClearColorAttachment); \ HookInit(CmdClearDepthStencilAttachment); \ HookInit(CmdPipelineBarrier); \ + HookInit(CmdWriteTimestamp); \ + HookInit(CmdCopyQueryPoolResults); \ HookInit(CmdBeginQuery); \ HookInit(CmdEndQuery); \ HookInit(CmdResetQueryPool); \ @@ -151,6 +155,8 @@ HookInit(CreateRenderPass); \ HookInit(DestroyRenderPass); \ HookInit(CmdBeginRenderPass); \ + HookInit(CmdNextSubpass); \ + HookInit(CmdExecuteCommands); \ HookInit(CmdEndRenderPass); \ HookInit(GetSurfacePropertiesKHR); \ HookInit(GetSurfaceFormatsKHR); \ @@ -269,11 +275,15 @@ HookDefine8(void, vkCmdBlitImage, VkCmdBuffer, cmdBuffer, VkImage, srcImage, VkImageLayout, srcImageLayout, VkImage, destImage, VkImageLayout, destImageLayout, uint32_t, regionCount, const VkImageBlit*, pRegions, VkTexFilter, filter); \ HookDefine7(void, vkCmdResolveImage, VkCmdBuffer, cmdBuffer, VkImage, srcImage, VkImageLayout, srcImageLayout, VkImage, destImage, VkImageLayout, destImageLayout, uint32_t, regionCount, const VkImageResolve*, pRegions); \ HookDefine5(void, vkCmdUpdateBuffer, VkCmdBuffer, cmdBuffer, VkBuffer, destBuffer, VkDeviceSize, destOffset, VkDeviceSize, dataSize, const uint32_t*, pData); \ + HookDefine5(void, vkCmdFillBuffer, VkCmdBuffer, cmdBuffer, VkBuffer, destBuffer, VkDeviceSize, destOffset, VkDeviceSize, fillSize, uint32_t, data); \ + HookDefine6(void, vkCmdPushConstants, VkCmdBuffer, cmdBuffer, VkPipelineLayout, layout, VkShaderStageFlags, stageFlags, uint32_t, start, uint32_t, length, const void*, values); \ HookDefine6(void, vkCmdClearColorImage, VkCmdBuffer, cmdBuffer, VkImage, image, VkImageLayout, imageLayout, const VkClearColorValue*, pColor, uint32_t, rangeCount, const VkImageSubresourceRange*, pRanges); \ HookDefine6(void, vkCmdClearDepthStencilImage, VkCmdBuffer, cmdBuffer, VkImage, image, VkImageLayout, imageLayout, const VkClearDepthStencilValue*, pDepthStencil, uint32_t, rangeCount, const VkImageSubresourceRange*, pRanges); \ HookDefine6(void, vkCmdClearColorAttachment, VkCmdBuffer, cmdBuffer, uint32_t, colorAttachment, VkImageLayout, imageLayout, const VkClearColorValue*, pColor, uint32_t, rectCount, const VkRect3D*, pRects); \ HookDefine6(void, vkCmdClearDepthStencilAttachment, VkCmdBuffer, cmdBuffer, VkImageAspectFlags, aspectMask, VkImageLayout, imageLayout, const VkClearDepthStencilValue*, pDepthStencil, uint32_t, rectCount, const VkRect3D*, pRects); \ HookDefine6(void, vkCmdPipelineBarrier, VkCmdBuffer, cmdBuffer, VkPipelineStageFlags, srcStageMask, VkPipelineStageFlags, destStageMask, VkBool32, byRegion, uint32_t, memBarrierCount, const void* const*, ppMemBarriers); \ + HookDefine4(void, vkCmdWriteTimestamp, VkCmdBuffer, cmdBuffer, VkTimestampType, timestampType, VkBuffer, destBuffer, VkDeviceSize, destOffset); \ + HookDefine8(void, vkCmdCopyQueryPoolResults, VkCmdBuffer, cmdBuffer, VkQueryPool, queryPool, uint32_t, startQuery, uint32_t, queryCount, VkBuffer, destBuffer, VkDeviceSize, destOffset, VkDeviceSize, destStride, VkQueryResultFlags, flags); \ HookDefine4(void, vkCmdBeginQuery, VkCmdBuffer, cmdBuffer, VkQueryPool, queryPool, uint32_t, slot, VkQueryControlFlags, flags); \ HookDefine3(void, vkCmdEndQuery, VkCmdBuffer, cmdBuffer, VkQueryPool, queryPool, uint32_t, slot); \ HookDefine4(void, vkCmdResetQueryPool, VkCmdBuffer, cmdBuffer, VkQueryPool, queryPool, uint32_t, startQuery, uint32_t, queryCount); \ @@ -283,6 +293,8 @@ HookDefine2(void, vkDestroyRenderPass, VkDevice, device, VkRenderPass, renderPass); \ HookDefine3(VkResult, vkGetRenderAreaGranularity, VkDevice, device, VkRenderPass, renderPass, VkExtent2D*, pGranularity); \ HookDefine3(void, vkCmdBeginRenderPass, VkCmdBuffer, cmdBuffer, const VkRenderPassBeginInfo*, pRenderPassBegin, VkRenderPassContents, contents); \ + HookDefine2(void, vkCmdNextSubpass, VkCmdBuffer, cmdBuffer, VkRenderPassContents, contents); \ + HookDefine3(void, vkCmdExecuteCommands, VkCmdBuffer, cmdBuffer, uint32_t, cmdBuffersCount, const VkCmdBuffer*, pCmdBuffers); \ HookDefine1(void, vkCmdEndRenderPass, VkCmdBuffer, cmdBuffer); \ HookDefine5(VkResult, vkDbgCreateMsgCallback, VkInstance, instance, VkFlags, msgFlags, const PFN_vkDbgMsgCallback, pfnMsgCallback, void*, pUserData, VkDbgMsgCallback*, pMsgCallback); \ HookDefine2(VkResult, vkDbgDestroyMsgCallback, VkInstance, instance, VkDbgMsgCallback, msgCallback); \ diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 31c0e2ee4..42acad945 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -583,6 +583,118 @@ void WrappedVulkan::vkCmdBeginRenderPass( } } +bool WrappedVulkan::Serialise_vkCmdNextSubpass( + Serialiser* localSerialiser, + VkCmdBuffer cmdBuffer, + VkRenderPassContents contents) +{ + SERIALISE_ELEMENT(ResourceId, cmdid, GetResID(cmdBuffer)); + SERIALISE_ELEMENT(VkRenderPassContents, cont, contents); + + if(m_State < WRITING) + m_LastCmdBufferID = cmdid; + + if(m_State == EXECUTING) + { + if(IsPartialCmd(cmdid) && InPartialRange()) + { + cmdBuffer = PartialCmdBuf(); + + // VKTODOMED subpass tracking here + ObjDisp(cmdBuffer)->CmdNextSubpass(Unwrap(cmdBuffer), cont); + } + } + else if(m_State == READING) + { + cmdBuffer = GetResourceManager()->GetLiveHandle(cmdid); + + ObjDisp(cmdBuffer)->CmdNextSubpass(Unwrap(cmdBuffer), cont); + } + + return true; +} + +void WrappedVulkan::vkCmdNextSubpass( + VkCmdBuffer cmdBuffer, + VkRenderPassContents contents) +{ + ObjDisp(cmdBuffer)->CmdNextSubpass(Unwrap(cmdBuffer), contents); + + if(m_State >= WRITING) + { + VkResourceRecord *record = GetRecord(cmdBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CONTEXT(NEXT_SUBPASS); + Serialise_vkCmdNextSubpass(localSerialiser, cmdBuffer, contents); + + record->AddChunk(scope.Get()); + } +} + +bool WrappedVulkan::Serialise_vkCmdExecuteCommands( + Serialiser* localSerialiser, + VkCmdBuffer cmdBuffer, + uint32_t cmdBuffersCount, + const VkCmdBuffer* pCmdBuffers) +{ + SERIALISE_ELEMENT(ResourceId, cmdid, GetResID(cmdBuffer)); + SERIALISE_ELEMENT(uint32_t, count, cmdBuffersCount); + + if(m_State < WRITING) + m_LastCmdBufferID = cmdid; + + vector cmdids; + vector cmds; + + for(uint32_t i=0; i < count; i++) + { + ResourceId id; + if(m_State >= WRITING) + id = GetResID(pCmdBuffers[i]); + + localSerialiser->Serialise("pCmdBuffers[]", id); + + if(m_State < WRITING) + { + cmdids.push_back(id); + cmds.push_back(Unwrap(GetResourceManager()->GetLiveHandle(id))); + } + } + + if(m_State == EXECUTING) + { + if(IsPartialCmd(cmdid) && InPartialRange()) + { + cmdBuffer = PartialCmdBuf(); + + // VKTODOHIGH proper handling of partial sub-executes + ObjDisp(cmdBuffer)->CmdExecuteCommands(Unwrap(cmdBuffer), count, &cmds[0]); + } + } + else if(m_State == READING) + { + cmdBuffer = GetResourceManager()->GetLiveHandle(cmdid); + + ObjDisp(cmdBuffer)->CmdExecuteCommands(Unwrap(cmdBuffer), count, &cmds[0]); + } + + return true; +} + +void WrappedVulkan::vkCmdExecuteCommands( + VkCmdBuffer cmdBuffer, + uint32_t cmdBuffersCount, + const VkCmdBuffer* pCmdBuffers) +{ + VkCmdBuffer *unwrapped = GetTempArray(cmdBuffersCount); + for(uint32_t i=0; i < cmdBuffersCount; i++) unwrapped[i] = Unwrap(pCmdBuffers[i]); + ObjDisp(cmdBuffer)->CmdExecuteCommands(Unwrap(cmdBuffer), cmdBuffersCount, unwrapped); + + // VKTODOHIGH stub function +} + bool WrappedVulkan::Serialise_vkCmdEndRenderPass( Serialiser* localSerialiser, VkCmdBuffer cmdBuffer) @@ -1069,6 +1181,138 @@ void WrappedVulkan::vkCmdUpdateBuffer( } } +bool WrappedVulkan::Serialise_vkCmdFillBuffer( + Serialiser* localSerialiser, + VkCmdBuffer cmdBuffer, + VkBuffer destBuffer, + VkDeviceSize destOffset, + VkDeviceSize fillSize, + uint32_t data) +{ + SERIALISE_ELEMENT(ResourceId, cmdid, GetResID(cmdBuffer)); + SERIALISE_ELEMENT(ResourceId, bufid, GetResID(destBuffer)); + SERIALISE_ELEMENT(VkDeviceSize, offs, destOffset); + SERIALISE_ELEMENT(VkDeviceSize, sz, fillSize); + SERIALISE_ELEMENT(uint32_t, d, data); + + if(m_State < WRITING) + m_LastCmdBufferID = cmdid; + + if(m_State == EXECUTING) + { + destBuffer = GetResourceManager()->GetLiveHandle(bufid); + + if(IsPartialCmd(cmdid) && InPartialRange()) + { + cmdBuffer = PartialCmdBuf(); + ObjDisp(cmdBuffer)->CmdFillBuffer(Unwrap(cmdBuffer), Unwrap(destBuffer), offs, sz, d); + } + } + else if(m_State == READING) + { + cmdBuffer = GetResourceManager()->GetLiveHandle(cmdid); + destBuffer = GetResourceManager()->GetLiveHandle(bufid); + + ObjDisp(cmdBuffer)->CmdFillBuffer(Unwrap(cmdBuffer), Unwrap(destBuffer), offs, sz, d); + } + + return true; +} + +void WrappedVulkan::vkCmdFillBuffer( + VkCmdBuffer cmdBuffer, + VkBuffer destBuffer, + VkDeviceSize destOffset, + VkDeviceSize fillSize, + uint32_t data) +{ + ObjDisp(cmdBuffer)->CmdFillBuffer(Unwrap(cmdBuffer), Unwrap(destBuffer), destOffset, fillSize, data); + + if(m_State >= WRITING) + { + VkResourceRecord *record = GetRecord(cmdBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CONTEXT(FILL_BUF); + Serialise_vkCmdFillBuffer(localSerialiser, cmdBuffer, destBuffer, destOffset, fillSize, data); + + record->AddChunk(scope.Get()); + record->MarkResourceFrameReferenced(GetResID(destBuffer), eFrameRef_Write); + + // Don't dirty the buffer, just the memory behind it. + { + VkResourceRecord *buf = GetRecord(destBuffer); + if(buf->GetMemoryRecord()) + record->dirtied.insert(buf->GetMemoryRecord()->GetResourceID()); + } + } +} + +bool WrappedVulkan::Serialise_vkCmdPushConstants( + Serialiser* localSerialiser, + VkCmdBuffer cmdBuffer, + VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t start, + uint32_t length, + const void* values) +{ + SERIALISE_ELEMENT(ResourceId, cmdid, GetResID(cmdBuffer)); + SERIALISE_ELEMENT(ResourceId, layid, GetResID(layout)); + SERIALISE_ELEMENT(VkShaderStageFlagBits, flags, (VkShaderStageFlagBits)stageFlags); + SERIALISE_ELEMENT(uint32_t, s, start); + SERIALISE_ELEMENT(uint32_t, len, length); + SERIALISE_ELEMENT_BUF(byte *, vals, (byte *)values, (size_t)(len*4)); + + if(m_State < WRITING) + m_LastCmdBufferID = cmdid; + + if(m_State == EXECUTING) + { + if(IsPartialCmd(cmdid) && InPartialRange()) + { + cmdBuffer = PartialCmdBuf(); + ObjDisp(cmdBuffer)->CmdPushConstants(Unwrap(cmdBuffer), Unwrap(layout), flags, s, len, vals); + + // VKTODOMED update pipeline state + } + } + else if(m_State == READING) + { + cmdBuffer = GetResourceManager()->GetLiveHandle(cmdid); + + ObjDisp(cmdBuffer)->CmdPushConstants(Unwrap(cmdBuffer), Unwrap(layout), flags, s, len, vals); + } + + SAFE_DELETE_ARRAY(vals); + + return true; +} + +void WrappedVulkan::vkCmdPushConstants( + VkCmdBuffer cmdBuffer, + VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t start, + uint32_t length, + const void* values) +{ + ObjDisp(cmdBuffer)->CmdPushConstants(Unwrap(cmdBuffer), Unwrap(layout), stageFlags, start, length, values); + + if(m_State >= WRITING) + { + VkResourceRecord *record = GetRecord(cmdBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CONTEXT(PUSH_CONST); + Serialise_vkCmdPushConstants(localSerialiser, cmdBuffer, layout, stageFlags, start, length, values); + + record->AddChunk(scope.Get()); + } +} + bool WrappedVulkan::Serialise_vkCmdPipelineBarrier( Serialiser* localSerialiser, VkCmdBuffer cmdBuffer, @@ -1234,6 +1478,151 @@ void WrappedVulkan::vkCmdPipelineBarrier( } } +bool WrappedVulkan::Serialise_vkCmdWriteTimestamp( + Serialiser* localSerialiser, + VkCmdBuffer cmdBuffer, + VkTimestampType timestampType, + VkBuffer destBuffer, + VkDeviceSize destOffset) +{ + SERIALISE_ELEMENT(ResourceId, cmdid, GetResID(cmdBuffer)); + SERIALISE_ELEMENT(VkTimestampType, type, timestampType); + SERIALISE_ELEMENT(ResourceId, bufid, GetResID(destBuffer)); + SERIALISE_ELEMENT(VkDeviceSize, offs, destOffset); + + if(m_State < WRITING) + m_LastCmdBufferID = cmdid; + + if(m_State == EXECUTING) + { + destBuffer = GetResourceManager()->GetLiveHandle(bufid); + + if(IsPartialCmd(cmdid) && InPartialRange()) + { + cmdBuffer = PartialCmdBuf(); + ObjDisp(cmdBuffer)->CmdWriteTimestamp(Unwrap(cmdBuffer), type, Unwrap(destBuffer), offs); + } + } + else if(m_State == READING) + { + cmdBuffer = GetResourceManager()->GetLiveHandle(cmdid); + destBuffer = GetResourceManager()->GetLiveHandle(bufid); + + ObjDisp(cmdBuffer)->CmdWriteTimestamp(Unwrap(cmdBuffer), type, Unwrap(destBuffer), offs); + } + + return true; +} + +void WrappedVulkan::vkCmdWriteTimestamp( + VkCmdBuffer cmdBuffer, + VkTimestampType timestampType, + VkBuffer destBuffer, + VkDeviceSize destOffset) +{ + ObjDisp(cmdBuffer)->CmdWriteTimestamp(Unwrap(cmdBuffer), timestampType, Unwrap(destBuffer), destOffset); + + if(m_State >= WRITING) + { + VkResourceRecord *record = GetRecord(cmdBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CONTEXT(WRITE_TIMESTAMP); + Serialise_vkCmdWriteTimestamp(localSerialiser, cmdBuffer, timestampType, destBuffer, destOffset); + + record->AddChunk(scope.Get()); + record->MarkResourceFrameReferenced(GetResID(destBuffer), eFrameRef_Write); + + // Don't dirty the buffer, just the memory behind it. + { + VkResourceRecord *buf = GetRecord(destBuffer); + if(buf->GetMemoryRecord()) + record->dirtied.insert(buf->GetMemoryRecord()->GetResourceID()); + } + } +} + +bool WrappedVulkan::Serialise_vkCmdCopyQueryPoolResults( + Serialiser* localSerialiser, + VkCmdBuffer cmdBuffer, + VkQueryPool queryPool, + uint32_t startQuery, + uint32_t queryCount, + VkBuffer destBuffer, + VkDeviceSize destOffset, + VkDeviceSize destStride, + VkQueryResultFlags flags) +{ + SERIALISE_ELEMENT(ResourceId, cmdid, GetResID(cmdBuffer)); + SERIALISE_ELEMENT(ResourceId, qid, GetResID(queryPool)); + SERIALISE_ELEMENT(uint32_t, start, startQuery); + SERIALISE_ELEMENT(uint32_t, count, queryCount); + SERIALISE_ELEMENT(ResourceId, bufid, GetResID(destBuffer)); + SERIALISE_ELEMENT(VkDeviceSize, offs, destOffset); + SERIALISE_ELEMENT(VkDeviceSize, stride, destStride); + SERIALISE_ELEMENT(VkQueryResultFlagBits, f, (VkQueryResultFlagBits)flags); + + if(m_State < WRITING) + m_LastCmdBufferID = cmdid; + + if(m_State == EXECUTING) + { + queryPool = GetResourceManager()->GetLiveHandle(qid); + destBuffer = GetResourceManager()->GetLiveHandle(bufid); + + if(IsPartialCmd(cmdid) && InPartialRange()) + { + cmdBuffer = PartialCmdBuf(); + ObjDisp(cmdBuffer)->CmdCopyQueryPoolResults(Unwrap(cmdBuffer), Unwrap(queryPool), start, count, Unwrap(destBuffer), offs, stride, f); + } + } + else if(m_State == READING) + { + cmdBuffer = GetResourceManager()->GetLiveHandle(cmdid); + queryPool = GetResourceManager()->GetLiveHandle(qid); + destBuffer = GetResourceManager()->GetLiveHandle(bufid); + + ObjDisp(cmdBuffer)->CmdCopyQueryPoolResults(Unwrap(cmdBuffer), Unwrap(queryPool), start, count, Unwrap(destBuffer), offs, stride, f); + } + + return true; +} + +void WrappedVulkan::vkCmdCopyQueryPoolResults( + VkCmdBuffer cmdBuffer, + VkQueryPool queryPool, + uint32_t startQuery, + uint32_t queryCount, + VkBuffer destBuffer, + VkDeviceSize destOffset, + VkDeviceSize destStride, + VkQueryResultFlags flags) +{ + ObjDisp(cmdBuffer)->CmdCopyQueryPoolResults(Unwrap(cmdBuffer), Unwrap(queryPool), startQuery, queryCount, Unwrap(destBuffer), destOffset, destStride, flags); + + if(m_State >= WRITING) + { + VkResourceRecord *record = GetRecord(cmdBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CONTEXT(COPY_QUERY_RESULTS); + Serialise_vkCmdCopyQueryPoolResults(localSerialiser, cmdBuffer, queryPool, startQuery, queryCount, destBuffer, destOffset, destStride, flags); + + record->AddChunk(scope.Get()); + record->MarkResourceFrameReferenced(GetResID(queryPool), eFrameRef_Read); + record->MarkResourceFrameReferenced(GetResID(destBuffer), eFrameRef_Write); + + // Don't dirty the buffer, just the memory behind it. + { + VkResourceRecord *buf = GetRecord(destBuffer); + if(buf->GetMemoryRecord()) + record->dirtied.insert(buf->GetMemoryRecord()->GetResourceID()); + } + } +} + bool WrappedVulkan::Serialise_vkCmdBeginQuery( Serialiser* localSerialiser, VkCmdBuffer cmdBuffer,