From 17f812b2a0bc441f29f8fac778ec644c42d1be8a Mon Sep 17 00:00:00 2001 From: spencer-lunarg Date: Tue, 4 Jun 2024 19:36:10 -0500 Subject: [PATCH] layers: Add Dual Source Blending check --- layers/core_checks/cc_drawdispatch.cpp | 91 ++++++++++++++++++++++ layers/core_checks/core_validation.h | 1 + layers/drawdispatch/drawdispatch_vuids.cpp | 15 ++++ layers/drawdispatch/drawdispatch_vuids.h | 1 + layers/state_tracker/cmd_buffer_state.cpp | 16 ---- layers/state_tracker/cmd_buffer_state.h | 1 - tests/unit/dynamic_state.cpp | 74 ++++++++---------- tests/unit/dynamic_state_positive.cpp | 66 +++++++++++++++- tests/unit/shader_limits.cpp | 59 ++++++-------- tests/unit/shader_limits_positive.cpp | 90 +++++++++++++++++++++ tests/unit/shader_object.cpp | 71 +++++++---------- 11 files changed, 347 insertions(+), 138 deletions(-) diff --git a/layers/core_checks/cc_drawdispatch.cpp b/layers/core_checks/cc_drawdispatch.cpp index d33b6cf21c1..c95ca0c5826 100644 --- a/layers/core_checks/cc_drawdispatch.cpp +++ b/layers/core_checks/cc_drawdispatch.cpp @@ -1533,6 +1533,7 @@ bool CoreChecks::ValidateActionState(const vvl::CommandBuffer &cb_state, const V skip |= ValidateDrawDynamicState(last_bound_state, vuid); skip |= ValidateDrawPrimitivesGeneratedQuery(last_bound_state, vuid); skip |= ValidateDrawProtectedMemory(last_bound_state, vuid); + skip |= ValidateDrawDualSourceBlend(last_bound_state, vuid); if (pipeline) { skip |= ValidateDrawPipeline(last_bound_state, *pipeline, vuid); @@ -1939,3 +1940,93 @@ bool CoreChecks::ValidateDrawProtectedMemory(const LastBound &last_bound_state, return skip; } + +bool CoreChecks::ValidateDrawDualSourceBlend(const LastBound &last_bound_state, const vvl::DrawDispatchVuid &vuid) const { + bool skip = false; + const vvl::CommandBuffer &cb_state = last_bound_state.cb_state; + const auto *pipeline = last_bound_state.pipeline_state; + if (pipeline && !pipeline->ColorBlendState()) return skip; + + // TODO - have better way to get fragment shader state + std::shared_ptr entrypoint; + if (pipeline) { + for (const auto &stage : pipeline->stage_states) { + if (stage.entrypoint && (stage.entrypoint->stage == VK_SHADER_STAGE_FRAGMENT_BIT)) { + entrypoint = stage.entrypoint; + break; + } + } + } else { + for (const auto stage : last_bound_state.shader_object_states) { + if (stage && stage->entrypoint && (stage->entrypoint->stage == VK_SHADER_STAGE_FRAGMENT_BIT)) { + entrypoint = stage->entrypoint; + break; + } + } + } + if (!entrypoint) return skip; + + uint32_t max_fragment_location = 0; + for (const auto *variable : entrypoint->user_defined_interface_variables) { + if (variable->storage_class != spv::StorageClassOutput) continue; + if (variable->decorations.location != spirv::kInvalidValue) { + max_fragment_location = std::max(max_fragment_location, variable->decorations.location); + } + } + if (max_fragment_location < phys_dev_props.limits.maxFragmentDualSrcAttachments) return skip; + + // If color blend is disabled, the blend equation doesn't matter + const bool dynamic_blend_enable = !pipeline || pipeline->IsDynamic(CB_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT); + const bool dynamic_blend_equation = !pipeline || pipeline->IsDynamic(CB_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT); + const uint32_t attachment_count = pipeline ? pipeline->ColorBlendState()->attachmentCount + : (uint32_t)cb_state.dynamic_state_value.color_blend_equations.size(); + for (uint32_t i = 0; i < attachment_count; ++i) { + const bool blend_enable = dynamic_blend_enable ? cb_state.dynamic_state_value.color_blend_enabled[i] + : pipeline->ColorBlendState()->pAttachments[i].blendEnable; + if (!blend_enable) continue; + if (dynamic_blend_equation) { + const VkColorBlendEquationEXT &color_blend_equation = cb_state.dynamic_state_value.color_blend_equations[i]; + if (IsSecondaryColorInputBlendFactor(color_blend_equation.srcColorBlendFactor) || + IsSecondaryColorInputBlendFactor(color_blend_equation.dstColorBlendFactor) || + IsSecondaryColorInputBlendFactor(color_blend_equation.srcAlphaBlendFactor) || + IsSecondaryColorInputBlendFactor(color_blend_equation.dstAlphaBlendFactor)) { + const LogObjectList objlist = cb_state.GetObjectList(VK_PIPELINE_BIND_POINT_GRAPHICS); + skip |= LogError(vuid.blend_dual_source_09239, objlist, vuid.loc(), + "Fragment output attachment %" PRIu32 + " is using Dual-Source Blending, but the largest output fragment Location (%" PRIu32 + ") is not less than maxFragmentDualSrcAttachments (%" PRIu32 + "). The following are set by vkCmdSetColorBlendEquationEXT:\n\tsrcColorBlendFactor = " + "%s\n\tdstColorBlendFactor = %s\n\tsrcAlphaBlendFactor = " + "%s\n\tdstAlphaBlendFactor = %s\n", + i, max_fragment_location, phys_dev_props.limits.maxFragmentDualSrcAttachments, + string_VkBlendFactor(color_blend_equation.srcColorBlendFactor), + string_VkBlendFactor(color_blend_equation.dstColorBlendFactor), + string_VkBlendFactor(color_blend_equation.srcAlphaBlendFactor), + string_VkBlendFactor(color_blend_equation.dstAlphaBlendFactor)); + break; + } + } else { + const VkPipelineColorBlendAttachmentState &attachment = pipeline->ColorBlendState()->pAttachments[i]; + if (IsSecondaryColorInputBlendFactor(attachment.srcColorBlendFactor) || + IsSecondaryColorInputBlendFactor(attachment.dstColorBlendFactor) || + IsSecondaryColorInputBlendFactor(attachment.srcAlphaBlendFactor) || + IsSecondaryColorInputBlendFactor(attachment.dstAlphaBlendFactor)) { + const LogObjectList objlist = cb_state.GetObjectList(VK_PIPELINE_BIND_POINT_GRAPHICS); + skip |= LogError( + vuid.blend_dual_source_09239, objlist, vuid.loc(), + "Fragment output attachment %" PRIu32 + " is using Dual-Source Blending, but the largest output fragment Location (%" PRIu32 + ") is not less than maxFragmentDualSrcAttachments (%" PRIu32 + "). The following are set by VkPipelineColorBlendAttachmentState:\n\tsrcColorBlendFactor = " + "%s\n\tdstColorBlendFactor = %s\n\tsrcAlphaBlendFactor = %s\n\tdstAlphaBlendFactor " + "= %s\n", + i, max_fragment_location, phys_dev_props.limits.maxFragmentDualSrcAttachments, + string_VkBlendFactor(attachment.srcColorBlendFactor), string_VkBlendFactor(attachment.dstColorBlendFactor), + string_VkBlendFactor(attachment.srcAlphaBlendFactor), string_VkBlendFactor(attachment.dstAlphaBlendFactor)); + break; + } + } + } + + return skip; +} \ No newline at end of file diff --git a/layers/core_checks/core_validation.h b/layers/core_checks/core_validation.h index 3534466e763..5f461799be2 100644 --- a/layers/core_checks/core_validation.h +++ b/layers/core_checks/core_validation.h @@ -108,6 +108,7 @@ class CoreChecks : public ValidationStateTracker { bool ValidateTraceRaysDynamicStateSetStatus(const LastBound& last_bound_state, const vvl::DrawDispatchVuid& vuid) const; bool ValidateDrawPrimitivesGeneratedQuery(const LastBound& last_bound_state, const vvl::DrawDispatchVuid& vuid) const; bool ValidateDrawProtectedMemory(const LastBound& last_bound_state, const vvl::DrawDispatchVuid& vuid) const; + bool ValidateDrawDualSourceBlend(const LastBound& last_bound_state, const vvl::DrawDispatchVuid& vuid) const; bool ValidateStageMaskHost(const LogObjectList& objlist, const Location& stage_mask_loc, VkPipelineStageFlags2KHR stageMask) const; bool ValidateMapMemory(const vvl::DeviceMemory& mem_info, VkDeviceSize offset, VkDeviceSize size, const Location& offset_loc, diff --git a/layers/drawdispatch/drawdispatch_vuids.cpp b/layers/drawdispatch/drawdispatch_vuids.cpp index 0939708eae4..5a0c606e689 100644 --- a/layers/drawdispatch/drawdispatch_vuids.cpp +++ b/layers/drawdispatch/drawdispatch_vuids.cpp @@ -73,6 +73,7 @@ struct DispatchVuidsCmdDraw : DrawDispatchVuid { vertex_input_04914 = "VUID-vkCmdDraw-None-04914"; vertex_input_08734 = "VUID-vkCmdDraw-Input-08734"; blend_enable_04727 = "VUID-vkCmdDraw-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDraw-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDraw-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDraw-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDraw-None-07881"; @@ -389,6 +390,7 @@ struct DispatchVuidsCmdDrawMultiEXT : DrawDispatchVuid { vertex_input_04914 = "VUID-vkCmdDrawMultiEXT-None-04914"; vertex_input_08734 = "VUID-vkCmdDrawMultiEXT-Input-08734"; blend_enable_04727 = "VUID-vkCmdDrawMultiEXT-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawMultiEXT-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawMultiEXT-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawMultiEXT-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawMultiEXT-None-07881"; @@ -706,6 +708,7 @@ struct DispatchVuidsCmdDrawIndexed : DrawDispatchVuid { vertex_input_04914 = "VUID-vkCmdDrawIndexed-None-04914"; vertex_input_08734 = "VUID-vkCmdDrawIndexed-Input-08734"; blend_enable_04727 = "VUID-vkCmdDrawIndexed-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawIndexed-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawIndexed-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawIndexed-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawIndexed-None-07881"; @@ -1023,6 +1026,7 @@ struct DispatchVuidsCmdDrawMultiIndexedEXT : DrawDispatchVuid { vertex_input_04914 = "VUID-vkCmdDrawMultiIndexedEXT-None-04914"; vertex_input_08734 = "VUID-vkCmdDrawMultiIndexedEXT-Input-08734"; blend_enable_04727 = "VUID-vkCmdDrawMultiIndexedEXT-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawMultiIndexedEXT-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawMultiIndexedEXT-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawMultiIndexedEXT-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawMultiIndexedEXT-None-07881"; @@ -1340,6 +1344,7 @@ struct DispatchVuidsCmdDrawIndirect : DrawDispatchVuid { vertex_input_04914 = "VUID-vkCmdDrawIndirect-None-04914"; vertex_input_08734 = "VUID-vkCmdDrawIndirect-Input-08734"; blend_enable_04727 = "VUID-vkCmdDrawIndirect-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawIndirect-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawIndirect-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawIndirect-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawIndirect-None-07881"; @@ -1656,6 +1661,7 @@ struct DispatchVuidsCmdDrawIndexedIndirect : DrawDispatchVuid { vertex_input_04914 = "VUID-vkCmdDrawIndexedIndirect-None-04914"; vertex_input_08734 = "VUID-vkCmdDrawIndexedIndirect-Input-08734"; blend_enable_04727 = "VUID-vkCmdDrawIndexedIndirect-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawIndexedIndirect-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawIndexedIndirect-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawIndexedIndirect-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawIndexedIndirect-None-07881"; @@ -2071,6 +2077,7 @@ struct DispatchVuidsCmdDrawIndirectCount : DrawDispatchVuid { vertex_input_04914 = "VUID-vkCmdDrawIndirectCount-None-04914"; vertex_input_08734 = "VUID-vkCmdDrawIndirectCount-Input-08734"; blend_enable_04727 = "VUID-vkCmdDrawIndirectCount-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawIndirectCount-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawIndirectCount-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawIndirectCount-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawIndirectCount-None-07881"; @@ -2390,6 +2397,7 @@ struct DispatchVuidsCmdDrawIndexedIndirectCount : DrawDispatchVuid { vertex_input_04914 = "VUID-vkCmdDrawIndexedIndirectCount-None-04914"; vertex_input_08734 = "VUID-vkCmdDrawIndexedIndirectCount-Input-08734"; blend_enable_04727 = "VUID-vkCmdDrawIndexedIndirectCount-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawIndexedIndirectCount-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawIndexedIndirectCount-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawIndexedIndirectCount-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawIndexedIndirectCount-None-07881"; @@ -2888,6 +2896,7 @@ struct DispatchVuidsCmdDrawMeshTasksNV: DrawDispatchVuid { depth_bias_enable_04877 = "VUID-vkCmdDrawMeshTasksNV-None-04877"; logic_op_04878 = "VUID-vkCmdDrawMeshTasksNV-logicOp-04878"; blend_enable_04727 = "VUID-vkCmdDrawMeshTasksNV-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawMeshTasksNV-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawMeshTasksNV-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawMeshTasksNV-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawMeshTasksNV-None-07881"; @@ -3190,6 +3199,7 @@ struct DispatchVuidsCmdDrawMeshTasksIndirectNV: DrawDispatchVuid { depth_bias_enable_04877 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-04877"; logic_op_04878 = "VUID-vkCmdDrawMeshTasksIndirectNV-logicOp-04878"; blend_enable_04727 = "VUID-vkCmdDrawMeshTasksIndirectNV-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawMeshTasksIndirectNV-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-07881"; @@ -3495,6 +3505,7 @@ struct DispatchVuidsCmdDrawMeshTasksIndirectCountNV : DrawDispatchVuid { depth_bias_enable_04877 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-04877"; logic_op_04878 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-logicOp-04878"; blend_enable_04727 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-07881"; @@ -3794,6 +3805,7 @@ struct DispatchVuidsCmdDrawMeshTasksEXT: DrawDispatchVuid { depth_bias_enable_04877 = "VUID-vkCmdDrawMeshTasksEXT-None-04877"; logic_op_04878 = "VUID-vkCmdDrawMeshTasksEXT-logicOp-04878"; blend_enable_04727 = "VUID-vkCmdDrawMeshTasksEXT-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawMeshTasksEXT-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawMeshTasksEXT-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawMeshTasksEXT-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawMeshTasksEXT-None-07881"; @@ -4096,6 +4108,7 @@ struct DispatchVuidsCmdDrawMeshTasksIndirectEXT: DrawDispatchVuid { depth_bias_enable_04877 = "VUID-vkCmdDrawMeshTasksIndirectEXT-None-04877"; logic_op_04878 = "VUID-vkCmdDrawMeshTasksIndirectEXT-logicOp-04878"; blend_enable_04727 = "VUID-vkCmdDrawMeshTasksIndirectEXT-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawMeshTasksIndirectEXT-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawMeshTasksIndirectEXT-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawMeshTasksIndirectEXT-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawMeshTasksIndirectEXT-None-07881"; @@ -4401,6 +4414,7 @@ struct DispatchVuidsCmdDrawMeshTasksIndirectCountEXT : DrawDispatchVuid { depth_bias_enable_04877 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-None-04877"; logic_op_04878 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-logicOp-04878"; blend_enable_04727 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-None-07881"; @@ -4713,6 +4727,7 @@ struct DispatchVuidsCmdDrawIndirectByteCountEXT: DrawDispatchVuid { vertex_input_04914 = "VUID-vkCmdDrawIndirectByteCountEXT-None-04914"; vertex_input_08734 = "VUID-vkCmdDrawIndirectByteCountEXT-Input-08734"; blend_enable_04727 = "VUID-vkCmdDrawIndirectByteCountEXT-blendEnable-04727"; + blend_dual_source_09239 = "VUID-vkCmdDrawIndirectByteCountEXT-maxFragmentDualSrcAttachments-09239"; dynamic_discard_rectangle_07751 = "VUID-vkCmdDrawIndirectByteCountEXT-None-07751"; dynamic_discard_rectangle_enable_07880 = "VUID-vkCmdDrawIndirectByteCountEXT-None-07880"; dynamic_discard_rectangle_mode_07881 = "VUID-vkCmdDrawIndirectByteCountEXT-None-07881"; diff --git a/layers/drawdispatch/drawdispatch_vuids.h b/layers/drawdispatch/drawdispatch_vuids.h index ea2d070ba04..654a598e4a4 100644 --- a/layers/drawdispatch/drawdispatch_vuids.h +++ b/layers/drawdispatch/drawdispatch_vuids.h @@ -89,6 +89,7 @@ struct DrawDispatchVuid { const char* vertex_input_04914 = kVUIDUndefined; const char* vertex_input_08734 = kVUIDUndefined; const char* blend_enable_04727 = kVUIDUndefined; + const char* blend_dual_source_09239 = kVUIDUndefined; const char* dynamic_discard_rectangle_07751 = kVUIDUndefined; const char* dynamic_discard_rectangle_enable_07880 = kVUIDUndefined; const char* dynamic_discard_rectangle_mode_07881 = kVUIDUndefined; diff --git a/layers/state_tracker/cmd_buffer_state.cpp b/layers/state_tracker/cmd_buffer_state.cpp index cdef23f6dfe..ac0a61539c4 100644 --- a/layers/state_tracker/cmd_buffer_state.cpp +++ b/layers/state_tracker/cmd_buffer_state.cpp @@ -1715,22 +1715,6 @@ bool CommandBuffer::HasExternalFormatResolveAttachment() const { } return false; } -bool CommandBuffer::HasDynamicDualSourceBlend(uint32_t attachmentCount) const { - if (dynamic_state_value.color_blend_enabled.any()) { - if (IsDynamicStateSet(CB_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT)) { - for (uint32_t i = 0; i < dynamic_state_value.color_blend_equations.size() && i < attachmentCount; ++i) { - const auto &color_blend_equation = dynamic_state_value.color_blend_equations[i]; - if (IsSecondaryColorInputBlendFactor(color_blend_equation.srcColorBlendFactor) || - IsSecondaryColorInputBlendFactor(color_blend_equation.dstColorBlendFactor) || - IsSecondaryColorInputBlendFactor(color_blend_equation.srcAlphaBlendFactor) || - IsSecondaryColorInputBlendFactor(color_blend_equation.dstAlphaBlendFactor)) { - return true; - } - } - } - } - return false; -} void CommandBuffer::BindShader(VkShaderStageFlagBits shader_stage, vvl::ShaderObject *shader_object_state) { auto &lastBoundState = lastBound[ConvertToPipelineBindPoint(shader_stage)]; diff --git a/layers/state_tracker/cmd_buffer_state.h b/layers/state_tracker/cmd_buffer_state.h index bbb820e2c7b..44c82d3844f 100644 --- a/layers/state_tracker/cmd_buffer_state.h +++ b/layers/state_tracker/cmd_buffer_state.h @@ -676,7 +676,6 @@ class CommandBuffer : public RefcountedStateObject { bool HasValidDynamicDepthAttachment() const; bool HasValidDynamicStencilAttachment() const; bool HasExternalFormatResolveAttachment() const; - bool HasDynamicDualSourceBlend(uint32_t attachmentCount) const; inline void BindPipeline(LvlBindPoint bind_point, vvl::Pipeline *pipe_state) { lastBound[bind_point].pipeline_state = pipe_state; diff --git a/tests/unit/dynamic_state.cpp b/tests/unit/dynamic_state.cpp index dcfe688b070..a7b8c960f36 100644 --- a/tests/unit/dynamic_state.cpp +++ b/tests/unit/dynamic_state.cpp @@ -2586,42 +2586,33 @@ TEST_F(NegativeDynamicState, RasterizationConservative) { m_errorMonitor->VerifyFound(); } -// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5208 -TEST_F(NegativeDynamicState, DISABLED_MaxFragmentDualSrcAttachmentsDynamicBlendEnable) { +TEST_F(NegativeDynamicState, MaxFragmentDualSrcAttachmentsDynamicBlendEnable) { TEST_DESCRIPTION( "Test drawing with dual source blending with too many fragment output attachments, but using dynamic blending."); SetTargetApiVersion(VK_API_VERSION_1_1); AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); - RETURN_IF_SKIP(InitFramework()); - - VkPhysicalDeviceExtendedDynamicState3FeaturesEXT extended_dynamic_state3_features = vku::InitStructHelper(); - auto features2 = GetPhysicalDeviceFeatures2(extended_dynamic_state3_features); + AddRequiredFeature(vkt::Feature::dualSrcBlend); + AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable); + AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEquation); + AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorWriteMask); + RETURN_IF_SKIP(Init()); - if (features2.features.dualSrcBlend == VK_FALSE) { - GTEST_SKIP() << "dualSrcBlend feature is not available"; - } - if (!extended_dynamic_state3_features.extendedDynamicState3ColorBlendEnable || - !extended_dynamic_state3_features.extendedDynamicState3ColorBlendEquation || - !extended_dynamic_state3_features.extendedDynamicState3ColorWriteMask) { - GTEST_SKIP() << "DynamicState3 features not supported"; + const uint32_t count = m_device->phy().limits_.maxFragmentDualSrcAttachments + 1; + if (count != 2) { + GTEST_SKIP() << "Test is designed for a maxFragmentDualSrcAttachments of 1"; } - - RETURN_IF_SKIP(InitState(nullptr, &features2)); - uint32_t count = m_device->phy().limits_.maxFragmentDualSrcAttachments + 1; InitRenderTarget(count); - std::stringstream fsSource; - fsSource << "#version 450\n"; - for (uint32_t i = 0; i < count; ++i) { - fsSource << "layout(location = " << i << ") out vec4 c" << i << ";\n"; - } - fsSource << " void main() {\n"; - for (uint32_t i = 0; i < count; ++i) { - fsSource << "c" << i << " = vec4(0.0f);\n"; - } - - fsSource << "}"; - VkShaderObj fs(this, fsSource.str().c_str(), VK_SHADER_STAGE_FRAGMENT_BIT); + const char *fs_src = R"glsl( + #version 460 + layout(location = 0) out vec4 c0; + layout(location = 1) out vec4 c1; + void main() { + c0 = vec4(0.0f); + c1 = vec4(0.0f); + } + )glsl"; + VkShaderObj fs(this, fs_src, VK_SHADER_STAGE_FRAGMENT_BIT); // This is all ignored, but checking it will be ignored VkPipelineColorBlendAttachmentState cb_attachments = DefaultColorBlendAttachmentState(); @@ -2633,32 +2624,33 @@ TEST_F(NegativeDynamicState, DISABLED_MaxFragmentDualSrcAttachmentsDynamicBlendE pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT); pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT); pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT); - pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT); pipe.CreateGraphicsPipeline(); m_commandBuffer->begin(); m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + VkColorBlendEquationEXT dual_color_blend_equation = { + VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD}; + VkColorBlendEquationEXT normal_color_blend_equation = { + VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD}; + vk::CmdSetColorBlendEquationEXT(m_commandBuffer->handle(), 0, 1, &dual_color_blend_equation); + vk::CmdSetColorBlendEquationEXT(m_commandBuffer->handle(), 1, 1, &normal_color_blend_equation); + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + // The normal blend is disabled VkBool32 color_blend_enabled[2] = {VK_TRUE, VK_FALSE}; - VkColorBlendEquationEXT color_blend_equation = { - VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD, - VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD}; - VkColorComponentFlags color_component_flags = VK_COLOR_COMPONENT_R_BIT; + vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 0, 2, color_blend_enabled); - vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 0, 1, &color_blend_enabled[0]); // enables - vk::CmdSetColorBlendEquationEXT(m_commandBuffer->handle(), 0, 1, &color_blend_equation); - vk::CmdSetColorWriteMaskEXT(m_commandBuffer->handle(), 0, 1, &color_component_flags); + VkColorComponentFlags color_component_flags[2] = {VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_R_BIT}; + vk::CmdSetColorWriteMaskEXT(m_commandBuffer->handle(), 0, 2, color_component_flags); - m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Fragment-06427"); + m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-maxFragmentDualSrcAttachments-09239"); vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); m_errorMonitor->VerifyFound(); - // disables blending so no error should appear - vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 0, 1, &color_blend_enabled[1]); - vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); - m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); } diff --git a/tests/unit/dynamic_state_positive.cpp b/tests/unit/dynamic_state_positive.cpp index a55c5716d40..2753955419e 100644 --- a/tests/unit/dynamic_state_positive.cpp +++ b/tests/unit/dynamic_state_positive.cpp @@ -1042,4 +1042,68 @@ TEST_F(PositiveDynamicState, ColorBlendEquationMultipleAttachments) { vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); -} \ No newline at end of file +} + +TEST_F(PositiveDynamicState, MaxFragmentDualSrcAttachmentsDynamicBlendEnable) { + TEST_DESCRIPTION("Test maxFragmentDualSrcAttachments when blend is not enabled."); + SetTargetApiVersion(VK_API_VERSION_1_1); + AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::dualSrcBlend); + AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable); + AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEquation); + AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorWriteMask); + RETURN_IF_SKIP(Init()); + + const uint32_t count = m_device->phy().limits_.maxFragmentDualSrcAttachments + 1; + if (count != 2) { + GTEST_SKIP() << "Test is designed for a maxFragmentDualSrcAttachments of 1"; + } + InitRenderTarget(count); + + const char *fs_src = R"glsl( + #version 460 + layout(location = 0) out vec4 c0; + layout(location = 1) out vec4 c1; + void main() { + c0 = vec4(0.0f); + c1 = vec4(0.0f); + } + )glsl"; + VkShaderObj fs(this, fs_src, VK_SHADER_STAGE_FRAGMENT_BIT); + + VkPipelineColorBlendAttachmentState cb_attachments = DefaultColorBlendAttachmentState(); + + CreatePipelineHelper pipe(*this); + pipe.cb_ci_.pAttachments = &cb_attachments; + pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; + pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT); + pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT); + pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT); + pipe.CreateGraphicsPipeline(); + + m_commandBuffer->begin(); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + + VkColorBlendEquationEXT dual_color_blend_equation = { + VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD}; + VkColorBlendEquationEXT normal_color_blend_equation = { + VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD}; + vk::CmdSetColorBlendEquationEXT(m_commandBuffer->handle(), 0, 1, &dual_color_blend_equation); + vk::CmdSetColorBlendEquationEXT(m_commandBuffer->handle(), 1, 1, &normal_color_blend_equation); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + + // The dual color blend is disabled + VkBool32 color_blend_enabled[2] = {VK_FALSE, VK_TRUE}; + vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 0, 2, color_blend_enabled); + + VkColorComponentFlags color_component_flags[2] = {VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_R_BIT}; + vk::CmdSetColorWriteMaskEXT(m_commandBuffer->handle(), 0, 2, color_component_flags); + + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); +} diff --git a/tests/unit/shader_limits.cpp b/tests/unit/shader_limits.cpp index dca8d29db4e..1d7038be6c6 100644 --- a/tests/unit/shader_limits.cpp +++ b/tests/unit/shader_limits.cpp @@ -271,49 +271,38 @@ TEST_F(NegativeShaderLimits, MinAndMaxTexelOffset) { m_errorMonitor->VerifyFound(); } -// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5208 -// Asserting in MoltenVK -TEST_F(NegativeShaderLimits, DISABLED_MaxFragmentDualSrcAttachments) { +TEST_F(NegativeShaderLimits, MaxFragmentDualSrcAttachments) { TEST_DESCRIPTION("Test drawing with dual source blending with too many fragment output attachments."); SetTargetApiVersion(VK_API_VERSION_1_1); - RETURN_IF_SKIP(InitFramework()); - - VkPhysicalDeviceFeatures2 features2 = vku::InitStructHelper(); - GetPhysicalDeviceFeatures2(features2); + AddRequiredFeature(vkt::Feature::dualSrcBlend); + RETURN_IF_SKIP(Init()); - if (features2.features.dualSrcBlend == VK_FALSE) { - GTEST_SKIP() << "dualSrcBlend feature is not available"; + const uint32_t count = m_device->phy().limits_.maxFragmentDualSrcAttachments + 1; + if (count != 2) { + GTEST_SKIP() << "Test is designed for a maxFragmentDualSrcAttachments of 1"; } - - RETURN_IF_SKIP(InitState(nullptr, &features2)); - uint32_t count = m_device->phy().limits_.maxFragmentDualSrcAttachments + 1; InitRenderTarget(count); - std::stringstream fsSource; - fsSource << "#version 450\n"; - for (uint32_t i = 0; i < count; ++i) { - fsSource << "layout(location = " << i << ") out vec4 c" << i << ";\n"; - } - fsSource << " void main() {\n"; - for (uint32_t i = 0; i < count; ++i) { - fsSource << "c" << i << " = vec4(0.0f);\n"; - } - - fsSource << "}"; - VkShaderObj fs(this, fsSource.str().c_str(), VK_SHADER_STAGE_FRAGMENT_BIT); - - VkPipelineColorBlendAttachmentState cb_attachments = {}; - cb_attachments.blendEnable = VK_TRUE; - cb_attachments.srcColorBlendFactor = VK_BLEND_FACTOR_SRC1_COLOR; // bad! - cb_attachments.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; - cb_attachments.colorBlendOp = VK_BLEND_OP_ADD; - cb_attachments.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - cb_attachments.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - cb_attachments.alphaBlendOp = VK_BLEND_OP_ADD; + const char *fs_src = R"glsl( + #version 460 + layout(location = 0) out vec4 c0; + layout(location = 1) out vec4 c1; + void main() { + c0 = vec4(0.0f); + c1 = vec4(0.0f); + } + )glsl"; + VkShaderObj fs(this, fs_src, VK_SHADER_STAGE_FRAGMENT_BIT); + + VkPipelineColorBlendAttachmentState color_blend[2] = {}; + color_blend[0] = DefaultColorBlendAttachmentState(); + color_blend[1] = DefaultColorBlendAttachmentState(); + color_blend[1].srcColorBlendFactor = VK_BLEND_FACTOR_SRC1_COLOR; // bad! CreatePipelineHelper pipe(*this); - pipe.cb_ci_.pAttachments = &cb_attachments; + pipe.cb_ci_.attachmentCount = 2; + pipe.cb_ci_.pAttachments = color_blend; pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; pipe.CreateGraphicsPipeline(); @@ -322,7 +311,7 @@ TEST_F(NegativeShaderLimits, DISABLED_MaxFragmentDualSrcAttachments) { vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); - m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Fragment-06427"); + m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-maxFragmentDualSrcAttachments-09239"); vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); m_errorMonitor->VerifyFound(); diff --git a/tests/unit/shader_limits_positive.cpp b/tests/unit/shader_limits_positive.cpp index d918d6c9e56..37466230c3a 100644 --- a/tests/unit/shader_limits_positive.cpp +++ b/tests/unit/shader_limits_positive.cpp @@ -204,3 +204,93 @@ TEST_F(PositiveShaderLimits, TaskSharedMemoryAtLimit) { CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit); } +TEST_F(PositiveShaderLimits, MaxFragmentDualSrcAttachments) { + TEST_DESCRIPTION("Test maxFragmentDualSrcAttachments when blend is not enabled."); + SetTargetApiVersion(VK_API_VERSION_1_1); + AddRequiredFeature(vkt::Feature::dualSrcBlend); + RETURN_IF_SKIP(Init()); + + const uint32_t count = m_device->phy().limits_.maxFragmentDualSrcAttachments + 1; + if (count != 2) { + GTEST_SKIP() << "Test is designed for a maxFragmentDualSrcAttachments of 1"; + } + InitRenderTarget(count); + + const char *fs_src = R"glsl( + #version 460 + layout(location = 0) out vec4 c0; + layout(location = 1) out vec4 c1; + void main() { + c0 = vec4(0.0f); + c1 = vec4(0.0f); + } + )glsl"; + VkShaderObj fs(this, fs_src, VK_SHADER_STAGE_FRAGMENT_BIT); + + VkPipelineColorBlendAttachmentState color_blend[2] = {}; + color_blend[0] = DefaultColorBlendAttachmentState(); + color_blend[1] = DefaultColorBlendAttachmentState(); + color_blend[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC1_COLOR; // bad! + color_blend[0].blendEnable = false; // but ignored + + CreatePipelineHelper pipe(*this); + pipe.cb_ci_.attachmentCount = 2; + pipe.cb_ci_.pAttachments = color_blend; + pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; + pipe.CreateGraphicsPipeline(); + + m_commandBuffer->begin(); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); +} + +TEST_F(PositiveShaderLimits, MaxFragmentDualSrcAttachmentsDynamicEnabled) { + TEST_DESCRIPTION("Test maxFragmentDualSrcAttachments when blend is not enabled."); + SetTargetApiVersion(VK_API_VERSION_1_1); + AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::dualSrcBlend); + AddRequiredFeature(vkt::Feature::extendedDynamicState3ColorBlendEnable); + RETURN_IF_SKIP(Init()); + + const uint32_t count = m_device->phy().limits_.maxFragmentDualSrcAttachments + 1; + if (count != 2) { + GTEST_SKIP() << "Test is designed for a maxFragmentDualSrcAttachments of 1"; + } + InitRenderTarget(count); + + const char *fs_src = R"glsl( + #version 460 + layout(location = 0) out vec4 c0; + layout(location = 1) out vec4 c1; + void main() { + c0 = vec4(0.0f); + c1 = vec4(0.0f); + } + )glsl"; + VkShaderObj fs(this, fs_src, VK_SHADER_STAGE_FRAGMENT_BIT); + + VkPipelineColorBlendAttachmentState color_blend[2] = {}; + color_blend[0] = DefaultColorBlendAttachmentState(); + color_blend[1] = DefaultColorBlendAttachmentState(); + color_blend[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC1_COLOR; // bad! + + CreatePipelineHelper pipe(*this); + pipe.cb_ci_.attachmentCount = 2; + pipe.cb_ci_.pAttachments = color_blend; + pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; + pipe.AddDynamicState(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT); + pipe.CreateGraphicsPipeline(); + + m_commandBuffer->begin(); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + VkBool32 color_blend_enabled[2] = {VK_FALSE, VK_FALSE}; // disable any blending + vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 0, 2, color_blend_enabled); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); +} diff --git a/tests/unit/shader_object.cpp b/tests/unit/shader_object.cpp index 4fc0484cae9..4db550fa907 100644 --- a/tests/unit/shader_object.cpp +++ b/tests/unit/shader_object.cpp @@ -5987,37 +5987,30 @@ TEST_F(NegativeShaderObject, MaxMultiviewInstanceIndex) { m_errorMonitor->VerifyFound(); } -// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5208 -TEST_F(NegativeShaderObject, DISABLED_MaxFragmentDualSrcAttachmentsDynamicBlendEnable) { +TEST_F(NegativeShaderObject, MaxFragmentDualSrcAttachmentsDynamicBlendEnable) { TEST_DESCRIPTION( "Test drawing with dual source blending with too many fragment output attachments, but using dynamic blending."); - + AddRequiredFeature(vkt::Feature::dualSrcBlend); RETURN_IF_SKIP(InitBasicShaderObject()); - - VkPhysicalDeviceFeatures features; - GetPhysicalDeviceFeatures(&features); - if (features.dualSrcBlend == VK_FALSE) { - GTEST_SKIP() << "dualSrcBlend feature is not available"; - } - InitDynamicRenderTarget(); - uint32_t count = m_device->phy().limits_.maxFragmentDualSrcAttachments + 1; - - std::stringstream fsSource; - fsSource << "#version 450\n"; - for (uint32_t i = 0; i < count; ++i) { - fsSource << "layout(location = " << i << ") out vec4 c" << i << ";\n"; - } - fsSource << " void main() {\n"; - for (uint32_t i = 0; i < count; ++i) { - fsSource << "c" << i << " = vec4(0.0f);\n"; + const uint32_t count = m_device->phy().limits_.maxFragmentDualSrcAttachments + 1; + if (count != 2) { + GTEST_SKIP() << "Test is designed for a maxFragmentDualSrcAttachments of 1"; } - fsSource << "}"; + + const char* fs_src = R"glsl( + #version 460 + layout(location = 0) out vec4 c0; + layout(location = 1) out vec4 c1; + void main() { + c0 = vec4(0.0f); + c1 = vec4(0.0f); + } + )glsl"; const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); - const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, - GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, fsSource.str().c_str())); + const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, fs_src)); vkt::Image img1(*m_device, m_width, m_height, 1, m_render_target_fmt, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); @@ -6050,36 +6043,26 @@ TEST_F(NegativeShaderObject, DISABLED_MaxFragmentDualSrcAttachmentsDynamicBlendE SetDefaultDynamicStatesExclude(); - VkBool32 color_blend_enabled[2] = {VK_TRUE, VK_FALSE}; - VkColorBlendEquationEXT color_blend_equation = { + VkBool32 color_blend_enabled[2] = {VK_TRUE, VK_TRUE}; + VkColorBlendEquationEXT dual_color_blend_equation = { VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD}; - VkColorComponentFlags color_component_flags = VK_COLOR_COMPONENT_R_BIT; - - vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 0, 1, &color_blend_enabled[0]); // enables - vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 1, 1, &color_blend_enabled[1]); - vk::CmdSetColorBlendEquationEXT(m_commandBuffer->handle(), 0, 1, &color_blend_equation); - vk::CmdSetColorWriteMaskEXT(m_commandBuffer->handle(), 0, 1, &color_component_flags); + VkColorBlendEquationEXT normal_color_blend_equation = { + VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD}; + VkColorComponentFlags color_component_flags[2] = {VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_R_BIT}; - VkColorBlendAdvancedEXT colorBlendAdvanced; - colorBlendAdvanced.advancedBlendOp = VK_BLEND_OP_ADD; - colorBlendAdvanced.srcPremultiplied = VK_FALSE; - colorBlendAdvanced.dstPremultiplied = VK_FALSE; - colorBlendAdvanced.blendOverlap = VK_BLEND_OVERLAP_UNCORRELATED_EXT; - colorBlendAdvanced.clampResults = VK_FALSE; - vk::CmdSetColorBlendAdvancedEXT(m_commandBuffer->handle(), 0u, 1u, &colorBlendAdvanced); - vk::CmdSetColorBlendAdvancedEXT(m_commandBuffer->handle(), 1u, 1u, &colorBlendAdvanced); + vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 0, 2, color_blend_enabled); + vk::CmdSetColorBlendEquationEXT(m_commandBuffer->handle(), 0, 1, &normal_color_blend_equation); + vk::CmdSetColorBlendEquationEXT(m_commandBuffer->handle(), 1, 1, &dual_color_blend_equation); + vk::CmdSetColorWriteMaskEXT(m_commandBuffer->handle(), 0, 2, color_component_flags); m_commandBuffer->BindVertFragShader(vertShader, fragShader); - m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Fragment-06427"); + m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-maxFragmentDualSrcAttachments-09239"); vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); m_errorMonitor->VerifyFound(); - // disables blending so no error should appear - vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 0, 1, &color_blend_enabled[1]); - vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); - m_commandBuffer->EndRendering(); m_commandBuffer->end(); }