| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2019 Valve Corporation. |
| * Copyright (c) 2019 The Khronos Group Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief VK_EXT_blend_operation_advanced tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktPipelineBlendOperationAdvancedTests.hpp" |
| #include "vktPipelineImageUtil.hpp" |
| #include "vktPipelineReferenceRenderer.hpp" |
| #include "vktTestCaseUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkBuilderUtil.hpp" |
| #include "vkObjUtil.hpp" |
| |
| #include "tcuTestLog.hpp" |
| #include "tcuImageCompare.hpp" |
| |
| namespace vkt |
| { |
| namespace pipeline |
| { |
| |
| using namespace vk; |
| |
| namespace |
| { |
| using tcu::Vec3; |
| using tcu::Vec4; |
| |
| const deUint32 widthArea = 32u; |
| const deUint32 heightArea = 32u; |
| |
| static const float A1 = 0.750f; // Between 1 and 0.5 |
| static const float A2 = 0.375f; // Between 0.5 and 0.25 |
| static const float A3 = 0.125f; // Between 0.25 and 0.0 |
| |
| const Vec4 srcColors[] = { |
| // Test that pre-multiplied is converted correctly. |
| // Should not test invalid premultiplied colours (1, 1, 1, 0). |
| { 1.000f, 0.750f, 0.500f, 1.00f }, |
| { 0.250f, 0.125f, 0.000f, 1.00f }, |
| |
| // Test clamping. |
| { 1.000f, 0.750f, 0.500f, 1.00f }, |
| { 0.250f, 0.125f, 0.000f, 1.00f }, |
| { 1.000f, 0.750f, 0.500f, 1.00f }, |
| { 0.250f, 0.125f, 0.000f, 1.00f }, |
| |
| // Combinations that test other branches of blend equations. |
| { 1.000f, 0.750f, 0.500f, 1.00f }, |
| { 0.250f, 0.125f, 0.000f, 1.00f }, |
| { 1.000f, 0.750f, 0.500f, 1.00f }, |
| { 0.250f, 0.125f, 0.000f, 1.00f }, |
| { 1.000f, 0.750f, 0.500f, 1.00f }, |
| { 0.250f, 0.125f, 0.000f, 1.00f }, |
| { 1.000f, 0.750f, 0.500f, 1.00f }, |
| { 0.250f, 0.125f, 0.000f, 1.00f }, |
| { 1.000f, 0.750f, 0.500f, 1.00f }, |
| { 0.250f, 0.125f, 0.000f, 1.00f }, |
| |
| // Above block with few different pre-multiplied alpha values. |
| { 1.000f * A1, 0.750f * A1, 0.500f * A1, 1.00f * A1}, |
| { 0.250f * A1, 0.125f * A1, 0.000f * A1, 1.00f * A1}, |
| { 1.000f * A1, 0.750f * A1, 0.500f * A1, 1.00f * A1}, |
| { 0.250f * A1, 0.125f * A1, 0.000f * A1, 1.00f * A1}, |
| { 1.000f * A1, 0.750f * A1, 0.500f * A1, 1.00f * A1}, |
| { 0.250f * A1, 0.125f * A1, 0.000f * A1, 1.00f * A1}, |
| { 1.000f * A1, 0.750f * A1, 0.500f * A1, 1.00f * A1}, |
| { 0.250f * A1, 0.125f * A1, 0.000f * A1, 1.00f * A1}, |
| { 1.000f * A1, 0.750f * A1, 0.500f * A1, 1.00f * A1}, |
| { 0.250f * A1, 0.125f * A1, 0.000f * A1, 1.00f * A1}, |
| |
| { 1.000f * A2, 0.750f * A2, 0.500f * A2, 1.00f * A2}, |
| { 0.250f * A2, 0.125f * A2, 0.000f * A2, 1.00f * A2}, |
| { 1.000f * A2, 0.750f * A2, 0.500f * A2, 1.00f * A2}, |
| { 0.250f * A2, 0.125f * A2, 0.000f * A2, 1.00f * A2}, |
| { 1.000f * A2, 0.750f * A2, 0.500f * A2, 1.00f * A2}, |
| { 0.250f * A2, 0.125f * A2, 0.000f * A2, 1.00f * A2}, |
| { 1.000f * A2, 0.750f * A2, 0.500f * A2, 1.00f * A2}, |
| { 0.250f * A2, 0.125f * A2, 0.000f * A2, 1.00f * A2}, |
| { 1.000f * A2, 0.750f * A2, 0.500f * A2, 1.00f * A2}, |
| { 0.250f * A2, 0.125f * A2, 0.000f * A2, 1.00f * A2}, |
| |
| { 1.000f * A3, 0.750f * A3, 0.500f * A3, 1.00f * A3}, |
| { 0.250f * A3, 0.125f * A3, 0.000f * A3, 1.00f * A3}, |
| { 1.000f * A3, 0.750f * A3, 0.500f * A3, 1.00f * A3}, |
| { 0.250f * A3, 0.125f * A3, 0.000f * A3, 1.00f * A3}, |
| { 1.000f * A3, 0.750f * A3, 0.500f * A3, 1.00f * A3}, |
| { 0.250f * A3, 0.125f * A3, 0.000f * A3, 1.00f * A3}, |
| { 1.000f * A3, 0.750f * A3, 0.500f * A3, 1.00f * A3}, |
| { 0.250f * A3, 0.125f * A3, 0.000f * A3, 1.00f * A3}, |
| { 1.000f * A3, 0.750f * A3, 0.500f * A3, 1.00f * A3}, |
| { 0.250f * A3, 0.125f * A3, 0.000f * A3, 1.00f * A3}, |
| |
| // Add some source colors with alpha component that is different than the respective destination color |
| { 0.750f, 0.750f, 0.500f, 0.750f }, |
| { 0.250f, 0.500f, 0.500f, 0.750f }, |
| { 0.250f, 0.125f, 0.000f, 0.500f }, |
| { 0.250f, 0.250f, 0.500f, 0.500f }, |
| { 0.250f, 0.125f, 0.000f, 0.250f }, |
| { 0.125f, 0.125f, 0.125f, 0.250f }}; |
| |
| const Vec4 dstColors[] = { |
| // Test that pre-multiplied is converted correctly. |
| // Should not test invalid premultiplied colours (1, 1, 1, 0). |
| { 0.000f, 0.000f, 0.000f, 0.00f }, |
| { 0.000f, 0.000f, 0.000f, 0.00f }, |
| |
| // Test clamping. |
| { -0.125f, -0.125f, -0.125f, 1.00f }, |
| { -0.125f, -0.125f, -0.125f, 1.00f }, |
| { 1.125f, 1.125f, 1.125f, 1.00f }, |
| { 1.125f, 1.125f, 1.125f, 1.00f }, |
| |
| // Combinations that test other branches of blend equations. |
| { 1.000f, 1.000f, 1.000f, 1.00f }, |
| { 1.000f, 1.000f, 1.000f, 1.00f }, |
| { 0.500f, 0.500f, 0.500f, 1.00f }, |
| { 0.500f, 0.500f, 0.500f, 1.00f }, |
| { 0.250f, 0.250f, 0.250f, 1.00f }, |
| { 0.250f, 0.250f, 0.250f, 1.00f }, |
| { 0.125f, 0.125f, 0.125f, 1.00f }, |
| { 0.125f, 0.125f, 0.125f, 1.00f }, |
| { 0.000f, 0.000f, 0.000f, 1.00f }, |
| { 0.000f, 0.000f, 0.000f, 1.00f }, |
| |
| // Above block with few different pre-multiplied alpha values. |
| { 1.000f * A1, 1.000f * A1, 1.000f * A1, 1.00f * A1}, |
| { 1.000f * A1, 1.000f * A1, 1.000f * A1, 1.00f * A1}, |
| { 0.500f * A1, 0.500f * A1, 0.500f * A1, 1.00f * A1}, |
| { 0.500f * A1, 0.500f * A1, 0.500f * A1, 1.00f * A1}, |
| { 0.250f * A1, 0.250f * A1, 0.250f * A1, 1.00f * A1}, |
| { 0.250f * A1, 0.250f * A1, 0.250f * A1, 1.00f * A1}, |
| { 0.125f * A1, 0.125f * A1, 0.125f * A1, 1.00f * A1}, |
| { 0.125f * A1, 0.125f * A1, 0.125f * A1, 1.00f * A1}, |
| { 0.000f * A1, 0.000f * A1, 0.000f * A1, 1.00f * A1}, |
| { 0.000f * A1, 0.000f * A1, 0.000f * A1, 1.00f * A1}, |
| |
| { 1.000f * A2, 1.000f * A2, 1.000f * A2, 1.00f * A2}, |
| { 1.000f * A2, 1.000f * A2, 1.000f * A2, 1.00f * A2}, |
| { 0.500f * A2, 0.500f * A2, 0.500f * A2, 1.00f * A2}, |
| { 0.500f * A2, 0.500f * A2, 0.500f * A2, 1.00f * A2}, |
| { 0.250f * A2, 0.250f * A2, 0.250f * A2, 1.00f * A2}, |
| { 0.250f * A2, 0.250f * A2, 0.250f * A2, 1.00f * A2}, |
| { 0.125f * A2, 0.125f * A2, 0.125f * A2, 1.00f * A2}, |
| { 0.125f * A2, 0.125f * A2, 0.125f * A2, 1.00f * A2}, |
| { 0.000f * A2, 0.000f * A2, 0.000f * A2, 1.00f * A2}, |
| { 0.000f * A2, 0.000f * A2, 0.000f * A2, 1.00f * A2}, |
| |
| { 1.000f * A3, 1.000f * A3, 1.000f * A3, 1.00f * A3}, |
| { 1.000f * A3, 1.000f * A3, 1.000f * A3, 1.00f * A3}, |
| { 0.500f * A3, 0.500f * A3, 0.500f * A3, 1.00f * A3}, |
| { 0.500f * A3, 0.500f * A3, 0.500f * A3, 1.00f * A3}, |
| { 0.250f * A3, 0.250f * A3, 0.250f * A3, 1.00f * A3 }, |
| { 0.250f * A3, 0.250f * A3, 0.250f * A3, 1.00f * A3 }, |
| { 0.125f * A3, 0.125f * A3, 0.125f * A3, 1.00f * A3 }, |
| { 0.125f * A3, 0.125f * A3, 0.125f * A3, 1.00f * A3 }, |
| { 0.000f * A3, 0.000f * A3, 0.000f * A3, 1.00f * A3 }, |
| { 0.000f * A3, 0.000f * A3, 0.000f * A3, 1.00f * A3 }, |
| |
| // Add some source colors with alpha component that is different than the respective source color |
| { 1.000f, 1.000f, 1.000f, 1.000f }, |
| { 0.250f, 0.250f, 0.250f, 0.500f }, |
| { 0.500f, 0.500f, 0.500f, 0.750f }, |
| { 0.250f, 0.250f, 0.250f, 0.250f }, |
| { 0.250f, 0.250f, 0.250f, 0.500f }, |
| { 0.125f, 0.125f, 0.125f, 0.125f }}; |
| |
| const Vec4 clearColorVec4 (1.0f, 1.0f, 1.0f, 1.0f); |
| |
| enum TestMode |
| { |
| TEST_MODE_GENERIC = 0, |
| TEST_MODE_COHERENT = 1, |
| }; |
| |
| struct BlendOperationAdvancedParam |
| { |
| TestMode testMode; |
| deUint32 testNumber; |
| std::vector<VkBlendOp> blendOps; |
| deBool coherentOperations; |
| deBool independentBlend; |
| deUint32 colorAttachmentsCount; |
| VkBool32 premultipliedSrcColor; |
| VkBool32 premultipliedDstColor; |
| VkBlendOverlapEXT overlap; |
| }; |
| |
| // helper functions |
| const std::string generateTestName (struct BlendOperationAdvancedParam param) |
| { |
| std::ostringstream result; |
| |
| result << ((param.testMode == TEST_MODE_COHERENT && !param.coherentOperations) ? "barrier_" : ""); |
| result << "color_attachments_" << param.colorAttachmentsCount; |
| result << "_" << de::toLower(getBlendOverlapEXTStr(param.overlap).toString().substr(3)); |
| result << (!param.premultipliedSrcColor ? "_nonpremultipliedsrc" : ""); |
| result << (!param.premultipliedDstColor ? "_nonpremultiplieddst" : ""); |
| result << "_" << param.testNumber; |
| return result.str(); |
| } |
| |
| const std::string generateTestDescription () |
| { |
| std::string result("Test advanced blend operations"); |
| return result; |
| } |
| |
| Vec3 calculateWeightingFactors(BlendOperationAdvancedParam param, |
| float alphaSrc, float alphaDst) |
| { |
| Vec3 p = Vec3(0.0f, 0.0f, 0.0f); |
| switch(param.overlap) |
| { |
| case VK_BLEND_OVERLAP_UNCORRELATED_EXT: |
| p.x() = alphaSrc * alphaDst; |
| p.y() = alphaSrc * (1.0f - alphaDst); |
| p.z() = alphaDst * (1.0f - alphaSrc); |
| break; |
| case VK_BLEND_OVERLAP_CONJOINT_EXT: |
| p.x() = deFloatMin(alphaSrc, alphaDst); |
| p.y() = deFloatMax(alphaSrc - alphaDst, 0.0f); |
| p.z() = deFloatMax(alphaDst - alphaSrc, 0.0f); |
| break; |
| case VK_BLEND_OVERLAP_DISJOINT_EXT: |
| p.x() = deFloatMax(alphaSrc + alphaDst - 1.0f, 0.0f); |
| p.y() = deFloatMin(alphaSrc, 1.0f - alphaDst); |
| p.z() = deFloatMin(alphaDst, 1.0f - alphaSrc); |
| break; |
| default: |
| DE_FATAL("Unsupported Advanced Blend Overlap Mode"); |
| }; |
| return p; |
| } |
| |
| Vec3 calculateXYZFactors(VkBlendOp op) |
| { |
| Vec3 xyz = Vec3(0.0f, 0.0f, 0.0f); |
| switch (op) |
| { |
| case VK_BLEND_OP_ZERO_EXT: |
| xyz = Vec3(0.0f, 0.0f, 0.0f); |
| break; |
| |
| case VK_BLEND_OP_DST_ATOP_EXT: |
| case VK_BLEND_OP_SRC_EXT: |
| xyz = Vec3(1.0f, 1.0f, 0.0f); |
| break; |
| |
| case VK_BLEND_OP_DST_EXT: |
| xyz = Vec3(1.0f, 0.0f, 1.0f); |
| break; |
| |
| case VK_BLEND_OP_HSL_LUMINOSITY_EXT: |
| case VK_BLEND_OP_HSL_COLOR_EXT: |
| case VK_BLEND_OP_HSL_SATURATION_EXT: |
| case VK_BLEND_OP_HSL_HUE_EXT: |
| case VK_BLEND_OP_HARDMIX_EXT: |
| case VK_BLEND_OP_PINLIGHT_EXT: |
| case VK_BLEND_OP_LINEARLIGHT_EXT: |
| case VK_BLEND_OP_VIVIDLIGHT_EXT: |
| case VK_BLEND_OP_LINEARBURN_EXT: |
| case VK_BLEND_OP_LINEARDODGE_EXT: |
| case VK_BLEND_OP_EXCLUSION_EXT: |
| case VK_BLEND_OP_DIFFERENCE_EXT: |
| case VK_BLEND_OP_SOFTLIGHT_EXT: |
| case VK_BLEND_OP_HARDLIGHT_EXT: |
| case VK_BLEND_OP_COLORBURN_EXT: |
| case VK_BLEND_OP_COLORDODGE_EXT: |
| case VK_BLEND_OP_LIGHTEN_EXT: |
| case VK_BLEND_OP_DARKEN_EXT: |
| case VK_BLEND_OP_OVERLAY_EXT: |
| case VK_BLEND_OP_SCREEN_EXT: |
| case VK_BLEND_OP_MULTIPLY_EXT: |
| case VK_BLEND_OP_SRC_OVER_EXT: |
| case VK_BLEND_OP_DST_OVER_EXT: |
| xyz = Vec3(1.0f, 1.0f, 1.0f); |
| break; |
| |
| case VK_BLEND_OP_SRC_IN_EXT: |
| case VK_BLEND_OP_DST_IN_EXT: |
| xyz = Vec3(1.0f, 0.0f, 0.0f); |
| break; |
| |
| case VK_BLEND_OP_SRC_OUT_EXT: |
| xyz = Vec3(0.0f, 1.0f, 0.0f); |
| break; |
| |
| case VK_BLEND_OP_DST_OUT_EXT: |
| xyz = Vec3(0.0f, 0.0f, 1.0f); |
| break; |
| |
| case VK_BLEND_OP_INVERT_RGB_EXT: |
| case VK_BLEND_OP_INVERT_EXT: |
| case VK_BLEND_OP_SRC_ATOP_EXT: |
| xyz = Vec3(1.0f, 0.0f, 1.0f); |
| break; |
| |
| case VK_BLEND_OP_XOR_EXT: |
| xyz = Vec3(0.0f, 1.0f, 1.0f); |
| break; |
| |
| default: |
| DE_FATAL("Unsupported f/X/Y/Z Advanced Blend Operations Mode"); |
| }; |
| |
| return xyz; |
| } |
| |
| float blendOpOverlay(float src, float dst) |
| { |
| if (dst <= 0.5f) |
| return (2.0f * src * dst); |
| else |
| return (1.0f - (2.0f * (1.0f - src) * (1.0f - dst))); |
| } |
| |
| float blendOpColorDodge(float src, float dst) |
| { |
| if (dst <= 0.0f) |
| return 0.0f; |
| else if (src < 1.0f) |
| return deFloatMin(1.0f, (dst / (1.0f - src))); |
| else |
| return 1.0f; |
| } |
| |
| float blendOpColorBurn(float src, float dst) |
| { |
| if (dst >= 1.0f) |
| return 1.0f; |
| else if (src > 0.0f) |
| return 1.0f - deFloatMin(1.0f, (1.0f - dst) / src); |
| else |
| return 0.0f; |
| } |
| |
| float blendOpHardlight(float src, float dst) |
| { |
| if (src <= 0.5f) |
| return 2.0f * src * dst; |
| else |
| return 1.0f - (2.0f * (1.0f - src) * (1.0f - dst)); |
| } |
| |
| float blendOpSoftlight(float src, float dst) |
| { |
| if (src <= 0.5f) |
| return dst - ((1.0f - (2.0f * src)) * dst * (1.0f - dst)); |
| else if (dst <= 0.25f) |
| return dst + (((2.0f * src) - 1.0f) * dst * ((((16.0f * dst) - 12.0f) * dst) + 3.0f)); |
| else |
| return dst + (((2.0f * src) - 1.0f) * (deFloatSqrt(dst) - dst)); |
| } |
| |
| float blendOpLinearDodge(float src, float dst) |
| { |
| if ((src + dst) <= 1.0f) |
| return src + dst; |
| else |
| return 1.0f; |
| } |
| |
| float blendOpLinearBurn(float src, float dst) |
| { |
| if ((src + dst) > 1.0f) |
| return src + dst - 1.0f; |
| else |
| return 0.0f; |
| } |
| |
| float blendOpVividLight(float src, float dst) |
| { |
| if (src <= 0.0f) |
| return 0.0f; |
| if (src < 0.5f) |
| return 1.0f - (deFloatMin(1.0f, (1.0f - dst) / (2.0f * src))); |
| if (src < 1.0f) |
| return deFloatMin(1.0f, dst / (2.0f * (1.0f - src))); |
| else |
| return 1.0f; |
| } |
| |
| float blendOpLinearLight(float src, float dst) |
| { |
| if ((2.0f * src + dst) > 2.0f) |
| return 1.0f; |
| if ((2.0f * src + dst) <= 1.0f) |
| return 0.0f; |
| return (2.0f * src) + dst - 1.0f; |
| } |
| |
| float blendOpPinLight(float src, float dst) |
| { |
| if (((2.0f * src - 1.0f) > dst) && src < 0.5f) |
| return 0.0f; |
| if (((2.0f * src - 1.0f) > dst) && src >= 0.5f) |
| return 2.0f * src - 1.0f; |
| if (((2.0f * src - 1.0f) <= dst) && src < (0.5f * dst)) |
| return 2.0f * src; |
| if (((2.0f * src - 1.0f) <= dst) && src >= (0.5f * dst)) |
| return dst; |
| return 0.0f; |
| } |
| |
| float blendOpHardmix(float src, float dst) |
| { |
| if ((src + dst) < 1.0f) |
| return 0.0f; |
| else |
| return 1.0f; |
| } |
| |
| float minv3(Vec3 c) |
| { |
| return deFloatMin(deFloatMin(c.x(), c.y()), c.z()); |
| } |
| |
| float maxv3(Vec3 c) |
| { |
| return deFloatMax(deFloatMax(c.x(), c.y()), c.z()); |
| } |
| |
| float lumv3(Vec3 c) |
| { |
| return dot(c, Vec3(0.3f, 0.59f, 0.11f)); |
| } |
| |
| float satv3(Vec3 c) |
| { |
| return maxv3(c) - minv3(c); |
| } |
| |
| // If any color components are outside [0,1], adjust the color to |
| // get the components in range. |
| Vec3 clipColor(Vec3 color) |
| { |
| float lum = lumv3(color); |
| float mincol = minv3(color); |
| float maxcol = maxv3(color); |
| |
| if (mincol < 0.0) |
| { |
| color = lum + ((color - lum) * lum) / (lum - mincol); |
| } |
| if (maxcol > 1.0) |
| { |
| color = lum + ((color - lum) * (1.0f - lum)) / (maxcol - lum); |
| } |
| return color; |
| } |
| |
| // Take the base RGB color <cbase> and override its luminosity |
| // with that of the RGB color <clum>. |
| Vec3 setLum(Vec3 cbase, Vec3 clum) |
| { |
| float lbase = lumv3(cbase); |
| float llum = lumv3(clum); |
| float ldiff = llum - lbase; |
| |
| Vec3 color = cbase + Vec3(ldiff); |
| return clipColor(color); |
| } |
| |
| // Take the base RGB color <cbase> and override its saturation with |
| // that of the RGB color <csat>. The override the luminosity of the |
| // result with that of the RGB color <clum>. |
| Vec3 setLumSat(Vec3 cbase, Vec3 csat, Vec3 clum) |
| { |
| float minbase = minv3(cbase); |
| float sbase = satv3(cbase); |
| float ssat = satv3(csat); |
| Vec3 color; |
| |
| if (sbase > 0) |
| { |
| // Equivalent (modulo rounding errors) to setting the |
| // smallest (R,G,B) component to 0, the largest to <ssat>, |
| // and interpolating the "middle" component based on its |
| // original value relative to the smallest/largest. |
| color = (cbase - minbase) * ssat / sbase; |
| } else { |
| color = Vec3(0.0f); |
| } |
| return setLum(color, clum); |
| } |
| |
| Vec3 calculateFFunction(VkBlendOp op, |
| Vec3 src, Vec3 dst) |
| { |
| Vec3 f = Vec3(0.0f, 0.0f, 0.0f); |
| |
| switch (op) |
| { |
| case VK_BLEND_OP_XOR_EXT: |
| case VK_BLEND_OP_SRC_OUT_EXT: |
| case VK_BLEND_OP_DST_OUT_EXT: |
| case VK_BLEND_OP_ZERO_EXT: |
| f = Vec3(0.0f, 0.0f, 0.0f); |
| break; |
| |
| case VK_BLEND_OP_SRC_ATOP_EXT: |
| case VK_BLEND_OP_SRC_IN_EXT: |
| case VK_BLEND_OP_SRC_OVER_EXT: |
| case VK_BLEND_OP_SRC_EXT: |
| f = src; |
| break; |
| |
| case VK_BLEND_OP_DST_ATOP_EXT: |
| case VK_BLEND_OP_DST_IN_EXT: |
| case VK_BLEND_OP_DST_OVER_EXT: |
| case VK_BLEND_OP_DST_EXT: |
| f = dst; |
| break; |
| |
| case VK_BLEND_OP_MULTIPLY_EXT: |
| f = src * dst; |
| break; |
| |
| case VK_BLEND_OP_SCREEN_EXT: |
| f = src + dst - (src*dst); |
| break; |
| |
| case VK_BLEND_OP_OVERLAY_EXT: |
| f.x() = blendOpOverlay(src.x(), dst.x()); |
| f.y() = blendOpOverlay(src.y(), dst.y()); |
| f.z() = blendOpOverlay(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_DARKEN_EXT: |
| f.x() = deFloatMin(src.x(), dst.x()); |
| f.y() = deFloatMin(src.y(), dst.y()); |
| f.z() = deFloatMin(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_LIGHTEN_EXT: |
| f.x() = deFloatMax(src.x(), dst.x()); |
| f.y() = deFloatMax(src.y(), dst.y()); |
| f.z() = deFloatMax(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_COLORDODGE_EXT: |
| f.x() = blendOpColorDodge(src.x(), dst.x()); |
| f.y() = blendOpColorDodge(src.y(), dst.y()); |
| f.z() = blendOpColorDodge(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_COLORBURN_EXT: |
| f.x() = blendOpColorBurn(src.x(), dst.x()); |
| f.y() = blendOpColorBurn(src.y(), dst.y()); |
| f.z() = blendOpColorBurn(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_HARDLIGHT_EXT: |
| f.x() = blendOpHardlight(src.x(), dst.x()); |
| f.y() = blendOpHardlight(src.y(), dst.y()); |
| f.z() = blendOpHardlight(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_SOFTLIGHT_EXT: |
| f.x() = blendOpSoftlight(src.x(), dst.x()); |
| f.y() = blendOpSoftlight(src.y(), dst.y()); |
| f.z() = blendOpSoftlight(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_DIFFERENCE_EXT: |
| f.x() = deFloatAbs(dst.x() - src.x()); |
| f.y() = deFloatAbs(dst.y() - src.y()); |
| f.z() = deFloatAbs(dst.z() - src.z()); |
| break; |
| |
| |
| case VK_BLEND_OP_EXCLUSION_EXT: |
| f = src + dst - (2.0f * src * dst); |
| break; |
| |
| case VK_BLEND_OP_INVERT_EXT: |
| f = 1.0f - dst; |
| break; |
| |
| case VK_BLEND_OP_INVERT_RGB_EXT: |
| f = src * (1.0f - dst); |
| break; |
| |
| case VK_BLEND_OP_LINEARDODGE_EXT: |
| f.x() = blendOpLinearDodge(src.x(), dst.x()); |
| f.y() = blendOpLinearDodge(src.y(), dst.y()); |
| f.z() = blendOpLinearDodge(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_LINEARBURN_EXT: |
| f.x() = blendOpLinearBurn(src.x(), dst.x()); |
| f.y() = blendOpLinearBurn(src.y(), dst.y()); |
| f.z() = blendOpLinearBurn(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_VIVIDLIGHT_EXT: |
| f.x() = blendOpVividLight(src.x(), dst.x()); |
| f.y() = blendOpVividLight(src.y(), dst.y()); |
| f.z() = blendOpVividLight(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_LINEARLIGHT_EXT: |
| f.x() = blendOpLinearLight(src.x(), dst.x()); |
| f.y() = blendOpLinearLight(src.y(), dst.y()); |
| f.z() = blendOpLinearLight(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_PINLIGHT_EXT: |
| f.x() = blendOpPinLight(src.x(), dst.x()); |
| f.y() = blendOpPinLight(src.y(), dst.y()); |
| f.z() = blendOpPinLight(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_HARDMIX_EXT: |
| f.x() = blendOpHardmix(src.x(), dst.x()); |
| f.y() = blendOpHardmix(src.y(), dst.y()); |
| f.z() = blendOpHardmix(src.z(), dst.z()); |
| break; |
| |
| case VK_BLEND_OP_HSL_HUE_EXT: |
| f = setLumSat(src, dst, dst); |
| break; |
| |
| case VK_BLEND_OP_HSL_SATURATION_EXT: |
| f = setLumSat(dst, src, dst); |
| break; |
| |
| case VK_BLEND_OP_HSL_COLOR_EXT: |
| f = setLum(src, dst); |
| break; |
| |
| case VK_BLEND_OP_HSL_LUMINOSITY_EXT: |
| f = setLum(dst, src); |
| break; |
| |
| default: |
| DE_FATAL("Unsupported f/X/Y/Z Advanced Blend Operations Mode"); |
| }; |
| |
| return f; |
| } |
| |
| Vec4 additionalRGBBlendOperations(VkBlendOp op, |
| Vec4 src, Vec4 dst) |
| { |
| Vec4 res = Vec4(0.0f, 0.0f, 0.0f, 1.0f); |
| |
| switch (op) |
| { |
| case VK_BLEND_OP_PLUS_EXT: |
| res = src + dst; |
| break; |
| |
| case VK_BLEND_OP_PLUS_CLAMPED_EXT: |
| res.x() = deFloatMin(1.0f, src.x() + dst.x()); |
| res.y() = deFloatMin(1.0f, src.y() + dst.y()); |
| res.z() = deFloatMin(1.0f, src.z() + dst.z()); |
| res.w() = deFloatMin(1.0f, src.w() + dst.w()); |
| break; |
| |
| case VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT: |
| res.x() = deFloatMin(deFloatMin(1.0f, src.w() + dst.w()), src.x() + dst.x()); |
| res.y() = deFloatMin(deFloatMin(1.0f, src.w() + dst.w()), src.y() + dst.y()); |
| res.z() = deFloatMin(deFloatMin(1.0f, src.w() + dst.w()), src.z() + dst.z()); |
| res.w() = deFloatMin(1.0f, src.w() + dst.w()); |
| break; |
| |
| case VK_BLEND_OP_PLUS_DARKER_EXT: |
| res.x() = deFloatMax(0.0f, deFloatMin(1.0f, src.w() + dst.w()) - ((src.w() - src.x()) + (dst.w() - dst.x()))); |
| res.y() = deFloatMax(0.0f, deFloatMin(1.0f, src.w() + dst.w()) - ((src.w() - src.y()) + (dst.w() - dst.y()))); |
| res.z() = deFloatMax(0.0f, deFloatMin(1.0f, src.w() + dst.w()) - ((src.w() - src.z()) + (dst.w() - dst.z()))); |
| res.w() = deFloatMin(1.0f, src.w() + dst.w()); |
| break; |
| |
| case VK_BLEND_OP_MINUS_EXT: |
| res = dst - src; |
| break; |
| |
| case VK_BLEND_OP_MINUS_CLAMPED_EXT: |
| res.x() = deFloatMax(0.0f, dst.x() - src.x()); |
| res.y() = deFloatMax(0.0f, dst.y() - src.y()); |
| res.z() = deFloatMax(0.0f, dst.z() - src.z()); |
| res.w() = deFloatMax(0.0f, dst.w() - src.w()); |
| break; |
| |
| case VK_BLEND_OP_CONTRAST_EXT: |
| res.x() = (dst.w() / 2.0f) + 2.0f * (dst.x() - (dst.w() / 2.0f)) * (src.x() - (src.w() / 2.0f)); |
| res.y() = (dst.w() / 2.0f) + 2.0f * (dst.y() - (dst.w() / 2.0f)) * (src.y() - (src.w() / 2.0f)); |
| res.z() = (dst.w() / 2.0f) + 2.0f * (dst.z() - (dst.w() / 2.0f)) * (src.z() - (src.w() / 2.0f)); |
| res.w() = dst.w(); |
| break; |
| |
| case VK_BLEND_OP_INVERT_OVG_EXT: |
| res.x() = src.w() * (1.0f - dst.x()) + (1.0f - src.w()) * dst.x(); |
| res.y() = src.w() * (1.0f - dst.y()) + (1.0f - src.w()) * dst.y(); |
| res.z() = src.w() * (1.0f - dst.z()) + (1.0f - src.w()) * dst.z(); |
| res.w() = src.w() + dst.w() - src.w() * dst.w(); |
| break; |
| |
| case VK_BLEND_OP_RED_EXT: |
| res = dst; |
| res.x() = src.x(); |
| break; |
| |
| case VK_BLEND_OP_GREEN_EXT: |
| res = dst; |
| res.y() = src.y(); |
| break; |
| |
| case VK_BLEND_OP_BLUE_EXT: |
| res = dst; |
| res.z() = src.z(); |
| break; |
| |
| default: |
| DE_FATAL("Unsupported blend operation"); |
| }; |
| return res; |
| } |
| |
| Vec4 calculateFinalColor(BlendOperationAdvancedParam param, VkBlendOp op, |
| Vec4 source, Vec4 destination) |
| { |
| Vec4 result = Vec4(0.0f, 0.0f, 0.0f, 1.0f); |
| Vec3 srcColor = source.xyz(); |
| Vec3 dstColor = destination.xyz(); |
| |
| // Calculate weighting factors |
| Vec3 p = calculateWeightingFactors(param, source.w(), destination.w()); |
| |
| if (op > VK_BLEND_OP_MAX && op < VK_BLEND_OP_PLUS_EXT) |
| { |
| { |
| // If srcPremultiplied is set to VK_TRUE, the fragment color components |
| // are considered to have been premultiplied by the A component prior to |
| // blending. The base source color (Rs',Gs',Bs') is obtained by dividing |
| // through by the A component. |
| if (param.premultipliedSrcColor) |
| { |
| if (source.w() != 0.0f) |
| srcColor = srcColor / source.w(); |
| else |
| srcColor = Vec3(0.0f, 0.0f, 0.0f); |
| } |
| // If dstPremultiplied is set to VK_TRUE, the destination components are |
| // considered to have been premultiplied by the A component prior to |
| // blending. The base destination color (Rd',Gd',Bd') is obtained by dividing |
| // through by the A component. |
| if (param.premultipliedDstColor) |
| { |
| if (destination.w() != 0.0f) |
| dstColor = dstColor / destination.w(); |
| else |
| dstColor = Vec3(0.0f, 0.0f, 0.0f); |
| } |
| } |
| |
| // Calculate X, Y, Z terms of the equation |
| Vec3 xyz = calculateXYZFactors(op); |
| Vec3 fSrcDst = calculateFFunction(op, srcColor, dstColor); |
| |
| result.x() = fSrcDst.x() * p.x() + xyz.y() * srcColor.x() * p.y() + xyz.z() * dstColor.x() * p.z(); |
| result.y() = fSrcDst.y() * p.x() + xyz.y() * srcColor.y() * p.y() + xyz.z() * dstColor.y() * p.z(); |
| result.z() = fSrcDst.z() * p.x() + xyz.y() * srcColor.z() * p.y() + xyz.z() * dstColor.z() * p.z(); |
| result.w() = xyz.x() * p.x() + xyz.y() * p.y() + xyz.z() * p.z(); |
| } |
| else if (op >= VK_BLEND_OP_PLUS_EXT && op < VK_BLEND_OP_MAX_ENUM) |
| { |
| // Premultiply colors for additional RGB blend operations. The formula is different than the rest of operations. |
| { |
| if (!param.premultipliedSrcColor) |
| { |
| srcColor = srcColor * source.w(); |
| } |
| |
| if (!param.premultipliedDstColor) |
| { |
| dstColor = dstColor * destination.w(); |
| } |
| |
| } |
| Vec4 src = Vec4(srcColor.x(), srcColor.y(), srcColor.z(), source.w()); |
| Vec4 dst = Vec4(dstColor.x(), dstColor.y(), dstColor.z(), destination.w()); |
| result = additionalRGBBlendOperations(op, src, dst); |
| } |
| else |
| { |
| DE_FATAL("Unsupported Blend Operation"); |
| } |
| return result; |
| } |
| |
| static inline void getCoordinates (deUint32 index, deInt32 &x, deInt32 &y) |
| { |
| x = index % widthArea; |
| y = index / heightArea; |
| } |
| |
| static inline std::vector<Vec4> createPoints (void) |
| { |
| std::vector<Vec4> vertices; |
| vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4(-1.0f, 1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); |
| vertices.push_back(Vec4( 1.0f, -1.0f, 0.0f, 1.0f)); |
| return vertices; |
| } |
| |
| template <class Test> |
| vkt::TestCase* newTestCase (tcu::TestContext& testContext, |
| const BlendOperationAdvancedParam testParam) |
| { |
| return new Test(testContext, |
| generateTestName(testParam).c_str(), |
| generateTestDescription().c_str(), |
| testParam); |
| } |
| |
| Move<VkRenderPass> makeTestRenderPass (BlendOperationAdvancedParam param, |
| const DeviceInterface& vk, |
| const VkDevice device, |
| const VkFormat colorFormat, |
| VkAttachmentLoadOp colorLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR) |
| { |
| const VkAttachmentDescription colorAttachmentDescription = |
| { |
| (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags |
| colorFormat, // VkFormat format |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples |
| colorLoadOp, // VkAttachmentLoadOp loadOp |
| VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp |
| (colorLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD) ? |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout |
| }; |
| |
| std::vector<VkAttachmentDescription> attachmentDescriptions; |
| std::vector<VkAttachmentReference> colorAttachmentRefs; |
| |
| |
| for (deUint32 i = 0; i < param.colorAttachmentsCount; i++) |
| { |
| attachmentDescriptions.push_back(colorAttachmentDescription); |
| const VkAttachmentReference colorAttachmentRef = |
| { |
| i, // deUint32 attachment |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout |
| }; |
| |
| colorAttachmentRefs.push_back(colorAttachmentRef); |
| } |
| |
| const VkSubpassDescription subpassDescription = |
| { |
| (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags |
| VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint |
| 0u, // deUint32 inputAttachmentCount |
| DE_NULL, // const VkAttachmentReference* pInputAttachments |
| param.colorAttachmentsCount, // deUint32 colorAttachmentCount |
| colorAttachmentRefs.data(), // const VkAttachmentReference* pColorAttachments |
| DE_NULL, // const VkAttachmentReference* pResolveAttachments |
| DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment |
| 0u, // deUint32 preserveAttachmentCount |
| DE_NULL // const deUint32* pPreserveAttachments |
| }; |
| |
| const VkRenderPassCreateInfo renderPassInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags |
| (deUint32)attachmentDescriptions.size(), // deUint32 attachmentCount |
| attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments |
| 1u, // deUint32 subpassCount |
| &subpassDescription, // const VkSubpassDescription* pSubpasses |
| 0u, // deUint32 dependencyCount |
| DE_NULL // const VkSubpassDependency* pDependencies |
| }; |
| |
| return createRenderPass(vk, device, &renderPassInfo, DE_NULL); |
| } |
| |
| Move<VkBuffer> createBufferAndBindMemory (Context& context, VkDeviceSize size, VkBufferUsageFlags usage, de::MovePtr<Allocation>* pAlloc) |
| { |
| const DeviceInterface& vk = context.getDeviceInterface(); |
| const VkDevice vkDevice = context.getDevice(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| |
| const VkBufferCreateInfo vertexBufferParams = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkBufferCreateFlags flags; |
| size, // VkDeviceSize size; |
| usage, // VkBufferUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyCount; |
| &queueFamilyIndex // const deUint32* pQueueFamilyIndices; |
| }; |
| |
| Move<VkBuffer> vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams); |
| |
| *pAlloc = context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible); |
| VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, (*pAlloc)->getMemory(), (*pAlloc)->getOffset())); |
| |
| return vertexBuffer; |
| } |
| |
| Move<VkImage> createImage2DAndBindMemory (Context& context, |
| VkFormat format, |
| deUint32 width, |
| deUint32 height, |
| VkImageUsageFlags usage, |
| VkSampleCountFlagBits sampleCount, |
| de::details::MovePtr<Allocation>* pAlloc) |
| { |
| const DeviceInterface& vk = context.getDeviceInterface(); |
| const VkDevice vkDevice = context.getDevice(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| |
| const VkImageCreateInfo colorImageParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkImageCreateFlags flags; |
| VK_IMAGE_TYPE_2D, // VkImageType imageType; |
| format, // VkFormat format; |
| { width, height, 1u }, // VkExtent3D extent; |
| 1u, // deUint32 mipLevels; |
| 1u, // deUint32 arraySize; |
| sampleCount, // deUint32 samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| usage, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyCount; |
| &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| |
| Move<VkImage> image = createImage(vk, vkDevice, &colorImageParams); |
| |
| *pAlloc = context.getDefaultAllocator().allocate(getImageMemoryRequirements(vk, vkDevice, *image), MemoryRequirement::Any); |
| VK_CHECK(vk.bindImageMemory(vkDevice, *image, (*pAlloc)->getMemory(), (*pAlloc)->getOffset())); |
| |
| return image; |
| } |
| |
| // Test Classes |
| class BlendOperationAdvancedTestInstance : public vkt::TestInstance |
| { |
| public: |
| BlendOperationAdvancedTestInstance (Context& context, |
| const BlendOperationAdvancedParam param); |
| virtual ~BlendOperationAdvancedTestInstance (void); |
| virtual tcu::TestStatus iterate (void); |
| protected: |
| void prepareRenderPass (VkFramebuffer framebuffer, VkPipeline pipeline) const; |
| void prepareCommandBuffer (void) const; |
| void buildPipeline (VkBool32 premultiplySrc, VkBool32 premultiplyDst); |
| void bindShaderStage (VkShaderStageFlagBits stage, |
| const char* sourceName, |
| const char* entryName); |
| deBool verifyTestResult (void); |
| protected: |
| const BlendOperationAdvancedParam m_param; |
| const tcu::UVec2 m_renderSize; |
| const VkFormat m_colorFormat; |
| Move<VkPipelineLayout> m_pipelineLayout; |
| |
| Move<VkBuffer> m_vertexBuffer; |
| de::MovePtr<Allocation> m_vertexBufferMemory; |
| std::vector<Vec4> m_vertices; |
| |
| Move<VkRenderPass> m_renderPass; |
| Move<VkCommandPool> m_cmdPool; |
| Move<VkCommandBuffer> m_cmdBuffer; |
| std::vector<Move<VkImage>> m_colorImages; |
| std::vector<Move<VkImageView>> m_colorAttachmentViews; |
| std::vector<de::MovePtr<Allocation>> m_colorImageAllocs; |
| std::vector<VkImageMemoryBarrier> m_imageLayoutBarriers; |
| Move<VkFramebuffer> m_framebuffer; |
| Move<VkPipeline> m_pipeline; |
| |
| Move<VkShaderModule> m_shaderModules[2]; |
| deUint32 m_shaderStageCount; |
| VkPipelineShaderStageCreateInfo m_shaderStageInfo[2]; |
| }; |
| |
| void BlendOperationAdvancedTestInstance::bindShaderStage (VkShaderStageFlagBits stage, |
| const char* sourceName, |
| const char* entryName) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| |
| // Create shader module |
| deUint32* code = (deUint32*)m_context.getBinaryCollection().get(sourceName).getBinary(); |
| deUint32 codeSize = (deUint32)m_context.getBinaryCollection().get(sourceName).getSize(); |
| |
| const VkShaderModuleCreateInfo moduleCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkShaderModuleCreateFlags flags; |
| codeSize, // deUintptr codeSize; |
| code, // const deUint32* pCode; |
| }; |
| |
| m_shaderModules[m_shaderStageCount] = createShaderModule(vk, vkDevice, &moduleCreateInfo); |
| |
| // Prepare shader stage info |
| m_shaderStageInfo[m_shaderStageCount].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; |
| m_shaderStageInfo[m_shaderStageCount].pNext = DE_NULL; |
| m_shaderStageInfo[m_shaderStageCount].flags = 0u; |
| m_shaderStageInfo[m_shaderStageCount].stage = stage; |
| m_shaderStageInfo[m_shaderStageCount].module = *m_shaderModules[m_shaderStageCount]; |
| m_shaderStageInfo[m_shaderStageCount].pName = entryName; |
| m_shaderStageInfo[m_shaderStageCount].pSpecializationInfo = DE_NULL; |
| |
| m_shaderStageCount++; |
| } |
| |
| void BlendOperationAdvancedTestInstance::buildPipeline (VkBool32 srcPremultiplied, |
| VkBool32 dstPremultiplied) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| |
| // Create pipeline |
| const VkVertexInputBindingDescription vertexInputBindingDescription = |
| { |
| 0u, // deUint32 binding; |
| sizeof(Vec4), // deUint32 strideInBytes; |
| VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; |
| }; |
| |
| const VkVertexInputAttributeDescription vertexInputAttributeDescription = |
| { |
| 0u, // deUint32 location; |
| 0u, // deUint32 binding; |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; |
| 0u // deUint32 offsetInBytes; |
| }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineVertexInputStateCreateFlags flags; |
| 1u, // deUint32 vertexBindingDescriptionCount; |
| &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; |
| 1u, // deUint32 vertexAttributeDescriptionCount; |
| &vertexInputAttributeDescription, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; |
| }; |
| |
| const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineInputAssemblyStateCreateFlags flags; |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology; |
| VK_FALSE, // VkBool32 primitiveRestartEnable; |
| }; |
| |
| const VkRect2D scissor = makeRect2D(m_renderSize); |
| VkViewport viewport = makeViewport(m_renderSize); |
| |
| const VkPipelineViewportStateCreateInfo viewportStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineViewportStateCreateFlags flags; |
| 1u, // deUint32 viewportCount; |
| &viewport, // const VkViewport* pViewports; |
| 1u, // deUint32 scissorCount; |
| &scissor // const VkRect2D* pScissors; |
| }; |
| |
| const VkPipelineRasterizationStateCreateInfo rasterStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineRasterizationStateCreateFlags flags; |
| VK_FALSE, // VkBool32 depthClampEnable; |
| VK_FALSE, // VkBool32 rasterizerDiscardEnable; |
| VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; |
| VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; |
| VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; |
| VK_FALSE, // VkBool32 depthBiasEnable; |
| 0.0f, // float depthBiasConstantFactor; |
| 0.0f, // float depthBiasClamp; |
| 0.0f, // float depthBiasSlopeFactor; |
| 1.0f, // float lineWidth; |
| }; |
| |
| const VkPipelineColorBlendAdvancedStateCreateInfoEXT blendAdvancedStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| srcPremultiplied, // VkBool32 srcPremultiplied; |
| dstPremultiplied, // VkBool32 dstPremultiplied; |
| m_param.overlap, // VkBlendOverlapEXT blendOverlap; |
| }; |
| |
| std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates; |
| |
| for (deUint32 i = 0; i < m_param.colorAttachmentsCount; i++) |
| { |
| const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = |
| { |
| VK_TRUE, // VkBool32 blendEnable; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor dstColorBlendFactor; |
| m_param.blendOps[i], // VkBlendOp colorBlendOp; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor; |
| m_param.blendOps[i], // VkBlendOp alphaBlendOp; |
| VK_COLOR_COMPONENT_R_BIT | |
| VK_COLOR_COMPONENT_G_BIT | |
| VK_COLOR_COMPONENT_B_BIT | |
| VK_COLOR_COMPONENT_A_BIT // VkColorComponentFlags colorWriteMask; |
| }; |
| colorBlendAttachmentStates.emplace_back(colorBlendAttachmentState); |
| } |
| |
| const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; |
| &blendAdvancedStateParams, // const void* pNext; |
| 0u, // VkPipelineColorBlendStateCreateFlags flags; |
| VK_FALSE, // VkBool32 logicOpEnable; |
| VK_LOGIC_OP_COPY, // VkLogicOp logicOp; |
| (deUint32)colorBlendAttachmentStates.size(), // deUint32 attachmentCount; |
| colorBlendAttachmentStates.data(), // const VkPipelineColorBlendAttachmentState* pAttachments; |
| { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConst[4]; |
| }; |
| |
| const VkPipelineMultisampleStateCreateInfo multisampleStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineMultisampleStateCreateFlags flags; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; |
| VK_FALSE, // VkBool32 sampleShadingEnable; |
| 0.0f, // float minSampleShading; |
| DE_NULL, // const VkSampleMask* pSampleMask; |
| VK_FALSE, // VkBool32 alphaToCoverageEnable; |
| VK_FALSE, // VkBool32 alphaToOneEnable; |
| }; |
| |
| VkPipelineDepthStencilStateCreateInfo depthStencilStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineDepthStencilStateCreateFlags flags; |
| VK_FALSE, // VkBool32 depthTestEnable; |
| VK_FALSE, // VkBool32 depthWriteEnable; |
| VK_COMPARE_OP_NEVER, // VkCompareOp depthCompareOp; |
| VK_FALSE, // VkBool32 depthBoundsTestEnable; |
| VK_FALSE, // VkBool32 stencilTestEnable; |
| // VkStencilOpState front; |
| { |
| VK_STENCIL_OP_KEEP, // VkStencilOp failOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp passOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp; |
| VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; |
| 0u, // deUint32 compareMask; |
| 0u, // deUint32 writeMask; |
| 0u, // deUint32 reference; |
| }, |
| // VkStencilOpState back; |
| { |
| VK_STENCIL_OP_KEEP, // VkStencilOp failOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp passOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp; |
| VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; |
| 0u, // deUint32 compareMask; |
| 0u, // deUint32 writeMask; |
| 0u, // deUint32 reference; |
| }, |
| 0.0f, // float minDepthBounds; |
| 1.0f, // float maxDepthBounds; |
| }; |
| |
| const VkDynamicState dynamicState = VK_DYNAMIC_STATE_SCISSOR; |
| const VkPipelineDynamicStateCreateInfo dynamicStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineDynamicStateCreateFlags flags; |
| 1u, // uint32_t dynamicStateCount; |
| &dynamicState // const VkDynamicState* pDynamicStates; |
| }; |
| |
| const VkGraphicsPipelineCreateInfo graphicsPipelineParams = |
| { |
| VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineCreateFlags flags; |
| m_shaderStageCount, // deUint32 stageCount; |
| m_shaderStageInfo, // const VkPipelineShaderStageCreateInfo* pStages; |
| &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; |
| &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; |
| DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; |
| &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState; |
| &rasterStateParams, // const VkPipelineRasterizationStateCreateInfo* pRasterState; |
| &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; |
| &depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; |
| &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; |
| &dynamicStateParams, // const VkPipelineDynamicStateCreateInfo* pDynamicState; |
| *m_pipelineLayout, // VkPipelineLayout layout; |
| *m_renderPass, // VkRenderPass renderPass; |
| 0u, // deUint32 subpass; |
| DE_NULL, // VkPipeline basePipelineHandle; |
| 0u, // deInt32 basePipelineIndex; |
| }; |
| |
| m_pipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams); |
| } |
| |
| void BlendOperationAdvancedTestInstance::prepareRenderPass (VkFramebuffer framebuffer, VkPipeline pipeline) const |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| |
| std::vector<VkClearValue> attachmentClearValues; |
| |
| for (deUint32 i = 0; i < m_param.colorAttachmentsCount; i++) |
| attachmentClearValues.emplace_back(makeClearValueColor(clearColorVec4)); |
| |
| beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), |
| m_param.colorAttachmentsCount, attachmentClearValues.data()); |
| vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); |
| VkDeviceSize offsets = 0u; |
| vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &offsets); |
| |
| // Draw all colors |
| deUint32 skippedColors = 0u; |
| for (deUint32 color = 0; color < DE_LENGTH_OF_ARRAY(srcColors); color++) |
| { |
| // Skip ill-formed colors when we have non-premultiplied destination colors. |
| if (m_param.premultipliedDstColor == VK_FALSE) |
| { |
| deBool skipColor = false; |
| for (deUint32 i = 0; i < m_param.colorAttachmentsCount; i++) |
| { |
| Vec4 calculatedColor = calculateFinalColor(m_param, m_param.blendOps[i], srcColors[color], dstColors[color]); |
| if (calculatedColor.w() <= 0.0f && calculatedColor != Vec4(0.0f)) |
| { |
| // Skip ill-formed colors, because the spec says the result is undefined. |
| skippedColors++; |
| skipColor = true; |
| break; |
| } |
| } |
| if (skipColor) |
| continue; |
| } |
| |
| deInt32 x = 0; |
| deInt32 y = 0; |
| getCoordinates(color, x, y); |
| |
| // Set source color as push constant |
| vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(Vec4), &srcColors[color]); |
| |
| VkRect2D scissor = makeRect2D(x, y, 1u, 1u); |
| vk.cmdSetScissor(*m_cmdBuffer, 0u, 1u, &scissor); |
| |
| // To set destination color, we do clear attachment restricting the area to the respective pixel of each color attachment. |
| { |
| // Set destination color as push constant. |
| std::vector<VkClearAttachment> attachments; |
| VkClearValue clearValue = vk::makeClearValueColorVec4(dstColors[color]); |
| |
| for (deUint32 i = 0; i < m_param.colorAttachmentsCount; i++) |
| { |
| VkClearAttachment attachment = |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, |
| i, |
| clearValue |
| }; |
| attachments.emplace_back(attachment); |
| } |
| |
| const VkClearRect rect = |
| { |
| scissor, |
| 0u, |
| 1u |
| }; |
| vk.cmdClearAttachments(*m_cmdBuffer, (deUint32)attachments.size(), attachments.data(), 1u, &rect); |
| } |
| |
| // Draw |
| vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1u, 0u, 0u); |
| } |
| |
| // If we break this assert, then we are not testing anything in this test. |
| DE_ASSERT(skippedColors < DE_LENGTH_OF_ARRAY(srcColors)); |
| |
| // Log number of skipped colors |
| if (skippedColors != 0u) |
| { |
| tcu::TestLog& log = m_context.getTestContext().getLog(); |
| log << tcu::TestLog::Message << "Skipped " << skippedColors << " out of " << DE_LENGTH_OF_ARRAY(srcColors) << " color cases due to ill-formed colors" << tcu::TestLog::EndMessage; |
| } |
| endRenderPass(vk, *m_cmdBuffer); |
| } |
| |
| void BlendOperationAdvancedTestInstance::prepareCommandBuffer () const |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| |
| |
| beginCommandBuffer(vk, *m_cmdBuffer, 0u); |
| |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, (VkDependencyFlags)0, |
| 0u, DE_NULL, 0u, DE_NULL, (deUint32)m_imageLayoutBarriers.size(), m_imageLayoutBarriers.data()); |
| |
| prepareRenderPass(*m_framebuffer, *m_pipeline); |
| |
| endCommandBuffer(vk, *m_cmdBuffer); |
| } |
| |
| BlendOperationAdvancedTestInstance::BlendOperationAdvancedTestInstance (Context& context, |
| const BlendOperationAdvancedParam param) |
| : TestInstance (context) |
| , m_param (param) |
| , m_renderSize (tcu::UVec2(widthArea, heightArea)) |
| , m_colorFormat (VK_FORMAT_R16G16B16A16_SFLOAT) |
| , m_shaderStageCount (0) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| |
| // Create vertex buffer and upload data |
| { |
| // Load vertices into vertex buffer |
| m_vertices = createPoints(); |
| DE_ASSERT((deUint32)m_vertices.size() == 6); |
| |
| m_vertexBuffer = createBufferAndBindMemory(m_context, m_vertices.size() * sizeof(Vec4), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &m_vertexBufferMemory); |
| deMemcpy(m_vertexBufferMemory->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vec4)); |
| flushAlloc(vk, vkDevice, *m_vertexBufferMemory); |
| } |
| |
| // Create render pass |
| m_renderPass = makeTestRenderPass(param, vk, vkDevice, m_colorFormat); |
| |
| const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; |
| |
| // Create color images |
| for (deUint32 i = 0; i < param.colorAttachmentsCount; i++) |
| { |
| de::MovePtr<Allocation> colorImageAlloc; |
| m_colorImageAllocs.emplace_back(colorImageAlloc); |
| |
| Move<VkImage> colorImage = createImage2DAndBindMemory(m_context, |
| m_colorFormat, |
| m_renderSize.x(), |
| m_renderSize.y(), |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, |
| VK_SAMPLE_COUNT_1_BIT, |
| &m_colorImageAllocs.back()); |
| m_colorImages.emplace_back(colorImage); |
| |
| // Set up image layout transition barriers |
| { |
| VkImageMemoryBarrier colorImageBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkAccessFlags srcAccessMask; |
| (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
| VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT), // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; |
| *m_colorImages.back(), // VkImage image; |
| { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; |
| }; |
| |
| m_imageLayoutBarriers.emplace_back(colorImageBarrier); |
| } |
| |
| // Create color attachment view |
| { |
| VkImageViewCreateInfo colorAttachmentViewParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkImageViewCreateFlags flags; |
| *m_colorImages.back(), // VkImage image; |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; |
| m_colorFormat, // VkFormat format; |
| componentMappingRGBA, // VkComponentMapping components; |
| { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; |
| }; |
| |
| m_colorAttachmentViews.emplace_back(createImageView(vk, vkDevice, &colorAttachmentViewParams)); |
| } |
| } |
| |
| // Create framebuffer |
| { |
| std::vector<VkImageView> imageViews; |
| |
| for (auto& movePtr : m_colorAttachmentViews) |
| imageViews.push_back(movePtr.get()); |
| |
| const VkFramebufferCreateInfo framebufferParams = |
| { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkFramebufferCreateFlags flags; |
| *m_renderPass, // VkRenderPass renderPass; |
| (deUint32)imageViews.size(), // deUint32 attachmentCount; |
| imageViews.data(), // const VkImageView* pAttachments; |
| (deUint32)m_renderSize.x(), // deUint32 width; |
| (deUint32)m_renderSize.y(), // deUint32 height; |
| 1u, // deUint32 layers; |
| }; |
| |
| m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams); |
| } |
| |
| // Bind shader stages |
| { |
| bindShaderStage(VK_SHADER_STAGE_VERTEX_BIT, "vert", "main"); |
| bindShaderStage(VK_SHADER_STAGE_FRAGMENT_BIT, "frag", "main"); |
| } |
| |
| |
| // Create pipeline layout |
| { |
| const VkPushConstantRange pushConstantRange = |
| { |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags |
| 0, // deUint32 offset |
| sizeof(Vec4) // deUint32 size |
| }; |
| |
| const VkPipelineLayoutCreateInfo pipelineLayoutParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineLayoutCreateFlags flags; |
| 0u, // deUint32 setLayoutCount; |
| DE_NULL, // const VkDescriptorSetLayout* pSetLayouts; |
| 1u, // deUint32 pushConstantRangeCount; |
| &pushConstantRange // const VkPushConstantRange* pPushConstantRanges; |
| }; |
| |
| m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams); |
| } |
| |
| // Create pipeline |
| buildPipeline(m_param.premultipliedSrcColor, m_param.premultipliedDstColor); |
| |
| // Create command pool |
| m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex); |
| |
| // Create command buffer |
| m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| } |
| |
| BlendOperationAdvancedTestInstance::~BlendOperationAdvancedTestInstance (void) |
| { |
| } |
| |
| tcu::TestStatus BlendOperationAdvancedTestInstance::iterate (void) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| tcu::TestLog& log = m_context.getTestContext().getLog(); |
| |
| // Log the blend operations to test |
| { |
| if (m_param.independentBlend) |
| { |
| for (deUint32 i = 0; (i < m_param.colorAttachmentsCount); i++) |
| log << tcu::TestLog::Message << "Color attachment " << i << " uses depth op: "<< de::toLower(getBlendOpStr(m_param.blendOps[i]).toString().substr(3)) << tcu::TestLog::EndMessage; |
| |
| } |
| else |
| { |
| log << tcu::TestLog::Message << "All color attachments use depth op: " << de::toLower(getBlendOpStr(m_param.blendOps[0]).toString().substr(3)) << tcu::TestLog::EndMessage; |
| |
| } |
| } |
| prepareCommandBuffer(); |
| submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get()); |
| |
| if (verifyTestResult() == DE_FALSE) |
| return tcu::TestStatus::fail("Image mismatch"); |
| |
| return tcu::TestStatus::pass("Result images matches references"); |
| } |
| |
| deBool BlendOperationAdvancedTestInstance::verifyTestResult () |
| { |
| deBool compareOk = DE_TRUE; |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| Allocator& allocator = m_context.getDefaultAllocator(); |
| std::vector<tcu::TextureLevel> referenceImages; |
| |
| for (deUint32 colorAtt = 0; colorAtt < m_param.colorAttachmentsCount; colorAtt++) |
| { |
| tcu::TextureLevel refImage (vk::mapVkFormat(m_colorFormat), 32, 32); |
| tcu::clear(refImage.getAccess(), clearColorVec4); |
| referenceImages.emplace_back(refImage); |
| } |
| |
| for (deUint32 color = 0; color < DE_LENGTH_OF_ARRAY(srcColors); color++) |
| { |
| deBool skipColor = DE_FALSE; |
| |
| // Check if any color attachment will generate an ill-formed color. If that's the case, skip that color in the verification. |
| for (deUint32 colorAtt = 0; colorAtt < m_param.colorAttachmentsCount; colorAtt++) |
| { |
| Vec4 rectColor = calculateFinalColor(m_param, m_param.blendOps[colorAtt], srcColors[color], dstColors[color]); |
| if (m_param.premultipliedDstColor == VK_FALSE) |
| { |
| if (rectColor.w() > 0.0f) |
| { |
| rectColor.x() = rectColor.x() / rectColor.w(); |
| rectColor.y() = rectColor.y() / rectColor.w(); |
| rectColor.z() = rectColor.z() / rectColor.w(); |
| } |
| else |
| { |
| // Skip the color check if it is ill-formed. |
| if (rectColor != Vec4(0.0f)) |
| { |
| skipColor = DE_TRUE; |
| break; |
| } |
| } |
| } |
| } |
| |
| // Skip ill-formed colors that appears in any color attachment. |
| if (skipColor) |
| continue; |
| |
| // If we reach this point, the final color for all color attachment is not ill-formed. |
| for (deUint32 colorAtt = 0; colorAtt < m_param.colorAttachmentsCount; colorAtt++) |
| { |
| Vec4 rectColor = calculateFinalColor(m_param, m_param.blendOps[colorAtt], srcColors[color], dstColors[color]); |
| if (m_param.premultipliedDstColor == VK_FALSE) |
| { |
| if (rectColor.w() > 0.0f) |
| { |
| rectColor.x() = rectColor.x() / rectColor.w(); |
| rectColor.y() = rectColor.y() / rectColor.w(); |
| rectColor.z() = rectColor.z() / rectColor.w(); |
| } |
| else |
| { |
| // Ill-formed colors were already skipped |
| DE_ASSERT(rectColor == Vec4(0.0f)); |
| } |
| } |
| deInt32 x = 0; |
| deInt32 y = 0; |
| getCoordinates(color, x, y); |
| tcu::clear(tcu::getSubregion(referenceImages[colorAtt].getAccess(), x, y, 1u, 1u), rectColor); |
| } |
| } |
| |
| for (deUint32 colorAtt = 0; colorAtt < m_param.colorAttachmentsCount; colorAtt++) |
| { |
| // Compare image |
| de::MovePtr<tcu::TextureLevel> result = vkt::pipeline::readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImages[colorAtt], m_colorFormat, m_renderSize); |
| std::ostringstream name; |
| name << "Image comparison. Color attachment: " << colorAtt << ". Depth op: " << de::toLower(getBlendOpStr(m_param.blendOps[colorAtt]).toString().substr(3)); |
| |
| compareOk = tcu::floatThresholdCompare(m_context.getTestContext().getLog(), |
| "FloatImageCompare", |
| name.str().c_str(), |
| referenceImages[colorAtt].getAccess(), |
| result->getAccess(), |
| Vec4(0.01f, 0.01f, 0.01f, 0.01f), |
| tcu::COMPARE_LOG_RESULT); |
| if (!compareOk) |
| return DE_FALSE; |
| } |
| return DE_TRUE; |
| } |
| |
| class BlendOperationAdvancedTest : public vkt::TestCase |
| { |
| public: |
| BlendOperationAdvancedTest (tcu::TestContext& testContext, |
| const std::string& name, |
| const std::string& description, |
| const BlendOperationAdvancedParam param) |
| : vkt::TestCase (testContext, name, description) |
| , m_param (param) |
| { } |
| virtual ~BlendOperationAdvancedTest (void) { } |
| virtual void initPrograms (SourceCollections& programCollection) const; |
| virtual TestInstance* createInstance (Context& context) const; |
| virtual void checkSupport (Context& context) const; |
| |
| protected: |
| const BlendOperationAdvancedParam m_param; |
| }; |
| |
| void BlendOperationAdvancedTest::checkSupport(Context& context) const |
| { |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| |
| context.requireDeviceFunctionality("VK_EXT_blend_operation_advanced"); |
| |
| VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT blendProperties; |
| blendProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT; |
| blendProperties.pNext = DE_NULL; |
| |
| VkPhysicalDeviceProperties2 properties2; |
| properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; |
| properties2.pNext = &blendProperties; |
| vki.getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties2); |
| |
| if (!blendProperties.advancedBlendAllOperations) |
| { |
| for (deUint32 index = 0u; index < m_param.blendOps.size(); index++) |
| { |
| switch (m_param.blendOps[index]) |
| { |
| case VK_BLEND_OP_MULTIPLY_EXT: |
| case VK_BLEND_OP_SCREEN_EXT: |
| case VK_BLEND_OP_OVERLAY_EXT: |
| case VK_BLEND_OP_DARKEN_EXT: |
| case VK_BLEND_OP_LIGHTEN_EXT: |
| case VK_BLEND_OP_COLORDODGE_EXT: |
| case VK_BLEND_OP_COLORBURN_EXT: |
| case VK_BLEND_OP_HARDLIGHT_EXT: |
| case VK_BLEND_OP_SOFTLIGHT_EXT: |
| case VK_BLEND_OP_DIFFERENCE_EXT: |
| case VK_BLEND_OP_EXCLUSION_EXT: |
| case VK_BLEND_OP_HSL_HUE_EXT: |
| case VK_BLEND_OP_HSL_SATURATION_EXT: |
| case VK_BLEND_OP_HSL_COLOR_EXT: |
| case VK_BLEND_OP_HSL_LUMINOSITY_EXT: |
| break; |
| default: |
| throw tcu::NotSupportedError("Unsupported all advanced blend operations and unsupported advanced blend operation"); |
| } |
| } |
| } |
| |
| if (m_param.colorAttachmentsCount > blendProperties.advancedBlendMaxColorAttachments) |
| { |
| std::ostringstream error; |
| error << "Unsupported number of color attachments (" << blendProperties.advancedBlendMaxColorAttachments << " < " << m_param.colorAttachmentsCount; |
| throw tcu::NotSupportedError(error.str().c_str()); |
| } |
| |
| if (m_param.overlap != VK_BLEND_OVERLAP_UNCORRELATED_EXT && !blendProperties.advancedBlendCorrelatedOverlap) |
| { |
| throw tcu::NotSupportedError("Unsupported blend correlated overlap"); |
| } |
| |
| if (m_param.colorAttachmentsCount > 1 && m_param.independentBlend && !blendProperties.advancedBlendIndependentBlend) |
| { |
| throw tcu::NotSupportedError("Unsupported independent blend"); |
| } |
| |
| if (!m_param.premultipliedSrcColor && !blendProperties.advancedBlendNonPremultipliedSrcColor) |
| { |
| throw tcu::NotSupportedError("Unsupported non-premultiplied source color"); |
| } |
| |
| if (!m_param.premultipliedDstColor && !blendProperties.advancedBlendNonPremultipliedDstColor) |
| { |
| throw tcu::NotSupportedError("Unsupported non-premultiplied destination color"); |
| } |
| |
| const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT blendFeatures = context.getBlendOperationAdvancedFeaturesEXT(); |
| if (m_param.coherentOperations && !blendFeatures.advancedBlendCoherentOperations) |
| { |
| throw tcu::NotSupportedError("Unsupported required coherent operations"); |
| } |
| } |
| |
| void BlendOperationAdvancedTest::initPrograms (SourceCollections& programCollection) const |
| { |
| programCollection.glslSources.add("vert") << glu::VertexSource( |
| "#version 310 es\n" |
| "layout(location = 0) in vec4 position;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = position;\n" |
| "}\n"); |
| |
| std::ostringstream fragmentSource; |
| fragmentSource << "#version 310 es\n"; |
| fragmentSource << "layout(push_constant) uniform Color { highp vec4 color; };\n"; |
| for (deUint32 i = 0; i < m_param.colorAttachmentsCount; i++) |
| fragmentSource << "layout(location = "<< i <<") out highp vec4 fragColor" << i <<";\n"; |
| fragmentSource << "void main (void)\n"; |
| fragmentSource << "{\n"; |
| for (deUint32 i = 0; i < m_param.colorAttachmentsCount; i++) |
| fragmentSource << " fragColor" << i <<" = color;\n"; |
| fragmentSource << "}\n"; |
| programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSource.str().c_str()); |
| } |
| |
| class BlendOperationAdvancedTestCoherentInstance : public vkt::TestInstance |
| { |
| public: |
| BlendOperationAdvancedTestCoherentInstance (Context& context, |
| const BlendOperationAdvancedParam param); |
| virtual ~BlendOperationAdvancedTestCoherentInstance (void); |
| virtual tcu::TestStatus iterate (void); |
| protected: |
| void prepareRenderPass (VkFramebuffer framebuffer, VkPipeline pipeline, |
| VkRenderPass renderpass, deBool secondDraw); |
| virtual void prepareCommandBuffer (void); |
| virtual void buildPipeline (void); |
| virtual void bindShaderStage (VkShaderStageFlagBits stage, |
| const char* sourceName, |
| const char* entryName); |
| virtual tcu::TestStatus verifyTestResult (void); |
| |
| protected: |
| const BlendOperationAdvancedParam m_param; |
| const tcu::UVec2 m_renderSize; |
| const VkFormat m_colorFormat; |
| Move<VkPipelineLayout> m_pipelineLayout; |
| |
| Move<VkBuffer> m_vertexBuffer; |
| de::MovePtr<Allocation> m_vertexBufferMemory; |
| std::vector<Vec4> m_vertices; |
| |
| std::vector<Move<VkRenderPass>> m_renderPasses; |
| Move<VkCommandPool> m_cmdPool; |
| Move<VkCommandBuffer> m_cmdBuffer; |
| Move<VkImage> m_colorImage; |
| Move<VkImageView> m_colorAttachmentView; |
| de::MovePtr<Allocation> m_colorImageAlloc; |
| std::vector<VkImageMemoryBarrier> m_imageLayoutBarriers; |
| std::vector<Move<VkFramebuffer>> m_framebuffers; |
| std::vector<Move<VkPipeline>> m_pipelines; |
| |
| Move<VkShaderModule> m_shaderModules[2]; |
| deUint32 m_shaderStageCount; |
| VkPipelineShaderStageCreateInfo m_shaderStageInfo[2]; |
| }; |
| |
| BlendOperationAdvancedTestCoherentInstance::~BlendOperationAdvancedTestCoherentInstance (void) |
| { |
| } |
| |
| void BlendOperationAdvancedTestCoherentInstance::bindShaderStage (VkShaderStageFlagBits stage, |
| const char* sourceName, |
| const char* entryName) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| |
| // Create shader module |
| deUint32* code = (deUint32*)m_context.getBinaryCollection().get(sourceName).getBinary(); |
| deUint32 codeSize = (deUint32)m_context.getBinaryCollection().get(sourceName).getSize(); |
| |
| const VkShaderModuleCreateInfo moduleCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkShaderModuleCreateFlags flags; |
| codeSize, // deUintptr codeSize; |
| code, // const deUint32* pCode; |
| }; |
| |
| m_shaderModules[m_shaderStageCount] = createShaderModule(vk, vkDevice, &moduleCreateInfo); |
| |
| // Prepare shader stage info |
| m_shaderStageInfo[m_shaderStageCount].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; |
| m_shaderStageInfo[m_shaderStageCount].pNext = DE_NULL; |
| m_shaderStageInfo[m_shaderStageCount].flags = 0u; |
| m_shaderStageInfo[m_shaderStageCount].stage = stage; |
| m_shaderStageInfo[m_shaderStageCount].module = *m_shaderModules[m_shaderStageCount]; |
| m_shaderStageInfo[m_shaderStageCount].pName = entryName; |
| m_shaderStageInfo[m_shaderStageCount].pSpecializationInfo = DE_NULL; |
| |
| m_shaderStageCount++; |
| } |
| |
| void BlendOperationAdvancedTestCoherentInstance::buildPipeline () |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| |
| // Create pipeline |
| const VkVertexInputBindingDescription vertexInputBindingDescription = |
| { |
| 0u, // deUint32 binding; |
| sizeof(Vec4) , // deUint32 strideInBytes; |
| VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; |
| }; |
| |
| const VkVertexInputAttributeDescription vertexInputAttributeDescription = |
| { |
| 0u, // deUint32 location; |
| 0u, // deUint32 binding; |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; |
| 0u // deUint32 offsetInBytes; |
| }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineVertexInputStateCreateFlags flags; |
| 1u, // deUint32 vertexBindingDescriptionCount; |
| &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; |
| 1u, // deUint32 vertexAttributeDescriptionCount; |
| &vertexInputAttributeDescription, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; |
| }; |
| |
| const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineInputAssemblyStateCreateFlags flags; |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology; |
| VK_FALSE, // VkBool32 primitiveRestartEnable; |
| }; |
| |
| const VkRect2D scissor = makeRect2D(m_renderSize); |
| VkViewport viewport = makeViewport(m_renderSize); |
| |
| const VkPipelineViewportStateCreateInfo viewportStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineViewportStateCreateFlags flags; |
| 1u, // deUint32 viewportCount; |
| &viewport, // const VkViewport* pViewports; |
| 1u, // deUint32 scissorCount; |
| &scissor // const VkRect2D* pScissors; |
| }; |
| |
| const VkPipelineRasterizationStateCreateInfo rasterStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineRasterizationStateCreateFlags flags; |
| VK_FALSE, // VkBool32 depthClampEnable; |
| VK_FALSE, // VkBool32 rasterizerDiscardEnable; |
| VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; |
| VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; |
| VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; |
| VK_FALSE, // VkBool32 depthBiasEnable; |
| 0.0f, // float depthBiasConstantFactor; |
| 0.0f, // float depthBiasClamp; |
| 0.0f, // float depthBiasSlopeFactor; |
| 1.0f, // float lineWidth; |
| }; |
| |
| const VkPipelineColorBlendAdvancedStateCreateInfoEXT blendAdvancedStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_TRUE, // VkBool32 srcPremultiplied; |
| VK_TRUE, // VkBool32 dstPremultiplied; |
| m_param.overlap, // VkBlendOverlapEXT blendOverlap; |
| }; |
| |
| std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates; |
| |
| // One VkPipelineColorBlendAttachmentState for each pipeline, we only have one color attachment. |
| for (deUint32 i = 0; i < 2; i++) |
| { |
| const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = |
| { |
| VK_TRUE, // VkBool32 blendEnable; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor dstColorBlendFactor; |
| m_param.blendOps[i], // VkBlendOp colorBlendOp; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor; |
| m_param.blendOps[i], // VkBlendOp alphaBlendOp; |
| VK_COLOR_COMPONENT_R_BIT | |
| VK_COLOR_COMPONENT_G_BIT | |
| VK_COLOR_COMPONENT_B_BIT | |
| VK_COLOR_COMPONENT_A_BIT // VkColorComponentFlags colorWriteMask; |
| }; |
| colorBlendAttachmentStates.emplace_back(colorBlendAttachmentState); |
| } |
| |
| std::vector<VkPipelineColorBlendStateCreateInfo> colorBlendStateParams; |
| VkPipelineColorBlendStateCreateInfo colorBlendStateParam = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; |
| &blendAdvancedStateParams, // const void* pNext; |
| 0u, // VkPipelineColorBlendStateCreateFlags flags; |
| VK_FALSE, // VkBool32 logicOpEnable; |
| VK_LOGIC_OP_COPY, // VkLogicOp logicOp; |
| 1u, // deUint32 attachmentCount; |
| &colorBlendAttachmentStates[0], // const VkPipelineColorBlendAttachmentState* pAttachments; |
| { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConst[4]; |
| }; |
| colorBlendStateParams.emplace_back(colorBlendStateParam); |
| |
| // For the second pipeline, the blendOp changed. |
| colorBlendStateParam.pAttachments = &colorBlendAttachmentStates[1]; |
| colorBlendStateParams.emplace_back(colorBlendStateParam); |
| |
| const VkPipelineMultisampleStateCreateInfo multisampleStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineMultisampleStateCreateFlags flags; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; |
| VK_FALSE, // VkBool32 sampleShadingEnable; |
| 0.0f, // float minSampleShading; |
| DE_NULL, // const VkSampleMask* pSampleMask; |
| VK_FALSE, // VkBool32 alphaToCoverageEnable; |
| VK_FALSE, // VkBool32 alphaToOneEnable; |
| }; |
| |
| VkPipelineDepthStencilStateCreateInfo depthStencilStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineDepthStencilStateCreateFlags flags; |
| VK_FALSE, // VkBool32 depthTestEnable; |
| VK_FALSE, // VkBool32 depthWriteEnable; |
| VK_COMPARE_OP_NEVER, // VkCompareOp depthCompareOp; |
| VK_FALSE, // VkBool32 depthBoundsTestEnable; |
| VK_FALSE, // VkBool32 stencilTestEnable; |
| // VkStencilOpState front; |
| { |
| VK_STENCIL_OP_KEEP, // VkStencilOp failOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp passOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp; |
| VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; |
| 0u, // deUint32 compareMask; |
| 0u, // deUint32 writeMask; |
| 0u, // deUint32 reference; |
| }, |
| // VkStencilOpState back; |
| { |
| VK_STENCIL_OP_KEEP, // VkStencilOp failOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp passOp; |
| VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp; |
| VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; |
| 0u, // deUint32 compareMask; |
| 0u, // deUint32 writeMask; |
| 0u, // deUint32 reference; |
| }, |
| 0.0f, // float minDepthBounds; |
| 1.0f, // float maxDepthBounds; |
| }; |
| |
| const VkDynamicState dynamicState = VK_DYNAMIC_STATE_SCISSOR; |
| const VkPipelineDynamicStateCreateInfo dynamicStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineDynamicStateCreateFlags flags; |
| 1u, // uint32_t dynamicStateCount; |
| &dynamicState // const VkDynamicState* pDynamicStates; |
| }; |
| |
| VkGraphicsPipelineCreateInfo graphicsPipelineParams = |
| { |
| VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineCreateFlags flags; |
| m_shaderStageCount, // deUint32 stageCount; |
| m_shaderStageInfo, // const VkPipelineShaderStageCreateInfo* pStages; |
| &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; |
| &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; |
| DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; |
| &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState; |
| &rasterStateParams, // const VkPipelineRasterizationStateCreateInfo* pRasterState; |
| &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; |
| &depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; |
| &colorBlendStateParams[0], // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; |
| &dynamicStateParams, // const VkPipelineDynamicStateCreateInfo* pDynamicState; |
| *m_pipelineLayout, // VkPipelineLayout layout; |
| m_renderPasses[0].get(), // VkRenderPass renderPass; |
| 0u, // deUint32 subpass; |
| DE_NULL, // VkPipeline basePipelineHandle; |
| 0u, // deInt32 basePipelineIndex; |
| }; |
| |
| // Create first pipeline |
| m_pipelines.emplace_back(createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams)); |
| // Create second pipeline |
| graphicsPipelineParams.pColorBlendState = &colorBlendStateParams[1]; |
| graphicsPipelineParams.renderPass = m_renderPasses[1].get(); |
| m_pipelines.emplace_back(createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams)); |
| } |
| |
| void BlendOperationAdvancedTestCoherentInstance::prepareRenderPass (VkFramebuffer framebuffer, VkPipeline pipeline, VkRenderPass renderpass, deBool secondDraw) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| |
| VkClearValue attachmentClearValue = makeClearValueColor(clearColorVec4); |
| |
| beginRenderPass(vk, *m_cmdBuffer, renderpass, framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), |
| (secondDraw ? 0u : 1u), |
| (secondDraw ? DE_NULL : &attachmentClearValue)); |
| |
| vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); |
| VkDeviceSize offsets = 0u; |
| vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &offsets); |
| |
| // There are two different renderpasses, each of them draw |
| // one half of the colors. |
| deBool skippedColors = 0u; |
| for (deUint32 color = 0; color < DE_LENGTH_OF_ARRAY(srcColors)/2; color++) |
| { |
| // Skip ill-formed colors when we have non-premultiplied destination colors. |
| if (m_param.premultipliedDstColor == VK_FALSE) |
| { |
| deBool skipColor = false; |
| for (deUint32 i = 0; i < m_param.colorAttachmentsCount; i++) |
| { |
| Vec4 calculatedColor = calculateFinalColor(m_param, m_param.blendOps[i], srcColors[color], dstColors[color]); |
| if (calculatedColor.w() <= 0.0f && calculatedColor != Vec4(0.0f)) |
| { |
| // Skip ill-formed colors, because the spec says the result is undefined. |
| skippedColors++; |
| skipColor = true; |
| break; |
| } |
| } |
| if (skipColor) |
| continue; |
| } |
| deInt32 x = 0; |
| deInt32 y = 0; |
| getCoordinates(color, x, y); |
| |
| deUint32 index = secondDraw ? (color + DE_LENGTH_OF_ARRAY(srcColors) / 2) : color; |
| |
| // Set source color as push constant |
| vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(Vec4), &srcColors[index]); |
| VkRect2D scissor = makeRect2D(x, y, 1u, 1u); |
| vk.cmdSetScissor(*m_cmdBuffer, 0u, 1u, &scissor); |
| |
| // To set destination color, we do clear attachment restricting the area to the respective pixel of each color attachment. |
| // Only clear in the first draw, for the second draw the destination color is the result of the first draw's blend. |
| if (secondDraw == DE_FALSE) |
| { |
| std::vector<VkClearAttachment> attachments; |
| VkClearValue clearValue = vk::makeClearValueColorVec4(dstColors[index]); |
| |
| const VkClearAttachment attachment = |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, |
| 0u, |
| clearValue |
| }; |
| |
| const VkClearRect rect = |
| { |
| scissor, |
| 0u, |
| 1u |
| }; |
| vk.cmdClearAttachments(*m_cmdBuffer, 1u, &attachment, 1u, &rect); |
| } |
| |
| // Draw |
| vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1u, 0u, 0u); |
| } |
| |
| // If we break this assert, then we are not testing anything in this test. |
| DE_ASSERT(skippedColors < (DE_LENGTH_OF_ARRAY(srcColors) / 2)); |
| |
| // Log number of skipped colors |
| if (skippedColors != 0u) |
| { |
| tcu::TestLog& log = m_context.getTestContext().getLog(); |
| log << tcu::TestLog::Message << "Skipped " << skippedColors << " out of " << (DE_LENGTH_OF_ARRAY(srcColors) / 2) << " color cases due to ill-formed colors" << tcu::TestLog::EndMessage; |
| } |
| endRenderPass(vk, *m_cmdBuffer); |
| } |
| |
| void BlendOperationAdvancedTestCoherentInstance::prepareCommandBuffer () |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| |
| beginCommandBuffer(vk, *m_cmdBuffer, 0u); |
| |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, (VkDependencyFlags)0, |
| 0u, DE_NULL, 0u, DE_NULL, (deUint32)m_imageLayoutBarriers.size(), m_imageLayoutBarriers.data()); |
| |
| prepareRenderPass(m_framebuffers[0].get(), m_pipelines[0].get(), m_renderPasses[0].get(), false); |
| |
| if (m_param.coherentOperations == DE_FALSE) |
| { |
| const VkImageMemoryBarrier colorImageBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
| VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT), // VkAccessFlags srcAccessMask; |
| (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
| VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT), // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; |
| *m_colorImage, // VkImage image; |
| { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; |
| }; |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, (VkDependencyFlags)0, |
| 0u, DE_NULL, 0u, DE_NULL, 1u, &colorImageBarrier); |
| } |
| |
| prepareRenderPass(m_framebuffers[1].get(), m_pipelines[1].get(), m_renderPasses[1].get(), true); |
| |
| endCommandBuffer(vk, *m_cmdBuffer); |
| } |
| |
| BlendOperationAdvancedTestCoherentInstance::BlendOperationAdvancedTestCoherentInstance (Context& context, |
| const BlendOperationAdvancedParam param) |
| : TestInstance (context) |
| , m_param (param) |
| , m_renderSize (tcu::UVec2(widthArea, heightArea)) |
| , m_colorFormat (VK_FORMAT_R16G16B16A16_SFLOAT) |
| , m_shaderStageCount (0) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| |
| // Create vertex buffer |
| { |
| m_vertices = createPoints(); |
| DE_ASSERT((deUint32)m_vertices.size() == 6); |
| |
| m_vertexBuffer = createBufferAndBindMemory(m_context, m_vertices.size() * sizeof(Vec4), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &m_vertexBufferMemory); |
| // Load vertices into vertex buffer |
| deMemcpy(m_vertexBufferMemory->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vec4)); |
| flushAlloc(vk, vkDevice, *m_vertexBufferMemory); |
| } |
| |
| // Create render passes |
| m_renderPasses.emplace_back(makeTestRenderPass(param, vk, vkDevice, m_colorFormat, VK_ATTACHMENT_LOAD_OP_CLEAR)); |
| m_renderPasses.emplace_back(makeTestRenderPass(param, vk, vkDevice, m_colorFormat, VK_ATTACHMENT_LOAD_OP_LOAD)); |
| |
| const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; |
| |
| // Create color image |
| m_colorImage = createImage2DAndBindMemory(m_context, |
| m_colorFormat, |
| m_renderSize.x(), |
| m_renderSize.y(), |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, |
| VK_SAMPLE_COUNT_1_BIT, |
| &m_colorImageAlloc); |
| // Set up image layout transition barriers |
| { |
| VkImageMemoryBarrier colorImageBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkAccessFlags srcAccessMask; |
| (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | |
| VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT), // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; |
| *m_colorImage, // VkImage image; |
| { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; |
| }; |
| |
| m_imageLayoutBarriers.emplace_back(colorImageBarrier); |
| } |
| |
| // Create color attachment view |
| { |
| VkImageViewCreateInfo colorAttachmentViewParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkImageViewCreateFlags flags; |
| *m_colorImage, // VkImage image; |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; |
| m_colorFormat, // VkFormat format; |
| componentMappingRGBA, // VkComponentMapping components; |
| { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; |
| }; |
| |
| m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams); |
| } |
| |
| // Create framebuffers |
| { |
| VkFramebufferCreateInfo framebufferParams = |
| { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkFramebufferCreateFlags flags; |
| m_renderPasses[0].get(), // VkRenderPass renderPass; |
| 1u, // deUint32 attachmentCount; |
| &m_colorAttachmentView.get(), // const VkImageView* pAttachments; |
| (deUint32)m_renderSize.x(), // deUint32 width; |
| (deUint32)m_renderSize.y(), // deUint32 height; |
| 1u, // deUint32 layers; |
| }; |
| |
| m_framebuffers.emplace_back(createFramebuffer(vk, vkDevice, &framebufferParams)); |
| framebufferParams.renderPass = m_renderPasses[1].get(); |
| m_framebuffers.emplace_back(createFramebuffer(vk, vkDevice, &framebufferParams)); |
| } |
| |
| // Bind shader stages |
| { |
| bindShaderStage(VK_SHADER_STAGE_VERTEX_BIT, "vert", "main"); |
| bindShaderStage(VK_SHADER_STAGE_FRAGMENT_BIT, "frag", "main"); |
| } |
| |
| |
| // Create pipeline layout |
| { |
| const VkPushConstantRange pushConstantRange = |
| { |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags |
| 0, // deUint32 offset |
| sizeof(Vec4) // deUint32 size |
| }; |
| |
| const VkPipelineLayoutCreateInfo pipelineLayoutParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineLayoutCreateFlags flags; |
| 0u, // deUint32 setLayoutCount; |
| DE_NULL, // const VkDescriptorSetLayout* pSetLayouts; |
| 1u, // deUint32 pushConstantRangeCount; |
| &pushConstantRange // const VkPushConstantRange* pPushConstantRanges; |
| }; |
| |
| m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams); |
| } |
| |
| // Create pipeline |
| buildPipeline(); |
| |
| // Create command pool |
| m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex); |
| |
| // Create command buffer |
| m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| } |
| |
| tcu::TestStatus BlendOperationAdvancedTestCoherentInstance::iterate (void) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| tcu::TestLog& log = m_context.getTestContext().getLog(); |
| |
| // Log the blend operations to test |
| { |
| DE_ASSERT(m_param.blendOps.size() == 2u); |
| log << tcu::TestLog::Message << "First depth op: " << de::toLower(getBlendOpStr(m_param.blendOps[0]).toString().substr(3)) << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message << "Second depth op: " << de::toLower(getBlendOpStr(m_param.blendOps[1]).toString().substr(3)) << tcu::TestLog::EndMessage; |
| |
| } |
| |
| prepareCommandBuffer(); |
| |
| submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get()); |
| return verifyTestResult(); |
| } |
| |
| tcu::TestStatus BlendOperationAdvancedTestCoherentInstance::verifyTestResult (void) |
| { |
| deBool compareOk = DE_TRUE; |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| Allocator& allocator = m_context.getDefaultAllocator(); |
| tcu::TextureLevel refImage (vk::mapVkFormat(m_colorFormat), 32, 32); |
| |
| tcu::clear(refImage.getAccess(), clearColorVec4); |
| |
| // Generate reference image |
| for (deUint32 color = 0; color < DE_LENGTH_OF_ARRAY(srcColors)/2; color++) |
| { |
| deUint32 secondDrawColorIndex = color + DE_LENGTH_OF_ARRAY(srcColors)/2; |
| // Calculate first draw final color |
| Vec4 rectColorTmp = calculateFinalColor(m_param, m_param.blendOps[0], srcColors[color], dstColors[color]); |
| |
| if (m_param.premultipliedDstColor == VK_FALSE) |
| { |
| if (rectColorTmp.w() > 0.0f) |
| { |
| rectColorTmp.x() = rectColorTmp.x() / rectColorTmp.w(); |
| rectColorTmp.y() = rectColorTmp.y() / rectColorTmp.w(); |
| rectColorTmp.z() = rectColorTmp.z() / rectColorTmp.w(); |
| } |
| else |
| { |
| // Skip the color check if it is ill-formed. |
| if (rectColorTmp != Vec4(0.0f)) |
| continue; |
| } |
| } |
| // Calculate second draw final color |
| Vec4 rectColor = calculateFinalColor(m_param, m_param.blendOps[1], srcColors[secondDrawColorIndex], rectColorTmp); |
| if (m_param.premultipliedDstColor == VK_FALSE) |
| { |
| if (rectColor.w() > 0.0f) |
| { |
| rectColor.x() = rectColor.x() / rectColor.w(); |
| rectColor.y() = rectColor.y() / rectColor.w(); |
| rectColor.z() = rectColor.z() / rectColor.w(); |
| } |
| else |
| { |
| // Skip the color check if it is ill-formed. |
| if (rectColor != Vec4(0.0f)) |
| continue; |
| } |
| } |
| |
| deInt32 x = 0; |
| deInt32 y = 0; |
| getCoordinates(color, x, y); |
| tcu::clear(tcu::getSubregion(refImage.getAccess(), x, y, 1u, 1u), rectColor); |
| } |
| |
| de::MovePtr<tcu::TextureLevel> result = vkt::pipeline::readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize); |
| std::ostringstream name; |
| name << "Image comparison. Depth ops: " << de::toLower(getBlendOpStr(m_param.blendOps[0]).toString().substr(3)) << " and " << de::toLower(getBlendOpStr(m_param.blendOps[1]).toString().substr(3)); |
| compareOk = tcu::floatThresholdCompare(m_context.getTestContext().getLog(), |
| "FloatImageCompare", |
| name.str().c_str(), |
| refImage.getAccess(), |
| result->getAccess(), |
| Vec4(0.01f, 0.01f, 0.01f, 0.01f), |
| tcu::COMPARE_LOG_RESULT); |
| if (!compareOk) |
| return tcu::TestStatus::fail("Image mismatch"); |
| |
| return tcu::TestStatus::pass("Result images matches references"); |
| } |
| |
| TestInstance* BlendOperationAdvancedTest::createInstance (Context& context) const |
| { |
| if (m_param.testMode == TEST_MODE_GENERIC) |
| return new BlendOperationAdvancedTestInstance(context, m_param); |
| else |
| return new BlendOperationAdvancedTestCoherentInstance(context, m_param); |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createBlendOperationAdvancedTests (tcu::TestContext& testCtx) |
| { |
| enum nonpremultiplyEnum |
| { |
| PREMULTIPLY_SRC = 1u, |
| PREMULTIPLY_DST = 2u |
| }; |
| deUint32 premultiplyModes[] = { 0u, PREMULTIPLY_SRC, PREMULTIPLY_DST, PREMULTIPLY_SRC | PREMULTIPLY_DST }; |
| deUint32 colorAttachmentCounts[] = { 1u, 2u, 4u, 8u, 16u }; |
| deBool coherentOps[] = { DE_FALSE, DE_TRUE }; |
| VkBlendOp blendOps[] = |
| { |
| VK_BLEND_OP_ZERO_EXT, VK_BLEND_OP_SRC_EXT, VK_BLEND_OP_DST_EXT, VK_BLEND_OP_SRC_OVER_EXT, VK_BLEND_OP_DST_OVER_EXT, |
| VK_BLEND_OP_SRC_IN_EXT, VK_BLEND_OP_DST_IN_EXT, VK_BLEND_OP_SRC_OUT_EXT, VK_BLEND_OP_DST_OUT_EXT, VK_BLEND_OP_SRC_ATOP_EXT, |
| VK_BLEND_OP_DST_ATOP_EXT, VK_BLEND_OP_XOR_EXT, VK_BLEND_OP_MULTIPLY_EXT, VK_BLEND_OP_SCREEN_EXT, VK_BLEND_OP_OVERLAY_EXT, |
| VK_BLEND_OP_DARKEN_EXT, VK_BLEND_OP_LIGHTEN_EXT, VK_BLEND_OP_COLORDODGE_EXT, VK_BLEND_OP_COLORBURN_EXT, VK_BLEND_OP_HARDLIGHT_EXT, |
| VK_BLEND_OP_SOFTLIGHT_EXT, VK_BLEND_OP_DIFFERENCE_EXT, VK_BLEND_OP_EXCLUSION_EXT, VK_BLEND_OP_INVERT_EXT, VK_BLEND_OP_INVERT_RGB_EXT, |
| VK_BLEND_OP_LINEARDODGE_EXT, VK_BLEND_OP_LINEARBURN_EXT, VK_BLEND_OP_VIVIDLIGHT_EXT, VK_BLEND_OP_LINEARLIGHT_EXT, VK_BLEND_OP_PINLIGHT_EXT, |
| VK_BLEND_OP_HARDMIX_EXT, VK_BLEND_OP_HSL_HUE_EXT, VK_BLEND_OP_HSL_SATURATION_EXT, VK_BLEND_OP_HSL_COLOR_EXT, VK_BLEND_OP_HSL_LUMINOSITY_EXT, |
| VK_BLEND_OP_PLUS_EXT, VK_BLEND_OP_PLUS_CLAMPED_EXT, VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT, VK_BLEND_OP_PLUS_DARKER_EXT, VK_BLEND_OP_MINUS_EXT, |
| VK_BLEND_OP_MINUS_CLAMPED_EXT, VK_BLEND_OP_CONTRAST_EXT, VK_BLEND_OP_INVERT_OVG_EXT, VK_BLEND_OP_RED_EXT, VK_BLEND_OP_GREEN_EXT, VK_BLEND_OP_BLUE_EXT, |
| }; |
| |
| de::MovePtr<tcu::TestCaseGroup> tests (new tcu::TestCaseGroup(testCtx, "blend_operation_advanced", "VK_EXT_blend_operation_advanced tests")); |
| de::Random rnd (deStringHash(tests->getName())); |
| |
| de::MovePtr<tcu::TestCaseGroup> opsTests (new tcu::TestCaseGroup(testCtx, "ops", "Test each blend operation advance op")); |
| |
| |
| for (deUint32 colorAttachmentCount = 0u; colorAttachmentCount < DE_LENGTH_OF_ARRAY(colorAttachmentCounts); colorAttachmentCount++) |
| { |
| for (deUint32 overlap = 0; overlap <= VK_BLEND_OVERLAP_CONJOINT_EXT; overlap++) |
| { |
| for (deUint32 premultiply = 0u; premultiply < DE_LENGTH_OF_ARRAY(premultiplyModes); premultiply++) |
| { |
| deUint32 testNumber = 0u; |
| for (deUint64 blendOp = 0u; blendOp < DE_LENGTH_OF_ARRAY(blendOps); blendOp++) |
| { |
| deBool isAdditionalRGBBlendOp = blendOps[blendOp] >= VK_BLEND_OP_PLUS_EXT && blendOps[blendOp] < VK_BLEND_OP_MAX_ENUM; |
| |
| // Additional RGB Blend operations are not affected by the blend overlap modes |
| if (isAdditionalRGBBlendOp && overlap != VK_BLEND_OVERLAP_UNCORRELATED_EXT) |
| continue; |
| |
| BlendOperationAdvancedParam testParams; |
| testParams.testMode = TEST_MODE_GENERIC; |
| testParams.overlap = (VkBlendOverlapEXT) overlap; |
| testParams.coherentOperations = DE_FALSE; |
| testParams.colorAttachmentsCount = colorAttachmentCounts[colorAttachmentCount]; |
| testParams.independentBlend = DE_FALSE; |
| testParams.premultipliedSrcColor = (premultiplyModes[premultiply] & PREMULTIPLY_SRC) ? VK_TRUE : VK_FALSE; |
| testParams.premultipliedDstColor = (premultiplyModes[premultiply] & PREMULTIPLY_DST) ? VK_TRUE : VK_FALSE; |
| testParams.testNumber = testNumber++; |
| |
| for (deUint32 numColorAtt = 0; numColorAtt < colorAttachmentCounts[colorAttachmentCount]; numColorAtt++) |
| testParams.blendOps.push_back(blendOps[blendOp]); |
| opsTests->addChild(newTestCase<BlendOperationAdvancedTest>(testCtx, testParams)); |
| } |
| } |
| } |
| } |
| tests->addChild(opsTests.release()); |
| |
| // Independent Blend Tests: test more than one color attachment. |
| de::MovePtr<tcu::TestCaseGroup> independentTests (new tcu::TestCaseGroup(testCtx, "independent", "Test independent blend feature")); |
| deUint32 testNumber = 0u; |
| |
| for (deUint32 colorAttachmentCount = 1u; colorAttachmentCount < DE_LENGTH_OF_ARRAY(colorAttachmentCounts); colorAttachmentCount++) |
| { |
| BlendOperationAdvancedParam testParams; |
| testParams.testMode = TEST_MODE_GENERIC; |
| testParams.overlap = VK_BLEND_OVERLAP_UNCORRELATED_EXT; |
| testParams.coherentOperations = DE_FALSE; |
| testParams.colorAttachmentsCount = colorAttachmentCounts[colorAttachmentCount]; |
| testParams.independentBlend = DE_TRUE; |
| testParams.premultipliedSrcColor = VK_TRUE; |
| testParams.premultipliedDstColor = VK_TRUE; |
| testParams.testNumber = testNumber++; |
| |
| for (deUint32 numColorAtt = 0; numColorAtt < colorAttachmentCounts[colorAttachmentCount]; numColorAtt++) |
| { |
| deUint32 i = de::randomScalar<deUint32>(rnd, 0, DE_LENGTH_OF_ARRAY(blendOps) - 1); |
| testParams.blendOps.push_back(blendOps[i]); |
| } |
| independentTests->addChild(newTestCase<BlendOperationAdvancedTest>(testCtx, testParams)); |
| } |
| |
| tests->addChild(independentTests.release()); |
| |
| // Coherent tests, do two consecutive advanced blending operations on the same color attachment. |
| de::MovePtr<tcu::TestCaseGroup> coherentTests (new tcu::TestCaseGroup(testCtx, "coherent", "Test coherent memory")); |
| testNumber = 0u; |
| |
| for (deUint32 coherent = 0u; coherent < DE_LENGTH_OF_ARRAY(coherentOps); coherent++) |
| { |
| BlendOperationAdvancedParam testParams; |
| testParams.testMode = TEST_MODE_COHERENT; |
| testParams.overlap = VK_BLEND_OVERLAP_UNCORRELATED_EXT; |
| testParams.coherentOperations = coherentOps[coherent]; |
| testParams.colorAttachmentsCount = 1u; |
| testParams.independentBlend = DE_FALSE; |
| testParams.premultipliedSrcColor = VK_TRUE; |
| testParams.premultipliedDstColor = VK_TRUE; |
| testParams.testNumber = testNumber++; |
| |
| // We do two consecutive advanced blending operations |
| deUint32 i = de::randomScalar<deUint32>(rnd, 0, DE_LENGTH_OF_ARRAY(blendOps) - 1); |
| testParams.blendOps.push_back(blendOps[i]); |
| i = de::randomScalar<deUint32>(rnd, 0, DE_LENGTH_OF_ARRAY(blendOps) - 1); |
| testParams.blendOps.push_back(blendOps[i]); |
| |
| coherentTests->addChild(newTestCase<BlendOperationAdvancedTest>(testCtx, testParams)); |
| } |
| tests->addChild(coherentTests.release()); |
| |
| |
| return tests.release(); |
| } |
| |
| } // pipeline |
| |
| } // vkt |