Merge vk-gl-cts/vulkan-cts-1.1.6 into vk-gl-cts/master
authorAlexander Galazin <alexander.galazin@arm.com>
Fri, 25 Oct 2019 19:01:47 +0000 (21:01 +0200)
committerAlexander Galazin <alexander.galazin@arm.com>
Sat, 26 Oct 2019 07:13:08 +0000 (09:13 +0200)
Change-Id: I563fc81549024a61aadc779285e8d4686c9c931a

17 files changed:
1  2 
external/vulkancts/modules/vulkan/api/vktApiCopiesAndBlittingTests.cpp
external/vulkancts/modules/vulkan/binding_model/vktBindingDescriptorCopyTests.cpp
external/vulkancts/modules/vulkan/image/vktImageTranscodingSupportTests.cpp
external/vulkancts/modules/vulkan/pipeline/vktPipelineBlendOperationAdvancedTests.cpp
external/vulkancts/modules/vulkan/pipeline/vktPipelineRenderToImageTests.cpp
external/vulkancts/modules/vulkan/pipeline/vktPipelineTimestampTests.cpp
external/vulkancts/modules/vulkan/subgroups/vktSubgroupsBallotBroadcastTests.cpp
external/vulkancts/modules/vulkan/subgroups/vktSubgroupsBallotTests.cpp
external/vulkancts/modules/vulkan/subgroups/vktSubgroupsTestsUtils.cpp
external/vulkancts/modules/vulkan/synchronization/vktSynchronizationWin32KeyedMutexTests.cpp
external/vulkancts/modules/vulkan/vktCustomInstancesDevices.cpp
external/vulkancts/modules/vulkan/wsi/vktWsiSurfaceTests.cpp
external/vulkancts/modules/vulkan/ycbcr/vktYCbCrConversionTests.cpp
external/vulkancts/modules/vulkan/ycbcr/vktYCbCrFormatTests.cpp
external/vulkancts/modules/vulkan/ycbcr/vktYCbCrStorageImageWriteTests.cpp
external/vulkancts/modules/vulkan/ycbcr/vktYCbCrUtil.cpp
external/vulkancts/scripts/gen_framework.py

@@@ -1559,39 -1419,9 +1559,39 @@@ tcu::TestStatus DescriptorCommands::ru
        vector<VkAttachmentDescription>                 attachmentDescriptions;
        vector<VkImageView>                                             imageViews;
  
 -      if(limits.maxBoundDescriptorSets <= m_descriptorSets.size())
 +      if (limits.maxBoundDescriptorSets <= m_descriptorSets.size())
                TCU_THROW(NotSupportedError, "Maximum bound descriptor sets limit exceeded.");
  
