Patch imageless framebuffer image usage/formats to match image patching

This commit is contained in:
baldurk
2021-04-12 17:19:59 +01:00
parent 3bc996116d
commit 02e8e8fdf7
7 changed files with 193 additions and 33 deletions
+3
View File
@@ -844,6 +844,9 @@ private:
template <class T>
T *UnwrapInfos(const T *infos, uint32_t count);
void PatchAttachment(VkFramebufferAttachmentImageInfo *att, VkFormat imgFormat,
VkSampleCountFlagBits samples);
VkIndirectPatchData FetchIndirectData(VkIndirectPatchType type, VkCommandBuffer commandBuffer,
VkBuffer dataBuffer, VkDeviceSize dataOffset, uint32_t count,
uint32_t stride = 0, VkBuffer counterBuffer = VK_NULL_HANDLE,
+84 -3
View File
@@ -162,9 +162,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct,
COPY_STRUCT(VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, VkFenceCreateInfo); \
COPY_STRUCT(VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT, \
VkFilterCubicImageViewImageFormatPropertiesEXT); \
COPY_STRUCT(VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO, \
VkFramebufferAttachmentsCreateInfo) \
COPY_STRUCT(VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO, VkFramebufferAttachmentImageInfo) \
COPY_STRUCT(VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, VkFormatProperties2); \
COPY_STRUCT(VK_STRUCTURE_TYPE_HDR_METADATA_EXT, VkHdrMetadataEXT) \
COPY_STRUCT(VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR, VkImageBlit2KHR); \
@@ -897,6 +894,32 @@ size_t GetNextPatchSize(const void *pNext)
memSize += info->attachmentCount * sizeof(VkImageView);
break;
}
// this struct doesn't really need to be unwrapped but we allocate space for it since it
// contains arrays that we will very commonly need to patch, to adjust image info/formats.
// this saves us needing to iterate it outside and allocate extra space
case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO:
{
memSize += sizeof(VkFramebufferAttachmentsCreateInfo);
VkFramebufferAttachmentsCreateInfo *info = (VkFramebufferAttachmentsCreateInfo *)next;
memSize += info->attachmentImageInfoCount * sizeof(VkFramebufferAttachmentImageInfo);
for(uint32_t i = 0; i < info->attachmentImageInfoCount; i++)
memSize += GetNextPatchSize(&info->pAttachmentImageInfos[i]);
break;
}
case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO:
{
memSize += sizeof(VkFramebufferAttachmentImageInfo);
// we add space for an extra VkFormat so we can push one onto the list
VkFramebufferAttachmentImageInfo *info = (VkFramebufferAttachmentImageInfo *)next;
if(info->viewFormatCount > 0)
memSize += (info->viewFormatCount + 1) * sizeof(VkFormat);
break;
}
case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO:
{
memSize += sizeof(VkGraphicsPipelineCreateInfo);
@@ -1624,6 +1647,56 @@ void UnwrapNextChain(CaptureState state, const char *structName, byte *&tempMem,
break;
}
// this struct doesn't really need to be unwrapped but we allocate space for it since it
// contains arrays that we will very commonly need to patch, to adjust image info/formats.
// this saves us needing to iterate it outside and allocate extra space
case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO:
{
const VkFramebufferAttachmentsCreateInfo *in =
(const VkFramebufferAttachmentsCreateInfo *)nextInput;
VkFramebufferAttachmentsCreateInfo *out = (VkFramebufferAttachmentsCreateInfo *)tempMem;
// append immediately so tempMem is incremented
AppendModifiedChainedStruct(tempMem, out, nextChainTail);
// allocate unwrapped array
VkFramebufferAttachmentImageInfo *outAtts = (VkFramebufferAttachmentImageInfo *)tempMem;
tempMem += sizeof(VkFramebufferAttachmentImageInfo) * in->attachmentImageInfoCount;
*out = *in;
out->pAttachmentImageInfos = outAtts;
for(uint32_t i = 0; i < in->attachmentImageInfoCount; i++)
{
outAtts[i] = in->pAttachmentImageInfos[i];
UnwrapNextChain(state, "VkFramebufferAttachmentImageInfo", tempMem,
(VkBaseInStructure *)&outAtts[i]);
}
break;
}
case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO:
{
const VkFramebufferAttachmentImageInfo *in =
(const VkFramebufferAttachmentImageInfo *)nextInput;
VkFramebufferAttachmentImageInfo *out = (VkFramebufferAttachmentImageInfo *)tempMem;
// append immediately so tempMem is incremented
AppendModifiedChainedStruct(tempMem, out, nextChainTail);
*out = *in;
// allocate extra array
if(in->viewFormatCount > 0)
{
VkFormat *outFormats = (VkFormat *)tempMem;
tempMem += sizeof(VkFormat) * (in->viewFormatCount + 1);
out->pViewFormats = outFormats;
memcpy(outFormats, in->pViewFormats, sizeof(VkFormat) * in->viewFormatCount);
}
break;
}
case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO:
{
const VkGraphicsPipelineCreateInfo *in = (const VkGraphicsPipelineCreateInfo *)nextInput;
@@ -2192,6 +2265,14 @@ void CopyNextChainForPatching(const char *structName, byte *&tempMem, VkBaseInSt
case VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO:
CopyNextChainedStruct(sizeof(VkFramebufferCreateInfo), tempMem, nextInput, nextChainTail);
break;
case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO:
CopyNextChainedStruct(sizeof(VkFramebufferAttachmentsCreateInfo), tempMem, nextInput,
nextChainTail);
break;
case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO:
CopyNextChainedStruct(sizeof(VkFramebufferAttachmentImageInfo), tempMem, nextInput,
nextChainTail);
break;
case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO:
CopyNextChainedStruct(sizeof(VkGraphicsPipelineCreateInfo), tempMem, nextInput,
nextChainTail);
+4
View File
@@ -3251,6 +3251,8 @@ RenderPassInfo::RenderPassInfo(const VkRenderPassCreateInfo &ci)
imageAttachments[i].barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageAttachments[i].barrier.oldLayout = ci.pAttachments[i].initialLayout;
imageAttachments[i].barrier.newLayout = ci.pAttachments[i].finalLayout;
imageAttachments[i].format = ci.pAttachments[i].format;
imageAttachments[i].samples = ci.pAttachments[i].samples;
}
// VK_KHR_multiview
@@ -3383,6 +3385,8 @@ RenderPassInfo::RenderPassInfo(const VkRenderPassCreateInfo2 &ci)
imageAttachments[a].barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageAttachments[a].barrier.oldLayout = ci.pAttachments[i].initialLayout;
imageAttachments[a].barrier.newLayout = ci.pAttachments[i].finalLayout;
imageAttachments[i].format = ci.pAttachments[i].format;
imageAttachments[i].samples = ci.pAttachments[i].samples;
indexRemapTable[i] = a;
+3
View File
@@ -1147,6 +1147,9 @@ struct AttachmentInfo
{
VkResourceRecord *record;
VkFormat format;
VkSampleCountFlagBits samples;
// 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
@@ -23,6 +23,7 @@
******************************************************************************/
#include "../vk_core.h"
#include "../vk_debug.h"
static void PatchSeparateStencil(VkAttachmentDescription &att, const VkAttachmentReference *ref)
{
@@ -144,24 +145,6 @@ static void MakeSubpassLoadRP(RPCreateInfo &info, const RPCreateInfo *origInfo,
}
}
template <>
VkFramebufferCreateInfo WrappedVulkan::UnwrapInfo(const VkFramebufferCreateInfo *info)
{
VkFramebufferCreateInfo ret = *info;
if((ret.flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) == 0)
{
VkImageView *unwrapped = GetTempArray<VkImageView>(info->attachmentCount);
for(uint32_t i = 0; i < info->attachmentCount; i++)
unwrapped[i] = Unwrap(info->pAttachments[i]);
ret.pAttachments = unwrapped;
}
ret.renderPass = Unwrap(ret.renderPass);
return ret;
}
// 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
@@ -653,6 +636,36 @@ VkResult WrappedVulkan::vkCreateSampler(VkDevice device, const VkSamplerCreateIn
return ret;
}
void WrappedVulkan::PatchAttachment(VkFramebufferAttachmentImageInfo *att, VkFormat imgFormat,
VkSampleCountFlagBits samples)
{
// this matches the mutations we do to images, so see vkCreateImage
att->usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
att->usage |= VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
att->usage &= ~VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
if(IsYUVFormat(imgFormat))
att->flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
if(samples != VK_SAMPLE_COUNT_1_BIT)
{
att->usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
att->flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
if(!IsDepthOrStencilFormat(imgFormat))
{
if(GetDebugManager() && GetShaderCache()->IsArray2MSSupported())
att->usage |= VK_IMAGE_USAGE_STORAGE_BIT;
}
else
{
att->usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
}
att->flags &= ~VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT;
}
template <typename SerialiserType>
bool WrappedVulkan::Serialise_vkCreateFramebuffer(SerialiserType &ser, VkDevice device,
const VkFramebufferCreateInfo *pCreateInfo,
@@ -670,8 +683,25 @@ bool WrappedVulkan::Serialise_vkCreateFramebuffer(SerialiserType &ser, VkDevice
{
VkFramebuffer fb = VK_NULL_HANDLE;
VkFramebufferCreateInfo unwrapped = UnwrapInfo(&CreateInfo);
VkResult ret = ObjDisp(device)->CreateFramebuffer(Unwrap(device), &unwrapped, NULL, &fb);
byte *tempMem = GetTempMemory(GetNextPatchSize(&CreateInfo));
VkFramebufferCreateInfo *unwrappedInfo = UnwrapStructAndChain(m_State, tempMem, &CreateInfo);
const VulkanCreationInfo::RenderPass &rpinfo =
m_CreationInfo.m_RenderPass[GetResID(CreateInfo.renderPass)];
VkFramebufferAttachmentsCreateInfo *attachmentsInfo =
(VkFramebufferAttachmentsCreateInfo *)FindNextStruct(
unwrappedInfo, VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO);
for(uint32_t a = 0; attachmentsInfo && a < attachmentsInfo->attachmentImageInfoCount; a++)
{
VkFramebufferAttachmentImageInfo *att =
(VkFramebufferAttachmentImageInfo *)&attachmentsInfo->pAttachmentImageInfos[a];
PatchAttachment(att, rpinfo.attachments[a].format, rpinfo.attachments[a].samples);
}
VkResult ret = ObjDisp(device)->CreateFramebuffer(Unwrap(device), unwrappedInfo, NULL, &fb);
if(ret != VK_SUCCESS)
{
@@ -701,17 +731,14 @@ bool WrappedVulkan::Serialise_vkCreateFramebuffer(SerialiserType &ser, VkDevice
VulkanCreationInfo::Framebuffer fbinfo;
fbinfo.Init(GetResourceManager(), m_CreationInfo, &CreateInfo);
const VulkanCreationInfo::RenderPass &rpinfo =
m_CreationInfo.m_RenderPass[GetResID(CreateInfo.renderPass)];
fbinfo.loadFBs.resize(rpinfo.loadRPs.size());
// create a render pass for each subpass that maintains attachment layouts
for(size_t s = 0; s < fbinfo.loadFBs.size(); s++)
{
unwrapped.renderPass = Unwrap(rpinfo.loadRPs[s]);
unwrappedInfo->renderPass = Unwrap(rpinfo.loadRPs[s]);
ret = ObjDisp(device)->CreateFramebuffer(Unwrap(device), &unwrapped, NULL,
ret = ObjDisp(device)->CreateFramebuffer(Unwrap(device), unwrappedInfo, NULL,
&fbinfo.loadFBs[s]);
RDCASSERTEQUAL(ret, VK_SUCCESS);
@@ -761,9 +788,34 @@ VkResult WrappedVulkan::vkCreateFramebuffer(VkDevice device,
const VkAllocationCallbacks *pAllocator,
VkFramebuffer *pFramebuffer)
{
VkFramebufferCreateInfo unwrapped = UnwrapInfo(pCreateInfo);
byte *tempMem = GetTempMemory(GetNextPatchSize(pCreateInfo));
VkFramebufferCreateInfo *unwrappedInfo = UnwrapStructAndChain(m_State, tempMem, pCreateInfo);
VkFramebufferAttachmentsCreateInfo *attachmentsInfo =
(VkFramebufferAttachmentsCreateInfo *)FindNextStruct(
unwrappedInfo, VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO);
AttachmentInfo *capAtts = NULL;
VulkanCreationInfo::RenderPass::Attachment *replayAtts = NULL;
if(IsCaptureMode(m_State))
capAtts = GetRecord(pCreateInfo->renderPass)->renderPassInfo->imageAttachments;
else
replayAtts = m_CreationInfo.m_RenderPass[GetResID(pCreateInfo->renderPass)].attachments.data();
// this matches the mutations we do to images, so see vkCreateImage
for(uint32_t a = 0; attachmentsInfo && a < attachmentsInfo->attachmentImageInfoCount; a++)
{
VkFramebufferAttachmentImageInfo *att =
(VkFramebufferAttachmentImageInfo *)&attachmentsInfo->pAttachmentImageInfos[a];
if(IsCaptureMode(m_State))
PatchAttachment(att, capAtts[a].format, capAtts[a].samples);
else
PatchAttachment(att, replayAtts[a].format, replayAtts[a].samples);
}
VkResult ret;
SERIALISE_TIME_CALL(ret = ObjDisp(device)->CreateFramebuffer(Unwrap(device), &unwrapped,
SERIALISE_TIME_CALL(ret = ObjDisp(device)->CreateFramebuffer(Unwrap(device), unwrappedInfo,
pAllocator, pFramebuffer));
if(ret == VK_SUCCESS)
@@ -795,6 +847,8 @@ VkResult WrappedVulkan::vkCreateFramebuffer(VkDevice device,
for(uint32_t i = 0, a = 0; i < pCreateInfo->attachmentCount; i++, a++)
{
fbInfo->imageAttachments[a].barrier = rpInfo->imageAttachments[a].barrier;
fbInfo->imageAttachments[a].format = rpInfo->imageAttachments[a].format;
fbInfo->imageAttachments[a].samples = rpInfo->imageAttachments[a].samples;
if((pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) == 0)
{
@@ -854,10 +908,10 @@ VkResult WrappedVulkan::vkCreateFramebuffer(VkDevice device,
// create a render pass for each subpass that maintains attachment layouts
for(size_t s = 0; s < fbinfo.loadFBs.size(); s++)
{
unwrapped.renderPass = Unwrap(rpinfo.loadRPs[s]);
unwrappedInfo->renderPass = Unwrap(rpinfo.loadRPs[s]);
ret =
ObjDisp(device)->CreateFramebuffer(Unwrap(device), &unwrapped, NULL, &fbinfo.loadFBs[s]);
ret = ObjDisp(device)->CreateFramebuffer(Unwrap(device), unwrappedInfo, NULL,
&fbinfo.loadFBs[s]);
RDCASSERTEQUAL(ret, VK_SUCCESS);
ResourceId loadFBid = GetResourceManager()->WrapResource(Unwrap(device), fbinfo.loadFBs[s]);
@@ -668,6 +668,18 @@ VkResult WrappedVulkan::vkCreateSwapchainKHR(VkDevice device,
// make sure we can readback to get the screenshot, and render to it for the text overlay
createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
// if the surface supports them, add usage bits we don't need to look more like normal images
// (which is important when patching imageless framebuffer usage)
VkSurfaceCapabilitiesKHR surfCap = {};
ObjDisp(m_PhysicalDevice)
->GetPhysicalDeviceSurfaceCapabilitiesKHR(Unwrap(m_PhysicalDevice),
Unwrap(createInfo.surface), &surfCap);
if(surfCap.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT)
createInfo.imageUsage |= VK_IMAGE_USAGE_SAMPLED_BIT;
if(surfCap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
createInfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
createInfo.surface = Unwrap(createInfo.surface);
createInfo.oldSwapchain = Unwrap(createInfo.oldSwapchain);
@@ -174,6 +174,9 @@ void main()
Present();
}
vkDeviceWaitIdle(device);
vkDestroyFramebuffer(device, fb, NULL);
return 0;
}
};