bool WrappedVulkan::Serialise_vkCreateGraphicsPipelines( Serialiser *localSerialiser, VkDevice device, VkPipelineCache pipelineCache, uint32_t count, const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) { SERIALISE_ELEMENT(ResourceId, devId, GetResID(device)); SERIALISE_ELEMENT(ResourceId, cacheId, GetResID(pipelineCache)); SERIALISE_ELEMENT(VkGraphicsPipelineCreateInfo, info, *pCreateInfos); SERIALISE_ELEMENT(ResourceId, id, GetResID(*pPipelines)); if(m_State == READING) { VkPipeline pipe = VK_NULL_HANDLE; device = GetResourceManager()->GetLiveHandle<VkDevice>(devId); // don't use pipeline caches on replay pipelineCache = VK_NULL_HANDLE; // GetResourceManager()->GetLiveHandle<VkPipelineCache>(cacheId); VkResult ret = ObjDisp(device)->CreateGraphicsPipelines(Unwrap(device), Unwrap(pipelineCache), 1, &info, NULL, &pipe); if(ret != VK_SUCCESS) { RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret); } else { ResourceId live; if(GetResourceManager()->HasWrapper(ToTypedHandle(pipe))) { live = GetResourceManager()->GetNonDispWrapper(pipe)->id; // destroy this instance of the duplicate, as we must have matching create/destroy // calls and there won't be a wrapped resource hanging around to destroy this one. ObjDisp(device)->DestroyPipeline(Unwrap(device), pipe, NULL); // whenever the new ID is requested, return the old ID, via replacements. GetResourceManager()->ReplaceResource(id, GetResourceManager()->GetOriginalID(live)); } else { live = GetResourceManager()->WrapResource(Unwrap(device), pipe); GetResourceManager()->AddLiveResource(id, pipe); m_CreationInfo.m_Pipeline[live].Init(GetResourceManager(), m_CreationInfo, &info); } } } return true; }
bool WrappedVulkan::Serialise_vkCreateDescriptorSetLayout( Serialiser* localSerialiser, VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorSetLayout* pSetLayout) { SERIALISE_ELEMENT(ResourceId, devId, GetResID(device)); SERIALISE_ELEMENT(VkDescriptorSetLayoutCreateInfo, info, *pCreateInfo); SERIALISE_ELEMENT(ResourceId, id, GetResID(*pSetLayout)); if(m_State == READING) { VkDescriptorSetLayout layout = VK_NULL_HANDLE; device = GetResourceManager()->GetLiveHandle<VkDevice>(devId); VkResult ret = ObjDisp(device)->CreateDescriptorSetLayout(Unwrap(device), &info, NULL, &layout); if(ret != VK_SUCCESS) { RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret); } else { ResourceId live; if(GetResourceManager()->HasWrapper(ToTypedHandle(layout))) { live = GetResourceManager()->GetNonDispWrapper(layout)->id; // destroy this instance of the duplicate, as we must have matching create/destroy // calls and there won't be a wrapped resource hanging around to destroy this one. ObjDisp(device)->DestroyDescriptorSetLayout(Unwrap(device), layout, NULL); // whenever the new ID is requested, return the old ID, via replacements. GetResourceManager()->ReplaceResource(id, GetResourceManager()->GetOriginalID(live)); } else { live = GetResourceManager()->WrapResource(Unwrap(device), layout); GetResourceManager()->AddLiveResource(id, layout); m_CreationInfo.m_DescSetLayout[live].Init(GetResourceManager(), m_CreationInfo, &info); } } } return true; }
bool WrappedVulkan::Serialise_vkCreateRenderPass( Serialiser* localSerialiser, VkDevice device, const VkRenderPassCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) { SERIALISE_ELEMENT(ResourceId, devId, GetResID(device)); SERIALISE_ELEMENT(VkRenderPassCreateInfo, info, *pCreateInfo); SERIALISE_ELEMENT(ResourceId, id, GetResID(*pRenderPass)); if(m_State == READING) { device = GetResourceManager()->GetLiveHandle<VkDevice>(devId); VkRenderPass rp = VK_NULL_HANDLE; VulkanCreationInfo::RenderPass rpinfo; rpinfo.Init(GetResourceManager(), m_CreationInfo, &info); // we want to store off the data so we can display it after the pass. // override any user-specified DONT_CARE. VkAttachmentDescription *att = (VkAttachmentDescription *)info.pAttachments; for(uint32_t i=0; i < info.attachmentCount; i++) { att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; // renderpass can't start or end in presentable layout on replay ReplacePresentableImageLayout(att[i].initialLayout); ReplacePresentableImageLayout(att[i].finalLayout); } VkResult ret = ObjDisp(device)->CreateRenderPass(Unwrap(device), &info, NULL, &rp); if(ret != VK_SUCCESS) { RDCERR("Failed on resource serialise-creation, VkResult: 0x%08x", ret); } else { ResourceId live; if(GetResourceManager()->HasWrapper(ToTypedHandle(rp))) { live = GetResourceManager()->GetNonDispWrapper(rp)->id; // destroy this instance of the duplicate, as we must have matching create/destroy // calls and there won't be a wrapped resource hanging around to destroy this one. ObjDisp(device)->DestroyRenderPass(Unwrap(device), rp, NULL); // whenever the new ID is requested, return the old ID, via replacements. GetResourceManager()->ReplaceResource(id, GetResourceManager()->GetOriginalID(live)); } else { live = GetResourceManager()->WrapResource(Unwrap(device), rp); GetResourceManager()->AddLiveResource(id, rp); // make a version of the render pass that loads from its attachments, // so it can be used for replaying a single draw after a render pass // without doing a clear or a DONT_CARE load. for(uint32_t i=0; i < info.attachmentCount; i++) { att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; } ret = ObjDisp(device)->CreateRenderPass(Unwrap(device), &info, NULL, &rpinfo.loadRP); RDCASSERTEQUAL(ret, VK_SUCCESS); // handle the loadRP being a duplicate if(GetResourceManager()->HasWrapper(ToTypedHandle(rpinfo.loadRP))) { // just fetch the existing wrapped object rpinfo.loadRP = (VkRenderPass)(uint64_t)GetResourceManager()->GetNonDispWrapper(rpinfo.loadRP); // destroy this instance of the duplicate, as we must have matching create/destroy // calls and there won't be a wrapped resource hanging around to destroy this one. ObjDisp(device)->DestroyRenderPass(Unwrap(device), rpinfo.loadRP, NULL); // don't need to ReplaceResource as no IDs are involved } else { ResourceId loadRPid = GetResourceManager()->WrapResource(Unwrap(device), rpinfo.loadRP); // register as a live-only resource, so it is cleaned up properly GetResourceManager()->AddLiveResource(loadRPid, rpinfo.loadRP); } m_CreationInfo.m_RenderPass[live] = rpinfo; } } } return true; }
bool WrappedVulkan::ReleaseResource(WrappedVkRes *res) { if(res == NULL) return true; // MULTIDEVICE need to get the actual device that created this object VkDevice dev = GetDev(); const VkLayerDispatchTable *vt = ObjDisp(dev); WrappedVkNonDispRes *nondisp = (WrappedVkNonDispRes *)res; WrappedVkDispRes *disp = (WrappedVkDispRes *)res; uint64_t handle = (uint64_t)nondisp; switch(IdentifyTypeByPtr(res)) { case eResSurface: case eResSwapchain: if(m_State >= WRITING) RDCERR("Swapchain/swapchain object is leaking"); else RDCERR("Should be no swapchain/surface objects created on replay"); break; case eResUnknown: RDCERR("Unknown resource type!"); break; case eResCommandBuffer: // special case here, on replay we don't have the tracking // to remove these with the parent object so do it here. // This ensures we clean up after ourselves with a well- // behaved application. if(m_State < WRITING) GetResourceManager()->ReleaseWrappedResource((VkCommandBuffer)res); break; case eResDescriptorSet: if(m_State < WRITING) GetResourceManager()->ReleaseWrappedResource(VkDescriptorSet(handle)); break; case eResPhysicalDevice: if(m_State < WRITING) GetResourceManager()->ReleaseWrappedResource((VkPhysicalDevice)disp); break; case eResQueue: if(m_State < WRITING) GetResourceManager()->ReleaseWrappedResource((VkQueue)disp); break; case eResDevice: // these are explicitly released elsewhere, do not need to destroy // any API objects. // On replay though we do need to tidy up book-keeping for these. if(m_State < WRITING) { GetResourceManager()->ReleaseCurrentResource(disp->id); GetResourceManager()->RemoveWrapper(ToTypedHandle(disp->real.As<VkDevice>())); } break; case eResInstance: if(m_State < WRITING) { GetResourceManager()->ReleaseCurrentResource(disp->id); GetResourceManager()->RemoveWrapper(ToTypedHandle(disp->real.As<VkInstance>())); } break; case eResDeviceMemory: { VkDeviceMemory real = nondisp->real.As<VkDeviceMemory>(); GetResourceManager()->ReleaseWrappedResource(VkDeviceMemory(handle)); vt->FreeMemory(Unwrap(dev), real, NULL); break; } case eResBuffer: { VkBuffer real = nondisp->real.As<VkBuffer>(); GetResourceManager()->ReleaseWrappedResource(VkBuffer(handle)); vt->DestroyBuffer(Unwrap(dev), real, NULL); break; } case eResBufferView: { VkBufferView real = nondisp->real.As<VkBufferView>(); GetResourceManager()->ReleaseWrappedResource(VkBufferView(handle)); vt->DestroyBufferView(Unwrap(dev), real, NULL); break; } case eResImage: { VkImage real = nondisp->real.As<VkImage>(); GetResourceManager()->ReleaseWrappedResource(VkImage(handle)); vt->DestroyImage(Unwrap(dev), real, NULL); break; } case eResImageView: { VkImageView real = nondisp->real.As<VkImageView>(); GetResourceManager()->ReleaseWrappedResource(VkImageView(handle)); vt->DestroyImageView(Unwrap(dev), real, NULL); break; } case eResFramebuffer: { VkFramebuffer real = nondisp->real.As<VkFramebuffer>(); GetResourceManager()->ReleaseWrappedResource(VkFramebuffer(handle)); vt->DestroyFramebuffer(Unwrap(dev), real, NULL); break; } case eResRenderPass: { VkRenderPass real = nondisp->real.As<VkRenderPass>(); GetResourceManager()->ReleaseWrappedResource(VkRenderPass(handle)); vt->DestroyRenderPass(Unwrap(dev), real, NULL); break; } case eResShaderModule: { VkShaderModule real = nondisp->real.As<VkShaderModule>(); GetResourceManager()->ReleaseWrappedResource(VkShaderModule(handle)); vt->DestroyShaderModule(Unwrap(dev), real, NULL); break; } case eResPipelineCache: { VkPipelineCache real = nondisp->real.As<VkPipelineCache>(); GetResourceManager()->ReleaseWrappedResource(VkPipelineCache(handle)); vt->DestroyPipelineCache(Unwrap(dev), real, NULL); break; } case eResPipelineLayout: { VkPipelineLayout real = nondisp->real.As<VkPipelineLayout>(); GetResourceManager()->ReleaseWrappedResource(VkPipelineLayout(handle)); vt->DestroyPipelineLayout(Unwrap(dev), real, NULL); break; } case eResPipeline: { VkPipeline real = nondisp->real.As<VkPipeline>(); GetResourceManager()->ReleaseWrappedResource(VkPipeline(handle)); vt->DestroyPipeline(Unwrap(dev), real, NULL); break; } case eResSampler: { VkSampler real = nondisp->real.As<VkSampler>(); GetResourceManager()->ReleaseWrappedResource(VkSampler(handle)); vt->DestroySampler(Unwrap(dev), real, NULL); break; } case eResDescriptorPool: { VkDescriptorPool real = nondisp->real.As<VkDescriptorPool>(); GetResourceManager()->ReleaseWrappedResource(VkDescriptorPool(handle)); vt->DestroyDescriptorPool(Unwrap(dev), real, NULL); break; } case eResDescriptorSetLayout: { VkDescriptorSetLayout real = nondisp->real.As<VkDescriptorSetLayout>(); GetResourceManager()->ReleaseWrappedResource(VkDescriptorSetLayout(handle)); vt->DestroyDescriptorSetLayout(Unwrap(dev), real, NULL); break; } case eResCommandPool: { VkCommandPool real = nondisp->real.As<VkCommandPool>(); GetResourceManager()->ReleaseWrappedResource(VkCommandPool(handle)); vt->DestroyCommandPool(Unwrap(dev), real, NULL); break; } case eResFence: { VkFence real = nondisp->real.As<VkFence>(); GetResourceManager()->ReleaseWrappedResource(VkFence(handle)); vt->DestroyFence(Unwrap(dev), real, NULL); break; } case eResEvent: { VkEvent real = nondisp->real.As<VkEvent>(); GetResourceManager()->ReleaseWrappedResource(VkEvent(handle)); vt->DestroyEvent(Unwrap(dev), real, NULL); break; } case eResQueryPool: { VkQueryPool real = nondisp->real.As<VkQueryPool>(); GetResourceManager()->ReleaseWrappedResource(VkQueryPool(handle)); vt->DestroyQueryPool(Unwrap(dev), real, NULL); break; } case eResSemaphore: { VkSemaphore real = nondisp->real.As<VkSemaphore>(); GetResourceManager()->ReleaseWrappedResource(VkSemaphore(handle)); vt->DestroySemaphore(Unwrap(dev), real, NULL); break; } } return true; }