-               if (isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), "VK_EXT_inline_uniform_block"))
 +      // Check if inline uniform blocks are supported.
 +      VkPhysicalDeviceInlineUniformBlockFeaturesEXT   iubFeatures =
 +      {
 +              VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT,
 +              DE_NULL,
 +              VK_FALSE, VK_FALSE
 +      };
 +      VkPhysicalDeviceInlineUniformBlockPropertiesEXT iubProperties =
 +      {
 +              VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT,
 +              DE_NULL,
 +              0u, 0u, 0u, 0u, 0u
 +      };
 +      {
++              if (context.isDeviceFunctionalitySupported("VK_EXT_inline_uniform_block"))
 +              {
 +                      VkPhysicalDeviceFeatures2 features2;
 +                      deMemset(&features2, 0, sizeof(features2));
 +                      features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
 +                      features2.pNext = &iubFeatures;
 +                      vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
 +
 +                      VkPhysicalDeviceProperties2 properties2;
 +                      deMemset(&properties2, 0, sizeof(properties2));
 +                      properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
 +                      properties2.pNext = &iubProperties;
 +                      vki.getPhysicalDeviceProperties2(physicalDevice, &properties2);
 +              }
 +      }
 +
        // Check physical device limits of per stage and per desriptor set descriptor count
        {
                deUint32        numPerStageSamplers                     = 0;
index a2272f6,0000000..4b7896f
mode 100644,000000..100644
--- /dev/null
@@@ -1,2497 -1,0 +1,2497 @@@
-       context.requireDeviceExtension("VK_EXT_blend_operation_advanced");
 +/*------------------------------------------------------------------------
 + * 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)
 +      {
 +              throw tcu::NotSupportedError("Unsupported all advanced blend operations");
 +      }
 +
 +      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.getBlendOperationAdvancedFeatures();
 +      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
index b82b112,0000000..ec48454
mode 100644,000000..100644
--- /dev/null
@@@ -1,718 -1,0 +1,718 @@@
-               if (!isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), extIter))
 +/*-------------------------------------------------------------------------
 + * Vulkan Conformance Tests
 + * ------------------------
 + *
 + * Copyright (c) 2017 Google 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 Testing compute shader writing to separate planes of a multiplanar format
 + *//*--------------------------------------------------------------------*/
 +
 +#include "vktYCbCrStorageImageWriteTests.hpp"
 +#include "vktTestCaseUtil.hpp"
 +#include "vktTestGroupUtil.hpp"
 +#include "vktYCbCrUtil.hpp"
 +#include "vkBuilderUtil.hpp"
 +#include "vkObjUtil.hpp"
 +#include "vkCmdUtil.hpp"
 +#include "vkBarrierUtil.hpp"
 +#include "vkImageUtil.hpp"
 +#include "tcuTexVerifierUtil.hpp"
 +#include "vkTypeUtil.hpp"
 +#include "vkRefUtil.hpp"
 +#include "vkQueryUtil.hpp"
 +#include "tcuTestLog.hpp"
 +
 +namespace vkt
 +{
 +namespace ycbcr
 +{
 +namespace
 +{
 +
 +using namespace vk;
 +
 +struct TestParameters
 +{
 +      VkFormat                        format;
 +      tcu::UVec3                      size;
 +      VkImageCreateFlags      flags;
 +
 +      TestParameters (VkFormat                        format_,
 +                                      const tcu::UVec3&       size_,
 +                                      VkImageCreateFlags      flags_)
 +              : format                        (format_)
 +              , size                          (size_)
 +              , flags                         (flags_)
 +      {
 +      }
 +
 +      TestParameters (void)
 +              : format                        (VK_FORMAT_UNDEFINED)
 +              , flags                         (0u)
 +      {
 +      }
 +};
 +
 +void checkSupport (Context& context, const TestParameters params)
 +{
 +      const bool                                                      disjoint = (params.flags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0;
 +      std::vector<std::string>                        reqExts;
 +
 +      if (disjoint)
 +      {
 +              if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_bind_memory2"))
 +                      reqExts.push_back("VK_KHR_bind_memory2");
 +              if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_get_memory_requirements2"))
 +                      reqExts.push_back("VK_KHR_get_memory_requirements2");
 +      }
 +
 +      for ( const auto& extIter : reqExts )
 +      {
++              if (!context.isDeviceFunctionalitySupported(extIter))
 +                      TCU_THROW(NotSupportedError, (extIter + " is not supported").c_str());
 +      }
 +
 +      {
 +              const VkFormatProperties        formatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
 +                      context.getPhysicalDevice(),
 +                      params.format);
 +
 +              if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0)
 +                      TCU_THROW(NotSupportedError, "Storage images are not supported for this format");
 +
 +              if (disjoint && ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT) == 0))
 +                      TCU_THROW(NotSupportedError, "Disjoint planes are not supported for this format");
 +      }
 +}
 +
 +template<typename T>
 +inline de::SharedPtr<vk::Unique<T> > makeVkSharedPtr(vk::Move<T> vkMove)
 +{
 +      return de::SharedPtr<vk::Unique<T> >(new vk::Unique<T>(vkMove));
 +}
 +
 +tcu::UVec3 computeWorkGroupSize(const VkExtent3D& planeExtent)
 +{
 +      const deUint32          maxComputeWorkGroupInvocations  = 128u;
 +      const tcu::UVec3        maxComputeWorkGroupSize                 = tcu::UVec3(128u, 128u, 64u);
 +
 +      const deUint32          xWorkGroupSize                                  = std::min(std::min(planeExtent.width, maxComputeWorkGroupSize.x()), maxComputeWorkGroupInvocations);
 +      const deUint32          yWorkGroupSize                                  = std::min(std::min(planeExtent.height, maxComputeWorkGroupSize.y()), maxComputeWorkGroupInvocations / xWorkGroupSize);
 +      const deUint32          zWorkGroupSize                                  = std::min(std::min(planeExtent.depth, maxComputeWorkGroupSize.z()), maxComputeWorkGroupInvocations / (xWorkGroupSize*yWorkGroupSize));
 +
 +      return tcu::UVec3(xWorkGroupSize, yWorkGroupSize, zWorkGroupSize);
 +}
 +
 +Move<VkPipeline> makeComputePipeline (const DeviceInterface&          vk,
 +                                                                        const VkDevice                                device,
 +                                                                        const VkPipelineLayout                pipelineLayout,
 +                                                                        const VkShaderModule                  shaderModule,
 +                                                                        const VkSpecializationInfo*   specializationInfo)
 +{
 +      const VkPipelineShaderStageCreateInfo pipelineShaderStageParams =
 +      {
 +              VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,    // VkStructureType                                              sType;
 +              DE_NULL,                                                                                                // const void*                                                  pNext;
 +              0u,                                                                                                             // VkPipelineShaderStageCreateFlags             flags;
 +              VK_SHADER_STAGE_COMPUTE_BIT,                                                    // VkShaderStageFlagBits                                stage;
 +              shaderModule,                                                                                   // VkShaderModule                                               module;
 +              "main",                                                                                                 // const char*                                                  pName;
 +              specializationInfo,                                                                             // const VkSpecializationInfo*                  pSpecializationInfo;
 +      };
 +      const VkComputePipelineCreateInfo pipelineCreateInfo =
 +      {
 +              VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,         // VkStructureType                                      sType;
 +              DE_NULL,                                                                                        // const void*                                          pNext;
 +              0u,                                                                                                     // VkPipelineCreateFlags                        flags;
 +              pipelineShaderStageParams,                                                      // VkPipelineShaderStageCreateInfo      stage;
 +              pipelineLayout,                                                                         // VkPipelineLayout                                     layout;
 +              DE_NULL,                                                                                        // VkPipeline                                           basePipelineHandle;
 +              0,                                                                                                      // deInt32                                                      basePipelineIndex;
 +      };
 +      return createComputePipeline(vk, device, DE_NULL , &pipelineCreateInfo);
 +}
 +
 +vk::VkFormat getPlaneCompatibleFormatForWriting(const vk::PlanarFormatDescription& formatInfo, deUint32 planeNdx)
 +{
 +      DE_ASSERT(planeNdx < formatInfo.numPlanes);
 +      vk::VkFormat result = formatInfo.planes[planeNdx].planeCompatibleFormat;
 +
 +      // redirect result for some of the YCbCr image formats
 +      static const std::pair<vk::VkFormat, vk::VkFormat> ycbcrFormats[] =
 +      {
 +              { VK_FORMAT_G8B8G8R8_422_UNORM_KHR,                                             VK_FORMAT_R8G8B8A8_UNORM                },
 +              { VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR, VK_FORMAT_R16G16B16A16_UNORM    },
 +              { VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR, VK_FORMAT_R16G16B16A16_UNORM    },
 +              { VK_FORMAT_G16B16G16R16_422_UNORM_KHR,                                 VK_FORMAT_R16G16B16A16_UNORM    },
 +              { VK_FORMAT_B8G8R8G8_422_UNORM_KHR,                                             VK_FORMAT_R8G8B8A8_UNORM                },
 +              { VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR, VK_FORMAT_R16G16B16A16_UNORM    },
 +              { VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR, VK_FORMAT_R16G16B16A16_UNORM    },
 +              { VK_FORMAT_B16G16R16G16_422_UNORM_KHR,                                 VK_FORMAT_R16G16B16A16_UNORM    }
 +      };
 +      auto it = std::find_if(std::begin(ycbcrFormats), std::end(ycbcrFormats), [result](const std::pair<vk::VkFormat, vk::VkFormat>& p) { return p.first == result; });
 +      if (it != std::end(ycbcrFormats))
 +              result = it->second;
 +      return result;
 +}
 +
 +tcu::TestStatus testStorageImageWrite (Context& context, TestParameters params)
 +{
 +      const DeviceInterface&                                          vkd                                             = context.getDeviceInterface();
 +      const VkDevice                                                          device                                  = context.getDevice();
 +      const deUint32                                                          queueFamilyIndex                = context.getUniversalQueueFamilyIndex();
 +      const VkQueue                                                           queue                                   = context.getUniversalQueue();
 +      const PlanarFormatDescription                           formatDescription               = getPlanarFormatDescription(params.format);
 +
 +      VkImageCreateInfo                                                       imageCreateInfo =
 +      {
 +              VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
 +              DE_NULL,
 +              params.flags,
 +              VK_IMAGE_TYPE_2D,
 +              params.format,
 +              makeExtent3D(params.size.x(), params.size.y(), params.size.z()),
 +              1u,                     // mipLevels
 +              1u,                     // arrayLayers
 +              VK_SAMPLE_COUNT_1_BIT,
 +              VK_IMAGE_TILING_OPTIMAL,
 +              VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
 +              VK_SHARING_MODE_EXCLUSIVE,
 +              0u,
 +              (const deUint32*)DE_NULL,
 +              VK_IMAGE_LAYOUT_UNDEFINED,
 +      };
 +
 +      // check if we need to create VkImageView with different VkFormat than VkImage format
 +      VkFormat planeCompatibleFormat0 = getPlaneCompatibleFormatForWriting(formatDescription, 0);
 +      if (planeCompatibleFormat0 != getPlaneCompatibleFormat(formatDescription, 0))
 +      {
 +              imageCreateInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
 +      }
 +
 +      const Unique<VkImage>                                           image                                   (createImage(vkd, device, &imageCreateInfo));
 +      // allocate memory for the whole image, or for each separate plane ( if the params.flags include VK_IMAGE_CREATE_DISJOINT_BIT )
 +      const std::vector<AllocationSp>                         allocations                             (allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, params.format, params.flags, MemoryRequirement::Any));
 +
 +      // Create descriptor set layout
 +      const Unique<VkDescriptorSetLayout>                     descriptorSetLayout             (DescriptorSetLayoutBuilder()
 +              .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
 +              .build(vkd, device));
 +      const Unique<VkPipelineLayout>                          pipelineLayout                  (makePipelineLayout(vkd, device, *descriptorSetLayout));
 +
 +      // Create descriptor sets
 +      const Unique<VkDescriptorPool>                          descriptorPool                  (DescriptorPoolBuilder()
 +              .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u)
 +              .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, vk::PlanarFormatDescription::MAX_PLANES));
 +
 +      // Create command buffer for compute and transfer operations
 +      const Unique<VkCommandPool>                                     commandPool                             (makeCommandPool(vkd, device, queueFamilyIndex));
 +      const Unique<VkCommandBuffer>                           commandBuffer                   (allocateCommandBuffer(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
 +
 +      std::vector<de::SharedPtr<vk::Unique<vk::VkShaderModule>>>                      shaderModules;
 +      std::vector<de::SharedPtr<vk::Unique<vk::VkPipeline>>>                          computePipelines;
 +      std::vector<de::SharedPtr<vk::Unique<vk::VkDescriptorSet>>>                     descriptorSets;
 +      std::vector<de::SharedPtr<vk::Unique<vk::VkImageView>>>                         imageViews;
 +
 +      deUint32                                                                        imageSizeInBytes                = 0;
 +      deUint32                                                                        planeOffsets[PlanarFormatDescription::MAX_PLANES];
 +      deUint32                                                                        planeRowPitches[PlanarFormatDescription::MAX_PLANES];
 +      void*                                                                           planePointers[PlanarFormatDescription::MAX_PLANES];
 +
 +      {
 +              // Start recording commands
 +              beginCommandBuffer(vkd, *commandBuffer);
 +
 +              for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
 +              {
 +                      const VkImageAspectFlags                aspect                                          = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
 +                      const VkImageSubresourceRange   subresourceRange                        = makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u);
 +                      VkFormat                                                planeCompatibleFormat           = getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
 +                      vk::PlanarFormatDescription             compatibleFormatDescription = (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
 +                      const tcu::UVec3                                compatibleShaderGridSize        ( params.size.x() / formatDescription.blockWidth, params.size.y() / formatDescription.blockHeight, params.size.z() / 1u);
 +                      VkExtent3D                                              shaderExtent                            = getPlaneExtent(compatibleFormatDescription, VkExtent3D{ compatibleShaderGridSize.x(), compatibleShaderGridSize.y(), compatibleShaderGridSize.z() }, planeNdx, 0u);
 +
 +                      // Create and bind compute pipeline
 +                      std::ostringstream shaderName;
 +                      shaderName << "comp" << planeNdx;
 +                      auto                                                    shaderModule                    = makeVkSharedPtr(createShaderModule(vkd, device, context.getBinaryCollection().get(shaderName.str()), DE_NULL));
 +                      shaderModules.push_back(shaderModule);
 +                      auto                                                    computePipeline                 = makeVkSharedPtr(makeComputePipeline(vkd, device, *pipelineLayout, shaderModule->get(), DE_NULL));
 +                      computePipelines.push_back(computePipeline);
 +                      vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline->get());
 +
 +                      auto                                                    descriptorSet                   = makeVkSharedPtr(makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout));
 +                      descriptorSets.push_back(descriptorSet);
 +
 +                      auto                                                    imageView                               = makeVkSharedPtr(makeImageView(vkd, device, *image, VK_IMAGE_VIEW_TYPE_2D, planeCompatibleFormat, subresourceRange));
 +                      imageViews.push_back(imageView);
 +                      const VkDescriptorImageInfo             imageInfo                               = makeDescriptorImageInfo(DE_NULL, imageView->get(), VK_IMAGE_LAYOUT_GENERAL);
 +
 +                      DescriptorSetUpdateBuilder()
 +                              .writeSingle(descriptorSet->get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageInfo)
 +                              .update(vkd, device);
 +
 +                      vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet->get(), 0u, DE_NULL);
 +
 +                      {
 +                              const VkImageMemoryBarrier imageLayoutChangeBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, *image, subresourceRange, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED);
 +                              vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageLayoutChangeBarrier);
 +                      }
 +
 +                      {
 +                              const tcu::UVec3 workGroupSize = computeWorkGroupSize(shaderExtent);
 +
 +                              const deUint32 xWorkGroupCount = shaderExtent.width / workGroupSize.x() + (shaderExtent.width % workGroupSize.x() ? 1u : 0u);
 +                              const deUint32 yWorkGroupCount = shaderExtent.height / workGroupSize.y() + (shaderExtent.height % workGroupSize.y() ? 1u : 0u);
 +                              const deUint32 zWorkGroupCount = shaderExtent.depth / workGroupSize.z() + (shaderExtent.depth % workGroupSize.z() ? 1u : 0u);
 +
 +                              const tcu::UVec3 maxComputeWorkGroupCount = tcu::UVec3(65535u, 65535u, 65535u);
 +
 +                              if (maxComputeWorkGroupCount.x() < xWorkGroupCount ||
 +                                      maxComputeWorkGroupCount.y() < yWorkGroupCount ||
 +                                      maxComputeWorkGroupCount.z() < zWorkGroupCount)
 +                              {
 +                                      TCU_THROW(NotSupportedError, "Image size is not supported");
 +                              }
 +
 +                              vkd.cmdDispatch(*commandBuffer, xWorkGroupCount, yWorkGroupCount, zWorkGroupCount);
 +                      }
 +
 +                      {
 +                              const VkImageMemoryBarrier imageTransferBarrier = makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *image, subresourceRange);
 +                              vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageTransferBarrier);
 +                      }
 +              }
 +
 +              for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
 +              {
 +                      planeOffsets[planeNdx]          = imageSizeInBytes;
 +                      const deUint32  planeW          = imageCreateInfo.extent.width / (formatDescription.blockWidth * formatDescription.planes[planeNdx].widthDivisor);
 +                      planeRowPitches[planeNdx]       = formatDescription.planes[planeNdx].elementSizeBytes * planeW;
 +                      imageSizeInBytes                        += getPlaneSizeInBytes(formatDescription, makeExtent3D( params.size.x(), params.size.y(), params.size.z()) , planeNdx, 0u, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
 +              }
 +
 +              const VkBufferCreateInfo                outputBufferCreateInfo  = makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
 +              const Unique<VkBuffer>                  outputBuffer                    ( createBuffer(vkd, device, &outputBufferCreateInfo) );
 +              const de::UniquePtr<Allocation> outputBufferAlloc               ( bindBuffer(vkd, device, context.getDefaultAllocator(), *outputBuffer, MemoryRequirement::HostVisible) );
 +              std::vector<VkBufferImageCopy>  bufferImageCopy                 ( formatDescription.numPlanes );
 +
 +              for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
 +              {
 +                      const VkImageAspectFlags        aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
 +
 +                      bufferImageCopy[planeNdx] =
 +                      {
 +                              planeOffsets[planeNdx],                                                                                                                                                                                         //      VkDeviceSize                            bufferOffset;
 +                              0u,                                                                                                                                                                                                                                     //      deUint32                                        bufferRowLength;
 +                              0u,                                                                                                                                                                                                                                     //      deUint32                                        bufferImageHeight;
 +                              makeImageSubresourceLayers(aspect, 0u, 0u, 1u),                                                                                                                                         //      VkImageSubresourceLayers        imageSubresource;
 +                              makeOffset3D(0, 0, 0),                                                                                                                                                                                          //      VkOffset3D                                      imageOffset;
 +                              getPlaneExtent(formatDescription, makeExtent3D(params.size.x(), params.size.y(), params.size.z()), planeNdx, 0u)        //      VkExtent3D                                      imageExtent;
 +                      };
 +              }
 +              vkd.cmdCopyImageToBuffer(*commandBuffer, *image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *outputBuffer, static_cast<deUint32>(bufferImageCopy.size()), bufferImageCopy.data());
 +
 +              {
 +                      const VkBufferMemoryBarrier outputBufferHostReadBarrier = makeBufferMemoryBarrier
 +                      (
 +                              VK_ACCESS_TRANSFER_WRITE_BIT,
 +                              VK_ACCESS_HOST_READ_BIT,
 +                              *outputBuffer,
 +                              0u,
 +                              imageSizeInBytes
 +                      );
 +
 +                      vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferHostReadBarrier, 0u, DE_NULL);
 +              }
 +
 +              // End recording commands
 +              endCommandBuffer(vkd, *commandBuffer);
 +
 +              // Submit commands for execution and wait for completion
 +              submitCommandsAndWait(vkd, device, queue, *commandBuffer);
 +
 +              // Retrieve data from buffer to host memory
 +              invalidateAlloc(vkd, device, *outputBufferAlloc);
 +              deUint8*                                        outputData = static_cast<deUint8*>(outputBufferAlloc->getHostPtr());
 +
 +              for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
 +                      planePointers[planeNdx] = outputData + static_cast<size_t>(planeOffsets[planeNdx]);
 +      }
 +
 +      // write result images to log file
 +      for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
 +      {
 +              if (!formatDescription.hasChannelNdx(channelNdx))
 +                      continue;
 +              deUint32                                        planeNdx                                        = formatDescription.channels[channelNdx].planeNdx;
 +              vk::VkFormat                            planeCompatibleFormat           = getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
 +              vk::PlanarFormatDescription     compatibleFormatDescription     = (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
 +              const tcu::UVec3                        compatibleShaderGridSize        ( params.size.x() / formatDescription.blockWidth, params.size.y() / formatDescription.blockHeight, params.size.z() / 1u );
 +              tcu::ConstPixelBufferAccess     pixelBuffer                                     = vk::getChannelAccess(compatibleFormatDescription, compatibleShaderGridSize, planeRowPitches, (const void* const*)planePointers, channelNdx);
 +              std::ostringstream str;
 +              str << "image" << channelNdx;
 +              context.getTestContext().getLog() << tcu::LogImage(str.str(), str.str(), pixelBuffer);;
 +      }
 +
 +      // verify data
 +      const float                                     epsilon = 1e-5f;
 +      for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
 +      {
 +              if (!formatDescription.hasChannelNdx(channelNdx))
 +                      continue;
 +
 +              deUint32                                                        planeNdx                                        = formatDescription.channels[channelNdx].planeNdx;
 +              vk::VkFormat                                            planeCompatibleFormat           = getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
 +              vk::PlanarFormatDescription                     compatibleFormatDescription     = (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
 +              const tcu::UVec3                                        compatibleShaderGridSize        ( params.size.x() / formatDescription.blockWidth, params.size.y() / formatDescription.blockHeight, params.size.z() / 1u );
 +              VkExtent3D                                                      compatibleImageSize                     { imageCreateInfo.extent.width / formatDescription.blockWidth, imageCreateInfo.extent.height / formatDescription.blockHeight, imageCreateInfo.extent.depth / 1u };
 +              tcu::ConstPixelBufferAccess                     pixelBuffer                                     = vk::getChannelAccess(compatibleFormatDescription, compatibleShaderGridSize, planeRowPitches, (const void* const*)planePointers, channelNdx);
 +              VkExtent3D                                                      planeExtent                                     = getPlaneExtent(compatibleFormatDescription, compatibleImageSize, planeNdx, 0u);
 +              tcu::IVec3                                                      pixelDivider                            = pixelBuffer.getDivider();
 +              float                                                           fixedPointError                         = tcu::TexVerifierUtil::computeFixedPointError(formatDescription.channels[channelNdx].sizeBits);
 +
 +              for (deUint32 offsetZ = 0u; offsetZ < planeExtent.depth; ++offsetZ)
 +              for (deUint32 offsetY = 0u; offsetY < planeExtent.height; ++offsetY)
 +              for (deUint32 offsetX = 0u; offsetX < planeExtent.width; ++offsetX)
 +              {
 +                      deUint32        iReferenceValue;
 +                      float           fReferenceValue;
 +                      switch (channelNdx)
 +                      {
 +                              case 0:
 +                                      iReferenceValue = offsetX % 127u;
 +                                      fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
 +                                      break;
 +                              case 1:
 +                                      iReferenceValue = offsetY % 127u;
 +                                      fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
 +                                      break;
 +                              case 2:
 +                                      iReferenceValue = offsetZ % 127u;
 +                                      fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
 +                                      break;
 +                              case 3:
 +                                      iReferenceValue = 0u;
 +                                      fReferenceValue = 0.f;
 +                                      break;
 +                              default:        DE_FATAL("Unexpected channel index");   break;
 +                      }
 +                      float acceptableError = epsilon;
 +
 +                      switch (formatDescription.channels[channelNdx].type)
 +                      {
 +                              case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
 +                              case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
 +                              {
 +                                      tcu::UVec4 outputValue = pixelBuffer.getPixelUint(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), 0);
 +
 +                                      if (outputValue.x() != iReferenceValue)
 +                                              return tcu::TestStatus::fail("Failed");
 +
 +                                      break;
 +                              }
 +                              case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
 +                              case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
 +                              {
 +                                      acceptableError += fixedPointError;
 +                                      tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), 0);
 +
 +                                      if (deAbs(outputValue.x() - fReferenceValue) > acceptableError)
 +                                              return tcu::TestStatus::fail("Failed");
 +
 +                                      break;
 +                              }
 +                              case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
 +                              {
 +                                      const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), 0);
 +
 +                                      if (deAbs( outputValue.x() - fReferenceValue) > acceptableError)
 +                                              return tcu::TestStatus::fail("Failed");
 +
 +                                      break;
 +                              }
 +                              default:        DE_FATAL("Unexpected channel type");    break;
 +                      }
 +              }
 +      }
 +      return tcu::TestStatus::pass("Passed");
 +}
 +
 +std::string getShaderImageType (const vk::PlanarFormatDescription& description)
 +{
 +      std::string     formatPart;
 +
 +      // all PlanarFormatDescription types have at least one channel ( 0 ) and all channel types are the same :
 +      switch (description.channels[0].type)
 +      {
 +              case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
 +                      formatPart = "i";
 +                      break;
 +              case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
 +                      formatPart = "u";
 +                      break;
 +              case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
 +              case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
 +              case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
 +                      break;
 +
 +              default:
 +                      DE_FATAL("Unexpected channel type");
 +      }
 +
 +      return formatPart + "image2D";
 +}
 +
 +std::string getShaderImageDataType (const vk::PlanarFormatDescription& description)
 +{
 +      switch (description.channels[0].type)
 +      {
 +      case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
 +              return "uvec4";
 +      case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
 +              return "ivec4";
 +      case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
 +      case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
 +      case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
 +              return "vec4";
 +      default:
 +              DE_FATAL("Unexpected channel type");
 +              return "";
 +      }
 +}
 +
 +std::string getFormatValueString      (const std::vector<std::pair<deUint32, deUint32>>& channelsOnPlane,
 +                                                                       const std::vector<std::string>& formatValueStrings)
 +{
 +      std::string result = "( ";
 +      deUint32 i;
 +      for (i=0; i<channelsOnPlane.size(); ++i)
 +      {
 +              result += formatValueStrings[channelsOnPlane[i].first];
 +              if (i < 3)
 +                      result += ", ";
 +      }
 +      for (; i < 4; ++i)
 +      {
 +              result += "0";
 +              if (i < 3)
 +                      result += ", ";
 +      }
 +      result += " )";
 +      return result;
 +}
 +
 +std::string getShaderImageFormatQualifier (VkFormat format)
 +{
 +      switch (format)
 +      {
 +              case VK_FORMAT_R8_SINT:                                                                         return "r8i";
 +              case VK_FORMAT_R16_SINT:                                                                        return "r16i";
 +              case VK_FORMAT_R32_SINT:                                                                        return "r32i";
 +              case VK_FORMAT_R8_UINT:                                                                         return "r8ui";
 +              case VK_FORMAT_R16_UINT:                                                                        return "r16ui";
 +              case VK_FORMAT_R32_UINT:                                                                        return "r32ui";
 +              case VK_FORMAT_R8_SNORM:                                                                        return "r8_snorm";
 +              case VK_FORMAT_R16_SNORM:                                                                       return "r16_snorm";
 +              case VK_FORMAT_R8_UNORM:                                                                        return "r8";
 +              case VK_FORMAT_R16_UNORM:                                                                       return "r16";
 +
 +              case VK_FORMAT_R8G8_SINT:                                                                       return "rg8i";
 +              case VK_FORMAT_R16G16_SINT:                                                                     return "rg16i";
 +              case VK_FORMAT_R32G32_SINT:                                                                     return "rg32i";
 +              case VK_FORMAT_R8G8_UINT:                                                                       return "rg8ui";
 +              case VK_FORMAT_R16G16_UINT:                                                                     return "rg16ui";
 +              case VK_FORMAT_R32G32_UINT:                                                                     return "rg32ui";
 +              case VK_FORMAT_R8G8_SNORM:                                                                      return "rg8_snorm";
 +              case VK_FORMAT_R16G16_SNORM:                                                            return "rg16_snorm";
 +              case VK_FORMAT_R8G8_UNORM:                                                                      return "rg8";
 +              case VK_FORMAT_R16G16_UNORM:                                                            return "rg16";
 +
 +              case VK_FORMAT_R8G8B8A8_SINT:                                                           return "rgba8i";
 +              case VK_FORMAT_R16G16B16A16_SINT:                                                       return "rgba16i";
 +              case VK_FORMAT_R32G32B32A32_SINT:                                                       return "rgba32i";
 +              case VK_FORMAT_R8G8B8A8_UINT:                                                           return "rgba8ui";
 +              case VK_FORMAT_R16G16B16A16_UINT:                                                       return "rgba16ui";
 +              case VK_FORMAT_R32G32B32A32_UINT:                                                       return "rgba32ui";
 +              case VK_FORMAT_R8G8B8A8_SNORM:                                                          return "rgba8_snorm";
 +              case VK_FORMAT_R16G16B16A16_SNORM:                                                      return "rgba16_snorm";
 +              case VK_FORMAT_R8G8B8A8_UNORM:                                                          return "rgba8";
 +              case VK_FORMAT_R16G16B16A16_UNORM:                                                      return "rgba16";
 +
 +              case VK_FORMAT_G8B8G8R8_422_UNORM:                                                      return "rgba8";
 +              case VK_FORMAT_B8G8R8G8_422_UNORM:                                                      return "rgba8";
 +              case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:                                       return "rgba8";
 +              case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:                                        return "rgba8";
 +              case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:                                       return "rgba8";
 +              case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:                                        return "rgba8";
 +              case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:                                       return "rgba8";
 +              case VK_FORMAT_R10X6_UNORM_PACK16:                                                      return "r16";
 +              case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:                                        return "rg16";
 +              case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:                      return "rgba16";
 +              case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:          return "rgba16";
 +              case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:          return "rgba16";
 +              case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:      return "rgba16";
 +              case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:       return "rgba16";
 +              case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:      return "rgba16";
 +              case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:       return "rgba16";
 +              case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:      return "rgba16";
 +              case VK_FORMAT_R12X4_UNORM_PACK16:                                                      return "r16";
 +              case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:                                        return "rg16";
 +              case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:                      return "rgba16";
 +              case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:          return "rgba16";
 +              case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:          return "rgba16";
 +              case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:      return "rgba16";
 +              case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:       return "rgba16";
 +              case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:      return "rgba16";
 +              case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:       return "rgba16";
 +              case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:      return "rgba16";
 +              case VK_FORMAT_G16B16G16R16_422_UNORM:                                          return "rgba16";
 +              case VK_FORMAT_B16G16R16G16_422_UNORM:                                          return "rgba16";
 +              case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:                            return "rgba16";
 +              case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:                                     return "rgba16";
 +              case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:                            return "rgba16";
 +              case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:                                     return "rgba16";
 +              case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:                            return "rgba16";
 +
 +              default:
 +                      DE_FATAL("Unexpected texture format");
 +                      return "error";
 +      }
 +}
 +
 +void initPrograms (SourceCollections& sourceCollections, TestParameters params)
 +{
 +      // Create compute program
 +      const char* const                               versionDecl                     = glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440);
 +      const PlanarFormatDescription   formatDescription       = getPlanarFormatDescription(params.format);
 +      const std::string                               imageTypeStr            = getShaderImageType(formatDescription);
 +      const std::string                               formatDataStr           = getShaderImageDataType(formatDescription);
 +      const tcu::UVec3                                shaderGridSize          ( params.size.x(), params.size.y(), params.size.z() );
 +
 +      std::vector<std::string>                formatValueStrings;
 +      switch (formatDescription.channels[0].type)
 +      {
 +      case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
 +      case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
 +              formatValueStrings = {
 +                      "int(gl_GlobalInvocationID.x) % 127",
 +                      "int(gl_GlobalInvocationID.y) % 127",
 +                      "int(gl_GlobalInvocationID.z) % 127",
 +                      "1"
 +              };
 +              break;
 +      case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
 +      case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
 +      case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
 +              formatValueStrings = {
 +                      "float(int(gl_GlobalInvocationID.x) % 127) / 127.0" ,
 +                      "float(int(gl_GlobalInvocationID.y) % 127) / 127.0",
 +                      "float(int(gl_GlobalInvocationID.z) % 127) / 127.0",
 +                      "1.0"
 +              };
 +              break;
 +      default:        DE_ASSERT(false);       break;
 +      }
 +
 +      for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
 +      {
 +              VkFormat                                                planeCompatibleFormat           = getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
 +              vk::PlanarFormatDescription             compatibleFormatDescription     = (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
 +              VkExtent3D                                              compatibleShaderGridSize        { shaderGridSize.x() / formatDescription.blockWidth, shaderGridSize.y() / formatDescription.blockHeight, shaderGridSize.z() / 1u };
 +
 +              std::vector<std::pair<deUint32, deUint32>> channelsOnPlane;
 +              for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
 +              {
 +                      if (!formatDescription.hasChannelNdx(channelNdx))
 +                              continue;
 +                      if (formatDescription.channels[channelNdx].planeNdx != planeNdx)
 +                              continue;
 +                      channelsOnPlane.push_back({ channelNdx,formatDescription.channels[channelNdx].offsetBits });
 +              }
 +              // reorder channels for multi-planar images
 +              if (formatDescription.numPlanes > 1)
 +                      std::sort(begin(channelsOnPlane), end(channelsOnPlane), [](const std::pair<deUint32, deUint32>& lhs, const std::pair<deUint32, deUint32>& rhs) { return lhs.second < rhs.second; });
 +              std::string                     formatValueStr          = getFormatValueString(channelsOnPlane, formatValueStrings);
 +              VkExtent3D                      shaderExtent            = getPlaneExtent(compatibleFormatDescription, compatibleShaderGridSize, planeNdx, 0);
 +              const std::string       formatQualifierStr      = getShaderImageFormatQualifier(formatDescription.planes[planeNdx].planeCompatibleFormat);
 +              const tcu::UVec3        workGroupSize           = computeWorkGroupSize(shaderExtent);
 +
 +              std::ostringstream src;
 +              src << versionDecl << "\n"
 +                      << "layout (local_size_x = " << workGroupSize.x() << ", local_size_y = " << workGroupSize.y() << ", local_size_z = " << workGroupSize.z() << ") in; \n"
 +                      << "layout (binding = 0, " << formatQualifierStr << ") writeonly uniform highp " << imageTypeStr << " u_image;\n"
 +                      << "void main (void)\n"
 +                      << "{\n"
 +                      << "    if( gl_GlobalInvocationID.x < " << shaderExtent.width << " ) \n"
 +                      << "    if( gl_GlobalInvocationID.y < " << shaderExtent.height << " ) \n"
 +                      << "    if( gl_GlobalInvocationID.z < " << shaderExtent.depth << " ) \n"
 +                      << "    {\n"
 +                      << "            imageStore(u_image, ivec2( gl_GlobalInvocationID.x, gl_GlobalInvocationID.y ) ,"
 +                      << formatDataStr << formatValueStr << ");\n"
 +                      << "    }\n"
 +                      << "}\n";
 +              std::ostringstream shaderName;
 +              shaderName << "comp" << planeNdx;
 +              sourceCollections.glslSources.add(shaderName.str()) << glu::ComputeSource(src.str());
 +      }
 +}
 +
 +tcu::TestCaseGroup* populateStorageImageWriteFormatGroup (tcu::TestContext& testCtx, de::MovePtr<tcu::TestCaseGroup> testGroup)
 +{
 +      const std::vector<tcu::UVec3>   availableSizes{ tcu::UVec3(512u, 512u, 1u), tcu::UVec3(1024u, 128u, 1u), tcu::UVec3(66u, 32u, 1u) };
 +
 +      for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
 +      {
 +              const VkFormat                                  format                          = (VkFormat)formatNdx;
 +              tcu::UVec3                                              imageSizeAlignment      = getImageSizeAlignment(format);
 +              std::string                                             formatName                      = de::toLower(de::toString(format).substr(10));
 +              de::MovePtr<tcu::TestCaseGroup> formatGroup                     ( new tcu::TestCaseGroup(testCtx, formatName.c_str(), "") );
 +
 +              for (size_t sizeNdx = 0; sizeNdx < availableSizes.size(); sizeNdx++)
 +              {
 +                      const tcu::UVec3 imageSize = availableSizes[sizeNdx];
 +
 +                      // skip test for images with odd sizes for some YCbCr formats
 +                      if ((imageSize.x() % imageSizeAlignment.x()) != 0)
 +                              continue;
 +                      if ((imageSize.y() % imageSizeAlignment.y()) != 0)
 +                              continue;
 +
 +                      std::ostringstream stream;
 +                      stream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
 +                      de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, stream.str().c_str(), ""));
 +
 +                      addFunctionCaseWithPrograms(sizeGroup.get(), "joint", "", checkSupport, initPrograms, testStorageImageWrite, TestParameters(format, imageSize, 0u));
 +                      addFunctionCaseWithPrograms(sizeGroup.get(), "disjoint", "", checkSupport, initPrograms, testStorageImageWrite, TestParameters(format, imageSize, (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT));
 +
 +                      formatGroup->addChild(sizeGroup.release());
 +              }
 +              testGroup->addChild(formatGroup.release());
 +      }
 +      return testGroup.release();
 +}
 +
 +} // namespace
 +
 +tcu::TestCaseGroup* createStorageImageWriteTests (tcu::TestContext& testCtx)
 +{
 +      de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "storage_image_write", "Writing to YCbCr storage images"));
 +      return populateStorageImageWriteFormatGroup(testCtx, testGroup);
 +}
 +
 +} // ycbcr
 +} // vkt