Handle renderpasses with implicit attachment transitions. Closes #212

* We need to make sure we track these transitions, both during capture
  (so we have the right initial image states at frame begin), and during
  replay.
* Likewise when repurposing a renderpass for isolating a drawcall, we
  need to make sure the image layouts aren't transitioned - especially
  from UNDEFINED - otherwise we'd end up with garbage data.
This commit is contained in:
baldurk
2016-09-01 15:31:03 +02:00
parent 9c0f20c6b0
commit e96f980e66
10 changed files with 437 additions and 66 deletions
+3
View File
@@ -570,7 +570,10 @@ private:
void FirstFrame(VkSwapchainKHR swap);
std::vector<VkImageMemoryBarrier> GetImplicitRenderPassBarriers(uint32_t subpass = 0);
string MakeRenderPassOpString(bool store);
void MakeSubpassLoadRP(VkRenderPassCreateInfo &info, const VkRenderPassCreateInfo *origInfo,
uint32_t s);
void StartFrameCapture(void *dev, void *wnd);
bool EndFrameCapture(void *dev, void *wnd);
+13 -8
View File
@@ -403,14 +403,7 @@ void VulkanCreationInfo::RenderPass::Init(VulkanResourceManager *resourceMan,
{
attachments.reserve(pCreateInfo->attachmentCount);
for(uint32_t i = 0; i < pCreateInfo->attachmentCount; i++)
{
Attachment a;
a.loadOp = pCreateInfo->pAttachments[i].loadOp;
a.storeOp = pCreateInfo->pAttachments[i].storeOp;
a.stencilLoadOp = pCreateInfo->pAttachments[i].stencilLoadOp;
a.stencilStoreOp = pCreateInfo->pAttachments[i].stencilStoreOp;
attachments.push_back(a);
}
attachments.push_back(pCreateInfo->pAttachments[i]);
subpasses.resize(pCreateInfo->subpassCount);
for(uint32_t subp = 0; subp < pCreateInfo->subpassCount; subp++)
@@ -419,18 +412,30 @@ void VulkanCreationInfo::RenderPass::Init(VulkanResourceManager *resourceMan,
Subpass &dst = subpasses[subp];
dst.inputAttachments.resize(src.inputAttachmentCount);
dst.inputLayouts.resize(src.inputAttachmentCount);
for(uint32_t i = 0; i < src.inputAttachmentCount; i++)
{
dst.inputAttachments[i] = src.pInputAttachments[i].attachment;
dst.inputLayouts[i] = src.pInputAttachments[i].layout;
}
dst.colorAttachments.resize(src.colorAttachmentCount);
dst.colorLayouts.resize(src.colorAttachmentCount);
for(uint32_t i = 0; i < src.colorAttachmentCount; i++)
{
dst.colorAttachments[i] = src.pColorAttachments[i].attachment;
dst.colorLayouts[i] = src.pColorAttachments[i].layout;
}
dst.depthstencilAttachment =
(src.pDepthStencilAttachment != NULL &&
src.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED
? (int32_t)src.pDepthStencilAttachment->attachment
: -1);
dst.depthstencilLayout = (src.pDepthStencilAttachment != NULL &&
src.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED
? src.pDepthStencilAttachment->layout
: VK_IMAGE_LAYOUT_UNDEFINED);
}
}
+10 -9
View File
@@ -197,24 +197,25 @@ struct VulkanCreationInfo
void Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info,
const VkRenderPassCreateInfo *pCreateInfo);
struct Attachment
{
VkAttachmentLoadOp loadOp;
VkAttachmentStoreOp storeOp;
VkAttachmentLoadOp stencilLoadOp;
VkAttachmentStoreOp stencilStoreOp;
};
vector<Attachment> attachments;
vector<VkAttachmentDescription> attachments;
struct Subpass
{
// these are split apart since they layout is
// rarely used but the indices are often used
vector<uint32_t> inputAttachments;
vector<uint32_t> colorAttachments;
int32_t depthstencilAttachment;
vector<VkImageLayout> inputLayouts;
vector<VkImageLayout> colorLayouts;
VkImageLayout depthstencilLayout;
};
vector<Subpass> subpasses;
VkRenderPass loadRP;
// one for each subpass, as we preserve attachments
// in the layout that the subpass uses
vector<VkRenderPass> loadRPs;
};
map<ResourceId, RenderPass> m_RenderPass;
+4
View File
@@ -5180,11 +5180,15 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m
// if we have no tmpImage, we're copying directly from the real image
if(tmpImage == VK_NULL_HANDLE)
{
// ensure transfer has completed
srcimBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
// image layout back to normal
for(size_t si = 0; si < layouts.subresourceStates.size(); si++)
{
srcimBarrier.subresourceRange = layouts.subresourceStates[si].subresourceRange;
srcimBarrier.newLayout = layouts.subresourceStates[si].newLayout;
srcimBarrier.dstAccessMask = MakeAccessMask(srcimBarrier.newLayout);
DoPipelineBarrier(cmd, 1, &srcimBarrier);
}
}
+2 -2
View File
@@ -748,8 +748,8 @@ VkResourceRecord::~VkResourceRecord()
if(resType == eResCommandBuffer)
SAFE_DELETE(cmdInfo);
if(resType == eResFramebuffer)
SAFE_DELETE(imageAttachments);
if(resType == eResFramebuffer || resType == eResRenderPass)
SAFE_DELETE_ARRAY(imageAttachments);
// only the descriptor set layout actually owns this pointer, descriptor sets
// have a pointer to it but don't own it
+79 -2
View File
@@ -871,6 +871,8 @@ struct CmdBufferRecordingInfo
VkDevice device;
VkCommandBufferAllocateInfo allocInfo;
VkResourceRecord *framebuffer;
vector<pair<ResourceId, ImageRegionState> > imgbarriers;
// sparse resources referenced by this command buffer (at submit time
@@ -935,6 +937,17 @@ struct MemMapState
byte *refData;
};
struct AttachmentInfo
{
VkResourceRecord *record;
// the implicit barrier applied from initialLayout to finalLayout across a render pass
// for render passes this is partial (doesn't contain the image pointer), the image
// and subresource range are filled in when creating the framebuffer, which is what is
// used to apply the barrier in EndRenderPass
VkImageMemoryBarrier barrier;
};
struct VkResourceRecord : public ResourceRecord
{
public:
@@ -1046,18 +1059,82 @@ public:
SwapchainInfo *swapInfo; // only for swapchains
MemMapState *memMapState; // only for device memory
CmdBufferRecordingInfo *cmdInfo; // only for command buffers
VkResourceRecord **imageAttachments; // only for framebuffers
AttachmentInfo *imageAttachments; // only for framebuffers and render passes
DescriptorSetData *descInfo; // only for descriptor sets and descriptor set layouts
};
VkResourceRecord *bakedCommands;
static const int MaxImageAttachments = 9; // 8 Colour and 1 Depth
static const int MaxImageAttachments = 17; // 8 Input, 8 Colour and 1 Depth
// pointer to either the pool this item is allocated from, or the children allocated
// from this pool. Protected by the chunk lock
VkResourceRecord *pool;
vector<VkResourceRecord *> pooledChildren;
// we only need a couple of bytes to store the view's range,
// so just pack/unpack into bitfields
struct ViewRange
{
ViewRange &operator=(const VkImageSubresourceRange &range)
{
aspectMask = (uint32_t)range.aspectMask;
baseMipLevel = range.baseMipLevel;
baseArrayLayer = range.baseArrayLayer;
if(range.levelCount == VK_REMAINING_MIP_LEVELS)
levelCount = MipMaxValue;
else
levelCount = range.levelCount;
if(range.layerCount == VK_REMAINING_ARRAY_LAYERS)
layerCount = SliceMaxValue;
else
layerCount = range.layerCount;
return *this;
}
operator VkImageSubresourceRange() const
{
VkImageSubresourceRange ret;
ret.aspectMask = (VkImageAspectFlags)aspectMask;
ret.baseMipLevel = baseMipLevel;
ret.baseArrayLayer = baseArrayLayer;
if(levelCount == MipMaxValue)
ret.levelCount = VK_REMAINING_MIP_LEVELS;
else
ret.levelCount = levelCount;
if(layerCount == SliceMaxValue)
ret.layerCount = VK_REMAINING_ARRAY_LAYERS;
else
ret.layerCount = layerCount;
return ret;
}
// only need 4 bits for the aspects
uint32_t aspectMask : 4;
// 6 bits = refer to up to 62 mips = bloody huge textures.
// note we also need to pack in VK_REMAINING_MIPS etc so we can't
// necessarily use the maximum levelCount value (64)
uint32_t baseMipLevel : 6;
uint32_t levelCount : 6;
static const uint32_t MipMaxValue = 0x3f;
// 16 bits = refer to up to 64k array layers. This is less
// future proof than above, but at time of writing typical
// maxImageArrayLayers is 2048.
uint32_t baseArrayLayer : 16;
uint32_t layerCount : 16;
static const uint32_t SliceMaxValue = 0xffff;
} viewRange;
};
struct ImageLayouts
+1 -9
View File
@@ -98,7 +98,7 @@ void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd)
VkRenderPassBeginInfo rpbegin = {
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
NULL,
Unwrap(m_CreationInfo->m_RenderPass[renderPass].loadRP),
Unwrap(m_CreationInfo->m_RenderPass[renderPass].loadRPs[subpass]),
Unwrap(GetResourceManager()->GetCurrentHandle<VkFramebuffer>(framebuffer)),
renderArea,
(uint32_t)m_CreationInfo->m_RenderPass[renderPass].attachments.size(),
@@ -106,9 +106,6 @@ void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd)
};
ObjDisp(cmd)->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE);
for(uint32_t i = 0; i < subpass; i++)
ObjDisp(cmd)->CmdNextSubpass(Unwrap(cmd), VK_SUBPASS_CONTENTS_INLINE);
BindPipeline(cmd);
if(ibuffer.buf != ResourceId())
@@ -306,10 +303,5 @@ void VulkanRenderState::BindPipeline(VkCommandBuffer cmd)
void VulkanRenderState::EndRenderPass(VkCommandBuffer cmd)
{
uint32_t numSubpasses = (uint32_t)m_CreationInfo->m_RenderPass[renderPass].subpasses.size();
for(uint32_t sub = subpass; sub < numSubpasses - 1; sub++)
ObjDisp(cmd)->CmdNextSubpass(Unwrap(cmd), VK_SUBPASS_CONTENTS_INLINE);
ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd));
}
@@ -24,6 +24,155 @@
#include "../vk_core.h"
std::vector<VkImageMemoryBarrier> WrappedVulkan::GetImplicitRenderPassBarriers(uint32_t subpass)
{
ResourceId rp, fb;
if(m_State == EXECUTING)
{
rp = m_RenderState.renderPass;
fb = m_RenderState.framebuffer;
}
else
{
rp = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass;
fb = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer;
}
std::vector<VkImageMemoryBarrier> ret;
VulkanCreationInfo::Framebuffer fbinfo = m_CreationInfo.m_Framebuffer[fb];
VulkanCreationInfo::RenderPass rpinfo = m_CreationInfo.m_RenderPass[rp];
std::vector<VkAttachmentReference> atts;
// a bit of dancing to get a subpass index. Because we don't increment
// the subpass counter on EndRenderPass the value is the same for the last
// NextSubpass. Instead we pass in the subpass index of ~0U for End
if(subpass == ~0U)
{
// we transition all attachments to finalLayout from whichever they
// were in previously
atts.resize(rpinfo.attachments.size());
for(size_t i = 0; i < rpinfo.attachments.size(); i++)
{
atts[i].attachment = (uint32_t)i;
atts[i].layout = rpinfo.attachments[i].finalLayout;
}
}
else
{
if(m_State == EXECUTING)
subpass = m_RenderState.subpass;
else
subpass = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass;
// transition the attachments in this subpass
for(size_t i = 0; i < rpinfo.subpasses[subpass].colorAttachments.size(); i++)
{
atts.push_back(VkAttachmentReference());
atts.back().attachment = rpinfo.subpasses[subpass].colorAttachments[i];
atts.back().layout = rpinfo.subpasses[subpass].colorLayouts[i];
}
for(size_t i = 0; i < rpinfo.subpasses[subpass].inputAttachments.size(); i++)
{
atts.push_back(VkAttachmentReference());
atts.back().attachment = rpinfo.subpasses[subpass].inputAttachments[i];
atts.back().layout = rpinfo.subpasses[subpass].inputLayouts[i];
}
int32_t ds = rpinfo.subpasses[subpass].depthstencilAttachment;
if(ds != -1)
{
atts.push_back(VkAttachmentReference());
atts.back().attachment = (uint32_t)rpinfo.subpasses[subpass].depthstencilAttachment;
atts.back().layout = rpinfo.subpasses[subpass].depthstencilLayout;
}
}
for(size_t i = 0; i < atts.size(); i++)
{
uint32_t idx = atts[i].attachment;
VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
ResourceId view = fbinfo.attachments[idx].view;
barrier.subresourceRange = m_CreationInfo.m_ImageView[view].range;
barrier.image = Unwrap(
GetResourceManager()->GetCurrentHandle<VkImage>(m_CreationInfo.m_ImageView[view].image));
barrier.newLayout = atts[i].layout;
// search back from this subpass to see which layout it was in before. If it's
// not been used in a previous subpass, then default to initialLayout
barrier.oldLayout = rpinfo.attachments[idx].initialLayout;
if(subpass == ~0U)
subpass = (uint32_t)rpinfo.subpasses.size();
// subpass is at this point a 1-indexed value essentially, as it's the index
// of the subpass we just finished (or 0 if we're in BeginRenderPass in which
// case the loop just skips completely and we use initialLayout, which is
// correct).
for(uint32_t s = subpass; s > 0; s--)
{
bool found = false;
for(size_t a = 0; !found && a < rpinfo.subpasses[s - 1].colorAttachments.size(); a++)
{
if(rpinfo.subpasses[s - 1].colorAttachments[a] == idx)
{
barrier.oldLayout = rpinfo.subpasses[s - 1].colorLayouts[a];
found = true;
break;
}
}
if(found)
break;
for(size_t a = 0; !found && a < rpinfo.subpasses[s - 1].inputAttachments.size(); a++)
{
if(rpinfo.subpasses[s - 1].inputAttachments[a] == idx)
{
barrier.oldLayout = rpinfo.subpasses[s - 1].inputLayouts[a];
found = true;
break;
}
}
if(found)
break;
if((uint32_t)rpinfo.subpasses[s - 1].depthstencilAttachment == idx)
{
barrier.oldLayout = rpinfo.subpasses[s - 1].depthstencilLayout;
break;
}
}
ReplacePresentableImageLayout(barrier.oldLayout);
ReplacePresentableImageLayout(barrier.newLayout);
ret.push_back(barrier);
}
// erase any do-nothing barriers
for(auto it = ret.begin(); it != ret.end();)
{
if(it->oldLayout == it->newLayout)
it = ret.erase(it);
else
++it;
}
return ret;
}
string WrappedVulkan::MakeRenderPassOpString(bool store)
{
string opDesc = "";
@@ -33,7 +182,7 @@ string WrappedVulkan::MakeRenderPassOpString(bool store)
const VulkanCreationInfo::Framebuffer &fbinfo =
m_CreationInfo.m_Framebuffer[m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer];
const vector<VulkanCreationInfo::RenderPass::Attachment> &atts = info.attachments;
const vector<VkAttachmentDescription> &atts = info.attachments;
if(atts.empty())
{
@@ -680,6 +829,12 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(Serialiser *localSerialiser,
m_RenderState.renderPass = GetResourceManager()->GetNonDispWrapper(beginInfo.renderPass)->id;
m_RenderState.framebuffer = GetResourceManager()->GetNonDispWrapper(beginInfo.framebuffer)->id;
m_RenderState.renderArea = beginInfo.renderArea;
std::vector<VkImageMemoryBarrier> imgBarriers = GetImplicitRenderPassBarriers();
ResourceId cmd = GetResID(commandBuffer);
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts,
(uint32_t)imgBarriers.size(), &imgBarriers[0]);
}
}
else if(m_State == READING)
@@ -695,6 +850,12 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(Serialiser *localSerialiser,
m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer =
GetResourceManager()->GetNonDispWrapper(beginInfo.framebuffer)->id;
std::vector<VkImageMemoryBarrier> imgBarriers = GetImplicitRenderPassBarriers();
ResourceId cmd = GetResID(commandBuffer);
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts,
(uint32_t)imgBarriers.size(), &imgBarriers[0]);
const string desc = localSerialiser->GetDebugStr();
string opDesc = MakeRenderPassOpString(false);
@@ -738,16 +899,19 @@ void WrappedVulkan::vkCmdBeginRenderPass(VkCommandBuffer commandBuffer,
record->MarkResourceFrameReferenced(fb->GetResourceID(), eFrameRef_Read);
for(size_t i = 0; i < VkResourceRecord::MaxImageAttachments; i++)
{
if(fb->imageAttachments[i] == NULL)
VkResourceRecord *att = fb->imageAttachments[i].record;
if(att == NULL)
break;
record->MarkResourceFrameReferenced(fb->imageAttachments[i]->baseResource, eFrameRef_Write);
if(fb->imageAttachments[i]->baseResourceMem != ResourceId())
record->MarkResourceFrameReferenced(fb->imageAttachments[i]->baseResourceMem, eFrameRef_Read);
if(fb->imageAttachments[i]->sparseInfo)
record->cmdInfo->sparse.insert(fb->imageAttachments[i]->sparseInfo);
record->cmdInfo->dirtied.insert(fb->imageAttachments[i]->baseResource);
record->MarkResourceFrameReferenced(att->baseResource, eFrameRef_Write);
if(att->baseResourceMem != ResourceId())
record->MarkResourceFrameReferenced(att->baseResourceMem, eFrameRef_Read);
if(att->sparseInfo)
record->cmdInfo->sparse.insert(att->sparseInfo);
record->cmdInfo->dirtied.insert(att->baseResource);
}
record->cmdInfo->framebuffer = fb;
}
}
@@ -772,6 +936,12 @@ bool WrappedVulkan::Serialise_vkCmdNextSubpass(Serialiser *localSerialiser,
m_RenderState.subpass++;
ObjDisp(commandBuffer)->CmdNextSubpass(Unwrap(commandBuffer), cont);
std::vector<VkImageMemoryBarrier> imgBarriers = GetImplicitRenderPassBarriers();
ResourceId cmd = GetResID(commandBuffer);
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts,
(uint32_t)imgBarriers.size(), &imgBarriers[0]);
}
}
else if(m_State == READING)
@@ -783,6 +953,12 @@ bool WrappedVulkan::Serialise_vkCmdNextSubpass(Serialiser *localSerialiser,
// track while reading, for fetching the right set of outputs in AddDrawcall
m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass++;
std::vector<VkImageMemoryBarrier> imgBarriers = GetImplicitRenderPassBarriers();
ResourceId cmd = GetResID(commandBuffer);
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts,
(uint32_t)imgBarriers.size(), &imgBarriers[0]);
const string desc = localSerialiser->GetDebugStr();
AddEvent(NEXT_SUBPASS, desc);
@@ -833,6 +1009,12 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass(Serialiser *localSerialiser,
m_Partial[Primary].renderPassActive = false;
ObjDisp(commandBuffer)->CmdEndRenderPass(Unwrap(commandBuffer));
std::vector<VkImageMemoryBarrier> imgBarriers = GetImplicitRenderPassBarriers(~0U);
ResourceId cmd = GetResID(commandBuffer);
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts,
(uint32_t)imgBarriers.size(), &imgBarriers[0]);
}
}
else if(m_State == READING)
@@ -841,6 +1023,12 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass(Serialiser *localSerialiser,
ObjDisp(commandBuffer)->CmdEndRenderPass(Unwrap(commandBuffer));
std::vector<VkImageMemoryBarrier> imgBarriers = GetImplicitRenderPassBarriers(~0U);
ResourceId cmd = GetResID(commandBuffer);
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts,
(uint32_t)imgBarriers.size(), &imgBarriers[0]);
const string desc = localSerialiser->GetDebugStr();
string opDesc = MakeRenderPassOpString(true);
@@ -877,6 +1065,25 @@ void WrappedVulkan::vkCmdEndRenderPass(VkCommandBuffer commandBuffer)
Serialise_vkCmdEndRenderPass(localSerialiser, commandBuffer);
record->AddChunk(scope.Get());
VkResourceRecord *fb = record->cmdInfo->framebuffer;
std::vector<VkImageMemoryBarrier> barriers;
for(size_t i = 0; i < VkResourceRecord::MaxImageAttachments; i++)
{
if(fb->imageAttachments[i].barrier.oldLayout == fb->imageAttachments[i].barrier.newLayout)
continue;
barriers.push_back(fb->imageAttachments[i].barrier);
}
// apply the implicit layout transitions here
{
SCOPED_LOCK(m_ImageLayoutsLock);
GetResourceManager()->RecordBarriers(GetRecord(commandBuffer)->cmdInfo->imgbarriers,
m_ImageLayouts, (uint32_t)barriers.size(), &barriers[0]);
}
}
}
@@ -1635,7 +1842,7 @@ bool WrappedVulkan::Serialise_vkCmdPipelineBarrier(
(uint32_t)bufBarriers.size(), &bufBarriers[0],
(uint32_t)imgBarriers.size(), &imgBarriers[0]);
ResourceId cmd = GetResID(RerecordCmdBuf(cmdid));
ResourceId cmd = GetResID(commandBuffer);
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts,
(uint32_t)imgBarriers.size(), &imgBarriers[0]);
}
@@ -24,6 +24,40 @@
#include "../vk_core.h"
void WrappedVulkan::MakeSubpassLoadRP(VkRenderPassCreateInfo &info,
const VkRenderPassCreateInfo *origInfo, uint32_t s)
{
info.subpassCount = 1;
info.pSubpasses = origInfo->pSubpasses + s;
// remove any dependencies
info.dependencyCount = 0;
const VkSubpassDescription *sub = info.pSubpasses;
VkAttachmentDescription *att = (VkAttachmentDescription *)info.pAttachments;
// apply this subpass's attachment layouts to the initial and final layouts
// so that this RP doesn't perform any layout transitions
for(uint32_t a = 0; a < sub->colorAttachmentCount; a++)
{
att[sub->pColorAttachments[a].attachment].initialLayout =
att[sub->pColorAttachments[a].attachment].finalLayout = sub->pColorAttachments[a].layout;
}
for(uint32_t a = 0; a < sub->inputAttachmentCount; a++)
{
att[sub->pInputAttachments[a].attachment].initialLayout =
att[sub->pInputAttachments[a].attachment].finalLayout = sub->pInputAttachments[a].layout;
}
if(sub->pDepthStencilAttachment && sub->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
{
att[sub->pDepthStencilAttachment->attachment].initialLayout =
att[sub->pDepthStencilAttachment->attachment].finalLayout =
sub->pDepthStencilAttachment->layout;
}
}
// note, for threading reasons we ensure to release the wrappers before
// releasing the underlying object. Otherwise after releasing the vulkan object
// that same handle could be returned by create on another thread, and we
@@ -501,20 +535,26 @@ VkResult WrappedVulkan::vkCreateFramebuffer(VkDevice device,
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pFramebuffer);
record->AddChunk(chunk);
record->imageAttachments = new VkResourceRecord *[VkResourceRecord::MaxImageAttachments];
record->imageAttachments = new AttachmentInfo[VkResourceRecord::MaxImageAttachments];
RDCASSERT(pCreateInfo->attachmentCount <= VkResourceRecord::MaxImageAttachments);
RDCEraseMem(record->imageAttachments,
sizeof(VkResourceRecord *) * VkResourceRecord::MaxImageAttachments);
sizeof(AttachmentInfo) * VkResourceRecord::MaxImageAttachments);
VkResourceRecord *rpRecord = GetRecord(pCreateInfo->renderPass);
record->AddParent(rpRecord);
if(pCreateInfo->renderPass != VK_NULL_HANDLE)
record->AddParent(GetRecord(pCreateInfo->renderPass));
for(uint32_t i = 0; i < pCreateInfo->attachmentCount; i++)
{
VkResourceRecord *attRecord = GetRecord(pCreateInfo->pAttachments[i]);
record->AddParent(attRecord);
record->imageAttachments[i] = attRecord;
record->imageAttachments[i].record = attRecord;
record->imageAttachments[i].barrier = rpRecord->imageAttachments[i].barrier;
record->imageAttachments[i].barrier.image =
GetResourceManager()->GetCurrentHandle<VkImage>(attRecord->baseResource);
record->imageAttachments[i].barrier.subresourceRange = attRecord->viewRange;
}
}
else
@@ -547,12 +587,20 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass(Serialiser *localSerialiser, Vk
// we want to store off the data so we can display it after the pass.
// override any user-specified DONT_CARE.
// Likewise we don't want to throw away data before we're ready, so change
// any load ops to LOAD instead of DONT_CARE (which is valid!). We of course
// leave any LOAD_OP_CLEAR alone.
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;
if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
// renderpass can't start or end in presentable layout on replay
ReplacePresentableImageLayout(att[i].initialLayout);
ReplacePresentableImageLayout(att[i].finalLayout);
@@ -593,28 +641,39 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass(Serialiser *localSerialiser, Vk
att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
}
ret = ObjDisp(device)->CreateRenderPass(Unwrap(device), &info, NULL, &rpinfo.loadRP);
RDCASSERTEQUAL(ret, VK_SUCCESS);
VkRenderPassCreateInfo loadInfo = info;
// handle the loadRP being a duplicate
if(GetResourceManager()->HasWrapper(ToTypedHandle(rpinfo.loadRP)))
rpinfo.loadRPs.resize(info.subpassCount);
// create a render pass for each subpass that maintains attachment layouts
for(uint32_t s = 0; s < info.subpassCount; s++)
{
// just fetch the existing wrapped object
rpinfo.loadRP =
(VkRenderPass)(uint64_t)GetResourceManager()->GetNonDispWrapper(rpinfo.loadRP);
MakeSubpassLoadRP(loadInfo, &info, s);
// 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);
ret = ObjDisp(device)->CreateRenderPass(Unwrap(device), &info, NULL, &rpinfo.loadRPs[s]);
RDCASSERTEQUAL(ret, VK_SUCCESS);
// don't need to ReplaceResource as no IDs are involved
}
else
{
ResourceId loadRPid = GetResourceManager()->WrapResource(Unwrap(device), rpinfo.loadRP);
// handle the loadRP being a duplicate
if(GetResourceManager()->HasWrapper(ToTypedHandle(rpinfo.loadRPs[s])))
{
// just fetch the existing wrapped object
rpinfo.loadRPs[s] =
(VkRenderPass)(uint64_t)GetResourceManager()->GetNonDispWrapper(rpinfo.loadRPs[s]);
// register as a live-only resource, so it is cleaned up properly
GetResourceManager()->AddLiveResource(loadRPid, 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.loadRPs[s], NULL);
// don't need to ReplaceResource as no IDs are involved
}
else
{
ResourceId loadRPid =
GetResourceManager()->WrapResource(Unwrap(device), rpinfo.loadRPs[s]);
// register as a live-only resource, so it is cleaned up properly
GetResourceManager()->AddLiveResource(loadRPid, rpinfo.loadRPs[s]);
}
}
m_CreationInfo.m_RenderPass[live] = rpinfo;
@@ -651,6 +710,20 @@ VkResult WrappedVulkan::vkCreateRenderPass(VkDevice device, const VkRenderPassCr
VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pRenderPass);
record->AddChunk(chunk);
record->imageAttachments = new AttachmentInfo[VkResourceRecord::MaxImageAttachments];
RDCASSERT(pCreateInfo->attachmentCount <= VkResourceRecord::MaxImageAttachments);
RDCEraseMem(record->imageAttachments,
sizeof(AttachmentInfo) * VkResourceRecord::MaxImageAttachments);
for(uint32_t i = 0; i < pCreateInfo->attachmentCount; i++)
{
record->imageAttachments[i].record = NULL;
record->imageAttachments[i].barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
record->imageAttachments[i].barrier.oldLayout = pCreateInfo->pAttachments[i].initialLayout;
record->imageAttachments[i].barrier.newLayout = pCreateInfo->pAttachments[i].finalLayout;
}
}
else
{
@@ -676,13 +749,21 @@ VkResult WrappedVulkan::vkCreateRenderPass(VkDevice device, const VkRenderPassCr
info.pAttachments = atts;
ret = ObjDisp(device)->CreateRenderPass(Unwrap(device), &info, NULL, &rpinfo.loadRP);
RDCASSERTEQUAL(ret, VK_SUCCESS);
rpinfo.loadRPs.resize(pCreateInfo->subpassCount);
ResourceId loadRPid = GetResourceManager()->WrapResource(Unwrap(device), rpinfo.loadRP);
// create a render pass for each subpass that maintains attachment layouts
for(uint32_t s = 0; s < pCreateInfo->subpassCount; s++)
{
MakeSubpassLoadRP(info, pCreateInfo, s);
// register as a live-only resource, so it is cleaned up properly
GetResourceManager()->AddLiveResource(loadRPid, rpinfo.loadRP);
ret = ObjDisp(device)->CreateRenderPass(Unwrap(device), &info, NULL, &rpinfo.loadRPs[s]);
RDCASSERTEQUAL(ret, VK_SUCCESS);
ResourceId loadRPid = GetResourceManager()->WrapResource(Unwrap(device), rpinfo.loadRPs[s]);
// register as a live-only resource, so it is cleaned up properly
GetResourceManager()->AddLiveResource(loadRPid, rpinfo.loadRPs[s]);
}
m_CreationInfo.m_RenderPass[id] = rpinfo;
}
@@ -1254,6 +1254,7 @@ VkResult WrappedVulkan::vkCreateImageView(VkDevice device, const VkImageViewCrea
record->baseResource = imageRecord->GetResourceID();
record->baseResourceMem = imageRecord->baseResource;
record->sparseInfo = imageRecord->sparseInfo;
record->viewRange = pCreateInfo->subresourceRange;
}
else
{