Merge vk-gl-cts/vulkan-cts-1.2.8 into vk-gl-cts/dev/VK_KHR_dynamic_rendering
authorMatthew Netsch <quic_mnetsch@quicinc.com>
Fri, 5 Nov 2021 23:03:54 +0000 (19:03 -0400)
committerMatthew Netsch <quic_mnetsch@quicinc.com>
Fri, 5 Nov 2021 23:03:54 +0000 (19:03 -0400)
Change-Id: Ica7c90f88986488142bc7c2b3e9b892b8104b7a1

28 files changed:
1  2 
AndroidGen.mk
android/cts/master/src/vk-master-2019-03-01.txt
android/cts/master/src/vk-master-2020-03-01.txt
android/cts/master/src/vk-waivers.txt
android/cts/master/vk-master-2021-03-01.txt
android/cts/master/vk-master.txt
external/vulkancts/framework/vulkan/vkBasicTypes.inl
external/vulkancts/framework/vulkan/vkDeviceExtensions.inl
external/vulkancts/framework/vulkan/vkDeviceFeatureTest.inl
external/vulkancts/framework/vulkan/vkDeviceFeatures.inl
external/vulkancts/framework/vulkan/vkDeviceFeaturesForContextDecl.inl
external/vulkancts/framework/vulkan/vkDeviceFeaturesForContextDefs.inl
external/vulkancts/framework/vulkan/vkDeviceFeaturesForDefaultDeviceDefs.inl
external/vulkancts/framework/vulkan/vkExtensionFunctions.inl
external/vulkancts/framework/vulkan/vkGetStructureTypeImpl.inl
external/vulkancts/framework/vulkan/vkObjUtil.cpp
external/vulkancts/framework/vulkan/vkObjUtil.hpp
external/vulkancts/framework/vulkan/vkStrUtil.inl
external/vulkancts/framework/vulkan/vkStrUtilImpl.inl
external/vulkancts/framework/vulkan/vkStructTypes.inl
external/vulkancts/framework/vulkan/vkVulkan_c.inl
external/vulkancts/modules/vulkan/mesh_shader/vktMeshShaderMiscTests.cpp
external/vulkancts/modules/vulkan/multiview/vktMultiViewRenderTests.cpp
external/vulkancts/modules/vulkan/renderpass/vktRenderPassSubpassDependencyTests.cpp
external/vulkancts/modules/vulkan/vktTestPackage.cpp
external/vulkancts/mustpass/master/vk-default.txt
external/vulkancts/scripts/src/extensions_data.txt
external/vulkancts/scripts/src/vulkan_core.h

diff --cc AndroidGen.mk
Simple merge
Simple merge
Simple merge
@@@ -82,6 -82,7 +82,8 @@@ static const char* s_allowedDeviceKhrEx
        "VK_KHR_shader_integer_dot_product",
        "VK_KHR_format_feature_flags2",
        "VK_KHR_maintenance4",
 +      "VK_KHR_dynamic_rendering",
+       "VK_EXT_border_color_swizzle",
+       "VK_NV_mesh_shader",
  };
  
@@@ -301,29 -301,29 +303,30 @@@ template<> void initFeatureFromBlob<VkP
  template<> void initFeatureFromBlob<VkPhysicalDevicePortabilitySubsetFeaturesKHR>(VkPhysicalDevicePortabilitySubsetFeaturesKHR&, const AllFeaturesBlobs&) {}
  
  
--template<> FeatureDesc makeFeatureDesc<VkPhysicalDevice16BitStorageFeatures>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, VK_KHR_16BIT_STORAGE_EXTENSION_NAME, VK_KHR_16BIT_STORAGE_SPEC_VERSION, 100}; }
--template<> FeatureDesc makeFeatureDesc<VkPhysicalDevice4444FormatsFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT, VK_EXT_4444_FORMATS_EXTENSION_NAME, VK_EXT_4444_FORMATS_SPEC_VERSION, 99}; }
--template<> FeatureDesc makeFeatureDesc<VkPhysicalDevice8BitStorageFeatures>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, VK_KHR_8BIT_STORAGE_EXTENSION_NAME, VK_KHR_8BIT_STORAGE_SPEC_VERSION, 98}; }
--template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceAccelerationStructureFeaturesKHR>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR, VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION, 97}; }
--template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceASTCDecodeFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT, VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME, VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION, 96}; }
--template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT, VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION, 95}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceBorderColorSwizzleFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT, VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME, VK_EXT_BORDER_COLOR_SWIZZLE_SPEC_VERSION, 94}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceBufferDeviceAddressFeatures>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, VK_KHR_BUFFER_DEVICE_ADDRESS_SPEC_VERSION, 93}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceBufferDeviceAddressFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION, 92}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceCoherentMemoryFeaturesAMD>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD, DECL_AMD_COHERENT_MEMORY_EXTENSION_NAME, 0, 91}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceColorWriteEnableFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT, VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME, VK_EXT_COLOR_WRITE_ENABLE_SPEC_VERSION, 90}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceComputeShaderDerivativesFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV, VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME, VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION, 89}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceConditionalRenderingFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT, VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME, VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION, 88}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceCooperativeMatrixFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV, VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME, VK_NV_COOPERATIVE_MATRIX_SPEC_VERSION, 87}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceCornerSampledImageFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV, VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME, VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION, 86}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceCoverageReductionModeFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV, VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME, VK_NV_COVERAGE_REDUCTION_MODE_SPEC_VERSION, 85}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceCustomBorderColorFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, VK_EXT_CUSTOM_BORDER_COLOR_SPEC_VERSION, 84}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV, VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_EXTENSION_NAME, VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_SPEC_VERSION, 83}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDepthClipEnableFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION, 82}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDescriptorIndexingFeatures>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES, VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION, 81}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV, VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME, VK_NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION, 80}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDeviceMemoryReportFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT, VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME, VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION, 79}; }
 -template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDiagnosticsConfigFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV, DECL_NV_DIAGNOSTICS_CONFIG_EXTENSION_NAME, 0, 78}; }
++template<> FeatureDesc makeFeatureDesc<VkPhysicalDevice16BitStorageFeatures>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, VK_KHR_16BIT_STORAGE_EXTENSION_NAME, VK_KHR_16BIT_STORAGE_SPEC_VERSION, 101}; }
++template<> FeatureDesc makeFeatureDesc<VkPhysicalDevice4444FormatsFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT, VK_EXT_4444_FORMATS_EXTENSION_NAME, VK_EXT_4444_FORMATS_SPEC_VERSION, 100}; }
++template<> FeatureDesc makeFeatureDesc<VkPhysicalDevice8BitStorageFeatures>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, VK_KHR_8BIT_STORAGE_EXTENSION_NAME, VK_KHR_8BIT_STORAGE_SPEC_VERSION, 99}; }
++template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceAccelerationStructureFeaturesKHR>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR, VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION, 98}; }
++template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceASTCDecodeFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT, VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME, VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION, 97}; }
++template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT, VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION, 96}; }
++template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceBorderColorSwizzleFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT, VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME, VK_EXT_BORDER_COLOR_SWIZZLE_SPEC_VERSION, 95}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceBufferDeviceAddressFeatures>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, VK_KHR_BUFFER_DEVICE_ADDRESS_SPEC_VERSION, 94}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceBufferDeviceAddressFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION, 93}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceCoherentMemoryFeaturesAMD>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD, DECL_AMD_COHERENT_MEMORY_EXTENSION_NAME, 0, 92}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceColorWriteEnableFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT, VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME, VK_EXT_COLOR_WRITE_ENABLE_SPEC_VERSION, 91}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceComputeShaderDerivativesFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV, VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME, VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION, 90}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceConditionalRenderingFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT, VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME, VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION, 89}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceCooperativeMatrixFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV, VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME, VK_NV_COOPERATIVE_MATRIX_SPEC_VERSION, 88}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceCornerSampledImageFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV, VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME, VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION, 87}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceCoverageReductionModeFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV, VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME, VK_NV_COVERAGE_REDUCTION_MODE_SPEC_VERSION, 86}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceCustomBorderColorFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, VK_EXT_CUSTOM_BORDER_COLOR_SPEC_VERSION, 85}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV, VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_EXTENSION_NAME, VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_SPEC_VERSION, 84}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDepthClipEnableFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION, 83}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDescriptorIndexingFeatures>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES, VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION, 82}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV, VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME, VK_NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION, 81}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDeviceMemoryReportFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT, VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME, VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION, 80}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDiagnosticsConfigFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV, DECL_NV_DIAGNOSTICS_CONFIG_EXTENSION_NAME, 0, 79}; }
 +template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceDynamicRenderingFeaturesKHR>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR, VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, VK_KHR_DYNAMIC_RENDERING_SPEC_VERSION, 78}; }
  template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceExclusiveScissorFeaturesNV>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV, VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME, VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION, 77}; }
  template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceExtendedDynamicStateFeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, VK_EXT_EXTENDED_DYNAMIC_STATE_SPEC_VERSION, 76}; }
  template<> FeatureDesc makeFeatureDesc<VkPhysicalDeviceExtendedDynamicState2FeaturesEXT>(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT, VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME, VK_EXT_EXTENDED_DYNAMIC_STATE_2_SPEC_VERSION, 75}; }
@@@ -77,9 -76,24 +77,25 @@@ Move<VkPipeline> makeGraphicsPipeline (
                                                                           const VkPipelineMultisampleStateCreateInfo*          multisampleStateCreateInfo = DE_NULL,
                                                                           const VkPipelineDepthStencilStateCreateInfo*         depthStencilStateCreateInfo = DE_NULL,
                                                                           const VkPipelineColorBlendStateCreateInfo*           colorBlendStateCreateInfo = DE_NULL,
 -                                                                         const VkPipelineDynamicStateCreateInfo*                      dynamicStateCreateInfo = DE_NULL);
 +                                                                         const VkPipelineDynamicStateCreateInfo*                      dynamicStateCreateInfo = DE_NULL,
 +                                                                         const void*                                                                          pNext = DE_NULL);
  
+ Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&                                                 vk,
+                                                                          const VkDevice                                                                       device,
+                                                                          const VkPipelineLayout                                                       pipelineLayout,
+                                                                          const VkShaderModule                                                         taskShaderModule,
+                                                                          const VkShaderModule                                                         meshShaderModule,
+                                                                          const VkShaderModule                                                         fragmentShaderModule,
+                                                                          const VkRenderPass                                                           renderPass,
+                                                                          const std::vector<VkViewport>&                                       viewports,
+                                                                          const std::vector<VkRect2D>&                                         scissors,
+                                                                          const deUint32                                                                       subpass = 0u,
+                                                                          const VkPipelineRasterizationStateCreateInfo*        rasterizationStateCreateInfo = nullptr,
+                                                                          const VkPipelineMultisampleStateCreateInfo*          multisampleStateCreateInfo = nullptr,
+                                                                          const VkPipelineDepthStencilStateCreateInfo*         depthStencilStateCreateInfo = nullptr,
+                                                                          const VkPipelineColorBlendStateCreateInfo*           colorBlendStateCreateInfo = nullptr,
+                                                                          const VkPipelineDynamicStateCreateInfo*                      dynamicStateCreateInfo = nullptr);
  Move<VkRenderPass> makeRenderPass (const DeviceInterface&                             vk,
                                                                   const VkDevice                                               device,
                                                                   const VkFormat                                               colorFormat                                     = VK_FORMAT_UNDEFINED,
index 0000000,05efdf1..28b7d8e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,2788 +1,2785 @@@
 -      constexpr auto Message          = tcu::TestLog::Message;
 -      constexpr auto EndMessage       = tcu::TestLog::EndMessage;
 -
+ /*------------------------------------------------------------------------
+  * Vulkan Conformance Tests
+  * ------------------------
+  *
+  * Copyright (c) 2021 The Khronos Group Inc.
+  * Copyright (c) 2021 Valve Corporation.
+  *
+  * 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 Mesh Shader Misc Tests
+  *//*--------------------------------------------------------------------*/
+ #include "vktMeshShaderMiscTests.hpp"
+ #include "vktTestCase.hpp"
+ #include "vkBuilderUtil.hpp"
+ #include "vkImageWithMemory.hpp"
+ #include "vkBufferWithMemory.hpp"
+ #include "vkObjUtil.hpp"
+ #include "vkTypeUtil.hpp"
+ #include "vkCmdUtil.hpp"
+ #include "vkImageUtil.hpp"
+ #include "vkBarrierUtil.hpp"
+ #include "tcuImageCompare.hpp"
+ #include "tcuTexture.hpp"
+ #include "tcuTextureUtil.hpp"
+ #include "tcuMaybe.hpp"
+ #include "tcuStringTemplate.hpp"
+ #include "tcuTestLog.hpp"
+ #include <memory>
+ #include <utility>
+ #include <vector>
+ #include <string>
+ #include <sstream>
+ #include <map>
+ namespace vkt
+ {
+ namespace MeshShader
+ {
+ namespace
+ {
+ using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
+ using namespace vk;
+ // Output images will use this format.
+ VkFormat getOutputFormat ()
+ {
+       return VK_FORMAT_R8G8B8A8_UNORM;
+ }
+ // Threshold that's reasonable for the previous format.
+ float getCompareThreshold ()
+ {
+       return 0.005f; // 1/256 < 0.005 < 2/256
+ }
+ // Check mesh shader support.
+ void genericCheckSupport (Context& context, bool requireTaskShader, bool requireVertexStores)
+ {
+       context.requireDeviceFunctionality("VK_NV_mesh_shader");
+       const auto& meshFeatures = context.getMeshShaderFeatures();
+       if (!meshFeatures.meshShader)
+               TCU_THROW(NotSupportedError, "Mesh shader not supported");
+       if (requireTaskShader && !meshFeatures.taskShader)
+               TCU_THROW(NotSupportedError, "Task shader not supported");
+       if (requireVertexStores)
+       {
+               const auto& features = context.getDeviceFeatures();
+               if (!features.vertexPipelineStoresAndAtomics)
+                       TCU_THROW(NotSupportedError, "Vertex pieline stores and atomics not supported");
+       }
+ }
+ struct MiscTestParams
+ {
+       tcu::Maybe<uint32_t>    taskCount;
+       uint32_t                                meshCount;
+       uint32_t                                width;
+       uint32_t                                height;
+       // Makes the class polymorphic and allows the right destructor to be used for subclasses.
+       virtual ~MiscTestParams () {}
+       bool needsTaskShader () const
+       {
+               return static_cast<bool>(taskCount);
+       }
+       uint32_t drawCount () const
+       {
+               if (needsTaskShader())
+                       return taskCount.get();
+               return meshCount;
+       }
+ };
+ using ParamsPtr = std::unique_ptr<MiscTestParams>;
+ class MeshShaderMiscCase : public vkt::TestCase
+ {
+ public:
+                                       MeshShaderMiscCase              (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params);
+       virtual                 ~MeshShaderMiscCase             (void) {}
+       void                    checkSupport                    (Context& context) const override;
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+ protected:
+       std::unique_ptr<MiscTestParams> m_params;
+ };
+ MeshShaderMiscCase::MeshShaderMiscCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+       : vkt::TestCase (testCtx, name, description)
+       , m_params              (params.release())
+ {}
+ void MeshShaderMiscCase::checkSupport (Context& context) const
+ {
+       genericCheckSupport(context, m_params->needsTaskShader(), /*requireVertexStores*/false);
+ }
+ // Adds the generic fragment shader. To be called by subclasses.
+ void MeshShaderMiscCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       std::string frag =
+               "#version 450\n"
+               "#extension GL_NV_mesh_shader : enable\n"
+               "\n"
+               "layout (location=0) in perprimitiveNV vec4 primitiveColor;\n"
+               "layout (location=0) out vec4 outColor;\n"
+               "\n"
+               "void main ()\n"
+               "{\n"
+               "    outColor = primitiveColor;\n"
+               "}\n"
+               ;
+       programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
+ }
+ class MeshShaderMiscInstance : public vkt::TestInstance
+ {
+ public:
+                                       MeshShaderMiscInstance  (Context& context, const MiscTestParams* params)
+                                               : vkt::TestInstance     (context)
+                                               , m_params                      (params)
+                                               , m_referenceLevel      ()
+                                       {
+                                       }
+       void                    generateSolidRefLevel   (const tcu::Vec4& color, std::unique_ptr<tcu::TextureLevel>& output);
+       virtual void    generateReferenceLevel  () = 0;
+       virtual bool    verifyResult                    (const tcu::ConstPixelBufferAccess& resultAccess, const tcu::TextureLevel& referenceLevel) const;
+       virtual bool    verifyResult                    (const tcu::ConstPixelBufferAccess& resultAccess) const;
+       tcu::TestStatus iterate                                 () override;
+ protected:
+       const MiscTestParams*                           m_params;
+       std::unique_ptr<tcu::TextureLevel>      m_referenceLevel;
+ };
+ void MeshShaderMiscInstance::generateSolidRefLevel (const tcu::Vec4& color, std::unique_ptr<tcu::TextureLevel>& output)
+ {
+       const auto format               = getOutputFormat();
+       const auto tcuFormat    = mapVkFormat(format);
+       const auto iWidth               = static_cast<int>(m_params->width);
+       const auto iHeight              = static_cast<int>(m_params->height);
+       output.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
+       const auto access               = output->getAccess();
+       // Fill with solid color.
+       tcu::clear(access, color);
+ }
+ bool MeshShaderMiscInstance::verifyResult (const tcu::ConstPixelBufferAccess& resultAccess) const
+ {
+       return verifyResult(resultAccess, *m_referenceLevel);
+ }
+ bool MeshShaderMiscInstance::verifyResult (const tcu::ConstPixelBufferAccess& resultAccess, const tcu::TextureLevel& referenceLevel) const
+ {
+       const auto referenceAccess = referenceLevel.getAccess();
+       const auto refWidth             = referenceAccess.getWidth();
+       const auto refHeight    = referenceAccess.getHeight();
+       const auto refDepth             = referenceAccess.getDepth();
+       const auto resWidth             = resultAccess.getWidth();
+       const auto resHeight    = resultAccess.getHeight();
+       const auto resDepth             = resultAccess.getDepth();
+       DE_ASSERT(resWidth == refWidth || resHeight == refHeight || resDepth == refDepth);
+       // For release builds.
+       DE_UNREF(refWidth);
+       DE_UNREF(refHeight);
+       DE_UNREF(refDepth);
+       DE_UNREF(resWidth);
+       DE_UNREF(resHeight);
+       DE_UNREF(resDepth);
+       const auto outputFormat         = getOutputFormat();
+       const auto expectedFormat       = mapVkFormat(outputFormat);
+       const auto resFormat            = resultAccess.getFormat();
+       const auto refFormat            = referenceAccess.getFormat();
+       DE_ASSERT(resFormat == expectedFormat && refFormat == expectedFormat);
+       // For release builds
+       DE_UNREF(expectedFormat);
+       DE_UNREF(resFormat);
+       DE_UNREF(refFormat);
+       auto&                   log                             = m_context.getTestContext().getLog();
+       const auto              threshold               = getCompareThreshold();
+       const tcu::Vec4 thresholdVec    (threshold, threshold, threshold, threshold);
+       return tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, thresholdVec, tcu::COMPARE_LOG_ON_ERROR);
+ }
+ tcu::TestStatus MeshShaderMiscInstance::iterate ()
+ {
+       const auto&             vkd                     = m_context.getDeviceInterface();
+       const auto              device          = m_context.getDevice();
+       auto&                   alloc           = m_context.getDefaultAllocator();
+       const auto              queueIndex      = m_context.getUniversalQueueFamilyIndex();
+       const auto              queue           = m_context.getUniversalQueue();
+       const auto              imageFormat     = getOutputFormat();
+       const auto              tcuFormat       = mapVkFormat(imageFormat);
+       const auto              imageExtent     = makeExtent3D(m_params->width, m_params->height, 1u);
+       const auto              imageUsage      = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+       const VkImageCreateInfo colorBufferInfo =
+       {
+               VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,    //      VkStructureType                 sType;
+               nullptr,                                                                //      const void*                             pNext;
+               0u,                                                                             //      VkImageCreateFlags              flags;
+               VK_IMAGE_TYPE_2D,                                               //      VkImageType                             imageType;
+               imageFormat,                                                    //      VkFormat                                format;
+               imageExtent,                                                    //      VkExtent3D                              extent;
+               1u,                                                                             //      uint32_t                                mipLevels;
+               1u,                                                                             //      uint32_t                                arrayLayers;
+               VK_SAMPLE_COUNT_1_BIT,                                  //      VkSampleCountFlagBits   samples;
+               VK_IMAGE_TILING_OPTIMAL,                                //      VkImageTiling                   tiling;
+               imageUsage,                                                             //      VkImageUsageFlags               usage;
+               VK_SHARING_MODE_EXCLUSIVE,                              //      VkSharingMode                   sharingMode;
+               0u,                                                                             //      uint32_t                                queueFamilyIndexCount;
+               nullptr,                                                                //      const uint32_t*                 pQueueFamilyIndices;
+               VK_IMAGE_LAYOUT_UNDEFINED,                              //      VkImageLayout                   initialLayout;
+       };
+       // Create color image and view.
+       ImageWithMemory colorImage      (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
+       const auto              colorSRR        = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+       const auto              colorSRL        = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
+       const auto              colorView       = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
+       // Create a memory buffer for verification.
+       const auto                      verificationBufferSize  = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
+       const auto                      verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+       const auto                      verificationBufferInfo  = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
+       BufferWithMemory        verificationBuffer              (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
+       auto&                           verificationBufferAlloc = verificationBuffer.getAllocation();
+       void*                           verificationBufferData  = verificationBufferAlloc.getHostPtr();
+       // Pipeline layout.
+       const auto pipelineLayout = makePipelineLayout(vkd, device);
+       // Shader modules.
+       const auto&     binaries        = m_context.getBinaryCollection();
+       const auto      hasTask         = binaries.contains("task");
+       const auto      meshShader      = createShaderModule(vkd, device, binaries.get("mesh"));
+       const auto      fragShader      = createShaderModule(vkd, device, binaries.get("frag"));
+       Move<VkShaderModule> taskShader;
+       if (hasTask)
+               taskShader = createShaderModule(vkd, device, binaries.get("task"));
+       // Render pass.
+       const auto renderPass = makeRenderPass(vkd, device, imageFormat);
+       // Framebuffer.
+       const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
+       // Viewport and scissor.
+       const std::vector<VkViewport>   viewports       (1u, makeViewport(imageExtent));
+       const std::vector<VkRect2D>             scissors        (1u, makeRect2D(imageExtent));
+       const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
+               taskShader.get(), meshShader.get(), fragShader.get(),
+               renderPass.get(), viewports, scissors);
+       // Command pool and buffer.
+       const auto cmdPool              = makeCommandPool(vkd, device, queueIndex);
+       const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+       const auto cmdBuffer    = cmdBufferPtr.get();
+       beginCommandBuffer(vkd, cmdBuffer);
+       // Run pipeline.
+       const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
+       beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
+       vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
+       vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params->drawCount(), 0u);
+       endRenderPass(vkd, cmdBuffer);
+       // Copy color buffer to verification buffer.
+       const auto colorAccess          = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
+       const auto transferRead         = VK_ACCESS_TRANSFER_READ_BIT;
+       const auto transferWrite        = VK_ACCESS_TRANSFER_WRITE_BIT;
+       const auto hostRead                     = VK_ACCESS_HOST_READ_BIT;
+       const auto preCopyBarrier       = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
+       const auto postCopyBarrier      = makeMemoryBarrier(transferWrite, hostRead);
+       const auto copyRegion           = makeBufferImageCopy(imageExtent, colorSRL);
+       vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
+       vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, &copyRegion);
+       vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
+       endCommandBuffer(vkd, cmdBuffer);
+       submitCommandsAndWait(vkd, device, queue, cmdBuffer);
+       // Generate reference image and compare results.
+       const tcu::IVec3                                        iExtent                         (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
+       const tcu::ConstPixelBufferAccess       verificationAccess      (tcuFormat, iExtent, verificationBufferData);
+       generateReferenceLevel();
+       invalidateAlloc(vkd, device, verificationBufferAlloc);
+       if (!verifyResult(verificationAccess))
+               TCU_FAIL("Result does not match reference; check log for details");
+       return tcu::TestStatus::pass("Pass");
+ }
+ // Verify passing more complex data between the task and mesh shaders.
+ class ComplexTaskDataCase : public MeshShaderMiscCase
+ {
+ public:
+                                       ComplexTaskDataCase             (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+ };
+ class ComplexTaskDataInstance : public MeshShaderMiscInstance
+ {
+ public:
+       ComplexTaskDataInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+ };
+ void ComplexTaskDataInstance::generateReferenceLevel ()
+ {
+       const auto format               = getOutputFormat();
+       const auto tcuFormat    = mapVkFormat(format);
+       const auto iWidth               = static_cast<int>(m_params->width);
+       const auto iHeight              = static_cast<int>(m_params->height);
+       const auto halfWidth    = iWidth / 2;
+       const auto halfHeight   = iHeight / 2;
+       m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
+       const auto access               = m_referenceLevel->getAccess();
+       // Each image quadrant gets a different color.
+       for (int y = 0; y < iHeight; ++y)
+       for (int x = 0; x < iWidth; ++x)
+       {
+               const float     red                     = ((y < halfHeight) ? 0.0f : 1.0f);
+               const float     green           = ((x < halfWidth)  ? 0.0f : 1.0f);
+               const auto      refColor        = tcu::Vec4(red, green, 1.0f, 1.0f);
+               access.setPixel(refColor, x, y);
+       }
+ }
+ void ComplexTaskDataCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       // Add the generic fragment shader.
+       MeshShaderMiscCase::initPrograms(programCollection);
+       const std::string taskDataDeclTemplate =
+               "struct RowId {\n"
+               "    uint id;\n"
+               "};\n"
+               "\n"
+               "struct WorkGroupData {\n"
+               "    float WorkGroupIdPlusOnex1000Iota[10];\n"
+               "    RowId rowId;\n"
+               "    uvec3 WorkGroupIdPlusOnex2000Iota;\n"
+               "    vec2  WorkGroupIdPlusOnex3000Iota;\n"
+               "};\n"
+               "\n"
+               "struct ExternalData {\n"
+               "    float OneMillion;\n"
+               "    uint  TwoMillion;\n"
+               "    WorkGroupData workGroupData;\n"
+               "};\n"
+               "\n"
+               "${INOUT} taskNV TaskData {\n"
+               "    uint yes;\n"
+               "    ExternalData externalData;\n"
+               "} td;\n"
+               ;
+       const tcu::StringTemplate taskDataDecl(taskDataDeclTemplate);
+       {
+               std::map<std::string, std::string> taskMap;
+               taskMap["INOUT"] = "out";
+               std::ostringstream task;
+               task
+                       << "#version 450\n"
+                       << "#extension GL_NV_mesh_shader : enable\n"
+                       << "\n"
+                       << "layout (local_size_x=1) in;\n"
+                       << "\n"
+                       << taskDataDecl.specialize(taskMap)
+                       << "\n"
+                       << "void main ()\n"
+                       << "{\n"
+                       << "    gl_TaskCountNV = 2u;\n"
+                       << "    td.yes = 1u;\n"
+                       << "    td.externalData.OneMillion = 1000000.0;\n"
+                       << "    td.externalData.TwoMillion = 2000000u;\n"
+                       << "    for (uint i = 0; i < 10; i++) {\n"
+                       << "        td.externalData.workGroupData.WorkGroupIdPlusOnex1000Iota[i] = float((gl_WorkGroupID.x + 1u) * 1000 + i);\n"
+                       << "    }\n"
+                       << "    {\n"
+                       << "        uint baseVal = (gl_WorkGroupID.x + 1u) * 2000;\n"
+                       << "        td.externalData.workGroupData.WorkGroupIdPlusOnex2000Iota = uvec3(baseVal, baseVal + 1, baseVal + 2);\n"
+                       << "    }\n"
+                       << "    {\n"
+                       << "        uint baseVal = (gl_WorkGroupID.x + 1u) * 3000;\n"
+                       << "        td.externalData.workGroupData.WorkGroupIdPlusOnex3000Iota = vec2(baseVal, baseVal + 1);\n"
+                       << "    }\n"
+                       << "    td.externalData.workGroupData.rowId.id = gl_WorkGroupID.x;\n"
+                       << "}\n"
+                       ;
+               programCollection.glslSources.add("task") << glu::TaskSource(task.str());
+       }
+       {
+               std::map<std::string, std::string> meshMap;
+               meshMap["INOUT"] = "in";
+               std::ostringstream mesh;
+               mesh
+                       << "#version 450\n"
+                       << "#extension GL_NV_mesh_shader : enable\n"
+                       << "\n"
+                       << "layout(local_size_x=2) in;\n"
+                       << "layout(triangles) out;\n"
+                       << "layout(max_vertices=4, max_primitives=2) out;\n"
+                       << "\n"
+                       << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
+                       << "\n"
+                       << taskDataDecl.specialize(meshMap)
+                       << "\n"
+                       << "void main ()\n"
+                       << "{\n"
+                       << "    bool dataOK = true;\n"
+                       << "    dataOK = (dataOK && (td.yes == 1u));\n"
+                       << "    dataOK = (dataOK && (td.externalData.OneMillion == 1000000.0 && td.externalData.TwoMillion == 2000000u));\n"
+                       << "    uint rowId = td.externalData.workGroupData.rowId.id;\n"
+                       << "    dataOK = (dataOK && (rowId == 0u || rowId == 1u));\n"
+                       << "\n"
+                       << "    {\n"
+                       << "        uint baseVal = (rowId + 1u) * 1000u;\n"
+                       << "        for (uint i = 0; i < 10; i++) {\n"
+                       << "            if (td.externalData.workGroupData.WorkGroupIdPlusOnex1000Iota[i] != float(baseVal + i)) {\n"
+                       << "                dataOK = false;\n"
+                       << "                break;\n"
+                       << "            }\n"
+                       << "        }\n"
+                       << "    }\n"
+                       << "\n"
+                       << "    {\n"
+                       << "        uint baseVal = (rowId + 1u) * 2000;\n"
+                       << "        uvec3 expected = uvec3(baseVal, baseVal + 1, baseVal + 2);\n"
+                       << "        if (td.externalData.workGroupData.WorkGroupIdPlusOnex2000Iota != expected) {\n"
+                       << "            dataOK = false;\n"
+                       << "        }\n"
+                       << "    }\n"
+                       << "\n"
+                       << "    {\n"
+                       << "        uint baseVal = (rowId + 1u) * 3000;\n"
+                       << "        vec2 expected = vec2(baseVal, baseVal + 1);\n"
+                       << "        if (td.externalData.workGroupData.WorkGroupIdPlusOnex3000Iota != expected) {\n"
+                       << "            dataOK = false;\n"
+                       << "        }\n"
+                       << "    }\n"
+                       << "\n"
+                       << "    uint columnId = gl_WorkGroupID.x;\n"
+                       << "\n"
+                       << "    if (dataOK) {\n"
+                       << "        gl_PrimitiveCountNV = 2u;\n"
+                       << "    }\n"
+                       << "    else {\n"
+                       << "        gl_PrimitiveCountNV = 0u;\n"
+                       << "        return;\n"
+                       << "    }\n"
+                       << "\n"
+                       << "    const vec4 outColor = vec4(rowId, columnId, 1.0f, 1.0f);\n"
+                       << "    triangleColor[0] = outColor;\n"
+                       << "    triangleColor[1] = outColor;\n"
+                       << "\n"
+                       << "    // Each local invocation will generate two points and one triangle from the quad.\n"
+                       << "    // The first local invocation will generate the top quad vertices.\n"
+                       << "    // The second invocation will generate the two bottom vertices.\n"
+                       << "    vec4 left  = vec4(0.0, 0.0, 0.0, 1.0);\n"
+                       << "    vec4 right = vec4(1.0, 0.0, 0.0, 1.0);\n"
+                       << "\n"
+                       << "    float localInvocationOffsetY = float(gl_LocalInvocationID.x);\n"
+                       << "    left.y  += localInvocationOffsetY;\n"
+                       << "    right.y += localInvocationOffsetY;\n"
+                       << "\n"
+                       << "    // The code above creates a quad from (0, 0) to (1, 1) but we need to offset it\n"
+                       << "    // in X and/or Y depending on the row and column, to place it in other quadrants.\n"
+                       << "    float quadrantOffsetX = float(int(columnId) - 1);\n"
+                       << "    float quadrantOffsetY = float(int(rowId) - 1);\n"
+                       << "\n"
+                       << "    left.x  += quadrantOffsetX;\n"
+                       << "    right.x += quadrantOffsetX;\n"
+                       << "\n"
+                       << "    left.y  += quadrantOffsetY;\n"
+                       << "    right.y += quadrantOffsetY;\n"
+                       << "\n"
+                       << "    uint baseVertexId = 2*gl_LocalInvocationID.x;\n"
+                       << "    gl_MeshVerticesNV[baseVertexId + 0].gl_Position = left;\n"
+                       << "    gl_MeshVerticesNV[baseVertexId + 1].gl_Position = right;\n"
+                       << "\n"
+                       << "    uint baseIndexId = 3*gl_LocalInvocationID.x;\n"
+                       << "    // 0,1,2 or 1,2,3 (note: triangles alternate front face this way)\n"
+                       << "    gl_PrimitiveIndicesNV[baseIndexId + 0] = 0 + gl_LocalInvocationID.x;\n"
+                       << "    gl_PrimitiveIndicesNV[baseIndexId + 1] = 1 + gl_LocalInvocationID.x;\n"
+                       << "    gl_PrimitiveIndicesNV[baseIndexId + 2] = 2 + gl_LocalInvocationID.x;\n"
+                       << "}\n"
+                       ;
+               programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+       }
+ }
+ TestInstance* ComplexTaskDataCase::createInstance (Context& context) const
+ {
+       return new ComplexTaskDataInstance(context, m_params.get());
+ }
+ // Verify drawing a single point.
+ class SinglePointCase : public MeshShaderMiscCase
+ {
+ public:
+                                       SinglePointCase         (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+ };
+ class SinglePointInstance : public MeshShaderMiscInstance
+ {
+ public:
+       SinglePointInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+ };
+ TestInstance* SinglePointCase::createInstance (Context& context) const
+ {
+       return new SinglePointInstance (context, m_params.get());
+ }
+ void SinglePointCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       DE_ASSERT(!m_params->needsTaskShader());
+       MeshShaderMiscCase::initPrograms(programCollection);
+       std::ostringstream mesh;
+       mesh
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout(local_size_x=1) in;\n"
+               << "layout(points) out;\n"
+               << "layout(max_vertices=256, max_primitives=256) out;\n"
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 pointColor[];\n"
+               << "\n"
+               << "void main ()\n"
+               << "{\n"
+               << "    gl_PrimitiveCountNV = 1u;\n"
+               << "    pointColor[0] = vec4(0.0f, 1.0f, 1.0f, 1.0f);\n"
+               << "    gl_MeshVerticesNV[0].gl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);\n"
+               << "    gl_MeshVerticesNV[0].gl_PointSize = 1.0f;\n"
+               << "    gl_PrimitiveIndicesNV[0] = 0;\n"
+               << "}\n"
+               ;
+       programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+ }
+ void SinglePointInstance::generateReferenceLevel ()
+ {
+       generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
+       const auto halfWidth    = static_cast<int>(m_params->width / 2u);
+       const auto halfHeight   = static_cast<int>(m_params->height / 2u);
+       const auto access               = m_referenceLevel->getAccess();
+       access.setPixel(tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), halfWidth, halfHeight);
+ }
+ // Verify drawing a single line.
+ class SingleLineCase : public MeshShaderMiscCase
+ {
+ public:
+                                       SingleLineCase          (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+ };
+ class SingleLineInstance : public MeshShaderMiscInstance
+ {
+ public:
+       SingleLineInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+ };
+ TestInstance* SingleLineCase::createInstance (Context& context) const
+ {
+       return new SingleLineInstance (context, m_params.get());
+ }
+ void SingleLineCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       DE_ASSERT(!m_params->needsTaskShader());
+       MeshShaderMiscCase::initPrograms(programCollection);
+       std::ostringstream mesh;
+       mesh
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout(local_size_x=1) in;\n"
+               << "layout(lines) out;\n"
+               << "layout(max_vertices=256, max_primitives=256) out;\n"
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 lineColor[];\n"
+               << "\n"
+               << "void main ()\n"
+               << "{\n"
+               << "    gl_PrimitiveCountNV = 1u;\n"
+               << "    lineColor[0] = vec4(0.0f, 1.0f, 1.0f, 1.0f);\n"
+               << "    gl_MeshVerticesNV[0].gl_Position = vec4(-1.0f, 0.0f, 0.0f, 1.0f);\n"
+               << "    gl_MeshVerticesNV[1].gl_Position = vec4( 1.0f, 0.0f, 0.0f, 1.0f);\n"
+               << "    gl_PrimitiveIndicesNV[0] = 0;\n"
+               << "    gl_PrimitiveIndicesNV[1] = 1;\n"
+               << "}\n"
+               ;
+       programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+ }
+ void SingleLineInstance::generateReferenceLevel ()
+ {
+       generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
+       const auto iWidth               = static_cast<int>(m_params->width);
+       const auto halfHeight   = static_cast<int>(m_params->height / 2u);
+       const auto access               = m_referenceLevel->getAccess();
+       // Center row.
+       for (int x = 0; x < iWidth; ++x)
+               access.setPixel(tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), x, halfHeight);
+ }
+ // Verify drawing a single triangle.
+ class SingleTriangleCase : public MeshShaderMiscCase
+ {
+ public:
+                                       SingleTriangleCase              (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+ };
+ class SingleTriangleInstance : public MeshShaderMiscInstance
+ {
+ public:
+       SingleTriangleInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+ };
+ TestInstance* SingleTriangleCase::createInstance (Context& context) const
+ {
+       return new SingleTriangleInstance (context, m_params.get());
+ }
+ void SingleTriangleCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       DE_ASSERT(!m_params->needsTaskShader());
+       MeshShaderMiscCase::initPrograms(programCollection);
+       const float halfPixelX = 2.0f / static_cast<float>(m_params->width);
+       const float halfPixelY = 2.0f / static_cast<float>(m_params->height);
+       std::ostringstream mesh;
+       mesh
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout(local_size_x=1) in;\n"
+               << "layout(triangles) out;\n"
+               << "layout(max_vertices=256, max_primitives=256) out;\n"
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
+               << "\n"
+               << "void main ()\n"
+               << "{\n"
+               << "    gl_PrimitiveCountNV = 1u;\n"
+               << "    triangleColor[0] = vec4(0.0f, 1.0f, 1.0f, 1.0f);\n"
+               << "    gl_MeshVerticesNV[0].gl_Position = vec4(" <<  halfPixelY << ", " << -halfPixelX << ", 0.0f, 1.0f);\n"
+               << "    gl_MeshVerticesNV[1].gl_Position = vec4(" <<  halfPixelY << ", " <<  halfPixelX << ", 0.0f, 1.0f);\n"
+               << "    gl_MeshVerticesNV[2].gl_Position = vec4(" << -halfPixelY << ", 0.0f, 0.0f, 1.0f);\n"
+               << "    gl_PrimitiveIndicesNV[0] = 0;\n"
+               << "    gl_PrimitiveIndicesNV[1] = 1;\n"
+               << "    gl_PrimitiveIndicesNV[2] = 2;\n"
+               << "}\n"
+               ;
+       programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+ }
+ void SingleTriangleInstance::generateReferenceLevel ()
+ {
+       generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
+       const auto halfWidth    = static_cast<int>(m_params->width / 2u);
+       const auto halfHeight   = static_cast<int>(m_params->height / 2u);
+       const auto access               = m_referenceLevel->getAccess();
+       // Single pixel in the center.
+       access.setPixel(tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), halfWidth, halfHeight);
+ }
+ // Verify drawing the maximum number of points.
+ class MaxPointsCase : public MeshShaderMiscCase
+ {
+ public:
+                                       MaxPointsCase           (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+ };
+ class MaxPointsInstance : public MeshShaderMiscInstance
+ {
+ public:
+       MaxPointsInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+ };
+ TestInstance* MaxPointsCase::createInstance (Context& context) const
+ {
+       return new MaxPointsInstance (context, m_params.get());
+ }
+ void MaxPointsCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       DE_ASSERT(!m_params->needsTaskShader());
+       MeshShaderMiscCase::initPrograms(programCollection);
+       // Fill a 16x16 image with 256 points. Each of the 32 local invocations will handle a segment of 8 pixels. Two segments per row.
+       DE_ASSERT(m_params->width == 16u && m_params->height == 16u);
+       std::ostringstream mesh;
+       mesh
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout(local_size_x=32) in;\n"
+               << "layout(points) out;\n"
+               << "layout(max_vertices=256, max_primitives=256) out;\n"
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 pointColor[];\n"
+               << "\n"
+               << "void main ()\n"
+               << "{\n"
+               << "    gl_PrimitiveCountNV = 256u;\n"
+               << "    uint firstPixel = 8u * gl_LocalInvocationID.x;\n"
+               << "    uint row = firstPixel / 16u;\n"
+               << "    uint col = firstPixel % 16u;\n"
+               << "    float pixSize = 2.0f / 16.0f;\n"
+               << "    float yCoord = pixSize * (float(row) + 0.5f) - 1.0f;\n"
+               << "    float baseXCoord = pixSize * (float(col) + 0.5f) - 1.0f;\n"
+               << "    for (uint i = 0; i < 8u; i++) {\n"
+               << "        float xCoord = baseXCoord + pixSize * float(i);\n"
+               << "        uint pixId = firstPixel + i;\n"
+               << "        gl_MeshVerticesNV[pixId].gl_Position = vec4(xCoord, yCoord, 0.0f, 1.0f);\n"
+               << "        gl_MeshVerticesNV[pixId].gl_PointSize = 1.0f;\n"
+               << "        gl_PrimitiveIndicesNV[pixId] = pixId;\n"
+               << "        pointColor[pixId] = vec4(((xCoord + 1.0f) / 2.0f), ((yCoord + 1.0f) / 2.0f), 0.0f, 1.0f);\n"
+               << "    }\n"
+               << "}\n"
+               ;
+       programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+ }
+ void MaxPointsInstance::generateReferenceLevel ()
+ {
+       const auto format               = getOutputFormat();
+       const auto tcuFormat    = mapVkFormat(format);
+       const auto iWidth               = static_cast<int>(m_params->width);
+       const auto iHeight              = static_cast<int>(m_params->height);
+       const auto fWidth               = static_cast<float>(m_params->width);
+       const auto fHeight              = static_cast<float>(m_params->height);
+       m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
+       const auto access               = m_referenceLevel->getAccess();
+       // Fill with gradient like the shader does.
+       for (int y = 0; y < iHeight; ++y)
+       for (int x = 0; x < iWidth; ++x)
+       {
+               const tcu::Vec4 color (
+                       ((static_cast<float>(x) + 0.5f) / fWidth),
+                       ((static_cast<float>(y) + 0.5f) / fHeight),
+                       0.0f, 1.0f);
+               access.setPixel(color, x, y);
+       }
+ }
+ // Verify drawing the maximum number of lines.
+ class MaxLinesCase : public MeshShaderMiscCase
+ {
+ public:
+                                       MaxLinesCase            (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+ };
+ class MaxLinesInstance : public MeshShaderMiscInstance
+ {
+ public:
+       MaxLinesInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+ };
+ TestInstance* MaxLinesCase::createInstance (Context& context) const
+ {
+       return new MaxLinesInstance (context, m_params.get());
+ }
+ void MaxLinesCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       DE_ASSERT(!m_params->needsTaskShader());
+       MeshShaderMiscCase::initPrograms(programCollection);
+       // Fill a 1x1020 image with 255 lines, each line being 4 pixels tall. Each invocation will generate ~8 lines.
+       DE_ASSERT(m_params->width == 1u && m_params->height == 1020u);
+       std::ostringstream mesh;
+       mesh
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout(local_size_x=32) in;\n"
+               << "layout(lines) out;\n"
+               << "layout(max_vertices=256, max_primitives=255) out;\n"
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 lineColor[];\n"
+               << "\n"
+               << "void main ()\n"
+               << "{\n"
+               << "    gl_PrimitiveCountNV = 255u;\n"
+               << "    uint firstLine = 8u * gl_LocalInvocationID.x;\n"
+               << "    for (uint i = 0u; i < 8u; i++) {\n"
+               << "        uint lineId = firstLine + i;\n"
+               << "        uint topPixel = 4u * lineId;\n"
+               << "        uint bottomPixel = 3u + topPixel;\n"
+               << "        if (bottomPixel < 1020u) {\n"
+               << "            float bottomCoord = ((float(bottomPixel) + 1.0f) / 1020.0) * 2.0 - 1.0;\n"
+               << "            gl_MeshVerticesNV[lineId + 1u].gl_Position = vec4(0.0, bottomCoord, 0.0f, 1.0f);\n"
+               << "            gl_PrimitiveIndicesNV[lineId * 2u] = lineId;\n"
+               << "            gl_PrimitiveIndicesNV[lineId * 2u + 1u] = lineId + 1u;\n"
+               << "            lineColor[lineId] = vec4(0.0f, 1.0f, float(lineId) / 255.0f, 1.0f);\n"
+               << "        } else {\n"
+               << "            // The last iteration of the last invocation emits the first point\n"
+               << "            gl_MeshVerticesNV[0].gl_Position = vec4(0.0, -1.0, 0.0f, 1.0f);\n"
+               << "        }\n"
+               << "    }\n"
+               << "}\n"
+               ;
+       programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+ }
+ void MaxLinesInstance::generateReferenceLevel ()
+ {
+       const auto format               = getOutputFormat();
+       const auto tcuFormat    = mapVkFormat(format);
+       const auto iWidth               = static_cast<int>(m_params->width);
+       const auto iHeight              = static_cast<int>(m_params->height);
+       m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
+       const auto access               = m_referenceLevel->getAccess();
+       // Fill lines, 4 pixels per line.
+       const uint32_t kNumLines = 255u;
+       const uint32_t kLineHeight = 4u;
+       for (uint32_t i = 0u; i < kNumLines; ++i)
+       {
+               const tcu::Vec4 color (0.0f, 1.0f, static_cast<float>(i) / static_cast<float>(kNumLines), 1.0f);
+               for (uint32_t j = 0u; j < kLineHeight; ++j)
+                       access.setPixel(color, 0, i*kLineHeight + j);
+       }
+ }
+ // Verify drawing the maximum number of triangles.
+ class MaxTrianglesCase : public MeshShaderMiscCase
+ {
+ public:
+                                       MaxTrianglesCase                (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+ };
+ class MaxTrianglesInstance : public MeshShaderMiscInstance
+ {
+ public:
+       MaxTrianglesInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+ };
+ TestInstance* MaxTrianglesCase::createInstance (Context& context) const
+ {
+       return new MaxTrianglesInstance (context, m_params.get());
+ }
+ void MaxTrianglesCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       DE_ASSERT(!m_params->needsTaskShader());
+       MeshShaderMiscCase::initPrograms(programCollection);
+       // Fill a sufficiently large image with solid color. Generate a quarter of a circle with the center in the top left corner,
+       // using a triangle fan that advances from top to bottom. Each invocation will generate ~8 triangles.
+       std::ostringstream mesh;
+       mesh
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout(local_size_x=32) in;\n"
+               << "layout(triangles) out;\n"
+               << "layout(max_vertices=256, max_primitives=254) out;\n"
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
+               << "\n"
+               << "const float PI_2 = 1.57079632679489661923;\n"
+               << "const float RADIUS = 4.5;\n"
+               << "\n"
+               << "void main ()\n"
+               << "{\n"
+               << "    gl_PrimitiveCountNV = 254u;\n"
+               << "    uint firstTriangle = 8u * gl_LocalInvocationID.x;\n"
+               << "    for (uint i = 0u; i < 8u; i++) {\n"
+               << "        uint triangleId = firstTriangle + i;\n"
+               << "        if (triangleId < 254u) {\n"
+               << "            uint vertexId = triangleId + 2u;\n"
+               << "            float angleProportion = float(vertexId - 1u) / 254.0f;\n"
+               << "            float angle = PI_2 * angleProportion;\n"
+               << "            float xCoord = cos(angle) * RADIUS - 1.0;\n"
+               << "            float yCoord = sin(angle) * RADIUS - 1.0;\n"
+               << "            gl_MeshVerticesNV[vertexId].gl_Position = vec4(xCoord, yCoord, 0.0, 1.0);\n"
+               << "            gl_PrimitiveIndicesNV[triangleId * 3u + 0u] = 0u;\n"
+               << "            gl_PrimitiveIndicesNV[triangleId * 3u + 1u] = triangleId + 1u;\n"
+               << "            gl_PrimitiveIndicesNV[triangleId * 3u + 2u] = triangleId + 2u;\n"
+               << "            triangleColor[triangleId] = vec4(0.0f, 0.0f, 1.0f, 1.0f);\n"
+               << "        } else {\n"
+               << "            // The last iterations of the last invocation emit the first two vertices\n"
+               << "            uint vertexId = triangleId - 254u;\n"
+               << "            if (vertexId == 0u) {\n"
+               << "                gl_MeshVerticesNV[0u].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
+               << "            } else {\n"
+               << "                gl_MeshVerticesNV[1u].gl_Position = vec4(RADIUS, -1.0, 0.0, 1.0);\n"
+               << "            }\n"
+               << "        }\n"
+               << "    }\n"
+               << "}\n"
+               ;
+       programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+ }
+ void MaxTrianglesInstance::generateReferenceLevel ()
+ {
+       generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
+ }
+ // Large work groups with many threads.
+ class LargeWorkGroupCase : public MeshShaderMiscCase
+ {
+ public:
+                                       LargeWorkGroupCase      (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+       static constexpr uint32_t kLocalInvocations = 32u;
+ };
+ class LargeWorkGroupInstance : public MeshShaderMiscInstance
+ {
+ public:
+       LargeWorkGroupInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+ };
+ TestInstance* LargeWorkGroupCase::createInstance (Context& context) const
+ {
+       return new LargeWorkGroupInstance(context, m_params.get());
+ }
+ void LargeWorkGroupInstance::generateReferenceLevel ()
+ {
+       generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
+ }
+ void LargeWorkGroupCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       const auto useTaskShader        = m_params->needsTaskShader();
+       const auto taskMultiplier       = (useTaskShader ? m_params->taskCount.get() : 1u);
+       // Add the frag shader.
+       MeshShaderMiscCase::initPrograms(programCollection);
+       std::ostringstream taskData;
+       taskData
+               << "taskNV TaskData {\n"
+               << "    uint parentTask[" << kLocalInvocations << "];\n"
+               << "} td;\n"
+               ;
+       const auto taskDataStr = taskData.str();
+       if (useTaskShader)
+       {
+               std::ostringstream task;
+               task
+                       << "#version 450\n"
+                       << "#extension GL_NV_mesh_shader : enable\n"
+                       << "\n"
+                       << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
+                       << "\n"
+                       << "out " << taskDataStr
+                       << "\n"
+                       << "void main () {\n"
+                       << "    gl_TaskCountNV = " << m_params->meshCount << ";\n"
+                       << "    td.parentTask[gl_LocalInvocationID.x] = gl_WorkGroupID.x;\n"
+                       << "}\n"
+                       ;
+               programCollection.glslSources.add("task") << glu::TaskSource(task.str());
+       }
+       // Needed for the code below to work.
+       DE_ASSERT(m_params->width * m_params->height == taskMultiplier * m_params->meshCount * kLocalInvocations);
+       DE_UNREF(taskMultiplier); // For release builds.
+       // Emit one point per framebuffer pixel. The number of jobs (kLocalInvocations in each mesh shader work group, multiplied by the
+       // number of mesh work groups emitted by each task work group) must be the same as the total framebuffer size. Calculate a job
+       // ID corresponding to the current mesh shader invocation, and assign a pixel position to it. Draw a point at that position.
+       std::ostringstream mesh;
+       mesh
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
+               << "layout (points) out;\n"
+               << "layout (max_vertices=" << kLocalInvocations << ", max_primitives=" << kLocalInvocations << ") out;\n"
+               << "\n"
+               << (useTaskShader ? "in " + taskDataStr : "")
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 pointColor[];\n"
+               << "\n"
+               << "void main () {\n"
+               ;
+       if (useTaskShader)
+       {
+               mesh
+                       << "    uint parentTask = td.parentTask[0];\n"
+                       << "    if (td.parentTask[gl_LocalInvocationID.x] != parentTask) {\n"
+                       << "        return;\n"
+                       << "    }\n"
+                       ;
+       }
+       else
+       {
+               mesh << "    uint parentTask = 0;\n";
+       }
+       mesh
+               << "    gl_PrimitiveCountNV = " << kLocalInvocations << ";\n"
+               << "    uint jobId = ((parentTask * " << m_params->meshCount << ") + gl_WorkGroupID.x) * " << kLocalInvocations << " + gl_LocalInvocationID.x;\n"
+               << "    uint row = jobId / " << m_params->width << ";\n"
+               << "    uint col = jobId % " << m_params->width << ";\n"
+               << "    float yCoord = (float(row + 0.5) / " << m_params->height << ".0) * 2.0 - 1.0;\n"
+               << "    float xCoord = (float(col + 0.5) / " << m_params->width << ".0) * 2.0 - 1.0;\n"
+               << "    gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_Position = vec4(xCoord, yCoord, 0.0, 1.0);\n"
+               << "    gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_PointSize = 1.0;\n"
+               << "    gl_PrimitiveIndicesNV[gl_LocalInvocationID.x] = gl_LocalInvocationID.x;\n"
+               << "    pointColor[gl_LocalInvocationID.x] = vec4(0.0, 0.0, 1.0, 1.0);\n"
+               << "}\n"
+               ;
+       programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+ }
+ // Tests that generate no primitives of a given type.
+ enum class PrimitiveType { POINTS=0, LINES, TRIANGLES };
+ std::string primitiveTypeName (PrimitiveType primitiveType)
+ {
+       std::string primitiveName;
+       switch (primitiveType)
+       {
+       case PrimitiveType::POINTS:             primitiveName = "points";               break;
+       case PrimitiveType::LINES:              primitiveName = "lines";                break;
+       case PrimitiveType::TRIANGLES:  primitiveName = "triangles";    break;
+       default: DE_ASSERT(false); break;
+       }
+       return primitiveName;
+ }
+ struct NoPrimitivesParams : public MiscTestParams
+ {
+       PrimitiveType primitiveType;
+ };
+ class NoPrimitivesCase : public MeshShaderMiscCase
+ {
+ public:
+                                       NoPrimitivesCase        (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+ };
+ class NoPrimitivesInstance : public MeshShaderMiscInstance
+ {
+ public:
+       NoPrimitivesInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+ };
+ void NoPrimitivesInstance::generateReferenceLevel ()
+ {
+       // No primitives: clear color.
+       generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), m_referenceLevel);
+ }
+ TestInstance* NoPrimitivesCase::createInstance (Context& context) const
+ {
+       return new NoPrimitivesInstance(context, m_params.get());
+ }
+ void NoPrimitivesCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       const auto params = dynamic_cast<NoPrimitivesParams*>(m_params.get());
+       DE_ASSERT(params);
+       DE_ASSERT(!params->needsTaskShader());
+       const auto primitiveName = primitiveTypeName(params->primitiveType);
+       std::ostringstream mesh;
+       mesh
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout (local_size_x=32) in;\n"
+               << "layout (" << primitiveName << ") out;\n"
+               << "layout (max_vertices=256, max_primitives=256) out;\n"
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 primitiveColor[];\n"
+               << "\n"
+               << "void main () {\n"
+               << "    gl_PrimitiveCountNV = 0u;\n"
+               << "}\n"
+               ;
+       MeshShaderMiscCase::initPrograms(programCollection);
+       programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+ }
+ class NoPrimitivesExtraWritesCase : public NoPrimitivesCase
+ {
+ public:
+                                       NoPrimitivesExtraWritesCase     (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : NoPrimitivesCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       static constexpr uint32_t kLocalInvocations = 32u;
+ };
+ void NoPrimitivesExtraWritesCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       const auto params = dynamic_cast<NoPrimitivesParams*>(m_params.get());
+       DE_ASSERT(params);
+       DE_ASSERT(m_params->needsTaskShader());
+       std::ostringstream taskData;
+       taskData
+               << "taskNV TaskData {\n"
+               << "    uint localInvocations[" << kLocalInvocations << "];\n"
+               << "} td;\n"
+               ;
+       const auto taskDataStr = taskData.str();
+       std::ostringstream task;
+       task
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
+               << "\n"
+               << "out " << taskDataStr
+               << "\n"
+               << "void main () {\n"
+               << "    gl_TaskCountNV = " << params->meshCount << ";\n"
+               << "    td.localInvocations[gl_LocalInvocationID.x] = gl_LocalInvocationID.x;\n"
+               << "}\n"
+               ;
+       programCollection.glslSources.add("task") << glu::TaskSource(task.str());
+       const auto primitiveName = primitiveTypeName(params->primitiveType);
+       // Otherwise the shader would be illegal.
+       DE_ASSERT(kLocalInvocations > 2u);
+       uint32_t maxPrimitives = 0u;
+       switch (params->primitiveType)
+       {
+       case PrimitiveType::POINTS:             maxPrimitives = kLocalInvocations - 0u; break;
+       case PrimitiveType::LINES:              maxPrimitives = kLocalInvocations - 1u; break;
+       case PrimitiveType::TRIANGLES:  maxPrimitives = kLocalInvocations - 2u; break;
+       default: DE_ASSERT(false); break;
+       }
+       const std::string pointSizeDecl = ((params->primitiveType == PrimitiveType::POINTS)
+                                                                       ? "        gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_PointSize = 1.0;\n"
+                                                                       : "");
+       std::ostringstream mesh;
+       mesh
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
+               << "layout (" << primitiveName << ") out;\n"
+               << "layout (max_vertices=" << kLocalInvocations << ", max_primitives=" << maxPrimitives << ") out;\n"
+               << "\n"
+               << "in " << taskDataStr
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 primitiveColor[];\n"
+               << "\n"
+               << "shared uint sumOfIds;\n"
+               << "\n"
+               << "const float PI_2 = 1.57079632679489661923;\n"
+               << "const float RADIUS = 1.0f;\n"
+               << "\n"
+               << "void main ()\n"
+               << "{\n"
+               << "    sumOfIds = 0u;\n"
+               << "    barrier();\n"
+               << "    atomicAdd(sumOfIds, td.localInvocations[gl_LocalInvocationID.x]);\n"
+               << "    barrier();\n"
+               << "    // This should dynamically give 0\n"
+               << "    gl_PrimitiveCountNV = sumOfIds - (" << kLocalInvocations * (kLocalInvocations - 1u) / 2u << ");\n"
+               << "\n"
+               << "    // Emit points and primitives to the arrays in any case\n"
+               << "    if (gl_LocalInvocationID.x > 0u) {\n"
+               << "        float proportion = (float(gl_LocalInvocationID.x - 1u) + 0.5f) / float(" << kLocalInvocations << " - 1u);\n"
+               << "        float angle = PI_2 * proportion;\n"
+               << "        float xCoord = cos(angle) * RADIUS - 1.0;\n"
+               << "        float yCoord = sin(angle) * RADIUS - 1.0;\n"
+               << "        gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_Position = vec4(xCoord, yCoord, 0.0, 1.0);\n"
+               << pointSizeDecl
+               << "    } else {\n"
+               << "        gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
+               << pointSizeDecl
+               << "    }\n"
+               << "    uint primitiveId = max(gl_LocalInvocationID.x, " << (maxPrimitives - 1u) << ");\n"
+               << "    primitiveColor[primitiveId] = vec4(0.0, 0.0, 1.0, 1.0);\n"
+               ;
+       if (params->primitiveType == PrimitiveType::POINTS)
+       {
+               mesh
+                       << "    gl_PrimitiveIndicesNV[primitiveId] = primitiveId;\n"
+                       ;
+       }
+       else if (params->primitiveType == PrimitiveType::LINES)
+       {
+               mesh
+                       << "    gl_PrimitiveIndicesNV[primitiveId * 2u + 0u] = primitiveId + 0u;\n"
+                       << "    gl_PrimitiveIndicesNV[primitiveId * 2u + 1u] = primitiveId + 1u;\n"
+                       ;
+       }
+       else if (params->primitiveType == PrimitiveType::TRIANGLES)
+       {
+               mesh
+                       << "    gl_PrimitiveIndicesNV[primitiveId * 3u + 0u] = 0u;\n"
+                       << "    gl_PrimitiveIndicesNV[primitiveId * 3u + 1u] = primitiveId + 1u;\n"
+                       << "    gl_PrimitiveIndicesNV[primitiveId * 3u + 2u] = primitiveId + 3u;\n"
+                       ;
+       }
+       else
+               DE_ASSERT(false);
+       mesh
+               << "}\n"
+               ;
+       programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+       MeshShaderMiscCase::initPrograms(programCollection);
+ }
+ // Case testing barrier().
+ class SimpleBarrierCase : public MeshShaderMiscCase
+ {
+ public:
+                                       SimpleBarrierCase       (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+       static constexpr uint32_t kLocalInvocations = 32u;
+ };
+ class SimpleBarrierInstance : public MeshShaderMiscInstance
+ {
+ public:
+       SimpleBarrierInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+ };
+ TestInstance* SimpleBarrierCase::createInstance (Context& context) const
+ {
+       return new SimpleBarrierInstance(context, m_params.get());
+ }
+ void SimpleBarrierInstance::generateReferenceLevel ()
+ {
+       generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
+ }
+ void SimpleBarrierCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       // Generate frag shader.
+       MeshShaderMiscCase::initPrograms(programCollection);
+       DE_ASSERT(m_params->meshCount == 1u);
+       DE_ASSERT(m_params->width == 1u && m_params->height == 1u);
+       std::ostringstream meshPrimData;
+       meshPrimData
+                       << "gl_PrimitiveCountNV = 1u;\n"
+                       << "gl_MeshVerticesNV[0].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
+                       << "gl_MeshVerticesNV[0].gl_PointSize = 1.0;\n"
+                       << "primitiveColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
+                       << "gl_PrimitiveIndicesNV[0] = 0;\n"
+                       ;
+       const std::string meshPrimStr   = meshPrimData.str();
+       const std::string taskOK                = "gl_TaskCountNV = 1u;\n";
+       const std::string taskFAIL              = "gl_TaskCountNV = 0u;\n";
+       const std::string meshOK                = meshPrimStr;
+       const std::string meshFAIL              = "gl_PrimitiveCountNV = 0u;\n";
+       const std::string okStatement   = (m_params->needsTaskShader() ? taskOK : meshOK);
+       const std::string failStatement = (m_params->needsTaskShader() ? taskFAIL : meshFAIL);
+       const std::string       sharedDecl = "shared uint counter;\n\n";
+       std::ostringstream      verification;
+       verification
+               << "counter = 0;\n"
+               << "barrier();\n"
+               << "atomicAdd(counter, 1u);\n"
+               << "barrier();\n"
+               << "if (gl_LocalInvocationID.x == 0u) {\n"
+               << "    if (counter == " << kLocalInvocations << ") {\n"
+               << "\n"
+               << okStatement
+               << "\n"
+               << "    } else {\n"
+               << "\n"
+               << failStatement
+               << "\n"
+               << "    }\n"
+               << "}\n"
+               ;
+       // The mesh shader is very similar in both cases, so we use a template.
+       std::ostringstream meshTemplateStr;
+       meshTemplateStr
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout (local_size_x=${LOCAL_SIZE}) in;\n"
+               << "layout (points) out;\n"
+               << "layout (max_vertices=1, max_primitives=1) out;\n"
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 primitiveColor[];\n"
+               << "\n"
+               << "${GLOBALS:opt}"
+               << "void main ()\n"
+               << "{\n"
+               << "${BODY}"
+               << "}\n"
+               ;
+       const tcu::StringTemplate meshTemplate = meshTemplateStr.str();
+       if (m_params->needsTaskShader())
+       {
+               std::ostringstream task;
+               task
+                       << "#version 450\n"
+                       << "#extension GL_NV_mesh_shader : enable\n"
+                       << "\n"
+                       << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
+                       << "\n"
+                       << sharedDecl
+                       << "void main ()\n"
+                       << "{\n"
+                       << verification.str()
+                       << "}\n"
+                       ;
+               std::map<std::string, std::string> replacements;
+               replacements["LOCAL_SIZE"]      = "1";
+               replacements["BODY"]            = meshPrimStr;
+               const auto meshStr = meshTemplate.specialize(replacements);
+               programCollection.glslSources.add("task") << glu::TaskSource(task.str());
+               programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr);
+       }
+       else
+       {
+               std::map<std::string, std::string> replacements;
+               replacements["LOCAL_SIZE"]      = std::to_string(kLocalInvocations);
+               replacements["BODY"]            = verification.str();
+               replacements["GLOBALS"]         = sharedDecl;
+               const auto meshStr = meshTemplate.specialize(replacements);
+               programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr);
+       }
+ }
+ // Case testing memoryBarrierShared() and groupMemoryBarrier().
+ enum class MemoryBarrierType { SHARED = 0, GROUP };
+ struct MemoryBarrierParams : public MiscTestParams
+ {
+       MemoryBarrierType memBarrierType;
+       std::string glslFunc () const
+       {
+               std::string funcName;
+               switch (memBarrierType)
+               {
+               case MemoryBarrierType::SHARED:         funcName = "memoryBarrierShared";       break;
+               case MemoryBarrierType::GROUP:          funcName = "groupMemoryBarrier";        break;
+               default: DE_ASSERT(false); break;
+               }
+               return funcName;
+       }
+ };
+ class MemoryBarrierCase : public MeshShaderMiscCase
+ {
+ public:
+                                       MemoryBarrierCase       (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+       static constexpr uint32_t kLocalInvocations = 2u;
+ };
+ class MemoryBarrierInstance : public MeshShaderMiscInstance
+ {
+ public:
+       MemoryBarrierInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void    generateReferenceLevel  () override;
+       bool    verifyResult                    (const tcu::ConstPixelBufferAccess& resultAccess) const override;
+ protected:
+       // Allow two possible outcomes.
+       std::unique_ptr<tcu::TextureLevel>      m_referenceLevel2;
+ };
+ TestInstance* MemoryBarrierCase::createInstance (Context& context) const
+ {
+       return new MemoryBarrierInstance(context, m_params.get());
+ }
+ void MemoryBarrierInstance::generateReferenceLevel ()
+ {
+       generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
+       generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), m_referenceLevel2);
+ }
+ bool MemoryBarrierInstance::verifyResult (const tcu::ConstPixelBufferAccess& resultAccess) const
+ {
+       // Any of the two results is considered valid.
 -              log << Message << "Comparing result with reference " << i << "..." << EndMessage;
+       // Clarify what we are checking in the logs; otherwise, they could be confusing.
+       auto& log = m_context.getTestContext().getLog();
+       const std::vector<tcu::TextureLevel*> levels = { m_referenceLevel.get(), m_referenceLevel2.get() };
+       bool good = false;
+       for (size_t i = 0; i < levels.size(); ++i)
+       {
 -                      log << Message << "Match! The test has passed" << EndMessage;
++              log << tcu::TestLog::Message << "Comparing result with reference " << i << "..." << tcu::TestLog::EndMessage;
+               const auto success = MeshShaderMiscInstance::verifyResult(resultAccess, *levels[i]);
+               if (success)
+               {
++                      log << tcu::TestLog::Message << "Match! The test has passed" << tcu::TestLog::EndMessage;
+                       good = true;
+                       break;
+               }
+       }
+       return good;
+ }
+ void MemoryBarrierCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       const auto params = dynamic_cast<MemoryBarrierParams*>(m_params.get());
+       DE_ASSERT(params);
+       // Generate frag shader.
+       MeshShaderMiscCase::initPrograms(programCollection);
+       DE_ASSERT(params->meshCount == 1u);
+       DE_ASSERT(params->width == 1u && params->height == 1u);
+       const bool taskShader = params->needsTaskShader();
+       const std::string       taskDataDecl    = "taskNV TaskData { float blue; } td;\n\n";
+       const std::string       inTaskData              = "in " + taskDataDecl;
+       const std::string       outTaskData             = "out " + taskDataDecl;
+       const auto                      barrierFunc             = params->glslFunc();
+       std::ostringstream meshPrimData;
+       meshPrimData
+                       << "gl_PrimitiveCountNV = 1u;\n"
+                       << "gl_MeshVerticesNV[0].gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
+                       << "gl_MeshVerticesNV[0].gl_PointSize = 1.0;\n"
+                       << "primitiveColor[0] = vec4(0.0, 0.0, " << (taskShader ? "td.blue" : "float(iterations % 2u)") << ", 1.0);\n"
+                       << "gl_PrimitiveIndicesNV[0] = 0;\n"
+                       ;
+       const std::string meshPrimStr   = meshPrimData.str();
+       const std::string taskAction    = "gl_TaskCountNV = 1u;\ntd.blue = float(iterations % 2u);\n";
+       const std::string meshAction    = meshPrimStr;
+       const std::string action                = (taskShader ? taskAction : meshAction);
+       const std::string       sharedDecl = "shared uint flags[2];\n\n";
+       std::ostringstream      verification;
+       verification
+               << "flags[gl_LocalInvocationID.x] = 0u;\n"
+               << "barrier();\n"
+               << "flags[gl_LocalInvocationID.x] = 1u;\n"
+               <<  barrierFunc << "();\n"
+               << "uint otherInvocation = 1u - gl_LocalInvocationID.x;\n"
+               << "uint iterations = 0u;\n"
+               << "while (flags[otherInvocation] != 1u) {\n"
+               << "    iterations++;\n"
+               << "}\n"
+               << "if (gl_LocalInvocationID.x == 0u) {\n"
+               << "\n"
+               << action
+               << "\n"
+               << "}\n"
+               ;
+       // The mesh shader is very similar in both cases, so we use a template.
+       std::ostringstream meshTemplateStr;
+       meshTemplateStr
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout (local_size_x=${LOCAL_SIZE}) in;\n"
+               << "layout (points) out;\n"
+               << "layout (max_vertices=1, max_primitives=1) out;\n"
+               << "\n"
+               << "layout (location=0) out perprimitiveNV vec4 primitiveColor[];\n"
+               << "\n"
+               << "${GLOBALS}"
+               << "void main ()\n"
+               << "{\n"
+               << "${BODY}"
+               << "}\n"
+               ;
+       const tcu::StringTemplate meshTemplate = meshTemplateStr.str();
+       if (params->needsTaskShader())
+       {
+               std::ostringstream task;
+               task
+                       << "#version 450\n"
+                       << "#extension GL_NV_mesh_shader : enable\n"
+                       << "\n"
+                       << "layout (local_size_x=" << kLocalInvocations << ") in;\n"
+                       << "\n"
+                       << sharedDecl
+                       << outTaskData
+                       << "void main ()\n"
+                       << "{\n"
+                       << verification.str()
+                       << "}\n"
+                       ;
+               std::map<std::string, std::string> replacements;
+               replacements["LOCAL_SIZE"]      = "1";
+               replacements["BODY"]            = meshPrimStr;
+               replacements["GLOBALS"]         = inTaskData;
+               const auto meshStr = meshTemplate.specialize(replacements);
+               programCollection.glslSources.add("task") << glu::TaskSource(task.str());
+               programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr);
+       }
+       else
+       {
+               std::map<std::string, std::string> replacements;
+               replacements["LOCAL_SIZE"]      = std::to_string(kLocalInvocations);
+               replacements["BODY"]            = verification.str();
+               replacements["GLOBALS"]         = sharedDecl;
+               const auto meshStr = meshTemplate.specialize(replacements);
+               programCollection.glslSources.add("mesh") << glu::MeshSource(meshStr);
+       }
+ }
+ class CustomAttributesCase : public MeshShaderMiscCase
+ {
+ public:
+                                       CustomAttributesCase            (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase(testCtx, name, description, std::move(params)) {}
+       virtual                 ~CustomAttributesCase           (void) {}
+       TestInstance*   createInstance                          (Context& context) const override;
+       void                    checkSupport                            (Context& context) const override;
+       void                    initPrograms                            (vk::SourceCollections& programCollection) const override;
+ };
+ class CustomAttributesInstance : public MeshShaderMiscInstance
+ {
+ public:
+                                               CustomAttributesInstance        (Context& context, const MiscTestParams* params)
+                                                       : MeshShaderMiscInstance(context, params) {}
+       virtual                         ~CustomAttributesInstance       (void) {}
+       void                            generateReferenceLevel          () override;
+       tcu::TestStatus         iterate                                         (void) override;
+ };
+ TestInstance* CustomAttributesCase::createInstance (Context& context) const
+ {
+       return new CustomAttributesInstance(context, m_params.get());
+ }
+ void CustomAttributesCase::checkSupport (Context& context) const
+ {
+       MeshShaderMiscCase::checkSupport(context);
+       context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
+       context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_CLIP_DISTANCE);
+ }
+ void CustomAttributesCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       std::ostringstream frag;
+       frag
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout (location=0) in vec4 customAttribute1;\n"
+               << "layout (location=1) in flat float customAttribute2;\n"
+               << "layout (location=2) in flat int customAttribute3;\n"
+               << "\n"
+               << "layout (location=3) in perprimitiveNV flat uvec4 customAttribute4;\n"
+               << "layout (location=4) in perprimitiveNV float customAttribute5;\n"
+               << "\n"
+               << "layout (location=0) out vec4 outColor;\n"
+               << "\n"
+               << "void main ()\n"
+               << "{\n"
+               << "    bool goodPrimitiveID = (gl_PrimitiveID == 1000 || gl_PrimitiveID == 1001);\n"
+               << "    bool goodViewportIndex = (gl_ViewportIndex == 1);\n"
+               << "    bool goodCustom1 = (customAttribute1.x >= 0.25 && customAttribute1.x <= 0.5 &&\n"
+               << "                        customAttribute1.y >= 0.5  && customAttribute1.y <= 1.0 &&\n"
+               << "                        customAttribute1.z >= 10.0 && customAttribute1.z <= 20.0 &&\n"
+               << "                        customAttribute1.w == 3.0);\n"
+               << "    bool goodCustom2 = (customAttribute2 == 1.0 || customAttribute2 == 2.0);\n"
+               << "    bool goodCustom3 = (customAttribute3 == 3 || customAttribute3 == 4);\n"
+               << "    bool goodCustom4 = ((gl_PrimitiveID == 1000 && customAttribute4 == uvec4(100, 101, 102, 103)) ||\n"
+               << "                        (gl_PrimitiveID == 1001 && customAttribute4 == uvec4(200, 201, 202, 203)));\n"
+               << "    bool goodCustom5 = ((gl_PrimitiveID == 1000 && customAttribute5 == 6.0) ||\n"
+               << "                        (gl_PrimitiveID == 1001 && customAttribute5 == 7.0));\n"
+               << "    \n"
+               << "    if (goodPrimitiveID && goodViewportIndex && goodCustom1 && goodCustom2 && goodCustom3 && goodCustom4 && goodCustom5) {\n"
+               << "        outColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
+               << "    } else {\n"
+               << "        outColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
+               << "    }\n"
+               << "}\n"
+               ;
+       programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
+       std::ostringstream pvdDataDeclStream;
+       pvdDataDeclStream
+               << "    vec4 positions[4];\n"
+               << "    float pointSizes[4];\n"
+               << "    float clipDistances[4];\n"
+               << "    vec4 custom1[4];\n"
+               << "    float custom2[4];\n"
+               << "    int custom3[4];\n"
+               ;
+       const auto pvdDataDecl = pvdDataDeclStream.str();
+       std::ostringstream ppdDataDeclStream;
+       ppdDataDeclStream
+               << "    int primitiveIds[2];\n"
+               << "    int viewportIndices[2];\n"
+               << "    uvec4 custom4[2];\n"
+               << "    float custom5[2];\n"
+               ;
+       const auto ppdDataDecl = ppdDataDeclStream.str();
+       std::ostringstream bindingsDeclStream;
+       bindingsDeclStream
+               << "layout (set=0, binding=0, std430) buffer PerVertexData {\n"
+               << pvdDataDecl
+               << "} pvd;\n"
+               << "layout (set=0, binding=1) uniform PerPrimitiveData {\n"
+               << ppdDataDecl
+               << "} ppd;\n"
+               << "\n"
+               ;
+       const auto bindingsDecl = bindingsDeclStream.str();
+       std::ostringstream taskDataStream;
+       taskDataStream
+               << "taskNV TaskData {\n"
+               << pvdDataDecl
+               << ppdDataDecl
+               << "} td;\n"
+               << "\n"
+               ;
+       const auto taskDataDecl = taskDataStream.str();
+       const auto taskShader = m_params->needsTaskShader();
+       const auto meshPvdPrefix = (taskShader ? "td" : "pvd");
+       const auto meshPpdPrefix = (taskShader ? "td" : "ppd");
+       std::ostringstream mesh;
+       mesh
+               << "#version 450\n"
+               << "#extension GL_NV_mesh_shader : enable\n"
+               << "\n"
+               << "layout (local_size_x=1) in;\n"
+               << "layout (max_primitives=2, max_vertices=4) out;\n"
+               << "layout (triangles) out;\n"
+               << "\n"
+               << "out gl_MeshPerVertexNV {\n"
+               << "    vec4  gl_Position;\n"
+               << "    float gl_PointSize;\n"
+               << "    float gl_ClipDistance[1];\n"
+               << "} gl_MeshVerticesNV[];\n"
+               << "\n"
+               << "layout (location=0) out vec4 customAttribute1[];\n"
+               << "layout (location=1) out flat float customAttribute2[];\n"
+               << "layout (location=2) out int customAttribute3[];\n"
+               << "\n"
+               << "layout (location=3) out perprimitiveNV uvec4 customAttribute4[];\n"
+               << "layout (location=4) out perprimitiveNV float customAttribute5[];\n"
+               << "\n"
+               << "out perprimitiveNV gl_MeshPerPrimitiveNV {\n"
+               << "  int gl_PrimitiveID;\n"
+               << "  int gl_ViewportIndex;\n"
+               << "} gl_MeshPrimitivesNV[];\n"
+               << "\n"
+               << (taskShader ? "in " + taskDataDecl : bindingsDecl)
+               << "void main ()\n"
+               << "{\n"
+               << "    gl_PrimitiveCountNV = 2u;\n"
+               << "\n"
+               << "    gl_MeshVerticesNV[0].gl_Position = " << meshPvdPrefix << ".positions[0]; //vec4(-1.0, -1.0, 0.0, 1.0)\n"
+               << "    gl_MeshVerticesNV[1].gl_Position = " << meshPvdPrefix << ".positions[1]; //vec4( 1.0, -1.0, 0.0, 1.0)\n"
+               << "    gl_MeshVerticesNV[2].gl_Position = " << meshPvdPrefix << ".positions[2]; //vec4(-1.0,  1.0, 0.0, 1.0)\n"
+               << "    gl_MeshVerticesNV[3].gl_Position = " << meshPvdPrefix << ".positions[3]; //vec4( 1.0,  1.0, 0.0, 1.0)\n"
+               << "\n"
+               << "    gl_MeshVerticesNV[0].gl_PointSize = " << meshPvdPrefix << ".pointSizes[0]; //1.0\n"
+               << "    gl_MeshVerticesNV[1].gl_PointSize = " << meshPvdPrefix << ".pointSizes[1]; //1.0\n"
+               << "    gl_MeshVerticesNV[2].gl_PointSize = " << meshPvdPrefix << ".pointSizes[2]; //1.0\n"
+               << "    gl_MeshVerticesNV[3].gl_PointSize = " << meshPvdPrefix << ".pointSizes[3]; //1.0\n"
+               << "\n"
+               << "    // Remove geometry on the right side.\n"
+               << "    gl_MeshVerticesNV[0].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[0]; // 1.0\n"
+               << "    gl_MeshVerticesNV[1].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[1]; //-1.0\n"
+               << "    gl_MeshVerticesNV[2].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[2]; // 1.0\n"
+               << "    gl_MeshVerticesNV[3].gl_ClipDistance[0] = " << meshPvdPrefix << ".clipDistances[3]; //-1.0\n"
+               << "    \n"
+               << "    gl_PrimitiveIndicesNV[0] = 0;\n"
+               << "    gl_PrimitiveIndicesNV[1] = 2;\n"
+               << "    gl_PrimitiveIndicesNV[2] = 1;\n"
+               << "\n"
+               << "    gl_PrimitiveIndicesNV[3] = 2;\n"
+               << "    gl_PrimitiveIndicesNV[4] = 3;\n"
+               << "    gl_PrimitiveIndicesNV[5] = 1;\n"
+               << "\n"
+               << "    gl_MeshPrimitivesNV[0].gl_PrimitiveID = " << meshPpdPrefix << ".primitiveIds[0]; //1000\n"
+               << "    gl_MeshPrimitivesNV[1].gl_PrimitiveID = " << meshPpdPrefix << ".primitiveIds[1]; //1001\n"
+               << "\n"
+               << "    gl_MeshPrimitivesNV[0].gl_ViewportIndex = " << meshPpdPrefix << ".viewportIndices[0]; //1\n"
+               << "    gl_MeshPrimitivesNV[1].gl_ViewportIndex = " << meshPpdPrefix << ".viewportIndices[1]; //1\n"
+               << "\n"
+               << "    // Custom per-vertex attributes\n"
+               << "    customAttribute1[0] = " << meshPvdPrefix << ".custom1[0]; //vec4(0.25, 0.5, 10.0, 3.0)\n"
+               << "    customAttribute1[1] = " << meshPvdPrefix << ".custom1[1]; //vec4(0.25, 1.0, 20.0, 3.0)\n"
+               << "    customAttribute1[2] = " << meshPvdPrefix << ".custom1[2]; //vec4( 0.5, 0.5, 20.0, 3.0)\n"
+               << "    customAttribute1[3] = " << meshPvdPrefix << ".custom1[3]; //vec4( 0.5, 1.0, 10.0, 3.0)\n"
+               << "\n"
+               << "    customAttribute2[0] = " << meshPvdPrefix << ".custom2[0]; //1.0f\n"
+               << "    customAttribute2[1] = " << meshPvdPrefix << ".custom2[1]; //1.0f\n"
+               << "    customAttribute2[2] = " << meshPvdPrefix << ".custom2[2]; //2.0f\n"
+               << "    customAttribute2[3] = " << meshPvdPrefix << ".custom2[3]; //2.0f\n"
+               << "\n"
+               << "    customAttribute3[0] = " << meshPvdPrefix << ".custom3[0]; //3\n"
+               << "    customAttribute3[1] = " << meshPvdPrefix << ".custom3[1]; //3\n"
+               << "    customAttribute3[2] = " << meshPvdPrefix << ".custom3[2]; //4\n"
+               << "    customAttribute3[3] = " << meshPvdPrefix << ".custom3[3]; //4\n"
+               << "\n"
+               << "    // Custom per-primitive attributes.\n"
+               << "    customAttribute4[0] = " << meshPpdPrefix << ".custom4[0]; //uvec4(100, 101, 102, 103)\n"
+               << "    customAttribute4[1] = " << meshPpdPrefix << ".custom4[1]; //uvec4(200, 201, 202, 203)\n"
+               << "\n"
+               << "    customAttribute5[0] = " << meshPpdPrefix << ".custom5[0]; //6.0\n"
+               << "    customAttribute5[1] = " << meshPpdPrefix << ".custom5[1]; //7.0\n"
+               << "}\n"
+               ;
+       programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+       if (taskShader)
+       {
+               std::ostringstream task;
+               task
+                       << "#version 450\n"
+                       << "#extension GL_NV_mesh_shader : enable\n"
+                       << "\n"
+                       << "out " << taskDataDecl
+                       << bindingsDecl
+                       << "void main ()\n"
+                       << "{\n"
+                       << "    gl_TaskCountNV = " << m_params->meshCount << ";\n"
+                       << "\n"
+                       << "    td.positions[0] = pvd.positions[0];\n"
+                       << "    td.positions[1] = pvd.positions[1];\n"
+                       << "    td.positions[2] = pvd.positions[2];\n"
+                       << "    td.positions[3] = pvd.positions[3];\n"
+                       << "\n"
+                       << "    td.pointSizes[0] = pvd.pointSizes[0];\n"
+                       << "    td.pointSizes[1] = pvd.pointSizes[1];\n"
+                       << "    td.pointSizes[2] = pvd.pointSizes[2];\n"
+                       << "    td.pointSizes[3] = pvd.pointSizes[3];\n"
+                       << "\n"
+                       << "    td.clipDistances[0] = pvd.clipDistances[0];\n"
+                       << "    td.clipDistances[1] = pvd.clipDistances[1];\n"
+                       << "    td.clipDistances[2] = pvd.clipDistances[2];\n"
+                       << "    td.clipDistances[3] = pvd.clipDistances[3];\n"
+                       << "\n"
+                       << "    td.custom1[0] = pvd.custom1[0];\n"
+                       << "    td.custom1[1] = pvd.custom1[1];\n"
+                       << "    td.custom1[2] = pvd.custom1[2];\n"
+                       << "    td.custom1[3] = pvd.custom1[3];\n"
+                       << "\n"
+                       << "    td.custom2[0] = pvd.custom2[0];\n"
+                       << "    td.custom2[1] = pvd.custom2[1];\n"
+                       << "    td.custom2[2] = pvd.custom2[2];\n"
+                       << "    td.custom2[3] = pvd.custom2[3];\n"
+                       << "\n"
+                       << "    td.custom3[0] = pvd.custom3[0];\n"
+                       << "    td.custom3[1] = pvd.custom3[1];\n"
+                       << "    td.custom3[2] = pvd.custom3[2];\n"
+                       << "    td.custom3[3] = pvd.custom3[3];\n"
+                       << "\n"
+                       << "    td.primitiveIds[0] = ppd.primitiveIds[0];\n"
+                       << "    td.primitiveIds[1] = ppd.primitiveIds[1];\n"
+                       << "\n"
+                       << "    td.viewportIndices[0] = ppd.viewportIndices[0];\n"
+                       << "    td.viewportIndices[1] = ppd.viewportIndices[1];\n"
+                       << "\n"
+                       << "    td.custom4[0] = ppd.custom4[0];\n"
+                       << "    td.custom4[1] = ppd.custom4[1];\n"
+                       << "\n"
+                       << "    td.custom5[0] = ppd.custom5[0];\n"
+                       << "    td.custom5[1] = ppd.custom5[1];\n"
+                       << "}\n"
+                       ;
+               programCollection.glslSources.add("task") << glu::TaskSource(task.str());
+       }
+ }
+ void CustomAttributesInstance::generateReferenceLevel ()
+ {
+       const auto format               = getOutputFormat();
+       const auto tcuFormat    = mapVkFormat(format);
+       const auto iWidth               = static_cast<int>(m_params->width);
+       const auto iHeight              = static_cast<int>(m_params->height);
+       const auto halfWidth    = iWidth / 2;
+       const auto halfHeight   = iHeight / 2;
+       m_referenceLevel.reset(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
+       const auto access               = m_referenceLevel->getAccess();
+       const auto clearColor   = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
+       const auto blueColor    = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
+       tcu::clear(access, clearColor);
+       // Fill the top left quarter.
+       for (int y = 0; y < halfWidth; ++y)
+       for (int x = 0; x < halfHeight; ++x)
+       {
+               access.setPixel(blueColor, x, y);
+       }
+ }
+ tcu::TestStatus CustomAttributesInstance::iterate ()
+ {
+       struct PerVertexData
+       {
+               tcu::Vec4       positions[4];
+               float           pointSizes[4];
+               float           clipDistances[4];
+               tcu::Vec4       custom1[4];
+               float           custom2[4];
+               int32_t         custom3[4];
+       };
+       struct PerPrimitiveData
+       {
+               // Note some of these are declared as vectors to match the std140 layout.
+               tcu::IVec4      primitiveIds[2];
+               tcu::IVec4      viewportIndices[2];
+               tcu::UVec4      custom4[2];
+               tcu::Vec4       custom5[2];
+       };
+       const auto&             vkd                     = m_context.getDeviceInterface();
+       const auto              device          = m_context.getDevice();
+       auto&                   alloc           = m_context.getDefaultAllocator();
+       const auto              queueIndex      = m_context.getUniversalQueueFamilyIndex();
+       const auto              queue           = m_context.getUniversalQueue();
+       const auto              imageFormat     = getOutputFormat();
+       const auto              tcuFormat       = mapVkFormat(imageFormat);
+       const auto              imageExtent     = makeExtent3D(m_params->width, m_params->height, 1u);
+       const auto              imageUsage      = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+       const auto&             binaries        = m_context.getBinaryCollection();
+       const auto              hasTask         = binaries.contains("task");
+       const auto              bufStages       = (hasTask ? VK_SHADER_STAGE_TASK_BIT_NV : VK_SHADER_STAGE_MESH_BIT_NV);
+       const VkImageCreateInfo colorBufferInfo =
+       {
+               VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,    //      VkStructureType                 sType;
+               nullptr,                                                                //      const void*                             pNext;
+               0u,                                                                             //      VkImageCreateFlags              flags;
+               VK_IMAGE_TYPE_2D,                                               //      VkImageType                             imageType;
+               imageFormat,                                                    //      VkFormat                                format;
+               imageExtent,                                                    //      VkExtent3D                              extent;
+               1u,                                                                             //      uint32_t                                mipLevels;
+               1u,                                                                             //      uint32_t                                arrayLayers;
+               VK_SAMPLE_COUNT_1_BIT,                                  //      VkSampleCountFlagBits   samples;
+               VK_IMAGE_TILING_OPTIMAL,                                //      VkImageTiling                   tiling;
+               imageUsage,                                                             //      VkImageUsageFlags               usage;
+               VK_SHARING_MODE_EXCLUSIVE,                              //      VkSharingMode                   sharingMode;
+               0u,                                                                             //      uint32_t                                queueFamilyIndexCount;
+               nullptr,                                                                //      const uint32_t*                 pQueueFamilyIndices;
+               VK_IMAGE_LAYOUT_UNDEFINED,                              //      VkImageLayout                   initialLayout;
+       };
+       // Create color image and view.
+       ImageWithMemory colorImage      (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
+       const auto              colorSRR        = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+       const auto              colorSRL        = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
+       const auto              colorView       = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
+       // Create a memory buffer for verification.
+       const auto                      verificationBufferSize  = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
+       const auto                      verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+       const auto                      verificationBufferInfo  = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
+       BufferWithMemory        verificationBuffer              (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
+       auto&                           verificationBufferAlloc = verificationBuffer.getAllocation();
+       void*                           verificationBufferData  = verificationBufferAlloc.getHostPtr();
+       // This needs to match what the fragment shader will expect.
+       const PerVertexData perVertexData =
+       {
+               //      tcu::Vec4       positions[4];
+               {
+                       tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
+                       tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
+                       tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
+                       tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
+               },
+               //      float           pointSizes[4];
+               { 1.0f, 1.0f, 1.0f, 1.0f, },
+               //      float           clipDistances[4];
+               {
+                       1.0f,
+                       -1.0f,
+                       1.0f,
+                       -1.0f,
+               },
+               //      tcu::Vec4       custom1[4];
+               {
+                       tcu::Vec4(0.25, 0.5, 10.0, 3.0),
+                       tcu::Vec4(0.25, 1.0, 20.0, 3.0),
+                       tcu::Vec4( 0.5, 0.5, 20.0, 3.0),
+                       tcu::Vec4( 0.5, 1.0, 10.0, 3.0),
+               },
+               //      float           custom2[4];
+               { 1.0f, 1.0f, 2.0f, 2.0f, },
+               //      int32_t         custom3[4];
+               { 3, 3, 4, 4 },
+       };
+       // This needs to match what the fragment shader will expect. Reminder: some of these are declared as gvec4 to match the std140
+       // layout, but only the first component is actually used.
+       const PerPrimitiveData perPrimitiveData =
+       {
+               //      int                     primitiveIds[2];
+               {
+                       tcu::IVec4(1000, 0, 0, 0),
+                       tcu::IVec4(1001, 0, 0, 0),
+               },
+               //      int                     viewportIndices[2];
+               {
+                       tcu::IVec4(1, 0, 0, 0),
+                       tcu::IVec4(1, 0, 0, 0),
+               },
+               //      uvec4           custom4[2];
+               {
+                       tcu::UVec4(100u, 101u, 102u, 103u),
+                       tcu::UVec4(200u, 201u, 202u, 203u),
+               },
+               //      float           custom5[2];
+               {
+                       tcu::Vec4(6.0f, 0.0f, 0.0f, 0.0f),
+                       tcu::Vec4(7.0f, 0.0f, 0.0f, 0.0f),
+               },
+       };
+       // Create and fill buffers with this data.
+       const auto                      pvdSize         = static_cast<VkDeviceSize>(sizeof(perVertexData));
+       const auto                      pvdInfo         = makeBufferCreateInfo(pvdSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
+       BufferWithMemory        pvdData         (vkd, device, alloc, pvdInfo, MemoryRequirement::HostVisible);
+       auto&                           pvdAlloc        = pvdData.getAllocation();
+       void*                           pvdPtr          = pvdAlloc.getHostPtr();
+       const auto                      ppdSize         = static_cast<VkDeviceSize>(sizeof(perPrimitiveData));
+       const auto                      ppdInfo         = makeBufferCreateInfo(ppdSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
+       BufferWithMemory        ppdData         (vkd, device, alloc, ppdInfo, MemoryRequirement::HostVisible);
+       auto&                           ppdAlloc        = ppdData.getAllocation();
+       void*                           ppdPtr          = ppdAlloc.getHostPtr();
+       deMemcpy(pvdPtr, &perVertexData, sizeof(perVertexData));
+       deMemcpy(ppdPtr, &perPrimitiveData, sizeof(perPrimitiveData));
+       flushAlloc(vkd, device, pvdAlloc);
+       flushAlloc(vkd, device, ppdAlloc);
+       // Descriptor set layout.
+       DescriptorSetLayoutBuilder setLayoutBuilder;
+       setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, bufStages);
+       setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, bufStages);
+       const auto setLayout = setLayoutBuilder.build(vkd, device);
+       // Create and update descriptor set.
+       DescriptorPoolBuilder descriptorPoolBuilder;
+       descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+       descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
+       const auto descriptorPool       = descriptorPoolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+       const auto descriptorSet        = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
+       DescriptorSetUpdateBuilder updateBuilder;
+       const auto storageBufferInfo = makeDescriptorBufferInfo(pvdData.get(), 0ull, pvdSize);
+       const auto uniformBufferInfo = makeDescriptorBufferInfo(ppdData.get(), 0ull, ppdSize);
+       updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &storageBufferInfo);
+       updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uniformBufferInfo);
+       updateBuilder.update(vkd, device);
+       // Pipeline layout.
+       const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
+       // Shader modules.
+       const auto      meshShader      = createShaderModule(vkd, device, binaries.get("mesh"));
+       const auto      fragShader      = createShaderModule(vkd, device, binaries.get("frag"));
+       Move<VkShaderModule> taskShader;
+       if (hasTask)
+               taskShader = createShaderModule(vkd, device, binaries.get("task"));
+       // Render pass.
+       const auto renderPass = makeRenderPass(vkd, device, imageFormat);
+       // Framebuffer.
+       const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
+       // Viewport and scissor.
+       const auto                                              topHalf         = makeViewport(imageExtent.width, imageExtent.height / 2u);
+       const std::vector<VkViewport>   viewports       { makeViewport(imageExtent), topHalf };
+       const std::vector<VkRect2D>             scissors        (2u, makeRect2D(imageExtent));
+       const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
+               taskShader.get(), meshShader.get(), fragShader.get(),
+               renderPass.get(), viewports, scissors);
+       // Command pool and buffer.
+       const auto cmdPool              = makeCommandPool(vkd, device, queueIndex);
+       const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+       const auto cmdBuffer    = cmdBufferPtr.get();
+       beginCommandBuffer(vkd, cmdBuffer);
+       // Run pipeline.
+       const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
+       beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
+       vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
+       vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
+       vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params->drawCount(), 0u);
+       endRenderPass(vkd, cmdBuffer);
+       // Copy color buffer to verification buffer.
+       const auto colorAccess          = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
+       const auto transferRead         = VK_ACCESS_TRANSFER_READ_BIT;
+       const auto transferWrite        = VK_ACCESS_TRANSFER_WRITE_BIT;
+       const auto hostRead                     = VK_ACCESS_HOST_READ_BIT;
+       const auto preCopyBarrier       = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
+       const auto postCopyBarrier      = makeMemoryBarrier(transferWrite, hostRead);
+       const auto copyRegion           = makeBufferImageCopy(imageExtent, colorSRL);
+       vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
+       vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, &copyRegion);
+       vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
+       endCommandBuffer(vkd, cmdBuffer);
+       submitCommandsAndWait(vkd, device, queue, cmdBuffer);
+       // Generate reference image and compare results.
+       const tcu::IVec3                                        iExtent                         (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
+       const tcu::ConstPixelBufferAccess       verificationAccess      (tcuFormat, iExtent, verificationBufferData);
+       generateReferenceLevel();
+       invalidateAlloc(vkd, device, verificationBufferAlloc);
+       if (!verifyResult(verificationAccess))
+               TCU_FAIL("Result does not match reference; check log for details");
+       return tcu::TestStatus::pass("Pass");
+ }
+ // Tests that use push constants in the new stages.
+ class PushConstantCase : public MeshShaderMiscCase
+ {
+ public:
+                                       PushConstantCase        (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params)
+                                               : MeshShaderMiscCase (testCtx, name, description, std::move(params))
+                                       {}
+       void                    initPrograms                    (vk::SourceCollections& programCollection) const override;
+       TestInstance*   createInstance                  (Context& context) const override;
+ };
+ class PushConstantInstance : public MeshShaderMiscInstance
+ {
+ public:
+       PushConstantInstance (Context& context, const MiscTestParams* params)
+               : MeshShaderMiscInstance (context, params)
+       {}
+       void                    generateReferenceLevel  () override;
+       tcu::TestStatus iterate                                 () override;
+ };
+ TestInstance* PushConstantCase::createInstance (Context& context) const
+ {
+       return new PushConstantInstance(context, m_params.get());
+ }
+ void PushConstantInstance::generateReferenceLevel ()
+ {
+       generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel);
+ }
+ void PushConstantCase::initPrograms (vk::SourceCollections& programCollection) const
+ {
+       const auto useTaskShader        = m_params->needsTaskShader();
+       const auto pcNumFloats          = (useTaskShader ? 2u : 4u);
+       std::ostringstream pushConstantStream;
+       pushConstantStream
+               << "layout (push_constant, std430) uniform PushConstantBlock {\n"
+               << "    layout (offset=${PCOFFSET}) float values[" << pcNumFloats << "];\n"
+               << "} pc;\n"
+               << "\n"
+               ;
+       const tcu::StringTemplate pushConstantsTemplate (pushConstantStream.str());
+       using TemplateMap = std::map<std::string, std::string>;
+       std::ostringstream taskDataStream;
+       taskDataStream
+               << "taskNV TaskData {\n"
+               << "    float values[2];\n"
+               << "} td;\n"
+               << "\n"
+               ;
+       const auto taskDataDecl = taskDataStream.str();
+       if (useTaskShader)
+       {
+               TemplateMap taskMap;
+               taskMap["PCOFFSET"] = std::to_string(2u * sizeof(float));
+               std::ostringstream task;
+               task
+                       << "#version 450\n"
+                       << "#extension GL_NV_mesh_shader : enable\n"
+                       << "\n"
+                       << "layout(local_size_x=1) in;\n"
+                       << "\n"
+                       << "out " << taskDataDecl
+                       << pushConstantsTemplate.specialize(taskMap)
+                       << "void main ()\n"
+                       << "{\n"
+                       << "    gl_TaskCountNV = " << m_params->meshCount << ";\n"
+                       << "\n"
+                       << "    td.values[0] = pc.values[0];\n"
+                       << "    td.values[1] = pc.values[1];\n"
+                       << "}\n"
+                       ;
+               programCollection.glslSources.add("task") << glu::TaskSource(task.str());
+       }
+       {
+               const std::string blue  = (useTaskShader ? "td.values[0] + pc.values[0]" : "pc.values[0] + pc.values[2]");
+               const std::string alpha = (useTaskShader ? "td.values[1] + pc.values[1]" : "pc.values[1] + pc.values[3]");
+               TemplateMap meshMap;
+               meshMap["PCOFFSET"] = "0";
+               std::ostringstream mesh;
+               mesh
+                       << "#version 450\n"
+                       << "#extension GL_NV_mesh_shader : enable\n"
+                       << "\n"
+                       << "layout(local_size_x=1) in;\n"
+                       << "layout(triangles) out;\n"
+                       << "layout(max_vertices=3, max_primitives=1) out;\n"
+                       << "\n"
+                       << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n"
+                       << "\n"
+                       << pushConstantsTemplate.specialize(meshMap)
+                       << (useTaskShader ? "in " + taskDataDecl : "")
+                       << "void main ()\n"
+                       << "{\n"
+                       << "    gl_PrimitiveCountNV = 1;\n"
+                       << "\n"
+                       << "    gl_MeshVerticesNV[0].gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
+                       << "    gl_MeshVerticesNV[1].gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
+                       << "    gl_MeshVerticesNV[2].gl_Position = vec4(-1.0,  3.0, 0.0, 1.0);\n"
+                       << "\n"
+                       << "    gl_PrimitiveIndicesNV[0] = 0;\n"
+                       << "    gl_PrimitiveIndicesNV[1] = 1;\n"
+                       << "    gl_PrimitiveIndicesNV[2] = 2;\n"
+                       << "\n"
+                       << "    triangleColor[0] = vec4(0.0, 0.0, " << blue << ", " << alpha << ");\n"
+                       << "}\n"
+                       ;
+               programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str());
+       }
+       // Add default fragment shader.
+       MeshShaderMiscCase::initPrograms(programCollection);
+ }
+ tcu::TestStatus PushConstantInstance::iterate ()
+ {
+       const auto&             vkd                     = m_context.getDeviceInterface();
+       const auto              device          = m_context.getDevice();
+       auto&                   alloc           = m_context.getDefaultAllocator();
+       const auto              queueIndex      = m_context.getUniversalQueueFamilyIndex();
+       const auto              queue           = m_context.getUniversalQueue();
+       const auto              imageFormat     = getOutputFormat();
+       const auto              tcuFormat       = mapVkFormat(imageFormat);
+       const auto              imageExtent     = makeExtent3D(m_params->width, m_params->height, 1u);
+       const auto              imageUsage      = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+       const auto&             binaries        = m_context.getBinaryCollection();
+       const auto              hasTask         = binaries.contains("task");
+       const VkImageCreateInfo colorBufferInfo =
+       {
+               VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,    //      VkStructureType                 sType;
+               nullptr,                                                                //      const void*                             pNext;
+               0u,                                                                             //      VkImageCreateFlags              flags;
+               VK_IMAGE_TYPE_2D,                                               //      VkImageType                             imageType;
+               imageFormat,                                                    //      VkFormat                                format;
+               imageExtent,                                                    //      VkExtent3D                              extent;
+               1u,                                                                             //      uint32_t                                mipLevels;
+               1u,                                                                             //      uint32_t                                arrayLayers;
+               VK_SAMPLE_COUNT_1_BIT,                                  //      VkSampleCountFlagBits   samples;
+               VK_IMAGE_TILING_OPTIMAL,                                //      VkImageTiling                   tiling;
+               imageUsage,                                                             //      VkImageUsageFlags               usage;
+               VK_SHARING_MODE_EXCLUSIVE,                              //      VkSharingMode                   sharingMode;
+               0u,                                                                             //      uint32_t                                queueFamilyIndexCount;
+               nullptr,                                                                //      const uint32_t*                 pQueueFamilyIndices;
+               VK_IMAGE_LAYOUT_UNDEFINED,                              //      VkImageLayout                   initialLayout;
+       };
+       // Create color image and view.
+       ImageWithMemory colorImage      (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
+       const auto              colorSRR        = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+       const auto              colorSRL        = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
+       const auto              colorView       = makeImageView(vkd, device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSRR);
+       // Create a memory buffer for verification.
+       const auto                      verificationBufferSize  = static_cast<VkDeviceSize>(imageExtent.width * imageExtent.height * tcu::getPixelSize(tcuFormat));
+       const auto                      verificationBufferUsage = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+       const auto                      verificationBufferInfo  = makeBufferCreateInfo(verificationBufferSize, verificationBufferUsage);
+       BufferWithMemory        verificationBuffer              (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
+       auto&                           verificationBufferAlloc = verificationBuffer.getAllocation();
+       void*                           verificationBufferData  = verificationBufferAlloc.getHostPtr();
+       // Push constant ranges.
+       std::vector<float> pcData { 0.25f, 0.25f, 0.75f, 0.75f };
+       const auto pcSize               = static_cast<uint32_t>(de::dataSize(pcData));
+       const auto pcHalfSize   = pcSize / 2u;
+       std::vector<VkPushConstantRange> pcRanges;
+       if (hasTask)
+       {
+               pcRanges.push_back(makePushConstantRange(VK_SHADER_STAGE_MESH_BIT_NV, 0u, pcHalfSize));
+               pcRanges.push_back(makePushConstantRange(VK_SHADER_STAGE_TASK_BIT_NV, pcHalfSize, pcHalfSize));
+       }
+       else
+       {
+               pcRanges.push_back(makePushConstantRange(VK_SHADER_STAGE_MESH_BIT_NV, 0u, pcSize));
+       }
+       // Pipeline layout.
+       const auto pipelineLayout = makePipelineLayout(vkd, device, 0u, nullptr, static_cast<uint32_t>(pcRanges.size()), de::dataOrNull(pcRanges));
+       // Shader modules.
+       const auto      meshShader      = createShaderModule(vkd, device, binaries.get("mesh"));
+       const auto      fragShader      = createShaderModule(vkd, device, binaries.get("frag"));
+       Move<VkShaderModule> taskShader;
+       if (hasTask)
+               taskShader = createShaderModule(vkd, device, binaries.get("task"));
+       // Render pass.
+       const auto renderPass = makeRenderPass(vkd, device, imageFormat);
+       // Framebuffer.
+       const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), imageExtent.width, imageExtent.height);
+       // Viewport and scissor.
+       const std::vector<VkViewport>   viewports       (1u, makeViewport(imageExtent));
+       const std::vector<VkRect2D>             scissors        (1u, makeRect2D(imageExtent));
+       const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
+               taskShader.get(), meshShader.get(), fragShader.get(),
+               renderPass.get(), viewports, scissors);
+       // Command pool and buffer.
+       const auto cmdPool              = makeCommandPool(vkd, device, queueIndex);
+       const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+       const auto cmdBuffer    = cmdBufferPtr.get();
+       beginCommandBuffer(vkd, cmdBuffer);
+       // Run pipeline.
+       const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 0.0f);
+       beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
+       vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
+       for (const auto& range : pcRanges)
+               vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), range.stageFlags, range.offset, range.size, reinterpret_cast<const char*>(pcData.data()) + range.offset);
+       vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params->drawCount(), 0u);
+       endRenderPass(vkd, cmdBuffer);
+       // Copy color buffer to verification buffer.
+       const auto colorAccess          = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
+       const auto transferRead         = VK_ACCESS_TRANSFER_READ_BIT;
+       const auto transferWrite        = VK_ACCESS_TRANSFER_WRITE_BIT;
+       const auto hostRead                     = VK_ACCESS_HOST_READ_BIT;
+       const auto preCopyBarrier       = makeImageMemoryBarrier(colorAccess, transferRead, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSRR);
+       const auto postCopyBarrier      = makeMemoryBarrier(transferWrite, hostRead);
+       const auto copyRegion           = makeBufferImageCopy(imageExtent, colorSRL);
+       vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preCopyBarrier);
+       vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, &copyRegion);
+       vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postCopyBarrier, 0u, nullptr, 0u, nullptr);
+       endCommandBuffer(vkd, cmdBuffer);
+       submitCommandsAndWait(vkd, device, queue, cmdBuffer);
+       // Generate reference image and compare results.
+       const tcu::IVec3                                        iExtent                         (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), 1);
+       const tcu::ConstPixelBufferAccess       verificationAccess      (tcuFormat, iExtent, verificationBufferData);
+       generateReferenceLevel();
+       invalidateAlloc(vkd, device, verificationBufferAlloc);
+       if (!verifyResult(verificationAccess))
+               TCU_FAIL("Result does not match reference; check log for details");
+       return tcu::TestStatus::pass("Pass");
+ }
+ }
+ tcu::TestCaseGroup* createMeshShaderMiscTests (tcu::TestContext& testCtx)
+ {
+       GroupPtr miscTests (new tcu::TestCaseGroup(testCtx, "misc", "Mesh Shader Misc Tests"));
+       {
+               ParamsPtr paramsPtr (new MiscTestParams);
+               paramsPtr->taskCount    = tcu::just(2u);
+               paramsPtr->meshCount    = 2u;
+               paramsPtr->width                = 8u;
+               paramsPtr->height               = 8u;
+               miscTests->addChild(new ComplexTaskDataCase(testCtx, "complex_task_data", "Pass a complex structure from the task to the mesh shader", std::move(paramsPtr)));
+       }
+       {
+               ParamsPtr paramsPtr (new MiscTestParams);
+               paramsPtr->taskCount    = tcu::nothing<uint32_t>();
+               paramsPtr->meshCount    = 1u;
+               paramsPtr->width                = 5u;   // Use an odd value so there's a pixel in the exact center.
+               paramsPtr->height               = 7u;   // Idem.
+               miscTests->addChild(new SinglePointCase(testCtx, "single_point", "Draw a single point", std::move(paramsPtr)));
+       }
+       {
+               ParamsPtr paramsPtr (new MiscTestParams);
+               paramsPtr->taskCount    = tcu::nothing<uint32_t>();
+               paramsPtr->meshCount    = 1u;
+               paramsPtr->width                = 8u;
+               paramsPtr->height               = 5u;   // Use an odd value so there's a center line.
+               miscTests->addChild(new SingleLineCase(testCtx, "single_line", "Draw a single line", std::move(paramsPtr)));
+       }
+       {
+               ParamsPtr paramsPtr (new MiscTestParams);
+               paramsPtr->taskCount    = tcu::nothing<uint32_t>();
+               paramsPtr->meshCount    = 1u;
+               paramsPtr->width                = 5u;   // Use an odd value so there's a pixel in the exact center.
+               paramsPtr->height               = 7u;   // Idem.
+               miscTests->addChild(new SingleTriangleCase(testCtx, "single_triangle", "Draw a single triangle", std::move(paramsPtr)));
+       }
+       {
+               ParamsPtr paramsPtr (new MiscTestParams);
+               paramsPtr->taskCount    = tcu::nothing<uint32_t>();
+               paramsPtr->meshCount    = 1u;
+               paramsPtr->width                = 16u;
+               paramsPtr->height               = 16u;
+               miscTests->addChild(new MaxPointsCase(testCtx, "max_points", "Draw the maximum number of points", std::move(paramsPtr)));
+       }
+       {
+               ParamsPtr paramsPtr (new MiscTestParams);
+               paramsPtr->taskCount    = tcu::nothing<uint32_t>();
+               paramsPtr->meshCount    = 1u;
+               paramsPtr->width                = 1u;
+               paramsPtr->height               = 1020u;
+               miscTests->addChild(new MaxLinesCase(testCtx, "max_lines", "Draw the maximum number of lines", std::move(paramsPtr)));
+       }
+       {
+               ParamsPtr paramsPtr (new MiscTestParams);
+               paramsPtr->taskCount    = tcu::nothing<uint32_t>();
+               paramsPtr->meshCount    = 1u;
+               paramsPtr->width                = 512u;
+               paramsPtr->height               = 512u;
+               miscTests->addChild(new MaxTrianglesCase(testCtx, "max_triangles", "Draw the maximum number of triangles", std::move(paramsPtr)));
+       }
+       {
+               ParamsPtr paramsPtr (new MiscTestParams);
+               paramsPtr->taskCount    = tcu::just(65535u);
+               paramsPtr->meshCount    = 1u;
+               paramsPtr->width                = 1360u;
+               paramsPtr->height               = 1542u;
+               miscTests->addChild(new LargeWorkGroupCase(testCtx, "many_task_work_groups", "Generate a large number of task work groups", std::move(paramsPtr)));
+       }
+       {
+               ParamsPtr paramsPtr (new MiscTestParams);
+               paramsPtr->taskCount    = tcu::nothing<uint32_t>();
+               paramsPtr->meshCount    = 65535u;
+               paramsPtr->width                = 1360u;
+               paramsPtr->height               = 1542u;
+               miscTests->addChild(new LargeWorkGroupCase(testCtx, "many_mesh_work_groups", "Generate a large number of mesh work groups", std::move(paramsPtr)));
+       }
+       {
+               ParamsPtr paramsPtr (new MiscTestParams);
+               paramsPtr->taskCount    = tcu::just(512u);
+               paramsPtr->meshCount    = 512u;
+               paramsPtr->width                = 4096u;
+               paramsPtr->height               = 2048u;
+               miscTests->addChild(new LargeWorkGroupCase(testCtx, "many_task_mesh_work_groups", "Generate a large number of task and mesh work groups", std::move(paramsPtr)));
+       }
+       {
+               const PrimitiveType types[] = {
+                       PrimitiveType::POINTS,
+                       PrimitiveType::LINES,
+                       PrimitiveType::TRIANGLES,
+               };
+               for (int i = 0; i < 2; ++i)
+               {
+                       const bool extraWrites = (i > 0);
+                       for (const auto primType : types)
+                       {
+                               std::unique_ptr<NoPrimitivesParams> params (new NoPrimitivesParams);
+                               params->taskCount               = (extraWrites ? tcu::just(1u) : tcu::nothing<uint32_t>());
+                               params->meshCount               = 1u;
+                               params->width                   = 16u;
+                               params->height                  = 16u;
+                               params->primitiveType   = primType;
+                               ParamsPtr                       paramsPtr       (params.release());
+                               const auto                      primName        = primitiveTypeName(primType);
+                               const std::string       name            = "no_" + primName + (extraWrites ? "_extra_writes" : "");
+                               const std::string       desc            = "Run a pipeline that generates no " + primName + (extraWrites ? " but generates primitive data" : "");
+                               miscTests->addChild(extraWrites
+                                       ? (new NoPrimitivesExtraWritesCase(testCtx, name, desc, std::move(paramsPtr)))
+                                       : (new NoPrimitivesCase(testCtx, name, desc, std::move(paramsPtr))));
+                       }
+               }
+       }
+       {
+               for (int i = 0; i < 2; ++i)
+               {
+                       const bool useTaskShader = (i == 0);
+                       ParamsPtr paramsPtr (new MiscTestParams);
+                       paramsPtr->taskCount            = (useTaskShader ? tcu::just(1u) : tcu::nothing<uint32_t>());
+                       paramsPtr->meshCount            = 1u;
+                       paramsPtr->width                        = 1u;
+                       paramsPtr->height                       = 1u;
+                       const std::string shader        = (useTaskShader ? "task" : "mesh");
+                       const std::string name          = "barrier_in_" + shader;
+                       const std::string desc          = "Use a control barrier in the " + shader + " shader";
+                       miscTests->addChild(new SimpleBarrierCase(testCtx, name, desc, std::move(paramsPtr)));
+               }
+       }
+       {
+               const struct
+               {
+                       MemoryBarrierType       memBarrierType;
+                       std::string                     caseName;
+               } barrierTypes[] =
+               {
+                       { MemoryBarrierType::SHARED,    "memory_barrier_shared" },
+                       { MemoryBarrierType::GROUP,             "group_memory_barrier"  },
+               };
+               for (const auto& barrierCase : barrierTypes)
+               {
+                       for (int i = 0; i < 2; ++i)
+                       {
+                               const bool useTaskShader = (i == 0);
+                               std::unique_ptr<MemoryBarrierParams> paramsPtr (new MemoryBarrierParams);
+                               paramsPtr->taskCount            = (useTaskShader ? tcu::just(1u) : tcu::nothing<uint32_t>());
+                               paramsPtr->meshCount            = 1u;
+                               paramsPtr->width                        = 1u;
+                               paramsPtr->height                       = 1u;
+                               paramsPtr->memBarrierType       = barrierCase.memBarrierType;
+                               const std::string shader        = (useTaskShader ? "task" : "mesh");
+                               const std::string name          = barrierCase.caseName + "_in_" + shader;
+                               const std::string desc          = "Use " + paramsPtr->glslFunc() + "() in the " + shader + " shader";
+                               miscTests->addChild(new MemoryBarrierCase(testCtx, name, desc, std::move(paramsPtr)));
+                       }
+               }
+       }
+       {
+               for (int i = 0; i < 2; ++i)
+               {
+                       const bool useTaskShader        = (i > 0);
+                       const auto name                         = std::string("custom_attributes") + (useTaskShader ? "_and_task_shader" : "");
+                       const auto desc                         = std::string("Use several custom vertex and primitive attributes") + (useTaskShader ? " and also a task shader" : "");
+                       ParamsPtr paramsPtr (new MiscTestParams);
+                       paramsPtr->taskCount            = (useTaskShader ? tcu::just(1u) : tcu::nothing<uint32_t>());
+                       paramsPtr->meshCount            = 1u;
+                       paramsPtr->width                        = 32u;
+                       paramsPtr->height                       = 32u;
+                       miscTests->addChild(new CustomAttributesCase(testCtx, name, desc, std::move(paramsPtr)));
+               }
+       }
+       {
+               for (int i = 0; i < 2; ++i)
+               {
+                       const bool useTaskShader        = (i > 0);
+                       const auto name                         = std::string("push_constant") + (useTaskShader ? "_and_task_shader" : "");
+                       const auto desc                         = std::string("Use push constants in the mesh shader stage") + (useTaskShader ? " and also in the task shader stage" : "");
+                       ParamsPtr paramsPtr (new MiscTestParams);
+                       paramsPtr->taskCount            = (useTaskShader ? tcu::just(1u) : tcu::nothing<uint32_t>());
+                       paramsPtr->meshCount            = 1u;
+                       paramsPtr->width                        = 16u;
+                       paramsPtr->height                       = 16u;
+                       miscTests->addChild(new PushConstantCase(testCtx, name, desc, std::move(paramsPtr)));
+               }
+       }
+       return miscTests.release();
+ }
+ } // MeshShader
+ } // vkt
@@@ -731,13 -705,13 +731,16 @@@ void MultiViewRenderTestInstance::creat
                if (!isCoreDeviceExtension(m_context.getUsedApiVersion(), "VK_KHR_multiview"))
                        deviceExtensions.push_back("VK_KHR_multiview");
  
 -              if (m_parameters.renderPassType == RENDERPASS_TYPE_RENDERPASS2)
 -                      if (!isCoreDeviceExtension(m_context.getUsedApiVersion(), "VK_KHR_create_renderpass2"))
 -                              deviceExtensions.push_back("VK_KHR_create_renderpass2");
 +              if ((m_parameters.renderingType == RENDERING_TYPE_RENDERPASS2) &&
 +                      !isCoreDeviceExtension(m_context.getUsedApiVersion(), "VK_KHR_create_renderpass2"))
 +                      deviceExtensions.push_back("VK_KHR_create_renderpass2");
 +              if ((m_parameters.renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) &&
 +                      !isCoreDeviceExtension(m_context.getUsedApiVersion(), "VK_KHR_dynamic_rendering"))
 +                      deviceExtensions.push_back("VK_KHR_dynamic_rendering");
  
