void VulkanResourceManager::SerialiseImageStates(map<ResourceId, ImageLayouts> &states, vector<VkImageMemoryBarrier> &barriers) { Serialiser *localSerialiser = m_pSerialiser; SERIALISE_ELEMENT(uint32_t, NumMems, (uint32_t)states.size()); auto srcit = states.begin(); vector<pair<ResourceId, ImageRegionState> > vec; for(uint32_t i = 0; i < NumMems; i++) { SERIALISE_ELEMENT(ResourceId, id, srcit->first); SERIALISE_ELEMENT(uint32_t, NumStates, (uint32_t)srcit->second.subresourceStates.size()); ResourceId liveid; if(m_State < WRITING && HasLiveResource(id)) liveid = GetLiveID(id); for(uint32_t m = 0; m < NumStates; m++) { SERIALISE_ELEMENT(ImageRegionState, state, srcit->second.subresourceStates[m]); if(m_State < WRITING && liveid != ResourceId() && srcit != states.end()) { VkImageMemoryBarrier t; t.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; t.pNext = NULL; // these access masks aren't used, we need to apply a global memory barrier // to memory each time we restart log replaying. These barriers are just // to get images into the right layout t.srcAccessMask = 0; t.dstAccessMask = 0; // MULTIDEVICE need to handle multiple queues t.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; t.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; t.image = Unwrap(GetCurrentHandle<VkImage>(liveid)); t.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; ReplacePresentableImageLayout(state.newLayout); t.newLayout = state.newLayout; t.subresourceRange = state.subresourceRange; barriers.push_back(t); vec.push_back(std::make_pair(liveid, state)); } } if(m_State >= WRITING) srcit++; } ApplyBarriers(vec, states); for(size_t i = 0; i < vec.size(); i++) barriers[i].oldLayout = vec[i].second.oldLayout; // erase any do-nothing barriers for(auto it = barriers.begin(); it != barriers.end();) { if(it->oldLayout == UNKNOWN_PREV_IMG_LAYOUT) it->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; if(it->oldLayout == it->newLayout) it = barriers.erase(it); else ++it; } }
bool WrappedVulkan::Serialise_vkCmdWaitEvents( Serialiser* localSerialiser, VkCommandBuffer cmdBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers) { SERIALISE_ELEMENT(ResourceId, cmdid, GetResID(cmdBuffer)); SERIALISE_ELEMENT(VkPipelineStageFlagBits, srcStages, (VkPipelineStageFlagBits)srcStageMask); SERIALISE_ELEMENT(VkPipelineStageFlagBits, destStages, (VkPipelineStageFlagBits)dstStageMask); // we don't serialise the original events as we are going to replace this // with our own SERIALISE_ELEMENT(uint32_t, memCount, memoryBarrierCount); SERIALISE_ELEMENT(uint32_t, bufCount, bufferMemoryBarrierCount); SERIALISE_ELEMENT(uint32_t, imgCount, imageMemoryBarrierCount); // we keep the original memory barriers SERIALISE_ELEMENT_ARR(VkMemoryBarrier, memBarriers, pMemoryBarriers, memCount); SERIALISE_ELEMENT_ARR(VkBufferMemoryBarrier, bufMemBarriers, pBufferMemoryBarriers, bufCount); SERIALISE_ELEMENT_ARR(VkImageMemoryBarrier, imgMemBarriers, pImageMemoryBarriers, imgCount); vector<VkImageMemoryBarrier> imgBarriers; vector<VkBufferMemoryBarrier> bufBarriers; // it's possible for buffer or image to be NULL if it refers to a resource that is otherwise // not in the log (barriers do not mark resources referenced). If the resource in question does // not exist, then it's safe to skip this barrier. if(m_State < WRITING) { for(uint32_t i=0; i < bufCount; i++) if(bufMemBarriers[i].buffer != VK_NULL_HANDLE) bufBarriers.push_back(bufMemBarriers[i]); for(uint32_t i=0; i < imgCount; i++) { if(imgMemBarriers[i].image != VK_NULL_HANDLE) { imgBarriers.push_back(imgMemBarriers[i]); ReplacePresentableImageLayout(imgBarriers.back().oldLayout); ReplacePresentableImageLayout(imgBarriers.back().newLayout); } } } SAFE_DELETE_ARRAY(bufMemBarriers); SAFE_DELETE_ARRAY(imgMemBarriers); // see top of this file for current event/fence handling if(m_State == EXECUTING) { if(ShouldRerecordCmd(cmdid) && InRerecordRange()) { cmdBuffer = RerecordCmdBuf(cmdid); VkEventCreateInfo evInfo = { VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, NULL, 0, }; VkEvent ev = VK_NULL_HANDLE; ObjDisp(cmdBuffer)->CreateEvent(Unwrap(GetDev()), &evInfo, NULL, &ev); // don't wrap this event ObjDisp(cmdBuffer)->ResetEvent(Unwrap(GetDev()), ev); ObjDisp(cmdBuffer)->CmdSetEvent(Unwrap(cmdBuffer), ev, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); ObjDisp(cmdBuffer)->CmdWaitEvents(Unwrap(cmdBuffer), 1, &ev, (VkPipelineStageFlags)srcStages, (VkPipelineStageFlags)destStages, memCount, memBarriers, (uint32_t)bufBarriers.size(), &bufBarriers[0], (uint32_t)imgBarriers.size(), &imgBarriers[0]); // register to clean this event up once we're done replaying this section of the log m_CleanupEvents.push_back(ev); ResourceId cmd = GetResID(RerecordCmdBuf(cmdid)); GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, (uint32_t)imgBarriers.size(), &imgBarriers[0]); } } else if(m_State == READING) { cmdBuffer = GetResourceManager()->GetLiveHandle<VkCommandBuffer>(cmdid); VkEventCreateInfo evInfo = { VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, NULL, 0, }; VkEvent ev = VK_NULL_HANDLE; ObjDisp(cmdBuffer)->CreateEvent(Unwrap(GetDev()), &evInfo, NULL, &ev); // don't wrap this event ObjDisp(cmdBuffer)->ResetEvent(Unwrap(GetDev()), ev); ObjDisp(cmdBuffer)->CmdSetEvent(Unwrap(cmdBuffer), ev, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); ObjDisp(cmdBuffer)->CmdWaitEvents(Unwrap(cmdBuffer), 1, &ev, (VkPipelineStageFlags)srcStages, (VkPipelineStageFlags)destStages, memCount, memBarriers, (uint32_t)bufBarriers.size(), &bufBarriers[0], (uint32_t)imgBarriers.size(), &imgBarriers[0]); // register to clean this event up once we're done replaying this section of the log m_CleanupEvents.push_back(ev); ResourceId cmd = GetResID(cmdBuffer); GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts, (uint32_t)imgBarriers.size(), &imgBarriers[0]); } SAFE_DELETE_ARRAY(memBarriers); 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; }