diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 3f29e95ef..715237e15 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -654,8 +654,8 @@ DECLARE_REFLECTION_STRUCT(VkBindImageMemorySwapchainInfoKHR); DECLARE_REFLECTION_STRUCT(VkBindImagePlaneMemoryInfo); DECLARE_REFLECTION_STRUCT(VkBindSparseInfo); DECLARE_REFLECTION_STRUCT(VkBufferCreateInfo); -DECLARE_REFLECTION_STRUCT(VkBufferDeviceAddressInfoEXT); DECLARE_REFLECTION_STRUCT(VkBufferDeviceAddressCreateInfoEXT); +DECLARE_REFLECTION_STRUCT(VkBufferDeviceAddressInfoEXT); DECLARE_REFLECTION_STRUCT(VkBufferMemoryBarrier); DECLARE_REFLECTION_STRUCT(VkBufferMemoryRequirementsInfo2); DECLARE_REFLECTION_STRUCT(VkBufferViewCreateInfo); @@ -725,6 +725,8 @@ DECLARE_REFLECTION_STRUCT(VkExternalSemaphoreProperties); DECLARE_REFLECTION_STRUCT(VkFenceCreateInfo); DECLARE_REFLECTION_STRUCT(VkFenceGetFdInfoKHR); DECLARE_REFLECTION_STRUCT(VkFormatProperties2); +DECLARE_REFLECTION_STRUCT(VkFramebufferAttachmentImageInfoKHR); +DECLARE_REFLECTION_STRUCT(VkFramebufferAttachmentsCreateInfoKHR); DECLARE_REFLECTION_STRUCT(VkFramebufferCreateInfo); DECLARE_REFLECTION_STRUCT(VkGraphicsPipelineCreateInfo); DECLARE_REFLECTION_STRUCT(VkHdrMetadataEXT); @@ -734,8 +736,8 @@ DECLARE_REFLECTION_STRUCT(VkImageFormatProperties2); DECLARE_REFLECTION_STRUCT(VkImageMemoryBarrier); DECLARE_REFLECTION_STRUCT(VkImageMemoryRequirementsInfo2); DECLARE_REFLECTION_STRUCT(VkImagePlaneMemoryRequirementsInfo); -DECLARE_REFLECTION_STRUCT(VkImageStencilUsageCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkImageSparseMemoryRequirementsInfo2); +DECLARE_REFLECTION_STRUCT(VkImageStencilUsageCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkImageSwapchainCreateInfoKHR); DECLARE_REFLECTION_STRUCT(VkImageViewASTCDecodeModeEXT); DECLARE_REFLECTION_STRUCT(VkImageViewCreateInfo); @@ -782,6 +784,7 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceGroupProperties); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceHostQueryResetFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceIDProperties); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceImageFormatInfo2); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceImagelessFramebufferFeaturesKHR); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceIndexTypeUint8FeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceMaintenance3Properties); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceMemoryBudgetPropertiesEXT); @@ -812,15 +815,15 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceTransformFeedbackFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceTransformFeedbackPropertiesEXT); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceVariablePointerFeatures); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT); -DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceVulkanMemoryModelFeaturesKHR); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceYcbcrImageArraysFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPipelineCacheCreateInfo); -DECLARE_REFLECTION_STRUCT(VkPipelineCreationFeedbackCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkPipelineColorBlendStateCreateInfo); +DECLARE_REFLECTION_STRUCT(VkPipelineCreationFeedbackCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkPipelineDepthStencilStateCreateInfo); DECLARE_REFLECTION_STRUCT(VkPipelineDiscardRectangleStateCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkPipelineDynamicStateCreateInfo); @@ -843,6 +846,7 @@ DECLARE_REFLECTION_STRUCT(VkPresentRegionsKHR); DECLARE_REFLECTION_STRUCT(VkProtectedSubmitInfo); DECLARE_REFLECTION_STRUCT(VkQueryPoolCreateInfo); DECLARE_REFLECTION_STRUCT(VkQueueFamilyProperties2); +DECLARE_REFLECTION_STRUCT(VkRenderPassAttachmentBeginInfoKHR); DECLARE_REFLECTION_STRUCT(VkRenderPassBeginInfo); DECLARE_REFLECTION_STRUCT(VkRenderPassCreateInfo); DECLARE_REFLECTION_STRUCT(VkRenderPassCreateInfo2KHR); @@ -966,6 +970,8 @@ DECLARE_DESERIALISE_TYPE(VkExternalSemaphoreProperties); DECLARE_DESERIALISE_TYPE(VkFenceCreateInfo); DECLARE_DESERIALISE_TYPE(VkFenceGetFdInfoKHR); DECLARE_DESERIALISE_TYPE(VkFormatProperties2); +DECLARE_DESERIALISE_TYPE(VkFramebufferAttachmentImageInfoKHR); +DECLARE_DESERIALISE_TYPE(VkFramebufferAttachmentsCreateInfoKHR); DECLARE_DESERIALISE_TYPE(VkFramebufferCreateInfo); DECLARE_DESERIALISE_TYPE(VkGraphicsPipelineCreateInfo); DECLARE_DESERIALISE_TYPE(VkImageCreateInfo); @@ -974,8 +980,8 @@ DECLARE_DESERIALISE_TYPE(VkImageFormatProperties2); DECLARE_DESERIALISE_TYPE(VkImageMemoryBarrier); DECLARE_DESERIALISE_TYPE(VkImageMemoryRequirementsInfo2); DECLARE_DESERIALISE_TYPE(VkImagePlaneMemoryRequirementsInfo); -DECLARE_DESERIALISE_TYPE(VkImageStencilUsageCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkImageSparseMemoryRequirementsInfo2); +DECLARE_DESERIALISE_TYPE(VkImageStencilUsageCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkImageSwapchainCreateInfoKHR); DECLARE_DESERIALISE_TYPE(VkImageViewASTCDecodeModeEXT); DECLARE_DESERIALISE_TYPE(VkImageViewCreateInfo); @@ -1021,6 +1027,7 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceGroupProperties); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceHostQueryResetFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceIDProperties); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceImageFormatInfo2); +DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceImagelessFramebufferFeaturesKHR); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceIndexTypeUint8FeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceMaintenance3Properties); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceMemoryBudgetPropertiesEXT); @@ -1051,15 +1058,15 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceTransformFeedbackFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceTransformFeedbackPropertiesEXT); +DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceVariablePointerFeatures); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT); -DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceVulkanMemoryModelFeaturesKHR); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceYcbcrImageArraysFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPipelineCacheCreateInfo); -DECLARE_DESERIALISE_TYPE(VkPipelineCreationFeedbackCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkPipelineColorBlendStateCreateInfo); +DECLARE_DESERIALISE_TYPE(VkPipelineCreationFeedbackCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkPipelineDepthStencilStateCreateInfo); DECLARE_DESERIALISE_TYPE(VkPipelineDiscardRectangleStateCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkPipelineDynamicStateCreateInfo); @@ -1082,6 +1089,7 @@ DECLARE_DESERIALISE_TYPE(VkPresentRegionsKHR); DECLARE_DESERIALISE_TYPE(VkProtectedSubmitInfo); DECLARE_DESERIALISE_TYPE(VkQueryPoolCreateInfo); DECLARE_DESERIALISE_TYPE(VkQueueFamilyProperties2); +DECLARE_DESERIALISE_TYPE(VkRenderPassAttachmentBeginInfoKHR); DECLARE_DESERIALISE_TYPE(VkRenderPassBeginInfo); DECLARE_DESERIALISE_TYPE(VkRenderPassCreateInfo); DECLARE_DESERIALISE_TYPE(VkRenderPassCreateInfo2KHR); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index d37fbe9d6..a49e8ecb2 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -915,6 +915,9 @@ static const VkExtensionProperties supportedExtensions[] = { { VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION, }, + { + VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME, VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION, + }, { VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION, }, @@ -3589,8 +3592,7 @@ void WrappedVulkan::AddDrawcall(const DrawcallDescription &d, bool hasEvents) if(fb != ResourceId() && rp != ResourceId()) { - std::vector &atts = - m_CreationInfo.m_Framebuffer[fb].attachments; + std::vector &atts = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments; RDCASSERT(sp < m_CreationInfo.m_RenderPass[rp].subpasses.size()); @@ -3605,15 +3607,15 @@ void WrappedVulkan::AddDrawcall(const DrawcallDescription &d, bool hasEvents) continue; RDCASSERT(colAtt[i] < atts.size()); - draw.outputs[i] = GetResourceManager()->GetOriginalID( - m_CreationInfo.m_ImageView[atts[colAtt[i]].view].image); + draw.outputs[i] = + GetResourceManager()->GetOriginalID(m_CreationInfo.m_ImageView[atts[colAtt[i]]].image); } if(dsAtt != -1) { RDCASSERT(dsAtt < (int32_t)atts.size()); draw.depthOut = - GetResourceManager()->GetOriginalID(m_CreationInfo.m_ImageView[atts[dsAtt].view].image); + GetResourceManager()->GetOriginalID(m_CreationInfo.m_ImageView[atts[dsAtt]].image); } } } @@ -3837,11 +3839,13 @@ void WrappedVulkan::AddUsage(VulkanDrawcallTreeNode &drawNode, ////////////////////////////// // Framebuffer/renderpass - AddFramebufferUsage(drawNode, state.renderPass, state.framebuffer, state.subpass); + AddFramebufferUsage(drawNode, state.renderPass, state.framebuffer, state.subpass, + state.fbattachments); } void WrappedVulkan::AddFramebufferUsage(VulkanDrawcallTreeNode &drawNode, ResourceId renderPass, - ResourceId framebuffer, uint32_t subpass) + ResourceId framebuffer, uint32_t subpass, + const std::vector &fbattachments) { VulkanCreationInfo &c = m_CreationInfo; uint32_t e = drawNode.draw.eventId; @@ -3849,7 +3853,6 @@ void WrappedVulkan::AddFramebufferUsage(VulkanDrawcallTreeNode &drawNode, Resour if(renderPass != ResourceId() && framebuffer != ResourceId()) { const VulkanCreationInfo::RenderPass &rp = c.m_RenderPass[renderPass]; - const VulkanCreationInfo::Framebuffer &fb = c.m_Framebuffer[framebuffer]; if(subpass >= rp.subpasses.size()) { @@ -3866,8 +3869,8 @@ void WrappedVulkan::AddFramebufferUsage(VulkanDrawcallTreeNode &drawNode, Resour if(att == VK_ATTACHMENT_UNUSED) continue; drawNode.resourceUsage.push_back( - make_rdcpair(c.m_ImageView[fb.attachments[att].view].image, - EventUsage(e, ResourceUsage::InputTarget, fb.attachments[att].view))); + make_rdcpair(c.m_ImageView[fbattachments[att]].image, + EventUsage(e, ResourceUsage::InputTarget, fbattachments[att]))); } for(size_t i = 0; i < sub.colorAttachments.size(); i++) @@ -3876,16 +3879,16 @@ void WrappedVulkan::AddFramebufferUsage(VulkanDrawcallTreeNode &drawNode, Resour if(att == VK_ATTACHMENT_UNUSED) continue; drawNode.resourceUsage.push_back( - make_rdcpair(c.m_ImageView[fb.attachments[att].view].image, - EventUsage(e, ResourceUsage::ColorTarget, fb.attachments[att].view))); + make_rdcpair(c.m_ImageView[fbattachments[att]].image, + EventUsage(e, ResourceUsage::ColorTarget, fbattachments[att]))); } if(sub.depthstencilAttachment >= 0) { int32_t att = sub.depthstencilAttachment; - drawNode.resourceUsage.push_back(make_rdcpair( - c.m_ImageView[fb.attachments[att].view].image, - EventUsage(e, ResourceUsage::DepthStencilTarget, fb.attachments[att].view))); + drawNode.resourceUsage.push_back( + make_rdcpair(c.m_ImageView[fbattachments[att]].image, + EventUsage(e, ResourceUsage::DepthStencilTarget, fbattachments[att]))); } } } @@ -3893,12 +3896,13 @@ void WrappedVulkan::AddFramebufferUsage(VulkanDrawcallTreeNode &drawNode, Resour void WrappedVulkan::AddFramebufferUsageAllChildren(VulkanDrawcallTreeNode &drawNode, ResourceId renderPass, ResourceId framebuffer, - uint32_t subpass) + uint32_t subpass, + const std::vector &fbattachments) { for(VulkanDrawcallTreeNode &c : drawNode.children) - AddFramebufferUsageAllChildren(c, renderPass, framebuffer, subpass); + AddFramebufferUsageAllChildren(c, renderPass, framebuffer, subpass, fbattachments); - AddFramebufferUsage(drawNode, renderPass, framebuffer, subpass); + AddFramebufferUsage(drawNode, renderPass, framebuffer, subpass, fbattachments); } void WrappedVulkan::AddEvent() diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index e1e6cdbf9..2223914b6 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -544,6 +544,7 @@ private: ResourceId renderPass; ResourceId framebuffer; + std::vector fbattachments; uint32_t subpass = 0; struct ConditionalRendering @@ -877,9 +878,11 @@ private: void AddUsage(VulkanDrawcallTreeNode &drawNode, std::vector &debugMessages); void AddFramebufferUsage(VulkanDrawcallTreeNode &drawNode, ResourceId renderPass, - ResourceId framebuffer, uint32_t subpass); + ResourceId framebuffer, uint32_t subpass, + const std::vector &fbattachments); void AddFramebufferUsageAllChildren(VulkanDrawcallTreeNode &drawNode, ResourceId renderPass, - ResourceId framebuffer, uint32_t subpass); + ResourceId framebuffer, uint32_t subpass, + const std::vector &fbattachments); // no copy semantics WrappedVulkan(const WrappedVulkan &); diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 274c40420..4d8e7cbad 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -801,11 +801,38 @@ void VulkanCreationInfo::Framebuffer::Init(VulkanResourceManager *resourceMan, height = pCreateInfo->height; layers = pCreateInfo->layers; + imageless = false; + attachments.resize(pCreateInfo->attachmentCount); - for(uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) + if(pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR) { - attachments[i].view = GetResID(pCreateInfo->pAttachments[i]); - attachments[i].format = info.m_ImageView[attachments[i].view].format; + imageless = true; + + // VK_KHR_imageless_framebuffer + const VkFramebufferAttachmentsCreateInfoKHR *attachmentsInfo = + (const VkFramebufferAttachmentsCreateInfoKHR *)FindNextStruct( + pCreateInfo, VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR); + + RDCASSERTEQUAL(pCreateInfo->attachmentCount, attachmentsInfo->attachmentImageInfoCount); + + for(uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) + { + attachments[i].createdView = ResourceId(); + // there must be at least one format in the list so we can safely look at [0]. + // also all entries must be compatible, so if [0] doesn't have stencil then none of them do, + // and vice-versa. + attachments[i].hasStencil = + IsStencilFormat(attachmentsInfo->pAttachmentImageInfos[i].pViewFormats[0]); + } + } + else + { + for(uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) + { + attachments[i].createdView = GetResID(pCreateInfo->pAttachments[i]); + attachments[i].hasStencil = + IsStencilFormat(info.m_ImageView[attachments[i].createdView].format); + } } } diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index e4650f9de..3fc69532c 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -345,10 +345,11 @@ struct VulkanCreationInfo struct Attachment { - ResourceId view; - VkFormat format; + ResourceId createdView; + bool hasStencil; }; std::vector attachments; + bool imageless; uint32_t width, height, layers; diff --git a/renderdoc/driver/vulkan/vk_next_chains.cpp b/renderdoc/driver/vulkan/vk_next_chains.cpp index dd5820e9b..bf5908a15 100644 --- a/renderdoc/driver/vulkan/vk_next_chains.cpp +++ b/renderdoc/driver/vulkan/vk_next_chains.cpp @@ -134,6 +134,10 @@ 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_KHR, \ + VkFramebufferAttachmentsCreateInfoKHR) \ + COPY_STRUCT(VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR, \ + VkFramebufferAttachmentImageInfoKHR) \ COPY_STRUCT(VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, VkFormatProperties2); \ COPY_STRUCT(VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, VkImageCreateInfo); \ COPY_STRUCT(VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR, VkImageFormatListCreateInfoKHR); \ @@ -202,6 +206,8 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, VkPhysicalDeviceImageFormatInfo2); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT, \ VkPhysicalDeviceImageViewImageFormatInfoEXT); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR, \ + VkPhysicalDeviceImagelessFramebufferFeaturesKHR) \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT, \ VkPhysicalDeviceIndexTypeUint8FeaturesEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, \ @@ -483,8 +489,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT: \ case VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT: \ case VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID: \ - case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR: \ - case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR: \ case VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV: \ case VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV: \ case VK_STRUCTURE_TYPE_GEOMETRY_NV: \ @@ -518,7 +522,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: \ - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT: \ @@ -562,7 +565,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV: \ case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV: \ case VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV: \ - case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR: \ case VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT: \ case VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT: \ case VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT: \ @@ -688,6 +690,14 @@ size_t GetNextPatchSize(const void *pNext) memSize += info->swapchainCount * sizeof(VkSwapchainKHR); break; } + case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR: + { + memSize += sizeof(VkRenderPassAttachmentBeginInfoKHR); + + VkRenderPassAttachmentBeginInfoKHR *info = (VkRenderPassAttachmentBeginInfoKHR *)next; + memSize += info->attachmentCount * sizeof(VkImageView); + break; + } case VK_STRUCTURE_TYPE_SUBMIT_INFO: { memSize += sizeof(VkSubmitInfo); @@ -1079,9 +1089,12 @@ void UnwrapNextChain(CaptureState state, const char *structName, byte *&tempMem, *out = *in; UnwrapInPlace(out->renderPass); - out->pAttachments = outAttachments; - for(uint32_t i = 0; i < in->attachmentCount; i++) - outAttachments[i] = Unwrap(in->pAttachments[i]); + if((out->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR) == 0) + { + out->pAttachments = outAttachments; + for(uint32_t i = 0; i < in->attachmentCount; i++) + outAttachments[i] = Unwrap(in->pAttachments[i]); + } break; } @@ -1169,6 +1182,27 @@ void UnwrapNextChain(CaptureState state, const char *structName, byte *&tempMem, break; } + case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR: + { + const VkRenderPassAttachmentBeginInfoKHR *in = + (const VkRenderPassAttachmentBeginInfoKHR *)nextInput; + VkRenderPassAttachmentBeginInfoKHR *out = (VkRenderPassAttachmentBeginInfoKHR *)tempMem; + + // append immediately so tempMem is incremented + AppendModifiedChainedStruct(tempMem, out, nextChainTail); + + // allocate unwrapped array + VkImageView *outAttachments = (VkImageView *)tempMem; + tempMem += sizeof(VkImageView) * in->attachmentCount; + + *out = *in; + + out->pAttachments = outAttachments; + for(uint32_t i = 0; i < in->attachmentCount; i++) + outAttachments[i] = Unwrap(in->pAttachments[i]); + + break; + } case VK_STRUCTURE_TYPE_SUBMIT_INFO: { const VkSubmitInfo *in = (const VkSubmitInfo *)nextInput; diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index 5b7226259..bd0f1beb5 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -409,7 +409,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa // refreshed before the UI layer can update the current texture. { const VulkanCreationInfo::Framebuffer &fb = - m_pDriver->m_CreationInfo.m_Framebuffer[m_pDriver->m_RenderState.framebuffer]; + m_pDriver->m_CreationInfo.m_Framebuffer[m_pDriver->m_RenderState.GetFramebuffer()]; if(fb.width != iminfo.extent.width || fb.height != iminfo.extent.height) return GetResID(m_Overlay.Image); @@ -833,7 +833,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa // modify state m_pDriver->m_RenderState.renderPass = GetResID(m_Overlay.NoDepthRP); m_pDriver->m_RenderState.subpass = 0; - m_pDriver->m_RenderState.framebuffer = GetResID(m_Overlay.NoDepthFB); + m_pDriver->m_RenderState.SetFramebuffer(GetResID(m_Overlay.NoDepthFB)); m_pDriver->m_RenderState.graphics.pipeline = GetResID(pipe); @@ -1167,7 +1167,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa // modify state m_pDriver->m_RenderState.renderPass = GetResID(m_Overlay.NoDepthRP); m_pDriver->m_RenderState.subpass = 0; - m_pDriver->m_RenderState.framebuffer = GetResID(m_Overlay.NoDepthFB); + m_pDriver->m_RenderState.SetFramebuffer(GetResID(m_Overlay.NoDepthFB)); m_pDriver->m_RenderState.graphics.pipeline = GetResID(pipe[0]); @@ -1242,7 +1242,8 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa // make a renderpass and framebuffer for rendering to overlay color and using // depth buffer from the orignial render - if(dsIdx >= 0 && dsIdx < (int32_t)createinfo.m_Framebuffer[state.framebuffer].attachments.size()) + if(dsIdx >= 0 && + dsIdx < (int32_t)createinfo.m_Framebuffer[state.GetFramebuffer()].attachments.size()) { VkAttachmentDescription attDescs[] = { {0, VK_FORMAT_R16G16B16A16_SFLOAT, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, @@ -1255,7 +1256,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}, }; - ResourceId depthView = createinfo.m_Framebuffer[state.framebuffer].attachments[dsIdx].view; + ResourceId depthView = state.GetFramebufferAttachments()[dsIdx]; VulkanCreationInfo::ImageView &depthViewInfo = createinfo.m_ImageView[depthView]; ResourceId depthIm = depthViewInfo.image; @@ -1465,7 +1466,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa // modify state m_pDriver->m_RenderState.renderPass = GetResID(m_Overlay.NoDepthRP); m_pDriver->m_RenderState.subpass = 0; - m_pDriver->m_RenderState.framebuffer = GetResID(m_Overlay.NoDepthFB); + m_pDriver->m_RenderState.SetFramebuffer(GetResID(m_Overlay.NoDepthFB)); m_pDriver->m_RenderState.graphics.pipeline = GetResID(failpipe); @@ -1487,7 +1488,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa if(depthRP != VK_NULL_HANDLE) { m_pDriver->m_RenderState.renderPass = GetResID(depthRP); - m_pDriver->m_RenderState.framebuffer = GetResID(depthFB); + m_pDriver->m_RenderState.SetFramebuffer(GetResID(depthFB)); } m_pDriver->ReplayLog(0, eventId, eReplay_OnlyDraw); @@ -1599,7 +1600,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa std::vector atts; VulkanCreationInfo::Framebuffer &fb = - m_pDriver->m_CreationInfo.m_Framebuffer[m_pDriver->m_RenderState.framebuffer]; + m_pDriver->m_CreationInfo.m_Framebuffer[m_pDriver->m_RenderState.GetFramebuffer()]; VulkanCreationInfo::RenderPass &rp = m_pDriver->m_CreationInfo.m_RenderPass[m_pDriver->m_RenderState.renderPass]; @@ -1997,7 +1998,8 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa // make a renderpass and framebuffer for rendering to overlay color and using // depth buffer from the orignial render - if(dsIdx >= 0 && dsIdx < (int32_t)createinfo.m_Framebuffer[state.framebuffer].attachments.size()) + if(dsIdx >= 0 && + dsIdx < (int32_t)createinfo.m_Framebuffer[state.GetFramebuffer()].attachments.size()) { depthUsed = true; @@ -2012,7 +2014,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, CompType typeHint, Floa VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}, }; - ResourceId depthView = createinfo.m_Framebuffer[state.framebuffer].attachments[dsIdx].view; + ResourceId depthView = state.GetFramebufferAttachments()[dsIdx]; VulkanCreationInfo::ImageView &depthViewInfo = createinfo.m_ImageView[depthView]; ResourceId depthIm = depthViewInfo.image; diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index 2ac81457b..9e86acdd9 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -370,7 +370,8 @@ struct VulkanPixelHistoryCallback : public VulkanDrawcallCallback VulkanRenderState &pipestate = m_pDriver->GetRenderState(); ResourceId prevState = pipestate.graphics.pipeline; ResourceId prevRenderpass = pipestate.renderPass; - ResourceId prevFramebuffer = pipestate.framebuffer; + ResourceId prevFramebuffer = pipestate.GetFramebuffer(); + std::vector prevFBattachments = pipestate.GetFramebufferAttachments(); uint32_t prevSubpass = pipestate.subpass; { @@ -395,7 +396,7 @@ struct VulkanPixelHistoryCallback : public VulkanDrawcallCallback for(uint32_t i = 0; i < pipestate.views.size(); i++) UpdateScissor(pipestate.views[i], pipestate.scissors[i]); - pipestate.framebuffer = GetResID(m_OffscreenFB); + pipestate.SetFramebuffer(GetResID(m_OffscreenFB)); pipestate.renderPass = GetResID(m_RenderPass); pipestate.subpass = 0; pipestate.graphics.pipeline = GetResID(replacements.occlusion); @@ -410,7 +411,7 @@ struct VulkanPixelHistoryCallback : public VulkanDrawcallCallback // Restore the state. m_pDriver->GetRenderState() = m_PrevState; - pipestate.framebuffer = prevFramebuffer; + pipestate.SetFramebuffer(prevFramebuffer, prevFBattachments); pipestate.renderPass = prevRenderpass; pipestate.subpass = prevSubpass; diff --git a/renderdoc/driver/vulkan/vk_postvs.cpp b/renderdoc/driver/vulkan/vk_postvs.cpp index 794382e57..cbcb36c21 100644 --- a/renderdoc/driver/vulkan/vk_postvs.cpp +++ b/renderdoc/driver/vulkan/vk_postvs.cpp @@ -2775,7 +2775,7 @@ void VulkanReplay::FetchTessGSOut(uint32_t eventId) RDCASSERTEQUAL(vkr, VK_SUCCESS); state.graphics.pipeline = GetResID(pipe); - state.framebuffer = GetResID(fb); + state.SetFramebuffer(GetResID(fb)); state.renderPass = GetResID(rp); state.subpass = 0; state.renderArea.offset.x = 0; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 7ab7abaa7..0f84cc460 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1272,21 +1272,21 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) c.m_RenderPass[state.renderPass].subpasses[state.subpass].multiviews; } - m_VulkanPipelineState.currentPass.framebuffer.resourceId = rm->GetOriginalID(state.framebuffer); + ResourceId fb = state.GetFramebuffer(); - if(state.framebuffer != ResourceId()) + m_VulkanPipelineState.currentPass.framebuffer.resourceId = rm->GetOriginalID(fb); + + if(fb != ResourceId()) { - m_VulkanPipelineState.currentPass.framebuffer.width = c.m_Framebuffer[state.framebuffer].width; - m_VulkanPipelineState.currentPass.framebuffer.height = - c.m_Framebuffer[state.framebuffer].height; - m_VulkanPipelineState.currentPass.framebuffer.layers = - c.m_Framebuffer[state.framebuffer].layers; + m_VulkanPipelineState.currentPass.framebuffer.width = c.m_Framebuffer[fb].width; + m_VulkanPipelineState.currentPass.framebuffer.height = c.m_Framebuffer[fb].height; + m_VulkanPipelineState.currentPass.framebuffer.layers = c.m_Framebuffer[fb].layers; m_VulkanPipelineState.currentPass.framebuffer.attachments.resize( - c.m_Framebuffer[state.framebuffer].attachments.size()); - for(size_t i = 0; i < c.m_Framebuffer[state.framebuffer].attachments.size(); i++) + c.m_Framebuffer[fb].attachments.size()); + for(size_t i = 0; i < c.m_Framebuffer[fb].attachments.size(); i++) { - ResourceId viewid = c.m_Framebuffer[state.framebuffer].attachments[i].view; + ResourceId viewid = state.GetFramebufferAttachments()[i]; if(viewid != ResourceId()) { diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 850e37119..48dee1f85 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -983,6 +983,11 @@ struct CmdBufferRecordingInfo // submit with latest binding refs. std::set boundDescSets; + // barriers to apply when the current render pass ends. Calculated at begin time in case the + // framebuffer is imageless and we need to use the image views passed in at begin time to + // construct the proper barriers. + std::vector rpbarriers; + std::vector subcmds; std::map imgFrameRefs; diff --git a/renderdoc/driver/vulkan/vk_serialise.cpp b/renderdoc/driver/vulkan/vk_serialise.cpp index 682103bfd..e7549a5e9 100644 --- a/renderdoc/driver/vulkan/vk_serialise.cpp +++ b/renderdoc/driver/vulkan/vk_serialise.cpp @@ -767,6 +767,16 @@ SERIALISE_VK_HANDLES(); /* VK_KHR_image_format_list */ \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR, VkImageFormatListCreateInfoKHR) \ \ + /* VK_KHR_imageless_framebuffer */ \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR, \ + VkPhysicalDeviceImagelessFramebufferFeaturesKHR) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR, \ + VkFramebufferAttachmentsCreateInfoKHR) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR, \ + VkFramebufferAttachmentImageInfoKHR) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR, \ + VkRenderPassAttachmentBeginInfoKHR) \ + \ /* VK_KHR_incremental_present */ \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR, VkPresentRegionsKHR) \ \ @@ -956,12 +966,6 @@ SERIALISE_VK_HANDLES(); /* VK_INTEL_shader_integer_functions2 */ \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL) \ \ - /* VK_KHR_imageless_framebuffer */ \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR) \ - \ /* VK_KHR_pipeline_executable_properties */ \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR) \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR) \ @@ -4327,6 +4331,78 @@ void Deserialise(const VkImageFormatListCreateInfoKHR &el) delete[] el.pViewFormats; } +template +void DoSerialise(SerialiserType &ser, VkPhysicalDeviceImagelessFramebufferFeaturesKHR &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(imagelessFramebuffer); +} + +template <> +void Deserialise(const VkPhysicalDeviceImagelessFramebufferFeaturesKHR &el) +{ + DeserialiseNext(el.pNext); +} + +template +void DoSerialise(SerialiserType &ser, VkFramebufferAttachmentsCreateInfoKHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(attachmentImageInfoCount); + SERIALISE_MEMBER_ARRAY(pAttachmentImageInfos, attachmentImageInfoCount); +} + +template <> +void Deserialise(const VkFramebufferAttachmentsCreateInfoKHR &el) +{ + DeserialiseNext(el.pNext); + delete[] el.pAttachmentImageInfos; +} + +template +void DoSerialise(SerialiserType &ser, VkFramebufferAttachmentImageInfoKHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER_VKFLAGS(VkImageCreateFlags, flags); + SERIALISE_MEMBER_VKFLAGS(VkImageUsageFlags, usage); + SERIALISE_MEMBER(width); + SERIALISE_MEMBER(height); + SERIALISE_MEMBER(layerCount); + SERIALISE_MEMBER(viewFormatCount); + SERIALISE_MEMBER_ARRAY(pViewFormats, viewFormatCount); +} + +template <> +void Deserialise(const VkFramebufferAttachmentImageInfoKHR &el) +{ + DeserialiseNext(el.pNext); + delete[] el.pViewFormats; +} + +template +void DoSerialise(SerialiserType &ser, VkRenderPassAttachmentBeginInfoKHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(attachmentCount); + SERIALISE_MEMBER_ARRAY(pAttachments, attachmentCount); +} + +template <> +void Deserialise(const VkRenderPassAttachmentBeginInfoKHR &el) +{ + DeserialiseNext(el.pNext); + delete[] el.pAttachments; +} + template void DoSerialise(SerialiserType &ser, VkRectLayerKHR &el) { @@ -6878,18 +6954,19 @@ INSTANTIATE_SERIALISE_TYPE(VkBindImageMemorySwapchainInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkBindImagePlaneMemoryInfo); INSTANTIATE_SERIALISE_TYPE(VkBindSparseInfo); INSTANTIATE_SERIALISE_TYPE(VkBufferCreateInfo); -INSTANTIATE_SERIALISE_TYPE(VkBufferDeviceAddressInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkBufferDeviceAddressCreateInfoEXT); +INSTANTIATE_SERIALISE_TYPE(VkBufferDeviceAddressInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkBufferMemoryBarrier); INSTANTIATE_SERIALISE_TYPE(VkBufferMemoryRequirementsInfo2); INSTANTIATE_SERIALISE_TYPE(VkBufferViewCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkCalibratedTimestampInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkCommandBufferAllocateInfo); INSTANTIATE_SERIALISE_TYPE(VkCommandBufferBeginInfo); -INSTANTIATE_SERIALISE_TYPE(VkCommandBufferInheritanceInfo); INSTANTIATE_SERIALISE_TYPE(VkCommandBufferInheritanceConditionalRenderingInfoEXT); +INSTANTIATE_SERIALISE_TYPE(VkCommandBufferInheritanceInfo); INSTANTIATE_SERIALISE_TYPE(VkCommandPoolCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkComputePipelineCreateInfo); +INSTANTIATE_SERIALISE_TYPE(VkConditionalRenderingBeginInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkCopyDescriptorSet); INSTANTIATE_SERIALISE_TYPE(VkDebugMarkerMarkerInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkDebugMarkerObjectNameInfoEXT); @@ -6948,6 +7025,8 @@ INSTANTIATE_SERIALISE_TYPE(VkExternalSemaphoreProperties); INSTANTIATE_SERIALISE_TYPE(VkFenceCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkFenceGetFdInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkFormatProperties2); +INSTANTIATE_SERIALISE_TYPE(VkFramebufferAttachmentImageInfoKHR); +INSTANTIATE_SERIALISE_TYPE(VkFramebufferAttachmentsCreateInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkFramebufferCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkGraphicsPipelineCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkHdrMetadataEXT); @@ -6957,8 +7036,8 @@ INSTANTIATE_SERIALISE_TYPE(VkImageFormatProperties2); INSTANTIATE_SERIALISE_TYPE(VkImageMemoryBarrier); INSTANTIATE_SERIALISE_TYPE(VkImageMemoryRequirementsInfo2); INSTANTIATE_SERIALISE_TYPE(VkImagePlaneMemoryRequirementsInfo); -INSTANTIATE_SERIALISE_TYPE(VkImageStencilUsageCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkImageSparseMemoryRequirementsInfo2); +INSTANTIATE_SERIALISE_TYPE(VkImageStencilUsageCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkImageSwapchainCreateInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkImageViewASTCDecodeModeEXT); INSTANTIATE_SERIALISE_TYPE(VkImageViewCreateInfo); @@ -6986,8 +7065,8 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceASTCDecodeFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceBufferDeviceAddressFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceConditionalRenderingFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceConservativeRasterizationPropertiesEXT); -INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDepthStencilResolvePropertiesKHR); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDepthClipEnableFeaturesEXT); +INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDepthStencilResolvePropertiesKHR); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDescriptorIndexingFeaturesEXT) INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDescriptorIndexingPropertiesEXT) INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDiscardRectanglePropertiesEXT); @@ -7004,6 +7083,7 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceGroupProperties); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceHostQueryResetFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceIDProperties); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceImageFormatInfo2); +INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceImagelessFramebufferFeaturesKHR); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceIndexTypeUint8FeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceMaintenance3Properties); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceMemoryBudgetPropertiesEXT); @@ -7017,6 +7097,7 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceProperties2); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceProtectedMemoryFeatures); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceProtectedMemoryProperties); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDevicePushDescriptorPropertiesKHR); +INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceSampleLocationsPropertiesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceSamplerYcbcrConversionFeatures); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceScalarBlockLayoutFeaturesEXT); @@ -7024,7 +7105,6 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderAtomicInt64FeaturesKHR); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderCorePropertiesAMD); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderDrawParametersFeatures); -INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceSampleLocationsPropertiesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceSparseImageFormatInfo2); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceSubgroupProperties); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceSurfaceInfo2KHR); @@ -7032,15 +7112,15 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceTransformFeedbackFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceTransformFeedbackPropertiesEXT); +INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceVariablePointerFeatures); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT); -INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceVulkanMemoryModelFeaturesKHR); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceYcbcrImageArraysFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPipelineCacheCreateInfo); -INSTANTIATE_SERIALISE_TYPE(VkPipelineCreationFeedbackCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkPipelineColorBlendStateCreateInfo); +INSTANTIATE_SERIALISE_TYPE(VkPipelineCreationFeedbackCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkPipelineDepthStencilStateCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkPipelineDiscardRectangleStateCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkPipelineDynamicStateCreateInfo); @@ -7063,6 +7143,7 @@ INSTANTIATE_SERIALISE_TYPE(VkPresentRegionsKHR); INSTANTIATE_SERIALISE_TYPE(VkProtectedSubmitInfo); INSTANTIATE_SERIALISE_TYPE(VkQueryPoolCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkQueueFamilyProperties2); +INSTANTIATE_SERIALISE_TYPE(VkRenderPassAttachmentBeginInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkRenderPassBeginInfo); INSTANTIATE_SERIALISE_TYPE(VkRenderPassCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkRenderPassCreateInfo2KHR); @@ -7100,7 +7181,6 @@ INSTANTIATE_SERIALISE_TYPE(VkTextureLODGatherFormatPropertiesAMD); INSTANTIATE_SERIALISE_TYPE(VkValidationCacheCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkValidationFlagsEXT); INSTANTIATE_SERIALISE_TYPE(VkWriteDescriptorSet); -INSTANTIATE_SERIALISE_TYPE(VkConditionalRenderingBeginInfoEXT); // plain structs with no next chain INSTANTIATE_SERIALISE_TYPE(VkAllocationCallbacks); diff --git a/renderdoc/driver/vulkan/vk_state.cpp b/renderdoc/driver/vulkan/vk_state.cpp index 2bcaaf8c7..a4834026d 100644 --- a/renderdoc/driver/vulkan/vk_state.cpp +++ b/renderdoc/driver/vulkan/vk_state.cpp @@ -68,15 +68,35 @@ void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd, Pipeli RDCASSERT(ARRAY_COUNT(empty) >= m_CreationInfo->m_RenderPass[renderPass].attachments.size()); + VulkanCreationInfo::Framebuffer fbinfo = m_CreationInfo->m_Framebuffer[framebuffer]; + VkRenderPassBeginInfo rpbegin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, NULL, Unwrap(m_CreationInfo->m_RenderPass[renderPass].loadRPs[subpass]), - Unwrap(m_CreationInfo->m_Framebuffer[framebuffer].loadFBs[subpass]), + Unwrap(fbinfo.loadFBs[subpass]), renderArea, (uint32_t)m_CreationInfo->m_RenderPass[renderPass].attachments.size(), empty, }; + + VkRenderPassAttachmentBeginInfoKHR imagelessAttachments = { + VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR, + }; + std::vector imagelessViews; + + if(fbinfo.imageless) + { + rpbegin.pNext = &imagelessAttachments; + imagelessAttachments.attachmentCount = (uint32_t)fbattachments.size(); + + for(size_t i = 0; i < fbattachments.size(); i++) + imagelessViews.push_back( + Unwrap(GetResourceManager()->GetCurrentHandle(fbattachments[i]))); + + imagelessAttachments.pAttachments = imagelessViews.data(); + } + ObjDisp(cmd)->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); BindPipeline(cmd, binding, true); @@ -540,6 +560,27 @@ void VulkanRenderState::BindDescriptorSet(const DescSetLayout &descLayout, VkCom } } +void VulkanRenderState::SetFramebuffer(ResourceId fb, + const VkRenderPassAttachmentBeginInfoKHR *attachmentsInfo) +{ + framebuffer = fb; + + VulkanCreationInfo::Framebuffer fbinfo = m_CreationInfo->m_Framebuffer[fb]; + + fbattachments.resize(fbinfo.attachments.size()); + + if(!fbinfo.imageless) + { + for(size_t i = 0; i < fbinfo.attachments.size(); i++) + fbattachments[i] = fbinfo.attachments[i].createdView; + } + else + { + for(size_t i = 0; i < fbinfo.attachments.size(); i++) + fbattachments[i] = GetResID(attachmentsInfo->pAttachments[i]); + } +} + VulkanResourceManager *VulkanRenderState::GetResourceManager() { return m_pDriver->GetResourceManager(); diff --git a/renderdoc/driver/vulkan/vk_state.h b/renderdoc/driver/vulkan/vk_state.h index e20fcf647..c07bb7b27 100644 --- a/renderdoc/driver/vulkan/vk_state.h +++ b/renderdoc/driver/vulkan/vk_state.h @@ -100,7 +100,19 @@ struct VulkanRenderState ResourceId renderPass; uint32_t subpass; - ResourceId framebuffer; + // framebuffer accessors - to allow for imageless framebuffers and prevent accidentally changing + // only the framebuffer without updating the attachments + void SetFramebuffer(ResourceId fb, + const VkRenderPassAttachmentBeginInfoKHR *attachmentsInfo = NULL); + void SetFramebuffer(ResourceId fb, const std::vector &dynamicAttachments) + { + framebuffer = fb; + fbattachments = dynamicAttachments; + } + ResourceId GetFramebuffer() const { return framebuffer; } + const std::vector &GetFramebufferAttachments() const { return fbattachments; } + // + VkRect2D renderArea; VulkanStatePipeline compute, graphics; @@ -147,4 +159,8 @@ struct VulkanRenderState VulkanResourceManager *GetResourceManager(); VulkanCreationInfo *m_CreationInfo; WrappedVulkan *m_pDriver; + +private: + ResourceId framebuffer; + std::vector fbattachments; }; diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index c29922fb7..7962e0076 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -48,16 +48,19 @@ static std::string ToHumanStr(const VkAttachmentStoreOp &el) std::vector WrappedVulkan::GetImplicitRenderPassBarriers(uint32_t subpass) { ResourceId rp, fb; + std::vector fbattachments; if(m_LastCmdBufferID == ResourceId()) { rp = m_RenderState.renderPass; - fb = m_RenderState.framebuffer; + fb = m_RenderState.GetFramebuffer(); + fbattachments = m_RenderState.GetFramebufferAttachments(); } else { rp = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass; fb = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer; + fbattachments = m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments; } std::vector ret; @@ -138,7 +141,7 @@ std::vector WrappedVulkan::GetImplicitRenderPassBarriers(u VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; - ResourceId view = fbinfo.attachments[idx].view; + ResourceId view = fbattachments[idx]; barrier.subresourceRange = m_CreationInfo.m_ImageView[view].range; barrier.image = Unwrap( @@ -252,7 +255,7 @@ std::string WrappedVulkan::MakeRenderPassOpString(bool store) // component and if the subpass is depth only (no other attachments) if(dsAttach >= 0) { - hasStencil = !IsDepthOnlyFormat(fbinfo.attachments[dsAttach].format); + hasStencil = fbinfo.attachments[dsAttach].hasStencil; depthonly = info.subpasses[subpass].colorAttachments.size() == 0; } @@ -1158,8 +1161,34 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(SerialiserType &ser, VkComman m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass = 0; m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass = GetResID(RenderPassBegin.renderPass); - m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = - GetResID(RenderPassBegin.framebuffer); + + ResourceId fb = GetResID(RenderPassBegin.framebuffer); + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = fb; + + const VkRenderPassAttachmentBeginInfoKHR *attachmentsInfo = + (const VkRenderPassAttachmentBeginInfoKHR *)FindNextStruct( + &RenderPassBegin, VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR); + + // set framebuffer attachments - by default from the ones used to create it, but if it is + // imageless then look for the attachments in our pNext chain + { + VulkanCreationInfo::Framebuffer fbinfo = m_CreationInfo.m_Framebuffer[fb]; + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments.resize( + fbinfo.attachments.size()); + + if(!fbinfo.imageless) + { + for(size_t i = 0; i < fbinfo.attachments.size(); i++) + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments[i] = + fbinfo.attachments[i].createdView; + } + else + { + for(size_t i = 0; i < fbinfo.attachments.size(); i++) + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments[i] = + GetResID(attachmentsInfo->pAttachments[i]); + } + } // only if we're partially recording do we update this state if(ShouldUpdateRenderState(m_LastCmdBufferID, true)) @@ -1169,7 +1198,7 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(SerialiserType &ser, VkComman m_RenderState.subpass = 0; m_RenderState.renderPass = GetResID(RenderPassBegin.renderPass); - m_RenderState.framebuffer = GetResID(RenderPassBegin.framebuffer); + m_RenderState.SetFramebuffer(GetResID(RenderPassBegin.framebuffer), attachmentsInfo); m_RenderState.renderArea = RenderPassBegin.renderArea; } @@ -1189,8 +1218,33 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(SerialiserType &ser, VkComman // track while reading, for fetching the right set of outputs in AddDrawcall m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass = 0; m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass = GetResID(RenderPassBegin.renderPass); - m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = - GetResID(RenderPassBegin.framebuffer); + + ResourceId fb = GetResID(RenderPassBegin.framebuffer); + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = fb; + + // set framebuffer attachments - by default from the ones used to create it, but if it is + // imageless then look for the attachments in our pNext chain + { + VulkanCreationInfo::Framebuffer fbinfo = m_CreationInfo.m_Framebuffer[fb]; + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments.resize(fbinfo.attachments.size()); + + if(!fbinfo.imageless) + { + for(size_t i = 0; i < fbinfo.attachments.size(); i++) + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments[i] = + fbinfo.attachments[i].createdView; + } + else + { + const VkRenderPassAttachmentBeginInfoKHR *attachmentsInfo = + (const VkRenderPassAttachmentBeginInfoKHR *)FindNextStruct( + &RenderPassBegin, VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR); + + for(size_t i = 0; i < fbinfo.attachments.size(); i++) + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments[i] = + GetResID(attachmentsInfo->pAttachments[i]); + } + } std::vector imgBarriers = GetImplicitRenderPassBarriers(); @@ -1243,13 +1297,49 @@ void WrappedVulkan::vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, VkResourceRecord *fb = GetRecord(pRenderPassBegin->framebuffer); record->MarkResourceFrameReferenced(fb->GetResourceID(), eFrameRef_Read); - for(size_t i = 0; fb->imageAttachments[i].barrier.sType; i++) - { - VkResourceRecord *att = fb->imageAttachments[i].record; - if(att == NULL) - break; - record->MarkImageViewFrameReferenced(att, ImageRange(), eFrameRef_ReadBeforeWrite); + std::vector &barriers = record->cmdInfo->rpbarriers; + + barriers.clear(); + + if(fb->imageAttachments[0].barrier.sType && fb->imageAttachments[0].record) + { + for(size_t i = 0; fb->imageAttachments[i].barrier.sType; i++) + { + VkResourceRecord *att = fb->imageAttachments[i].record; + if(att == NULL) + break; + + record->MarkImageViewFrameReferenced(att, ImageRange(), eFrameRef_ReadBeforeWrite); + + if(fb->imageAttachments[i].barrier.oldLayout != fb->imageAttachments[i].barrier.newLayout) + barriers.push_back(fb->imageAttachments[i].barrier); + } + } + else if(fb->imageAttachments[0].barrier.sType) + { + // if we have attachments but the framebuffer doesn't have images, then it's imageless. Look + // for the image records now + + const VkRenderPassAttachmentBeginInfoKHR *attachmentsInfo = + (const VkRenderPassAttachmentBeginInfoKHR *)FindNextStruct( + pRenderPassBegin, VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR); + + for(uint32_t i = 0; i < attachmentsInfo->attachmentCount; i++) + { + VkResourceRecord *att = GetRecord(attachmentsInfo->pAttachments[i]); + record->MarkImageViewFrameReferenced(att, ImageRange(), eFrameRef_ReadBeforeWrite); + + if(fb->imageAttachments[i].barrier.oldLayout != fb->imageAttachments[i].barrier.newLayout) + { + VkImageMemoryBarrier barrier = fb->imageAttachments[i].barrier; + + barrier.image = GetResourceManager()->GetCurrentHandle(att->baseResource); + barrier.subresourceRange = att->viewRange; + + barriers.push_back(barrier); + } + } } record->cmdInfo->framebuffer = fb; @@ -1363,6 +1453,7 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass(SerialiserType &ser, VkCommandB // always track this, for WrappedVulkan::IsDrawInRenderPass() m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass = ResourceId(); m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = ResourceId(); + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments.clear(); if(ShouldUpdateRenderState(m_LastCmdBufferID, true)) { @@ -1404,6 +1495,7 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass(SerialiserType &ser, VkCommandB // but only AFTER the above AddDrawcall (we want it grouped together) m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass = ResourceId(); m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = ResourceId(); + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments.clear(); } } @@ -1427,17 +1519,7 @@ void WrappedVulkan::vkCmdEndRenderPass(VkCommandBuffer commandBuffer) record->AddChunk(scope.Get()); - VkResourceRecord *fb = record->cmdInfo->framebuffer; - - std::vector barriers; - - for(size_t i = 0; fb->imageAttachments[i].barrier.sType; i++) - { - if(fb->imageAttachments[i].barrier.oldLayout == fb->imageAttachments[i].barrier.newLayout) - continue; - - barriers.push_back(fb->imageAttachments[i].barrier); - } + const std::vector &barriers = record->cmdInfo->rpbarriers; // apply the implicit layout transitions here { @@ -1490,8 +1572,34 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass2KHR(SerialiserType &ser, m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass = 0; m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass = GetResID(RenderPassBegin.renderPass); - m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = - GetResID(RenderPassBegin.framebuffer); + + ResourceId fb = GetResID(RenderPassBegin.framebuffer); + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = fb; + + const VkRenderPassAttachmentBeginInfoKHR *attachmentsInfo = + (const VkRenderPassAttachmentBeginInfoKHR *)FindNextStruct( + &RenderPassBegin, VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR); + + // set framebuffer attachments - by default from the ones used to create it, but if it is + // imageless then look for the attachments in our pNext chain + { + VulkanCreationInfo::Framebuffer fbinfo = m_CreationInfo.m_Framebuffer[fb]; + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments.resize( + fbinfo.attachments.size()); + + if(!fbinfo.imageless) + { + for(size_t i = 0; i < fbinfo.attachments.size(); i++) + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments[i] = + fbinfo.attachments[i].createdView; + } + else + { + for(size_t i = 0; i < fbinfo.attachments.size(); i++) + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments[i] = + GetResID(attachmentsInfo->pAttachments[i]); + } + } // only if we're partially recording do we update this state if(ShouldUpdateRenderState(m_LastCmdBufferID, true)) @@ -1501,7 +1609,7 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass2KHR(SerialiserType &ser, m_RenderState.subpass = 0; m_RenderState.renderPass = GetResID(RenderPassBegin.renderPass); - m_RenderState.framebuffer = GetResID(RenderPassBegin.framebuffer); + m_RenderState.SetFramebuffer(GetResID(RenderPassBegin.framebuffer), attachmentsInfo); m_RenderState.renderArea = RenderPassBegin.renderArea; } @@ -1523,8 +1631,33 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass2KHR(SerialiserType &ser, // track while reading, for fetching the right set of outputs in AddDrawcall m_BakedCmdBufferInfo[m_LastCmdBufferID].state.subpass = 0; m_BakedCmdBufferInfo[m_LastCmdBufferID].state.renderPass = GetResID(RenderPassBegin.renderPass); - m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = - GetResID(RenderPassBegin.framebuffer); + + ResourceId fb = GetResID(RenderPassBegin.framebuffer); + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.framebuffer = fb; + + // set framebuffer attachments - by default from the ones used to create it, but if it is + // imageless then look for the attachments in our pNext chain + { + VulkanCreationInfo::Framebuffer fbinfo = m_CreationInfo.m_Framebuffer[fb]; + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments.resize(fbinfo.attachments.size()); + + if(!fbinfo.imageless) + { + for(size_t i = 0; i < fbinfo.attachments.size(); i++) + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments[i] = + fbinfo.attachments[i].createdView; + } + else + { + const VkRenderPassAttachmentBeginInfoKHR *attachmentsInfo = + (const VkRenderPassAttachmentBeginInfoKHR *)FindNextStruct( + &RenderPassBegin, VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR); + + for(size_t i = 0; i < fbinfo.attachments.size(); i++) + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.fbattachments[i] = + GetResID(attachmentsInfo->pAttachments[i]); + } + } std::vector imgBarriers = GetImplicitRenderPassBarriers(); @@ -1583,18 +1716,49 @@ void WrappedVulkan::vkCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, VkResourceRecord *fb = GetRecord(pRenderPassBegin->framebuffer); record->MarkResourceFrameReferenced(fb->GetResourceID(), eFrameRef_Read); - for(size_t i = 0; fb->imageAttachments[i].barrier.sType; i++) - { - VkResourceRecord *att = fb->imageAttachments[i].record; - if(att == NULL) - break; - record->MarkResourceFrameReferenced(att->baseResource, eFrameRef_ReadBeforeWrite); - if(att->baseResourceMem != ResourceId()) - record->MarkResourceFrameReferenced(att->baseResourceMem, eFrameRef_Read); - if(att->resInfo && att->resInfo->IsSparse()) - record->cmdInfo->sparse.insert(att->resInfo); - record->cmdInfo->dirtied.insert(att->baseResource); + std::vector &barriers = record->cmdInfo->rpbarriers; + + barriers.clear(); + + if(fb->imageAttachments[0].barrier.sType && fb->imageAttachments[0].record) + { + for(size_t i = 0; fb->imageAttachments[i].barrier.sType; i++) + { + VkResourceRecord *att = fb->imageAttachments[i].record; + if(att == NULL) + break; + + record->MarkImageViewFrameReferenced(att, ImageRange(), eFrameRef_ReadBeforeWrite); + + if(fb->imageAttachments[i].barrier.oldLayout != fb->imageAttachments[i].barrier.newLayout) + barriers.push_back(fb->imageAttachments[i].barrier); + } + } + else + { + // if we have attachments but the framebuffer doesn't have images, then it's imageless. Look + // for the image records now + + const VkRenderPassAttachmentBeginInfoKHR *attachmentsInfo = + (const VkRenderPassAttachmentBeginInfoKHR *)FindNextStruct( + pRenderPassBegin, VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR); + + for(uint32_t i = 0; i < attachmentsInfo->attachmentCount; i++) + { + VkResourceRecord *att = GetRecord(attachmentsInfo->pAttachments[i]); + record->MarkImageViewFrameReferenced(att, ImageRange(), eFrameRef_ReadBeforeWrite); + + if(fb->imageAttachments[i].barrier.oldLayout != fb->imageAttachments[i].barrier.newLayout) + { + VkImageMemoryBarrier barrier = fb->imageAttachments[i].barrier; + + barrier.image = GetResourceManager()->GetCurrentHandle(att->baseResource); + barrier.subresourceRange = att->viewRange; + + barriers.push_back(barrier); + } + } } record->cmdInfo->framebuffer = fb; @@ -1811,17 +1975,7 @@ void WrappedVulkan::vkCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, record->AddChunk(scope.Get()); - VkResourceRecord *fb = record->cmdInfo->framebuffer; - - std::vector barriers; - - for(size_t i = 0; fb->imageAttachments[i].barrier.sType; i++) - { - if(fb->imageAttachments[i].barrier.oldLayout == fb->imageAttachments[i].barrier.newLayout) - continue; - - barriers.push_back(fb->imageAttachments[i].barrier); - } + const std::vector &barriers = record->cmdInfo->rpbarriers; // apply the implicit layout transitions here { @@ -3079,10 +3233,10 @@ bool WrappedVulkan::Serialise_vkCmdExecuteCommands(SerialiserType &ser, VkComman // primary command buffer's state for(size_t i = 0; i < numChildren; i++) { - AddFramebufferUsageAllChildren(parentCmdBufInfo.draw->children[total - numChildren + i], - parentCmdBufInfo.state.renderPass, - parentCmdBufInfo.state.framebuffer, - parentCmdBufInfo.state.subpass); + AddFramebufferUsageAllChildren( + parentCmdBufInfo.draw->children[total - numChildren + i], + parentCmdBufInfo.state.renderPass, parentCmdBufInfo.state.framebuffer, + parentCmdBufInfo.state.subpass, parentCmdBufInfo.state.fbattachments); } } @@ -3150,6 +3304,7 @@ bool WrappedVulkan::Serialise_vkCmdExecuteCommands(SerialiserType &ser, VkComman m_BakedCmdBufferInfo[cmd].state.renderPass = parentCmdBufInfo.state.renderPass; m_BakedCmdBufferInfo[cmd].state.subpass = parentCmdBufInfo.state.subpass; m_BakedCmdBufferInfo[cmd].state.framebuffer = parentCmdBufInfo.state.framebuffer; + m_BakedCmdBufferInfo[cmd].state.fbattachments = parentCmdBufInfo.state.fbattachments; // propagate conditional rendering if(m_BakedCmdBufferInfo[cmd].inheritConditionalRendering && diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index 6aa95ea1d..681c8380d 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -2112,6 +2112,13 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi CHECK_PHYS_EXT_FEATURE(indexTypeUint8); } END_PHYS_EXT_CHECK(); + + BEGIN_PHYS_EXT_CHECK(VkPhysicalDeviceImagelessFramebufferFeaturesKHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR); + { + CHECK_PHYS_EXT_FEATURE(imagelessFramebuffer); + } + END_PHYS_EXT_CHECK(); } if(availFeatures.depthClamp) diff --git a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp index fbf257b60..0763db46c 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp @@ -2334,7 +2334,6 @@ bool WrappedVulkan::Serialise_vkCmdClearAttachments(SerialiserType &ser, if(state.renderPass != ResourceId() && state.framebuffer != ResourceId()) { VulkanCreationInfo::RenderPass &rp = m_CreationInfo.m_RenderPass[state.renderPass]; - VulkanCreationInfo::Framebuffer &fb = m_CreationInfo.m_Framebuffer[state.framebuffer]; RDCASSERT(state.subpass < rp.subpasses.size()); @@ -2348,9 +2347,9 @@ bool WrappedVulkan::Serialise_vkCmdClearAttachments(SerialiserType &ser, { att = rp.subpasses[state.subpass].colorAttachments[att]; drawNode.resourceUsage.push_back( - make_rdcpair(m_CreationInfo.m_ImageView[fb.attachments[att].view].image, + make_rdcpair(m_CreationInfo.m_ImageView[state.fbattachments[att]].image, EventUsage(drawNode.draw.eventId, ResourceUsage::Clear, - fb.attachments[att].view))); + state.fbattachments[att]))); } } else if(pAttachments[a].aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) @@ -2359,9 +2358,9 @@ bool WrappedVulkan::Serialise_vkCmdClearAttachments(SerialiserType &ser, { att = (uint32_t)rp.subpasses[state.subpass].depthstencilAttachment; drawNode.resourceUsage.push_back( - make_rdcpair(m_CreationInfo.m_ImageView[fb.attachments[att].view].image, + make_rdcpair(m_CreationInfo.m_ImageView[state.fbattachments[att]].image, EventUsage(drawNode.draw.eventId, ResourceUsage::Clear, - fb.attachments[att].view))); + state.fbattachments[att]))); } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp index 8bbd9aa32..986f43880 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp @@ -75,12 +75,15 @@ VkFramebufferCreateInfo WrappedVulkan::UnwrapInfo(const VkFramebufferCreateInfo { VkFramebufferCreateInfo ret = *info; - VkImageView *unwrapped = GetTempArray(info->attachmentCount); - for(uint32_t i = 0; i < info->attachmentCount; i++) - unwrapped[i] = Unwrap(info->pAttachments[i]); + if((ret.flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR) == 0) + { + VkImageView *unwrapped = GetTempArray(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); - ret.pAttachments = unwrapped; return ret; } @@ -677,14 +680,18 @@ VkResult WrappedVulkan::vkCreateFramebuffer(VkDevice device, for(uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) { - VkResourceRecord *attRecord = GetRecord(pCreateInfo->pAttachments[i]); - record->AddParent(attRecord); - - record->imageAttachments[i].record = attRecord; record->imageAttachments[i].barrier = rpRecord->imageAttachments[i].barrier; - record->imageAttachments[i].barrier.image = - GetResourceManager()->GetCurrentHandle(attRecord->baseResource); - record->imageAttachments[i].barrier.subresourceRange = attRecord->viewRange; + + if((pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR) == 0) + { + VkResourceRecord *attRecord = GetRecord(pCreateInfo->pAttachments[i]); + record->AddParent(attRecord); + + record->imageAttachments[i].record = attRecord; + record->imageAttachments[i].barrier.image = + GetResourceManager()->GetCurrentHandle(attRecord->baseResource); + record->imageAttachments[i].barrier.subresourceRange = attRecord->viewRange; + } } } else diff --git a/util/test/demos/CMakeLists.txt b/util/test/demos/CMakeLists.txt index 729e5b026..035d948b9 100644 --- a/util/test/demos/CMakeLists.txt +++ b/util/test/demos/CMakeLists.txt @@ -13,6 +13,7 @@ set(VULKAN_SRC vk/vk_discard_rects.cpp vk/vk_draw_zoo.cpp vk/vk_image_layouts.cpp + vk/vk_imageless_framebuffer.cpp vk/vk_indirect.cpp vk/vk_int8_ibuffer.cpp vk/vk_multi_thread_windows.cpp diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index 6ef3aba07..daf16faf2 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -208,6 +208,7 @@ + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index 7cc5edd19..ddbb4234f 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -312,6 +312,9 @@ Vulkan\demos + + Vulkan\demos + diff --git a/util/test/demos/vk/vk_helpers.h b/util/test/demos/vk/vk_helpers.h index 8c0004d11..65d277ae8 100644 --- a/util/test/demos/vk/vk_helpers.h +++ b/util/test/demos/vk/vk_helpers.h @@ -657,11 +657,11 @@ struct AttachmentDescription : public VkAttachmentDescription struct FramebufferCreateInfo : public VkFramebufferCreateInfo { FramebufferCreateInfo(VkRenderPass renderPass, const std::vector &attachments, - VkExtent2D extent, uint32_t layers = 1) + VkExtent2D extent, uint32_t layers = 1, VkFramebufferCreateFlags flags = 0) { sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; pNext = NULL; - this->flags = 0; + this->flags = flags; this->renderPass = renderPass; this->attachmentCount = (uint32_t)attachments.size(); this->pAttachments = attachments.data(); @@ -670,6 +670,12 @@ struct FramebufferCreateInfo : public VkFramebufferCreateInfo this->layers = layers; } + FramebufferCreateInfo &next(const void *next) + { + this->pNext = next; + return *this; + } + operator const VkFramebufferCreateInfo *() const { return this; } }; diff --git a/util/test/demos/vk/vk_imageless_framebuffer.cpp b/util/test/demos/vk/vk_imageless_framebuffer.cpp new file mode 100644 index 000000000..28235284c --- /dev/null +++ b/util/test/demos/vk/vk_imageless_framebuffer.cpp @@ -0,0 +1,213 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "vk_test.h" + +TEST(VK_Imageless_Framebuffer, VulkanGraphicsTest) +{ + static constexpr const char *Description = + "Test using VK_KHR_imageless_framebuffer to specify image views at the last second"; + + std::string common = R"EOSHADER( + +#version 420 core + +struct v2f +{ + vec4 pos; + vec4 col; + vec4 uv; +}; + +)EOSHADER"; + + const std::string vertex = R"EOSHADER( + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec4 Color; +layout(location = 2) in vec2 UV; + +layout(location = 0) out v2f vertOut; + +void main() +{ + vertOut.pos = vec4(Position.xyz*vec3(1,-1,1), 1); + gl_Position = vertOut.pos; + vertOut.col = Color; + vertOut.uv = vec4(UV.xy, 0, 1); +} + +)EOSHADER"; + + const std::string pixel = R"EOSHADER( + +layout(location = 0) in v2f vertIn; + +layout(location = 0, index = 0) out vec4 Color; + +void main() +{ + Color = vec4(1, 0, 0, 1); +} + +)EOSHADER"; + + void Prepare(int argc, char **argv) + { + devExts.push_back(VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME); + + // dependencies of VK_EXT_descriptor_indexing + devExts.push_back(VK_KHR_MAINTENANCE2_EXTENSION_NAME); + devExts.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME); + + VulkanGraphicsTest::Prepare(argc, argv); + + if(!Avail.empty()) + return; + + static VkPhysicalDeviceImagelessFramebufferFeaturesKHR imageless = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR, + }; + + getPhysFeatures2(&imageless); + + if(!imageless.imagelessFramebuffer) + Avail = "feature 'imagelessFramebuffer' not available"; + + devInfoNext = &imageless; + } + + int main() + { + // initialise, create window, create context, etc + if(!Init()) + return 3; + + VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo()); + + vkh::GraphicsPipelineCreateInfo pipeCreateInfo; + + pipeCreateInfo.layout = layout; + pipeCreateInfo.renderPass = mainWindow->rp; + + pipeCreateInfo.vertexInputState.vertexBindingDescriptions = {vkh::vertexBind(0, DefaultA2V)}; + pipeCreateInfo.vertexInputState.vertexAttributeDescriptions = { + vkh::vertexAttr(0, 0, DefaultA2V, pos), vkh::vertexAttr(1, 0, DefaultA2V, col), + vkh::vertexAttr(2, 0, DefaultA2V, uv), + }; + + pipeCreateInfo.stages = { + CompileShaderModule(common + vertex, ShaderLang::glsl, ShaderStage::vert, "main"), + CompileShaderModule(common + pixel, ShaderLang::glsl, ShaderStage::frag, "main"), + }; + + VkPipeline pipe = createGraphicsPipeline(pipeCreateInfo); + + AllocatedBuffer vb( + allocator, vkh::BufferCreateInfo(sizeof(DefaultTri), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); + + vb.upload(DefaultTri); + + int lastWidth = -1; + VkFramebuffer fb = VK_NULL_HANDLE; + + while(Running()) + { + if(lastWidth != (int)mainWindow->scissor.extent.width) + { + lastWidth = (int)mainWindow->scissor.extent.width; + if(fb != VK_NULL_HANDLE) + { + // be lazy, hard sync + vkDeviceWaitIdle(device); + vkDestroyFramebuffer(device, fb, NULL); + } + + VkFramebufferAttachmentImageInfoKHR imageInfo = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR, + }; + + imageInfo.width = mainWindow->scissor.extent.width; + imageInfo.height = mainWindow->scissor.extent.height; + imageInfo.layerCount = 1; + imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageInfo.viewFormatCount = 1; + imageInfo.pViewFormats = &mainWindow->format; + + VkFramebufferAttachmentsCreateInfoKHR viewsInfo = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR, NULL, 1, &imageInfo, + }; + + CHECK_VKR(vkCreateFramebuffer( + device, + vkh::FramebufferCreateInfo(mainWindow->rp, {VK_NULL_HANDLE}, mainWindow->scissor.extent, + 1, VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR) + .next(&viewsInfo), + NULL, &fb)); + } + + VkCommandBuffer cmd = GetCommandBuffer(); + + vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); + + VkImage swapimg = + StartUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + + vkCmdClearColorImage(cmd, swapimg, VK_IMAGE_LAYOUT_GENERAL, + vkh::ClearColorValue(0.4f, 0.5f, 0.6f, 1.0f), 1, + vkh::ImageSubresourceRange()); + + VkImageView curView = mainWindow->GetView(); + VkRenderPassAttachmentBeginInfoKHR usedView = { + VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR, NULL, 1, &curView, + }; + + vkCmdBeginRenderPass( + cmd, vkh::RenderPassBeginInfo(mainWindow->rp, fb, mainWindow->scissor).next(&usedView), + VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); + vkCmdSetViewport(cmd, 0, 1, &mainWindow->viewport); + vkCmdSetScissor(cmd, 0, 1, &mainWindow->scissor); + vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {0}); + vkCmdDraw(cmd, 3, 1, 0, 0); + + vkCmdEndRenderPass(cmd); + + FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + + vkEndCommandBuffer(cmd); + + Submit(0, 1, {cmd}); + + Present(); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/tests/Vulkan/VK_Imageless_Framebuffer.py b/util/test/tests/Vulkan/VK_Imageless_Framebuffer.py new file mode 100644 index 000000000..5b975f0d4 --- /dev/null +++ b/util/test/tests/Vulkan/VK_Imageless_Framebuffer.py @@ -0,0 +1,34 @@ +import renderdoc as rd +import rdtest + + +class VK_Imageless_Framebuffer(rdtest.TestCase): + demos_test_name = 'VK_Imageless_Framebuffer' + + def check_capture(self): + draw = self.find_draw("Draw") + + self.check(draw is not None) + + self.controller.SetFrameEvent(draw.eventId, False) + + # Make an output so we can pick pixels + out: rd.ReplayOutput = self.controller.CreateOutput(rd.CreateHeadlessWindowingData(100, 100), rd.ReplayOutputType.Texture) + + pipe: rd.PipeState = self.controller.GetPipelineState() + + tex = rd.TextureDisplay() + tex.resourceId = pipe.GetOutputTargets()[0].resourceId + out.SetTextureDisplay(tex) + + texdetails = self.get_texture(tex.resourceId) + + picked: rd.PixelValue = out.PickPixel(tex.resourceId, False, + int(texdetails.width / 2), int(texdetails.height / 2), 0, 0, 0) + + if not rdtest.value_compare(picked.floatValue, [1.0, 0.0, 0.0, 1.0]): + raise rdtest.TestFailureException("Picked value {} doesn't match expectation".format(picked.floatValue)) + + rdtest.log.success("picked value is as expected") + + out.Shutdown()