diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index 594a7f763..636479034 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -291,6 +291,7 @@ TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, DescriptorBinding) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, DescriptorSet) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, ImageData) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, ImageLayout) +TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, RenderArea) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, SpecializationConstant) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, XFBBuffer) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, VKPipe, VertexBuffer) diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index e2ca8da1d..dfe3429a2 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -284,6 +284,18 @@ VulkanPipelineStateViewer::VulkanPipelineStateViewer(ICaptureContext &ctx, ui->scissors->setInstantTooltips(true); } + { + RDHeaderView *header = new RDHeaderView(Qt::Horizontal, this); + ui->discards->setHeader(header); + + ui->discards->setColumns({tr("Slot"), tr("X"), tr("Y"), tr("Width"), tr("Height")}); + header->setColumnStretchHints({-1, -1, -1, -1, 1}); + header->setMinimumSectionSize(40); + + ui->discards->setClearSelectionOnFocusLoss(true); + ui->discards->setInstantTooltips(true); + } + for(RDLabel *rp : {ui->renderpass, ui->framebuffer, ui->predicateBuffer, ui->csPredicateBuffer}) { rp->setAutoFillBackground(true); @@ -663,6 +675,9 @@ void VulkanPipelineStateViewer::clearState() ui->viewports->clear(); ui->scissors->clear(); + ui->discards->clear(); + ui->discardMode->setText(tr("Inclusive")); + ui->discardGroup->setVisible(false); ui->renderpass->setText(QFormatStr("Render Pass: %1").arg(ToQStr(ResourceId()))); ui->framebuffer->setText(QFormatStr("Framebuffer: %1").arg(ToQStr(ResourceId()))); @@ -1981,6 +1996,34 @@ void VulkanPipelineStateViewer::setState() //////////////////////////////////////////////// // Rasterizer + vs = ui->discards->verticalScrollBar()->value(); + ui->discards->beginUpdate(); + ui->discards->clear(); + + { + int i = 0; + for(const VKPipe::RenderArea &v : state.viewportScissor.discardRectangles) + { + RDTreeWidgetItem *node = new RDTreeWidgetItem({i, v.x, v.y, v.width, v.height}); + ui->discards->addTopLevelItem(node); + + if(v.width == 0 || v.height == 0) + setEmptyRow(node); + + i++; + } + } + + ui->discards->verticalScrollBar()->setValue(vs); + ui->discards->clearSelection(); + ui->discards->endUpdate(); + + ui->discardMode->setText(state.viewportScissor.discardRectanglesExclusive ? tr("Exclusive") + : tr("Inclusive")); + + ui->discardGroup->setVisible(!state.viewportScissor.discardRectanglesExclusive || + !state.viewportScissor.discardRectangles.isEmpty()); + vs = ui->viewports->verticalScrollBar()->value(); ui->viewports->beginUpdate(); ui->viewports->clear(); diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui index d0b626622..8e4f9fc0a 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui @@ -1696,116 +1696,6 @@ 0 - - - - - 0 - 0 - - - - Scissor Regions - - - - 2 - - - 2 - - - 2 - - - 2 - - - - - QFrame::Box - - - QFrame::Plain - - - QAbstractItemView::NoEditTriggers - - - false - - - 0 - - - false - - - true - - - 50 - - - - - - - - - - - 0 - 0 - - - - Viewports - - - - 2 - - - 2 - - - 2 - - - 2 - - - - - QFrame::Box - - - QFrame::Plain - - - QAbstractItemView::NoEditTriggers - - - false - - - 0 - - - false - - - true - - - 50 - - - - - - @@ -2512,6 +2402,193 @@ + + + + 0 + + + + + + 0 + 1 + + + + Scissor Regions + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractScrollArea::AdjustToContents + + + QAbstractItemView::NoEditTriggers + + + false + + + 0 + + + false + + + true + + + 50 + + + + + + + + + + + 0 + 1 + + + + Discard Rectangles + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 12 + + + + Exclusive + + + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractScrollArea::AdjustToContents + + + QAbstractItemView::NoEditTriggers + + + false + + + 0 + + + false + + + 50 + + + + + + + + + + + + + 0 + 0 + + + + Viewports + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QFrame::Box + + + QFrame::Plain + + + QAbstractItemView::NoEditTriggers + + + false + + + 0 + + + false + + + true + + + 50 + + + + + + @@ -3552,7 +3629,7 @@ 0 0 911 - 458 + 394 diff --git a/renderdoc/api/replay/vk_pipestate.h b/renderdoc/api/replay/vk_pipestate.h index d36d73dbe..e289de5cc 100644 --- a/renderdoc/api/replay/vk_pipestate.h +++ b/renderdoc/api/replay/vk_pipestate.h @@ -566,6 +566,39 @@ struct TransformFeedback rdcarray buffers; }; +DOCUMENT("Describes a render area in the current framebuffer."); +struct RenderArea +{ + DOCUMENT(""); + RenderArea() = default; + RenderArea(const RenderArea &) = default; + bool operator==(const RenderArea &o) const + { + return x == o.x && y == o.y && width == o.width && height == o.height; + } + bool operator<(const RenderArea &o) const + { + if(!(x == o.x)) + return x < o.x; + if(!(y == o.y)) + return y < o.y; + if(!(width == o.width)) + return width < o.width; + if(!(height == o.height)) + return height < o.height; + return false; + } + + DOCUMENT("The X co-ordinate of the render area."); + int32_t x = 0; + DOCUMENT("The Y co-ordinate of the render area."); + int32_t y = 0; + DOCUMENT("The width of the render area."); + int32_t width = 0; + DOCUMENT("The height of the render area."); + int32_t height = 0; +}; + DOCUMENT("Describes a combined viewport and scissor region."); struct ViewportScissor { @@ -574,7 +607,14 @@ struct ViewportScissor ViewportScissor(const ViewportScissor &) = default; bool operator==(const ViewportScissor &o) const { return vp == o.vp && scissor == o.scissor; } - bool operator<(const ViewportScissor &o) const { return vp == o.vp && scissor == o.scissor; } + bool operator<(const ViewportScissor &o) const + { + if(!(vp == o.vp)) + return vp < o.vp; + if(!(scissor == o.scissor)) + return scissor < o.scissor; + return false; + } DOCUMENT("The :class:`Viewport`."); Viewport vp; DOCUMENT("The :class:`Scissor`."); @@ -590,6 +630,21 @@ struct ViewState DOCUMENT("A list of :class:`VKViewportScissor`."); rdcarray viewportScissors; + + DOCUMENT("A list of :class:`VKRenderArea` defining discard rectangles."); + rdcarray discardRectangles; + + DOCUMENT(R"( ``True`` if a fragment in any one of the discard rectangles fails the discard test, +and a fragment in none of them passes. + +``False`` if a fragment in any one of the discard rectangles passes the discard test, +and a fragment in none of them is discarded. + +.. note: + A ``True`` value and an empty list of :data:`discardRectangles` means the test is effectively + disabled, since with no rectangles no fragment can be inside one. +)"); + bool discardRectanglesExclusive = true; }; DOCUMENT("Describes the rasterizer state in the pipeline."); @@ -839,23 +894,6 @@ struct Framebuffer uint32_t layers = 0; }; -DOCUMENT("Describes the render area for a render pass instance."); -struct RenderArea -{ - DOCUMENT(""); - RenderArea() = default; - RenderArea(const RenderArea &) = default; - - DOCUMENT("The X co-ordinate of the render area."); - int32_t x = 0; - DOCUMENT("The Y co-ordinate of the render area."); - int32_t y = 0; - DOCUMENT("The width of the render area."); - int32_t width = 0; - DOCUMENT("The height of the render area."); - int32_t height = 0; -}; - DOCUMENT("Describes the current pass instance at the current time."); struct CurrentPass { diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index c283478fc..5d68018b9 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -520,6 +520,7 @@ enum class VulkanChunk : uint32_t vkCmdBeginConditionalRenderingEXT, vkCmdEndConditionalRenderingEXT, vkCmdSetSampleLocationsEXT, + vkCmdSetDiscardRectangleEXT, Max, }; @@ -680,12 +681,15 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceASTCDecodeFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceConditionalRenderingFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceConservativeRasterizationPropertiesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDepthStencilResolvePropertiesKHR); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDiscardRectanglePropertiesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDriverPropertiesKHR); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceExternalBufferInfo); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceExternalFenceInfo); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceExternalImageFormatInfo); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceExternalSemaphoreInfo); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceFeatures2); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceFloat16Int8FeaturesKHR); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceFloatControlsPropertiesKHR); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceGroupProperties); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceIDProperties); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceImageFormatInfo2); @@ -707,8 +711,6 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderAtomicInt64FeaturesKHR); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderCorePropertiesAMD); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderDrawParameterFeatures); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderImageFootprintFeaturesNV); -DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceFloat16Int8FeaturesKHR); -DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceFloatControlsPropertiesKHR); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceSampleLocationsPropertiesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceSparseImageFormatInfo2); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceSubgroupProperties); @@ -722,6 +724,7 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceVulkanMemoryModelFeaturesKHR); DECLARE_REFLECTION_STRUCT(VkPipelineCacheCreateInfo); DECLARE_REFLECTION_STRUCT(VkPipelineColorBlendStateCreateInfo); DECLARE_REFLECTION_STRUCT(VkPipelineDepthStencilStateCreateInfo); +DECLARE_REFLECTION_STRUCT(VkPipelineDiscardRectangleStateCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkPipelineDynamicStateCreateInfo); DECLARE_REFLECTION_STRUCT(VkPipelineInputAssemblyStateCreateInfo); DECLARE_REFLECTION_STRUCT(VkPipelineLayoutCreateInfo); @@ -890,6 +893,7 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceASTCDecodeFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceConditionalRenderingFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceConservativeRasterizationPropertiesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDepthStencilResolvePropertiesKHR); +DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDiscardRectanglePropertiesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDriverPropertiesKHR); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceExternalBufferInfo); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceExternalFenceInfo); @@ -932,6 +936,7 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceVulkanMemoryModelFeaturesKHR); DECLARE_DESERIALISE_TYPE(VkPipelineCacheCreateInfo); DECLARE_DESERIALISE_TYPE(VkPipelineColorBlendStateCreateInfo); DECLARE_DESERIALISE_TYPE(VkPipelineDepthStencilStateCreateInfo); +DECLARE_DESERIALISE_TYPE(VkPipelineDiscardRectangleStateCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkPipelineDynamicStateCreateInfo); DECLARE_DESERIALISE_TYPE(VkPipelineInputAssemblyStateCreateInfo); DECLARE_DESERIALISE_TYPE(VkPipelineLayoutCreateInfo); @@ -1139,6 +1144,7 @@ DECLARE_REFLECTION_ENUM(VkDescriptorUpdateTemplateType); DECLARE_REFLECTION_ENUM(VkDeviceEventTypeEXT); DECLARE_REFLECTION_ENUM(VkDeviceGroupPresentModeFlagBitsKHR); DECLARE_REFLECTION_ENUM(VkDeviceQueueCreateFlagBits); +DECLARE_REFLECTION_ENUM(VkDiscardRectangleModeEXT); DECLARE_REFLECTION_ENUM(VkDisplayEventTypeEXT); DECLARE_REFLECTION_ENUM(VkDisplayPlaneAlphaFlagBitsKHR); DECLARE_REFLECTION_ENUM(VkDisplayPowerStateEXT); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 28e2faccf..3964417d4 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -657,6 +657,9 @@ static const VkExtensionProperties supportedExtensions[] = { { VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME, VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION, }, + { + VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME, VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION, + }, { VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME, VK_EXT_DISPLAY_CONTROL_SPEC_VERSION, }, @@ -2772,6 +2775,8 @@ bool WrappedVulkan::ProcessChunk(ReadSerialiser &ser, VulkanChunk chunk) return Serialise_vkCmdEndConditionalRenderingEXT(ser, VK_NULL_HANDLE); case VulkanChunk::vkCmdSetSampleLocationsEXT: return Serialise_vkCmdSetSampleLocationsEXT(ser, VK_NULL_HANDLE, NULL); + case VulkanChunk::vkCmdSetDiscardRectangleEXT: + return Serialise_vkCmdSetDiscardRectangleEXT(ser, VK_NULL_HANDLE, 0, 0, NULL); default: { SystemChunk system = (SystemChunk)chunk; diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 84a1a8a46..5a8269317 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -2007,4 +2007,10 @@ public: void vkGetPhysicalDeviceMultisamplePropertiesEXT(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT *pMultisampleProperties); + + // VK_EXT_discard_rectangles + + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdSetDiscardRectangleEXT, VkCommandBuffer commandBuffer, + uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, + const VkRect2D *pDiscardRectangles); }; diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index 2714c01cd..2b9ddafb5 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -354,7 +354,8 @@ DeclExt(KHR_create_renderpass2); \ DeclExt(EXT_transform_feedback); \ DeclExt(EXT_conditional_rendering); \ - DeclExt(EXT_sample_locations); + DeclExt(EXT_sample_locations); \ + DeclExt(EXT_discard_rectangles); // for simplicity and since the check itself is platform agnostic, // these aren't protected in platform defines @@ -421,7 +422,8 @@ CheckExt(KHR_create_renderpass2, VKXX); \ CheckExt(EXT_transform_feedback, VKXX); \ CheckExt(EXT_conditional_rendering, VKXX); \ - CheckExt(EXT_sample_locations, VKXX); + CheckExt(EXT_sample_locations, VKXX); \ + CheckExt(EXT_discard_rectangles, VKXX); #define HookInitVulkanInstanceExts() \ HookInitExtension(KHR_surface, DestroySurfaceKHR); \ @@ -552,6 +554,7 @@ HookInitExtension(EXT_conditional_rendering, CmdBeginConditionalRenderingEXT); \ HookInitExtension(EXT_conditional_rendering, CmdEndConditionalRenderingEXT); \ HookInitExtension(EXT_sample_locations, CmdSetSampleLocationsEXT); \ + HookInitExtension(EXT_discard_rectangles, CmdSetDiscardRectangleEXT); \ HookInitDevice_PlatformSpecific() #define DefineHooks() \ @@ -1112,6 +1115,9 @@ const VkSampleLocationsInfoEXT *, pSampleLocationsInfo); \ HookDefine3(void, vkGetPhysicalDeviceMultisamplePropertiesEXT, VkPhysicalDevice, physicalDevice, \ VkSampleCountFlagBits, samples, VkMultisamplePropertiesEXT *, pMultisampleProperties); \ + HookDefine4(void, vkCmdSetDiscardRectangleEXT, VkCommandBuffer, commandBuffer, uint32_t, \ + firstDiscardRectangle, uint32_t, discardRectangleCount, const VkRect2D *, \ + pDiscardRectangles); \ HookDefine_PlatformSpecific() struct VkLayerInstanceDispatchTableExtended : VkLayerInstanceDispatchTable diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 1794d0b52..1cf0bc306 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -334,6 +334,25 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, Vulk scissors[i] = pCreateInfo->pViewportState->pScissors[i]; } + // VkPipelineDiscardRectangleStateCreateInfoEXT + discardMode = VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT; + + const VkPipelineDiscardRectangleStateCreateInfoEXT *discardRects = + (const VkPipelineDiscardRectangleStateCreateInfoEXT *)FindNextStruct( + pCreateInfo, VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT); + if(discardRects) + { + discardRectangles.resize(discardRects->discardRectangleCount); + + if(discardRects->pDiscardRectangles) + { + for(uint32_t i = 0; i < discardRects->discardRectangleCount; i++) + discardRectangles[i] = discardRects->pDiscardRectangles[i]; + } + + discardMode = discardRects->discardRectangleMode; + } + // VkPipelineRasterStateCreateInfo depthClampEnable = pCreateInfo->pRasterizationState->depthClampEnable ? true : false; rasterizerDiscardEnable = pCreateInfo->pRasterizationState->rasterizerDiscardEnable ? true : false; diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 40b2e6891..53ab7c6fe 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -270,6 +270,10 @@ struct VulkanCreationInfo // VkPipelineDynamicStateCreateInfo bool dynamicStates[VkDynamicCount]; + + // VkPipelineDiscardRectangleStateCreateInfoEXT + std::vector discardRectangles; + VkDiscardRectangleModeEXT discardMode; }; map m_Pipeline; diff --git a/renderdoc/driver/vulkan/vk_next_chains.cpp b/renderdoc/driver/vulkan/vk_next_chains.cpp index e3bb3e83b..b9cca8c53 100644 --- a/renderdoc/driver/vulkan/vk_next_chains.cpp +++ b/renderdoc/driver/vulkan/vk_next_chains.cpp @@ -151,12 +151,16 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, VkPhysicalDeviceASTCDecodeFeaturesEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT, \ VkPhysicalDeviceBufferAddressFeaturesEXT); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT, \ + VkPhysicalDeviceConditionalRenderingFeaturesEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT, \ VkPhysicalDeviceConservativeRasterizationPropertiesEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV, \ VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR, \ VkPhysicalDeviceDepthStencilResolvePropertiesKHR); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT, \ + VkPhysicalDeviceDiscardRectanglePropertiesEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR, \ VkPhysicalDeviceDriverPropertiesKHR); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO, \ @@ -232,13 +236,13 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR, \ VkPhysicalDeviceVulkanMemoryModelFeaturesKHR); \ - COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT, \ - VkPhysicalDeviceConditionalRenderingFeaturesEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, VkPipelineCacheCreateInfo); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, \ VkPipelineColorBlendStateCreateInfo); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, \ VkPipelineDepthStencilStateCreateInfo); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT, \ + VkPipelineDiscardRectangleStateCreateInfoEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, \ VkPipelineDynamicStateCreateInfo); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, \ @@ -459,7 +463,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT: \ - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV: \ @@ -478,7 +481,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT: \ case VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV: \ case VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV: \ - case VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT: \ case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD: \ case VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV: \ case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV: \ diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index ef5c2b830..fd643e0d4 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1049,6 +1049,24 @@ void VulkanReplay::SavePipelineState() } } + { + m_VulkanPipelineState.viewportScissor.discardRectangles.resize(p.discardRectangles.size()); + for(size_t i = 0; i < p.discardRectangles.size() && i < state.discardRectangles.size(); i++) + { + m_VulkanPipelineState.viewportScissor.discardRectangles[i].x = + state.discardRectangles[i].offset.x; + m_VulkanPipelineState.viewportScissor.discardRectangles[i].y = + state.discardRectangles[i].offset.y; + m_VulkanPipelineState.viewportScissor.discardRectangles[i].width = + state.discardRectangles[i].extent.width; + m_VulkanPipelineState.viewportScissor.discardRectangles[i].height = + state.discardRectangles[i].extent.height; + } + + m_VulkanPipelineState.viewportScissor.discardRectanglesExclusive = + (p.discardMode == VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT); + } + // Rasterizer m_VulkanPipelineState.rasterizer.depthClampEnable = p.depthClampEnable; m_VulkanPipelineState.rasterizer.rasterizerDiscardEnable = p.rasterizerDiscardEnable; @@ -1211,6 +1229,9 @@ void VulkanReplay::SavePipelineState() *stages[i] = VKPipe::Shader(); m_VulkanPipelineState.viewportScissor.viewportScissors.clear(); + m_VulkanPipelineState.viewportScissor.discardRectangles.clear(); + m_VulkanPipelineState.viewportScissor.discardRectanglesExclusive = true; + m_VulkanPipelineState.colorBlend.blends.clear(); } diff --git a/renderdoc/driver/vulkan/vk_serialise.cpp b/renderdoc/driver/vulkan/vk_serialise.cpp index 04c1cbf6e..196d06f76 100644 --- a/renderdoc/driver/vulkan/vk_serialise.cpp +++ b/renderdoc/driver/vulkan/vk_serialise.cpp @@ -445,6 +445,12 @@ SERIALISE_VK_HANDLES(); PNEXT_STRUCT(VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, \ VkDebugUtilsMessengerCreateInfoEXT) \ \ + /* VK_EXT_discard_rectangles */ \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT, \ + VkPhysicalDeviceDiscardRectanglePropertiesEXT) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT, \ + VkPipelineDiscardRectangleStateCreateInfoEXT) \ + \ /* VK_EXT_display_control */ \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT, VkDisplayPowerInfoEXT) \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT, VkDeviceEventInfoEXT) \ @@ -788,10 +794,6 @@ SERIALISE_VK_HANDLES(); PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT) \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT) \ \ - /* VK_EXT_discard_rectangles */ \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT) \ - \ /* VK_EXT_external_memory_host */ \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT) \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT) \ @@ -4951,6 +4953,43 @@ void Deserialise(const VkFenceGetFdInfoKHR &el) DeserialiseNext(el.pNext); } +template +void DoSerialise(SerialiserType &ser, VkPhysicalDeviceDiscardRectanglePropertiesEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(maxDiscardRectangles); +} + +template <> +void Deserialise(const VkPhysicalDeviceDiscardRectanglePropertiesEXT &el) +{ + DeserialiseNext(el.pNext); +} + +template +void DoSerialise(SerialiserType &ser, VkPipelineDiscardRectangleStateCreateInfoEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER_VKFLAGS(VkPipelineDiscardRectangleStateCreateFlagsEXT, flags); + + SERIALISE_MEMBER(discardRectangleMode); + SERIALISE_MEMBER(discardRectangleCount); + SERIALISE_MEMBER_ARRAY(pDiscardRectangles, discardRectangleCount); +} + +template <> +void Deserialise(const VkPipelineDiscardRectangleStateCreateInfoEXT &el) +{ + DeserialiseNext(el.pNext); + delete[] el.pDiscardRectangles; +} + template void DoSerialise(SerialiserType &ser, VkDisplayPowerInfoEXT &el) { @@ -6173,6 +6212,7 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDevice8BitStorageFeaturesKHR); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceASTCDecodeFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceConservativeRasterizationPropertiesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDepthStencilResolvePropertiesKHR); +INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDiscardRectanglePropertiesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDriverPropertiesKHR); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceExternalBufferInfo); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceExternalFenceInfo); @@ -6213,6 +6253,7 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceConditionalRenderingFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPipelineCacheCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkPipelineColorBlendStateCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkPipelineDepthStencilStateCreateInfo); +INSTANTIATE_SERIALISE_TYPE(VkPipelineDiscardRectangleStateCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkPipelineDynamicStateCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkPipelineInputAssemblyStateCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkPipelineLayoutCreateInfo); diff --git a/renderdoc/driver/vulkan/vk_state.cpp b/renderdoc/driver/vulkan/vk_state.cpp index 54449caf5..6967dc9e0 100644 --- a/renderdoc/driver/vulkan/vk_state.cpp +++ b/renderdoc/driver/vulkan/vk_state.cpp @@ -275,6 +275,10 @@ void VulkanRenderState::BindPipeline(VkCommandBuffer cmd, PipelineBinding bindin ObjDisp(cmd)->CmdSetSampleLocationsEXT(Unwrap(cmd), &info); } + if(!discardRectangles.empty() && dynamicStates[VkDynamicDiscardRectangleEXT]) + ObjDisp(cmd)->CmdSetDiscardRectangleEXT(Unwrap(cmd), 0, (uint32_t)discardRectangles.size(), + &discardRectangles[0]); + // only set push constant ranges that the layout uses for(size_t i = 0; i < pushRanges.size(); i++) ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(layout), pushRanges[i].stageFlags, diff --git a/renderdoc/driver/vulkan/vk_state.h b/renderdoc/driver/vulkan/vk_state.h index bd6d01355..20c1ea7dd 100644 --- a/renderdoc/driver/vulkan/vk_state.h +++ b/renderdoc/driver/vulkan/vk_state.h @@ -82,6 +82,8 @@ struct VulkanRenderState std::vector locations; } sampleLocations; + std::vector discardRectangles; + // this should be big enough for any implementation byte pushconsts[1024]; // the actual number of bytes that have been uploaded diff --git a/renderdoc/driver/vulkan/vk_stringise.cpp b/renderdoc/driver/vulkan/vk_stringise.cpp index 7345a2e56..f1a9b5948 100644 --- a/renderdoc/driver/vulkan/vk_stringise.cpp +++ b/renderdoc/driver/vulkan/vk_stringise.cpp @@ -28,7 +28,7 @@ template <> std::string DoStringise(const VulkanChunk &el) { - RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1131, "Chunks changed without updating names"); + RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1132, "Chunks changed without updating names"); BEGIN_ENUM_STRINGISE(VulkanChunk) { @@ -163,6 +163,7 @@ std::string DoStringise(const VulkanChunk &el) STRINGISE_ENUM_CLASS(vkCmdBeginConditionalRenderingEXT) STRINGISE_ENUM_CLASS(vkCmdEndConditionalRenderingEXT) STRINGISE_ENUM_CLASS(vkCmdSetSampleLocationsEXT) + STRINGISE_ENUM_CLASS(vkCmdSetDiscardRectangleEXT) STRINGISE_ENUM_CLASS_NAMED(Max, "Max Chunk"); } END_ENUM_STRINGISE() @@ -2216,6 +2217,17 @@ std::string DoStringise(const VkDisplayEventTypeEXT &el) END_ENUM_STRINGISE(); } +template <> +std::string DoStringise(const VkDiscardRectangleModeEXT &el) +{ + BEGIN_ENUM_STRINGISE(VkDiscardRectangleModeEXT); + { + STRINGISE_ENUM(VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT) + STRINGISE_ENUM(VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT) + } + END_ENUM_STRINGISE(); +} + template <> std::string DoStringise(const VkPointClippingBehavior &el) { diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 9c7a4b867..0501ee5b5 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -1879,6 +1879,10 @@ bool WrappedVulkan::Serialise_vkCmdBindPipeline(SerialiserType &ser, VkCommandBu m_RenderState.sampleLocations.sampleCount = m_CreationInfo.m_Pipeline[liveid].rasterizationSamples; } + if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VkDynamicDiscardRectangleEXT]) + { + m_RenderState.discardRectangles = m_CreationInfo.m_Pipeline[liveid].discardRectangles; + } } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp index 2471b736e..df0a73d44 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp @@ -667,6 +667,81 @@ void WrappedVulkan::vkCmdSetSampleLocationsEXT(VkCommandBuffer commandBuffer, } } +template +bool WrappedVulkan::Serialise_vkCmdSetDiscardRectangleEXT(SerialiserType &ser, + VkCommandBuffer commandBuffer, + uint32_t firstDiscardRectangle, + uint32_t discardRectangleCount, + const VkRect2D *pDiscardRectangles) +{ + SERIALISE_ELEMENT(commandBuffer); + SERIALISE_ELEMENT(firstDiscardRectangle); + SERIALISE_ELEMENT(discardRectangleCount); + SERIALISE_ELEMENT_ARRAY(pDiscardRectangles, discardRectangleCount); + + Serialise_DebugMessages(ser); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + m_LastCmdBufferID = GetResourceManager()->GetOriginalID(GetResID(commandBuffer)); + + if(IsActiveReplaying(m_State)) + { + if(InRerecordRange(m_LastCmdBufferID)) + { + commandBuffer = RerecordCmdBuf(m_LastCmdBufferID); + + if(ShouldUpdateRenderState(m_LastCmdBufferID)) + { + if(m_RenderState.discardRectangles.size() < firstDiscardRectangle + discardRectangleCount) + m_RenderState.discardRectangles.resize(firstDiscardRectangle + discardRectangleCount); + + for(uint32_t i = 0; i < discardRectangleCount; i++) + m_RenderState.discardRectangles[firstDiscardRectangle + i] = pDiscardRectangles[i]; + } + } + else + { + commandBuffer = VK_NULL_HANDLE; + } + } + + if(commandBuffer != VK_NULL_HANDLE) + ObjDisp(commandBuffer) + ->CmdSetDiscardRectangleEXT(Unwrap(commandBuffer), firstDiscardRectangle, + discardRectangleCount, pDiscardRectangles); + } + + return true; +} + +void WrappedVulkan::vkCmdSetDiscardRectangleEXT(VkCommandBuffer commandBuffer, + uint32_t firstDiscardRectangle, + uint32_t discardRectangleCount, + const VkRect2D *pDiscardRectangles) +{ + SCOPED_DBG_SINK(); + + SERIALISE_TIME_CALL(ObjDisp(commandBuffer) + ->CmdSetDiscardRectangleEXT(Unwrap(commandBuffer), firstDiscardRectangle, + discardRectangleCount, pDiscardRectangles)); + + if(IsCaptureMode(m_State)) + { + VkResourceRecord *record = GetRecord(commandBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCmdSetDiscardRectangleEXT); + Serialise_vkCmdSetDiscardRectangleEXT(ser, commandBuffer, firstDiscardRectangle, + discardRectangleCount, pDiscardRectangles); + + record->AddChunk(scope.Get()); + } +} + INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetViewport, VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports); @@ -698,4 +773,8 @@ INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetStencilReference, VkCommandBuffer VkStencilFaceFlags faceMask, uint32_t reference); INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetSampleLocationsEXT, VkCommandBuffer commandBuffer, - const VkSampleLocationsInfoEXT *pSampleLocationsInfo); \ No newline at end of file + const VkSampleLocationsInfoEXT *pSampleLocationsInfo); + +INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetDiscardRectangleEXT, VkCommandBuffer commandBuffer, + uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, + const VkRect2D *pDiscardRectangles); \ No newline at end of file diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 40a908164..ebb2f1fd5 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -1976,8 +1976,10 @@ template void DoSerialise(SerialiserType &ser, VKPipe::ViewState &el) { SERIALISE_MEMBER(viewportScissors); + SERIALISE_MEMBER(discardRectangles); + SERIALISE_MEMBER(discardRectanglesExclusive); - SIZE_CHECK(16); + SIZE_CHECK(40); } template @@ -2181,7 +2183,7 @@ void DoSerialise(SerialiserType &ser, VKPipe::State &el) SERIALISE_MEMBER(conditionalRendering); - SIZE_CHECK(1408); + SIZE_CHECK(1432); } #pragma endregion Vulkan pipeline state diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index 4add3184f..3ff7a167e 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -192,6 +192,7 @@ + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index 84cfcd6c6..632f0c4b2 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -249,6 +249,9 @@ Vulkan\demos + + Vulkan\demos + diff --git a/util/test/demos/vk/vk_discard_rects.cpp b/util/test/demos/vk/vk_discard_rects.cpp new file mode 100644 index 000000000..b8f8495bf --- /dev/null +++ b/util/test/demos/vk/vk_discard_rects.cpp @@ -0,0 +1,209 @@ +/****************************************************************************** + * 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" + +struct VK_Discard_Rectangles : VulkanGraphicsTest +{ + static constexpr const char *Description = + "Draws a large number of triangles using VK_EXT_discard_rectangles discard rectangles to " + "either cut-out or filter for a series of rects"; + + 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 = vertIn.col; +} + +)EOSHADER"; + + int main(int argc, char **argv) + { + instExts.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + devExts.push_back(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME); + + // initialise, create window, create context, etc + if(!Init(argc, argv)) + return 3; + + VkPhysicalDeviceDiscardRectanglePropertiesEXT discardProps = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT}; + + vkGetPhysicalDeviceProperties2KHR(phys, vkh::PhysicalDeviceProperties2KHR().next(&discardProps)); + + const int32_t w = (int32_t)scissor.extent.width; + const int32_t h = (int32_t)scissor.extent.height; + + VkRect2D discardRects[] = { + // TL eye + {{64, 64}, {64, 64}}, + // TR eye + {{w - 64 * 2, 64}, {64, 64}}, + // nose + {{w / 2 - 16, 128}, {32, 32}}, + // long mouth + {{96, h - 48}, {(uint32_t)w - 96 * 2, 32}}, + // left mouth edge + {{64, h - 48 - 32}, {32, 32}}, + // right mouth edge + {{w - 96, h - 48 - 32}, {32, 32}}, + }; + + TEST_ASSERT(discardProps.maxDiscardRectangles >= ARRAY_COUNT(discardRects), + "not enough discard rectangles supported"); + + VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo()); + + vkh::GraphicsPipelineCreateInfo pipeCreateInfo; + + pipeCreateInfo.layout = layout; + pipeCreateInfo.renderPass = swapRenderPass; + + 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"), + }; + + pipeCreateInfo.dynamicState.dynamicStates.push_back(VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT); + + VkPipelineDiscardRectangleStateCreateInfoEXT discardInfo = { + VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT, + }; + discardInfo.discardRectangleMode = VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT; + discardInfo.discardRectangleCount = ARRAY_COUNT(discardRects); + + pipeCreateInfo.pNext = &discardInfo; + + VkPipeline pipe = createGraphicsPipeline(pipeCreateInfo); + + discardInfo.discardRectangleMode = VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT; + + VkPipeline pipe2 = createGraphicsPipeline(pipeCreateInfo); + + DefaultA2V trispam[3000]; + for(int i = 0; i < 3000; i++) + { + trispam[i].pos = Vec3f(RANDF(-1.0f, 1.0f), RANDF(-1.0f, 1.0f), RANDF(0.0f, 1.0f)); + trispam[i].col = Vec4f(RANDF(0.0f, 1.0f), RANDF(0.0f, 1.0f), RANDF(0.0f, 1.0f), 1.0f); + trispam[i].uv = Vec2f(0.0f, 0.0f); + } + + AllocatedBuffer vb(allocator, + vkh::BufferCreateInfo(sizeof(trispam), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); + + vb.upload(trispam); + + while(Running()) + { + 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()); + + vkCmdBeginRenderPass( + cmd, vkh::RenderPassBeginInfo(swapRenderPass, swapFramebuffers[swapIndex], scissor), + VK_SUBPASS_CONTENTS_INLINE); + + VkViewport view = viewport; + view.width /= 2.0f; + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); + vkCmdSetDiscardRectangleEXT(cmd, 0, ARRAY_COUNT(discardRects), discardRects); + vkCmdSetViewport(cmd, 0, 1, &view); + vkCmdSetScissor(cmd, 0, 1, &scissor); + vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {0}); + vkCmdDraw(cmd, 3000, 1, 0, 0); + + view.x += view.width; + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2); + vkCmdSetViewport(cmd, 0, 1, &view); + vkCmdDraw(cmd, 3000, 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(VK_Discard_Rectangles); \ No newline at end of file