From 7a4e68959f5235f1ad6b445882e4290620c9ae62 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 22 Oct 2021 14:48:58 +0100 Subject: [PATCH] Support VK_EXT_load_store_op_none & color_write_enable. Closes #2363 * These are added together because VK_EXT_load_store_op_none is easier to test in a realistic fashion using VK_EXT_color_write_enable --- renderdoc/driver/vulkan/extension_support.md | 4 +- renderdoc/driver/vulkan/vk_common.h | 5 + renderdoc/driver/vulkan/vk_core.cpp | 8 + renderdoc/driver/vulkan/vk_core.h | 7 + renderdoc/driver/vulkan/vk_hookset_defs.h | 11 +- renderdoc/driver/vulkan/vk_info.cpp | 16 ++ renderdoc/driver/vulkan/vk_info.h | 4 +- renderdoc/driver/vulkan/vk_next_chains.cpp | 6 +- renderdoc/driver/vulkan/vk_overlay.cpp | 5 + renderdoc/driver/vulkan/vk_pixelhistory.cpp | 9 + renderdoc/driver/vulkan/vk_replay.cpp | 3 + renderdoc/driver/vulkan/vk_serialise.cpp | 44 ++- renderdoc/driver/vulkan/vk_state.cpp | 7 + renderdoc/driver/vulkan/vk_state.h | 3 + renderdoc/driver/vulkan/vk_stringise.cpp | 3 +- .../driver/vulkan/wrappers/vk_cmd_funcs.cpp | 39 ++- .../vulkan/wrappers/vk_device_funcs.cpp | 9 + .../vulkan/wrappers/vk_dynamic_funcs.cpp | 69 +++++ .../driver/vulkan/wrappers/vk_misc_funcs.cpp | 36 ++- util/test/demos/CMakeLists.txt | 1 + util/test/demos/demos.vcxproj | 1 + util/test/demos/demos.vcxproj.filters | 3 + util/test/demos/vk/vk_load_store_none.cpp | 268 ++++++++++++++++++ util/test/tests/Vulkan/VK_Load_Store_None.py | 21 ++ 24 files changed, 550 insertions(+), 32 deletions(-) create mode 100644 util/test/demos/vk/vk_load_store_none.cpp create mode 100644 util/test/tests/Vulkan/VK_Load_Store_None.py diff --git a/renderdoc/driver/vulkan/extension_support.md b/renderdoc/driver/vulkan/extension_support.md index 316fd0550..9b9b42809 100644 --- a/renderdoc/driver/vulkan/extension_support.md +++ b/renderdoc/driver/vulkan/extension_support.md @@ -26,6 +26,7 @@ Maintainers can update this file by updating vk.xml in this folder and running ` * `VK_EXT_astc_decode_mode` * `VK_EXT_buffer_device_address` * `VK_EXT_calibrated_timestamps` +* `VK_EXT_color_write_enable` * `VK_EXT_conditional_rendering` * `VK_EXT_conservative_rasterization` * `VK_EXT_custom_border_color` @@ -55,6 +56,7 @@ Maintainers can update this file by updating vk.xml in this folder and running ` * `VK_EXT_index_type_uint8` * `VK_EXT_inline_uniform_block` * `VK_EXT_line_rasterization` +* `VK_EXT_load_store_op_none` * `VK_EXT_memory_budget` * `VK_EXT_memory_priority` * `VK_EXT_metal_surface` @@ -220,12 +222,10 @@ Ray tracing extensions are now standard and will likely be supported at some poi * `VK_EXT_acquire_drm_display` * `VK_EXT_blend_operation_advanced` * `VK_EXT_border_color_swizzle` -* `VK_EXT_color_write_enable` * `VK_EXT_device_memory_report` * `VK_EXT_extended_dynamic_state2` * `VK_EXT_external_memory_host` * `VK_EXT_image_drm_format_modifier` -* `VK_EXT_load_store_op_none` * `VK_EXT_multi_draw` * `VK_EXT_pageable_device_local_memory` * `VK_EXT_physical_device_drm` diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index fe6262bfb..dc17bafdd 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -715,6 +715,7 @@ enum class VulkanChunk : uint32_t vkCmdWriteTimestamp2KHR, vkQueueSubmit2KHR, vkCmdWriteBufferMarker2AMD, + vkCmdSetColorWriteEnableEXT, Max, }; @@ -917,6 +918,7 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceASTCDecodeFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceBufferDeviceAddressFeatures); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceBufferDeviceAddressFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceCoherentMemoryFeaturesAMD); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceColorWriteEnableFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceComputeShaderDerivativesFeaturesNV); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceConditionalRenderingFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceConservativeRasterizationPropertiesEXT); @@ -1026,6 +1028,7 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceYcbcrImageArraysFeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR); DECLARE_REFLECTION_STRUCT(VkPipelineCacheCreateInfo); DECLARE_REFLECTION_STRUCT(VkPipelineColorBlendStateCreateInfo); +DECLARE_REFLECTION_STRUCT(VkPipelineColorWriteCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkPipelineCreationFeedbackCreateInfoEXT); DECLARE_REFLECTION_STRUCT(VkPipelineDepthStencilStateCreateInfo); DECLARE_REFLECTION_STRUCT(VkPipelineDiscardRectangleStateCreateInfoEXT); @@ -1262,6 +1265,7 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDevice16BitStorageFeatures); DECLARE_DESERIALISE_TYPE(VkPhysicalDevice8BitStorageFeatures); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceASTCDecodeFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceCoherentMemoryFeaturesAMD); +DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceColorWriteEnableFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceComputeShaderDerivativesFeaturesNV); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceConditionalRenderingFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceConservativeRasterizationPropertiesEXT); @@ -1371,6 +1375,7 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceYcbcrImageArraysFeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR); DECLARE_DESERIALISE_TYPE(VkPipelineCacheCreateInfo); DECLARE_DESERIALISE_TYPE(VkPipelineColorBlendStateCreateInfo); +DECLARE_DESERIALISE_TYPE(VkPipelineColorWriteCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkPipelineCreationFeedbackCreateInfoEXT); DECLARE_DESERIALISE_TYPE(VkPipelineDepthStencilStateCreateInfo); DECLARE_DESERIALISE_TYPE(VkPipelineDiscardRectangleStateCreateInfoEXT); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 96779c071..dd11fd8f6 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -878,6 +878,9 @@ static const VkExtensionProperties supportedExtensions[] = { { VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION, }, + { + VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME, VK_EXT_COLOR_WRITE_ENABLE_SPEC_VERSION, + }, { VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME, VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION, }, @@ -965,6 +968,9 @@ static const VkExtensionProperties supportedExtensions[] = { { VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME, VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION, }, + { + VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME, VK_EXT_LOAD_STORE_OP_NONE_SPEC_VERSION, + }, { VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, VK_EXT_LINE_RASTERIZATION_SPEC_VERSION, }, @@ -3478,6 +3484,8 @@ bool WrappedVulkan::ProcessChunk(ReadSerialiser &ser, VulkanChunk chunk) case VulkanChunk::vkCmdWriteBufferMarker2AMD: return Serialise_vkCmdWriteBufferMarker2AMD(ser, VK_NULL_HANDLE, VK_PIPELINE_STAGE_2_NONE_KHR, VK_NULL_HANDLE, 0, 0); + case VulkanChunk::vkCmdSetColorWriteEnableEXT: + return Serialise_vkCmdSetColorWriteEnableEXT(ser, VK_NULL_HANDLE, 0, NULL); // chunks that are reserved but not yet serialised case VulkanChunk::vkResetCommandPool: diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 5de08e8ab..fbb2b7fa3 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -407,6 +407,7 @@ private: bool m_SeparateDepthStencil = false; bool m_NULLDescriptorsAllowed = false; bool m_ExtendedDynState = false; + bool m_DynColorWrite = false; PFN_vkSetDeviceLoaderData m_SetDeviceLoaderData; @@ -1122,6 +1123,7 @@ public: bool SeparateDepthStencil() const { return m_SeparateDepthStencil; } bool NULLDescriptorsAllowed() const { return m_NULLDescriptorsAllowed; } bool ExtendedDynamicState() const { return m_ExtendedDynState; } + bool DynamicColorWrite() const { return m_DynColorWrite; } VulkanRenderState &GetRenderState() { return m_RenderState; } void SetActionCB(VulkanActionCallback *cb) { m_ActionCallback = cb; } void SetSubmitChain(void *submitChain) { m_SubmitChain = submitChain; } @@ -2473,4 +2475,9 @@ public: const VkDeviceImageMemoryRequirementsKHR *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements); + + // VK_EXT_color_write_enable + + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdSetColorWriteEnableEXT, VkCommandBuffer commandBuffer, + uint32_t attachmentCount, const VkBool32 *pColorWriteEnables); }; diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index fb77f1d95..5734f4cfd 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -529,7 +529,8 @@ DeclExt(KHR_copy_commands2); \ DeclExt(KHR_synchronization2); \ DeclExt(KHR_present_wait); \ - DeclExt(KHR_maintenance4); + DeclExt(KHR_maintenance4); \ + DeclExt(EXT_color_write_enable); // for simplicity and since the check itself is platform agnostic, // these aren't protected in platform defines @@ -629,7 +630,10 @@ CheckExt(EXT_private_data, VKXX); \ CheckExt(EXT_extended_dynamic_state, VKXX); \ CheckExt(KHR_copy_commands2, VKXX); \ - CheckExt(KHR_synchronization2, VKXX); + CheckExt(KHR_synchronization2, VKXX); \ + CheckExt(KHR_present_wait, VKXX); \ + CheckExt(KHR_maintenance4, VKXX); \ + CheckExt(EXT_color_write_enable, VKXX); #define HookInitVulkanInstanceExts_PhysDev() \ HookInitExtension(KHR_surface, GetPhysicalDeviceSurfaceSupportKHR); \ @@ -874,6 +878,7 @@ HookInitExtension(KHR_maintenance4, GetDeviceBufferMemoryRequirementsKHR); \ HookInitExtension(KHR_maintenance4, GetDeviceImageMemoryRequirementsKHR); \ HookInitExtension(KHR_maintenance4, GetDeviceImageSparseMemoryRequirementsKHR); \ + HookInitExtension(EXT_color_write_enable, CmdSetColorWriteEnableEXT); \ /* No GetQueueCheckpointData2NV without VK_NV_device_diagnostic_checkpoints */ \ HookInitExtension_Device_Win32(); \ HookInitExtension_Device_Linux(); \ @@ -1570,6 +1575,8 @@ const VkDeviceImageMemoryRequirementsKHR *, pInfo, uint32_t *, \ pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *, \ pSparseMemoryRequirements); \ + HookDefine3(void, vkCmdSetColorWriteEnableEXT, VkCommandBuffer, commandBuffer, uint32_t, \ + attachmentCount, const VkBool32 *, pColorWriteEnables); \ HookDefine_Win32(); \ HookDefine_Linux(); \ HookDefine_GGP(); \ diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 8e3c3dd29..d859712fc 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -699,6 +699,22 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, attachments.clear(); } + + // this struct probably will never get used, since the user could just set the colorWriteMask + // above to 0. It's really only useful for specifying how the dynamic state works. However just + // for completeness... + const VkPipelineColorWriteCreateInfoEXT *colorWriteEnable = + (const VkPipelineColorWriteCreateInfoEXT *)FindNextStruct( + pCreateInfo->pRasterizationState, VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT); + if(colorWriteEnable) + { + RDCASSERTEQUAL(attachments.size(), colorWriteEnable->attachmentCount); + for(size_t i = 0; i < attachments.size() && i < colorWriteEnable->attachmentCount; i++) + { + if(!colorWriteEnable->pColorWriteEnables[i]) + attachments[i].channelWriteMask = 0; + } + } } void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, VulkanCreationInfo &info, diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 026c60f34..8cb415d6c 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -374,7 +374,7 @@ struct VulkanCreationInfo VkLogicOp logicOp; float blendConst[4]; - struct Attachment + struct CBAttachment { bool blendEnable; @@ -387,7 +387,7 @@ struct VulkanCreationInfo uint8_t channelWriteMask; }; - rdcarray attachments; + rdcarray attachments; // VkPipelineDynamicStateCreateInfo bool dynamicStates[VkDynamicCount]; diff --git a/renderdoc/driver/vulkan/vk_next_chains.cpp b/renderdoc/driver/vulkan/vk_next_chains.cpp index 9629bdd6b..11182c480 100644 --- a/renderdoc/driver/vulkan/vk_next_chains.cpp +++ b/renderdoc/driver/vulkan/vk_next_chains.cpp @@ -203,6 +203,8 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, VkPhysicalDeviceBufferDeviceAddressFeatures); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD, \ VkPhysicalDeviceCoherentMemoryFeaturesAMD); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT, \ + VkPhysicalDeviceColorWriteEnableFeaturesEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV, \ VkPhysicalDeviceComputeShaderDerivativesFeaturesNV); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT, \ @@ -416,6 +418,8 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, VkPipelineCreationFeedbackCreateInfoEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, \ VkPipelineColorBlendStateCreateInfo); \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT, \ + VkPipelineColorWriteCreateInfoEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT, \ VkPipelineRasterizationDepthClipStateCreateInfoEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, \ @@ -726,7 +730,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT: \ - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV: \ @@ -775,7 +778,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT: \ case VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT: \ - case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: \ case VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD: \ case VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV: \ case VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV: \ diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index b7bd3713a..7d3b965b0 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -2766,6 +2766,11 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D state.front.passOp, state.front.depthFailOp, state.front.compareOp); } + else if(d == VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT) + { + vt->CmdSetColorWriteEnableEXT(Unwrap(cmd), (uint32_t)state.colorWriteEnable.size(), + state.colorWriteEnable.data()); + } } if(fmt.indexByteStride) diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index 3f685b5e5..5f2abfa21 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -687,6 +687,15 @@ protected: descs[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; descs[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; descs[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + if(rpInfo.attachments[i].loadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT) + descs[i].loadOp = VK_ATTACHMENT_LOAD_OP_NONE_EXT; + if(rpInfo.attachments[i].storeOp == VK_ATTACHMENT_STORE_OP_NONE_EXT) + descs[i].storeOp = VK_ATTACHMENT_STORE_OP_NONE_EXT; + if(rpInfo.attachments[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT) + descs[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_NONE_EXT; + if(rpInfo.attachments[i].stencilStoreOp == VK_ATTACHMENT_STORE_OP_NONE_EXT) + descs[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_NONE_EXT; + descs[i].initialLayout = rpInfo.attachments[i].initialLayout; descs[i].finalLayout = rpInfo.attachments[i].finalLayout; } diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index d04ad935e..7a6154ad8 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1452,6 +1452,9 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) MakeBlendOp(p.attachments[i].alphaBlend.Operation); ret.colorBlend.blends[i].writeMask = p.attachments[i].channelWriteMask; + + if(i < state.colorWriteEnable.size() && !state.colorWriteEnable[i]) + ret.colorBlend.blends[i].writeMask = 0; } ret.colorBlend.blendFactor = state.blendConst; diff --git a/renderdoc/driver/vulkan/vk_serialise.cpp b/renderdoc/driver/vulkan/vk_serialise.cpp index 4e44187f2..9fb73e253 100644 --- a/renderdoc/driver/vulkan/vk_serialise.cpp +++ b/renderdoc/driver/vulkan/vk_serialise.cpp @@ -556,6 +556,12 @@ SERIALISE_VK_HANDLES(); /* VK_EXT_calibrated_timestamps */ \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, VkCalibratedTimestampInfoEXT) \ \ + /* VK_EXT_color_write_enable */ \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT, \ + VkPhysicalDeviceColorWriteEnableFeaturesEXT) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT, \ + VkPipelineColorWriteCreateInfoEXT) \ + \ /* VK_EXT_conditional_rendering */ \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT, \ VkCommandBufferInheritanceConditionalRenderingInfoEXT) \ @@ -1256,10 +1262,6 @@ SERIALISE_VK_HANDLES(); PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT) \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT) \ \ - /* VK_EXT_color_write_enable */ \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT) \ - \ /* VK_EXT_device_memory_report */ \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT) \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT) \ @@ -7695,6 +7697,38 @@ void Deserialise(const VkCalibratedTimestampInfoEXT &el) DeserialiseNext(el.pNext); } +template +void DoSerialise(SerialiserType &ser, VkPhysicalDeviceColorWriteEnableFeaturesEXT &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(colorWriteEnable); +} + +template <> +void Deserialise(const VkPhysicalDeviceColorWriteEnableFeaturesEXT &el) +{ + DeserialiseNext(el.pNext); +} + +template +void DoSerialise(SerialiserType &ser, VkPipelineColorWriteCreateInfoEXT &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(attachmentCount); + SERIALISE_MEMBER_ARRAY(pColorWriteEnables, attachmentCount); +} + +template <> +void Deserialise(const VkPipelineColorWriteCreateInfoEXT &el) +{ + DeserialiseNext(el.pNext); +} + template void DoSerialise(SerialiserType &ser, VkSwapchainCounterCreateInfoEXT &el) { @@ -9731,6 +9765,7 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceASTCDecodeFeaturesEXT) INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceBufferDeviceAddressFeatures); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceBufferDeviceAddressFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceCoherentMemoryFeaturesAMD); +INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceColorWriteEnableFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceComputeShaderDerivativesFeaturesNV); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceConditionalRenderingFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceConservativeRasterizationPropertiesEXT); @@ -9838,6 +9873,7 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceYcbcrImageArraysFeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR); INSTANTIATE_SERIALISE_TYPE(VkPipelineCacheCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkPipelineColorBlendStateCreateInfo); +INSTANTIATE_SERIALISE_TYPE(VkPipelineColorWriteCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkPipelineCreationFeedbackCreateInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkPipelineDepthStencilStateCreateInfo); INSTANTIATE_SERIALISE_TYPE(VkPipelineDiscardRectangleStateCreateInfoEXT); diff --git a/renderdoc/driver/vulkan/vk_state.cpp b/renderdoc/driver/vulkan/vk_state.cpp index c004593cf..cbcea9ea4 100644 --- a/renderdoc/driver/vulkan/vk_state.cpp +++ b/renderdoc/driver/vulkan/vk_state.cpp @@ -181,6 +181,13 @@ void VulkanRenderState::BindPipeline(WrappedVulkan *vk, VkCommandBuffer cmd, if(!scissors.empty() && dynamicStates[VkDynamicScissor]) ObjDisp(cmd)->CmdSetScissor(Unwrap(cmd), 0, (uint32_t)scissors.size(), &scissors[0]); + if(vk->DynamicColorWrite()) + { + if(!colorWriteEnable.empty() && dynamicStates[VkDynamicColorWriteEXT]) + ObjDisp(cmd)->CmdSetColorWriteEnableEXT(Unwrap(cmd), (uint32_t)colorWriteEnable.size(), + colorWriteEnable.data()); + } + if(vk->ExtendedDynamicState()) { if(!views.empty() && dynamicStates[VkDynamicViewportCountEXT]) diff --git a/renderdoc/driver/vulkan/vk_state.h b/renderdoc/driver/vulkan/vk_state.h index 50fa46531..410f6f787 100644 --- a/renderdoc/driver/vulkan/vk_state.h +++ b/renderdoc/driver/vulkan/vk_state.h @@ -191,6 +191,9 @@ struct VulkanRenderState VkBool32 stencilTestEnable = VK_FALSE; + // color write enable + rdcarray colorWriteEnable; + private: ResourceId framebuffer; rdcarray fbattachments; diff --git a/renderdoc/driver/vulkan/vk_stringise.cpp b/renderdoc/driver/vulkan/vk_stringise.cpp index 14c232977..07238c405 100644 --- a/renderdoc/driver/vulkan/vk_stringise.cpp +++ b/renderdoc/driver/vulkan/vk_stringise.cpp @@ -28,7 +28,7 @@ template <> rdcstr DoStringise(const VulkanChunk &el) { - RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1166, "Chunks changed without updating names"); + RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1167, "Chunks changed without updating names"); BEGIN_ENUM_STRINGISE(VulkanChunk) { @@ -198,6 +198,7 @@ rdcstr DoStringise(const VulkanChunk &el) STRINGISE_ENUM_CLASS(vkCmdWriteTimestamp2KHR); STRINGISE_ENUM_CLASS(vkQueueSubmit2KHR); STRINGISE_ENUM_CLASS(vkCmdWriteBufferMarker2AMD); + STRINGISE_ENUM_CLASS(vkCmdSetColorWriteEnableEXT); STRINGISE_ENUM_CLASS_NAMED(Max, "Max Chunk"); } END_ENUM_STRINGISE() diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 5bdf4f956..686912416 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -36,7 +36,7 @@ static rdcstr ToHumanStr(const VkAttachmentLoadOp &el) { case VK_ATTACHMENT_LOAD_OP_LOAD: return "Load"; case VK_ATTACHMENT_LOAD_OP_CLEAR: return "Clear"; - case VK_ATTACHMENT_LOAD_OP_DONT_CARE: return "Don't Care"; + case VK_ATTACHMENT_LOAD_OP_NONE_EXT: return "None"; } END_ENUM_STRINGISE(); } @@ -47,6 +47,7 @@ static rdcstr ToHumanStr(const VkAttachmentStoreOp &el) { case VK_ATTACHMENT_STORE_OP_STORE: return "Store"; case VK_ATTACHMENT_STORE_OP_DONT_CARE: return "Don't Care"; + case VK_ATTACHMENT_STORE_OP_NONE_EXT: return "None"; } END_ENUM_STRINGISE(); } @@ -1485,8 +1486,17 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(SerialiserType &ser, VkComman if(att >= rpinfo.attachments.size()) continue; - if(rpinfo.attachments[att].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR || - rpinfo.attachments[att].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) + VkImageAspectFlags clearAspects = 0; + + // loadOp governs color, and depth + if(rpinfo.attachments[att].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) + clearAspects |= VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT; + // stencilLoadOp governs the stencil + if(rpinfo.attachments[att].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) + clearAspects |= VK_IMAGE_ASPECT_STENCIL_BIT; + + // if any aspect is set to clear, go check it in more detail + if(clearAspects != 0) { VulkanCreationInfo::ImageView viewinfo = m_CreationInfo.m_ImageView[fbattachments[att]]; @@ -1498,8 +1508,15 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(SerialiserType &ser, VkComman clear.clearValue = unwrappedInfo.pClearValues[att]; else RDCWARN("Missing clear value for attachment %u", att); - clearrects.push_back(rect); - clearatts.push_back(clear); + + // check that the actual aspects in the attachment overlap with those being cleared. + // In particular this means we ignore stencil load op being CLEAR for a color + // attachment - that doesn't mean we should clear the color + if(clear.aspectMask & clearAspects) + { + clearrects.push_back(rect); + clearatts.push_back(clear); + } } } @@ -1662,7 +1679,8 @@ void WrappedVulkan::vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, if(renderArea_covers_entire_framebuffer && framebuffer_reference_entire_attachment) { - if(rpInfo->loadOpTable[i] != VK_ATTACHMENT_LOAD_OP_LOAD) + if(rpInfo->loadOpTable[i] != VK_ATTACHMENT_LOAD_OP_LOAD && + rpInfo->loadOpTable[i] != VK_ATTACHMENT_LOAD_OP_NONE_EXT) { refType = eFrameRef_CompleteWrite; } @@ -2291,7 +2309,8 @@ void WrappedVulkan::vkCmdBeginRenderPass2(VkCommandBuffer commandBuffer, if(renderArea_covers_entire_framebuffer && framebuffer_reference_entire_attachment) { - if(rpInfo->loadOpTable[i] != VK_ATTACHMENT_LOAD_OP_LOAD) + if(rpInfo->loadOpTable[i] != VK_ATTACHMENT_LOAD_OP_LOAD && + rpInfo->loadOpTable[i] != VK_ATTACHMENT_LOAD_OP_NONE_EXT) { refType = eFrameRef_CompleteWrite; } @@ -2758,6 +2777,12 @@ bool WrappedVulkan::Serialise_vkCmdBindPipeline(SerialiserType &ser, VkCommandBu renderstate.vbuffers[bind.vbufferBinding].stride = bind.bytestride; } } + if(!pipeInfo.dynamicStates[VkDynamicColorWriteEXT]) + { + renderstate.colorWriteEnable.resize(pipeInfo.attachments.size()); + for(size_t i = 0; i < renderstate.colorWriteEnable.size(); i++) + renderstate.colorWriteEnable[i] = pipeInfo.attachments[i].channelWriteMask != 0; + } } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index cc0529946..6be04b2f2 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -2799,6 +2799,15 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi CHECK_PHYS_EXT_FEATURE(globalPriorityQuery); } END_PHYS_EXT_CHECK(); + + BEGIN_PHYS_EXT_CHECK(VkPhysicalDeviceColorWriteEnableFeaturesEXT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT); + { + CHECK_PHYS_EXT_FEATURE(colorWriteEnable); + + m_DynColorWrite = (ext->colorWriteEnable != VK_FALSE); + } + END_PHYS_EXT_CHECK(); } if(availFeatures.depthClamp) diff --git a/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp index 04efbc445..f3f38762d 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp @@ -1514,6 +1514,72 @@ void WrappedVulkan::vkCmdSetStencilOpEXT(VkCommandBuffer commandBuffer, VkStenci } } +template +bool WrappedVulkan::Serialise_vkCmdSetColorWriteEnableEXT(SerialiserType &ser, + VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkBool32 *pColorWriteEnables) +{ + SERIALISE_ELEMENT(commandBuffer); + SERIALISE_ELEMENT(attachmentCount); + SERIALISE_ELEMENT_ARRAY(pColorWriteEnables, attachmentCount).Important(); + + 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); + + { + VulkanRenderState &renderstate = GetCmdRenderState(); + renderstate.colorWriteEnable.assign(pColorWriteEnables, attachmentCount); + } + } + else + { + commandBuffer = VK_NULL_HANDLE; + } + } + + if(commandBuffer != VK_NULL_HANDLE) + ObjDisp(commandBuffer) + ->CmdSetColorWriteEnableEXT(Unwrap(commandBuffer), attachmentCount, pColorWriteEnables); + } + + return true; +} + +void WrappedVulkan::vkCmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer, + uint32_t attachmentCount, + const VkBool32 *pColorWriteEnables) +{ + SCOPED_DBG_SINK(); + + SERIALISE_TIME_CALL( + ObjDisp(commandBuffer) + ->CmdSetColorWriteEnableEXT(Unwrap(commandBuffer), attachmentCount, pColorWriteEnables)); + + if(IsCaptureMode(m_State)) + { + VkResourceRecord *record = GetRecord(commandBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCmdSetColorWriteEnableEXT); + Serialise_vkCmdSetColorWriteEnableEXT(ser, commandBuffer, attachmentCount, pColorWriteEnables); + + record->AddChunk(scope.Get(&record->cmdInfo->alloc)); + } +} + INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetViewport, VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports); @@ -1587,3 +1653,6 @@ INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetStencilTestEnableEXT, VkCommandBuf INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetStencilOpEXT, VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); + +INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetColorWriteEnableEXT, VkCommandBuffer commandBuffer, + uint32_t attachmentCount, const VkBool32 *pColorWriteEnables); diff --git a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp index 48613daf1..3ae5743b4 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp @@ -957,8 +957,10 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass(SerialiserType &ser, VkDevice d { if(m_ReplayOptions.optimisation != ReplayOptimisationLevel::Fastest) { - att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + if(att[i].storeOp != VK_ATTACHMENT_STORE_OP_NONE_EXT) + att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + if(att[i].stencilStoreOp != VK_ATTACHMENT_STORE_OP_NONE_EXT) + att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE) { @@ -1035,8 +1037,10 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass(SerialiserType &ser, VkDevice d // without doing a clear or a DONT_CARE load. for(uint32_t i = 0; i < CreateInfo.attachmentCount; i++) { - att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + if(att[i].loadOp != VK_ATTACHMENT_LOAD_OP_NONE_EXT) + att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + if(att[i].stencilLoadOp != VK_ATTACHMENT_LOAD_OP_NONE_EXT) + att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; } VkRenderPassCreateInfo loadInfo = CreateInfo; @@ -1139,8 +1143,10 @@ VkResult WrappedVulkan::vkCreateRenderPass(VkDevice device, const VkRenderPassCr for(uint32_t i = 0; i < info.attachmentCount; i++) { atts[i] = info.pAttachments[i]; - atts[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - atts[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + if(atts[i].loadOp != VK_ATTACHMENT_LOAD_OP_NONE_EXT) + atts[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + if(atts[i].stencilLoadOp != VK_ATTACHMENT_LOAD_OP_NONE_EXT) + atts[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; } info.pAttachments = atts.data(); @@ -1207,8 +1213,10 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass2(SerialiserType &ser, VkDevice VkAttachmentDescription2 *att = (VkAttachmentDescription2 *)CreateInfo.pAttachments; for(uint32_t i = 0; i < CreateInfo.attachmentCount; i++) { - att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + if(att[i].storeOp != VK_ATTACHMENT_STORE_OP_NONE_EXT) + att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + if(att[i].stencilStoreOp != VK_ATTACHMENT_STORE_OP_NONE_EXT) + att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE) att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; @@ -1265,8 +1273,10 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass2(SerialiserType &ser, VkDevice // without doing a clear or a DONT_CARE load. for(uint32_t i = 0; i < CreateInfo.attachmentCount; i++) { - att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + if(att[i].loadOp != VK_ATTACHMENT_LOAD_OP_NONE_EXT) + att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + if(att[i].stencilLoadOp != VK_ATTACHMENT_LOAD_OP_NONE_EXT) + att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; } VkRenderPassCreateInfo2 loadInfo = CreateInfo; @@ -1371,8 +1381,10 @@ VkResult WrappedVulkan::vkCreateRenderPass2(VkDevice device, for(uint32_t i = 0; i < info.attachmentCount; i++) { atts[i] = info.pAttachments[i]; - atts[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - atts[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + if(atts[i].loadOp != VK_ATTACHMENT_LOAD_OP_NONE_EXT) + atts[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + if(atts[i].stencilLoadOp != VK_ATTACHMENT_LOAD_OP_NONE_EXT) + atts[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; } info.pAttachments = atts.data(); diff --git a/util/test/demos/CMakeLists.txt b/util/test/demos/CMakeLists.txt index 909f7b1dd..a56c23e2f 100644 --- a/util/test/demos/CMakeLists.txt +++ b/util/test/demos/CMakeLists.txt @@ -29,6 +29,7 @@ set(VULKAN_SRC vk/vk_large_descriptor_sets.cpp vk/vk_leak_check.cpp vk/vk_line_raster.cpp + vk/vk_load_store_none.cpp vk/vk_mesh_zoo.cpp vk/vk_misaligned_dirty.cpp vk/vk_multi_thread_windows.cpp diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index a93261701..f522be259 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -290,6 +290,7 @@ + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index 343d3725e..4083a4ab2 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -607,6 +607,9 @@ D3D12\demos + + Vulkan\demos + diff --git a/util/test/demos/vk/vk_load_store_none.cpp b/util/test/demos/vk/vk_load_store_none.cpp new file mode 100644 index 000000000..f1fb8fcc0 --- /dev/null +++ b/util/test/demos/vk/vk_load_store_none.cpp @@ -0,0 +1,268 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 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" + +RD_TEST(VK_Load_Store_None, VulkanGraphicsTest) +{ + static constexpr const char *Description = + "Tests the use of LOAD_OP_NONE and STORE_OP_NONE to preserve an attachment without " + "modification."; + + std::string pixel = R"EOSHADER( +#version 460 core + +layout(location = 0, index = 0) out vec4 Color1; +layout(location = 1, index = 0) out vec4 Color2; + +void main() +{ + Color1 = Color2 = vec4(1.0, 0.0, 0.0, 1.0); +} + +)EOSHADER"; + + void Prepare(int argc, char **argv) + { + devExts.push_back(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME); + + // require dynamic color write enable for the easiest time testing both load and store op none. + // + // these ops are there because renderpasses with different ops but everything else is the same + // are still compatible, so these can be switched last minute without needing to recompile a + // pipeline. So the cases they are useful are those where a pipeline is declared to use an + // attachment then at the last minute the application realises it doesn't need it. + // + // NONE store op can be useful on its own in a couple of scenarios when you're using read-only + // depth, as there's no way to express "this was not written and no synchronisation is needed" + // because don't care and store are both write operations. + // + // NONE load op is only useful when you want to preserve an attachment that's now unused but had + // it declared as modified and e.g. load/store'd at creation time. For depth this could happen + // with EXT_extended_dynamic_state if you disabled depth testing which was previously used, + // and wanted to preserve the depth. That's more annoying to test though, so we require + // color_write_enable for the same purpose (dynamically disabling). + // + // We could just create the pipeline as not writing to those attachments from the start, but + // that would be a bit too artificial and not how this is used in practice. + devExts.push_back(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME); + + VulkanGraphicsTest::Prepare(argc, argv); + + static VkPhysicalDeviceColorWriteEnableFeaturesEXT colorEnableFeats = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT, + }; + + colorEnableFeats.colorWriteEnable = VK_TRUE; + devInfoNext = &colorEnableFeats; + } + + int main() + { + // initialise, create window, create context, etc + if(!Init()) + return 3; + + VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo({})); + + AllocatedImage img( + this, + vkh::ImageCreateInfo(mainWindow->scissor.extent.width, mainWindow->scissor.extent.height, 0, + VK_FORMAT_R32G32B32A32_SFLOAT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); + + VkImageView imgview = createImageView( + vkh::ImageViewCreateInfo(img.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32G32B32A32_SFLOAT)); + + AllocatedImage preserveimg( + this, + vkh::ImageCreateInfo(mainWindow->scissor.extent.width, mainWindow->scissor.extent.height, 0, + VK_FORMAT_R32G32B32A32_SFLOAT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); + + setName(preserveimg.image, "PreserveImg"); + + VkImageView preserveimgview = createImageView(vkh::ImageViewCreateInfo( + preserveimg.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32G32B32A32_SFLOAT)); + + vkh::RenderPassCreator renderPassCreateInfo; + + renderPassCreateInfo.attachments.push_back( + vkh::AttachmentDescription(VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_CLEAR)); + // unused attachment + renderPassCreateInfo.attachments.push_back(vkh::AttachmentDescription( + VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, + VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE)); + + renderPassCreateInfo.addSubpass({VkAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL}), + VkAttachmentReference({1, VK_IMAGE_LAYOUT_GENERAL})}); + + // this RP has clear/store + VkRenderPass pipeRP = createRenderPass(renderPassCreateInfo); + + renderPassCreateInfo.attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_NONE_EXT; + renderPassCreateInfo.attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_NONE_EXT; + + // this RP has none/none and will be used for rendering + VkRenderPass renderPass = createRenderPass(renderPassCreateInfo); + + VkFramebuffer framebuffer = createFramebuffer(vkh::FramebufferCreateInfo( + renderPass, {imgview, preserveimgview}, mainWindow->scissor.extent)); + + vkh::GraphicsPipelineCreateInfo pipeCreateInfo; + + pipeCreateInfo.layout = layout; + pipeCreateInfo.renderPass = pipeRP; + + 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(VKDefaultVertex, ShaderLang::glsl, ShaderStage::vert, "main"), + CompileShaderModule(pixel, ShaderLang::glsl, ShaderStage::frag, "main"), + }; + + pipeCreateInfo.dynamicState.dynamicStates.push_back(VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT); + + pipeCreateInfo.colorBlendState.attachments.push_back({ + // blendEnable + VK_FALSE, + // color* + VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD, + // alpha* + VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD, + // colorWriteMask + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT, + }); + + VkPipeline pipe = createGraphicsPipeline(pipeCreateInfo); + + AllocatedBuffer vb( + this, 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); + + { + VkCommandBuffer cmd = GetCommandBuffer(); + + vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); + + // put the attachment in GENERAL + vkh::cmdPipelineBarrier( + cmd, { + vkh::ImageMemoryBarrier(0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, + preserveimg.image), + }); + + // use the original pipeline's RP to clear and store + vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(pipeRP, framebuffer, mainWindow->scissor, + {vkh::ClearValue(0.2f, 0.2f, 0.2f, 1.0f), + vkh::ClearValue(0.2f, 0.2f, 0.2f, 1.0f)}), + VK_SUBPASS_CONTENTS_INLINE); + + // clear a rect in the middle of the preserve attachment to green + VkClearAttachment att = {}; + att.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + att.clearValue.color.float32[1] = 1.0f; + att.clearValue.color.float32[3] = 1.0f; + att.colorAttachment = 1; + VkClearRect rect = {}; + rect.baseArrayLayer = 0; + rect.layerCount = 1; + rect.rect.offset.x = 150; + rect.rect.offset.y = 100; + rect.rect.extent.width = 75; + rect.rect.extent.height = 50; + vkCmdClearAttachments(cmd, 1, &att, 1, &rect); + + vkCmdEndRenderPass(cmd); + + // we'll be reading later, synchronise here once + vkh::cmdPipelineBarrier( + cmd, { + vkh::ImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_GENERAL, preserveimg.image), + }); + + vkEndCommandBuffer(cmd); + + Submit(99, 99, {cmd}); + } + + while(Running()) + { + VkCommandBuffer cmd = GetCommandBuffer(); + + vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); + + VkImage swapimg = + StartUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + + vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(renderPass, framebuffer, mainWindow->scissor, + {vkh::ClearValue(0.2f, 0.2f, 0.2f, 1.0f), + vkh::ClearValue(1.0f, 0.2f, 0.2f, 1.0f)}), + 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}); + + VkBool32 enables[2] = {true, false}; + vkCmdSetColorWriteEnableEXT(cmd, 2, enables); + + vkCmdDraw(cmd, 3, 1, 0, 0); + + vkCmdEndRenderPass(cmd); + + // no need to synchronise here, nothing changed the preserved image + + blitToSwap(cmd, preserveimg.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL); + + 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_Load_Store_None.py b/util/test/tests/Vulkan/VK_Load_Store_None.py new file mode 100644 index 000000000..7dcf47e0a --- /dev/null +++ b/util/test/tests/Vulkan/VK_Load_Store_None.py @@ -0,0 +1,21 @@ +import renderdoc as rd +import rdtest + + +class VK_Load_Store_None(rdtest.TestCase): + demos_test_name = 'VK_Load_Store_None' + + def check_capture(self): + res = self.get_resource_by_name('PreserveImg').resourceId + + for action in [self.find_action("BeginRender"), self.find_action("Draw"), self.find_action("EndRender"), + self.find_action("Blit")]: + self.controller.SetFrameEvent(action.eventId, True) + + self.check_pixel_value(res, 200, 125, [0.0, 1.0, 0.0, 1.0]) + self.check_pixel_value(res, 200, 90, [0.2, 0.2, 0.2, 1.0]) + self.check_pixel_value(res, 200, 160, [0.2, 0.2, 0.2, 1.0]) + self.check_pixel_value(res, 250, 125, [0.2, 0.2, 0.2, 1.0]) + self.check_pixel_value(res, 100, 125, [0.2, 0.2, 0.2, 1.0]) + + rdtest.log.success("Preserved image is as expected at {}".format(self.action_name(action)))