+               if (m_parameters.viewIndex == TEST_TYPE_DEPTH_DIFFERENT_RANGES)
+                       deviceExtensions.push_back("VK_EXT_depth_range_unrestricted");
                const VkDeviceCreateInfo                deviceInfo                      =
                {
                        VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,                                                   //VkStructureType                                       sType;
@@@ -3850,13 -3499,9 +3853,15 @@@ private
  
        virtual void            checkSupport            (Context& context) const
        {
 +              if (m_parameters.renderingType == RENDERING_TYPE_RENDERPASS2)
 +                      context.requireDeviceFunctionality("VK_KHR_create_renderpass2");
 +
 +              if (m_parameters.renderingType == RENDERING_TYPE_DYNAMIC_RENDERING)
 +                      context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
 +
                context.requireDeviceFunctionality("VK_KHR_multiview");
+               if (m_parameters.viewIndex == TEST_TYPE_DEPTH_DIFFERENT_RANGES)
+                       context.requireDeviceFunctionality("VK_EXT_depth_range_unrestricted");
        }
  
        void                            initPrograms            (SourceCollections& programCollection) const
@@@ -2559,8 -2559,15 +2559,15 @@@ tcu::TestStatus SeparateChannelsTestIns
                }
  
                const vector<Subpass>           subpasses       (1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, inputAttachmentReferences, colorAttachmentReferences, vector<AttachmentReference>(), isDSFormat ? dsAttachmentReference : AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<deUint32>()));
 -              renderPass = createRenderPass(vkd, device, RenderPass(attachments, subpasses, subpassDependency), m_renderPassType);
+               vector<SubpassDependency> subpassDependency;
+               if(!isDSFormat)
+               {
+                       /* Self supass-dependency */
+                       subpassDependency.push_back(SubpassDependency(0u, 0u, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+                                                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT));
+               }
++              renderPass = createRenderPass(vkd, device, RenderPass(attachments, subpasses, subpassDependency), m_renderingType);
  
-               renderPass = createRenderPass(vkd, device, RenderPass(attachments, subpasses, vector<SubpassDependency>()), m_renderingType);
        }
  
        // Create render pipeline.
@@@ -99,6 -99,7 +99,8 @@@ VK_KHR_shader_subgroup_uniform_control_
  VK_KHR_present_id                                                     DEVICE
  VK_KHR_present_wait                                                   DEVICE
  VK_KHR_shader_integer_dot_product                     DEVICE
- VK_KHR_format_feature_flags2                      DEVICE
+ VK_KHR_format_feature_flags2                          DEVICE
  VK_KHR_maintenance4                                                   DEVICE
 +VK_KHR_dynamic_rendering                                      DEVICE
+ VK_EXT_border_color_swizzle                                   DEVICE
+ VK_NV_mesh_shader                                                     DEVICE