From: Matthew Netsch Date: Fri, 5 Nov 2021 23:03:54 +0000 (-0400) Subject: Merge vk-gl-cts/vulkan-cts-1.2.8 into vk-gl-cts/dev/VK_KHR_dynamic_rendering X-Git-Tag: upstream/1.3.5~428^2~21^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=676d67085dbb431c9a829ce45bf33f94af5a9bfe;p=platform%2Fupstream%2FVK-GL-CTS.git Merge vk-gl-cts/vulkan-cts-1.2.8 into vk-gl-cts/dev/VK_KHR_dynamic_rendering Change-Id: Ica7c90f88986488142bc7c2b3e9b892b8104b7a1 --- 676d67085dbb431c9a829ce45bf33f94af5a9bfe diff --cc external/vulkancts/framework/vulkan/vkDeviceExtensions.inl index e60d749,5ce6155..12a21c4 --- a/external/vulkancts/framework/vulkan/vkDeviceExtensions.inl +++ b/external/vulkancts/framework/vulkan/vkDeviceExtensions.inl @@@ -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", }; diff --cc external/vulkancts/framework/vulkan/vkDeviceFeatures.inl index 12ee7fb,25f4c7c..a3d894e --- a/external/vulkancts/framework/vulkan/vkDeviceFeatures.inl +++ b/external/vulkancts/framework/vulkan/vkDeviceFeatures.inl @@@ -301,29 -301,29 +303,30 @@@ template<> void initFeatureFromBlob void initFeatureFromBlob(VkPhysicalDevicePortabilitySubsetFeaturesKHR&, const AllFeaturesBlobs&) {} --template<> FeatureDesc makeFeatureDesc(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(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(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(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(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(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(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(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(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(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD, DECL_AMD_COHERENT_MEMORY_EXTENSION_NAME, 0, 91}; } -template<> FeatureDesc makeFeatureDesc(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(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(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(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(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(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(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(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(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(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(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(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(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV, DECL_NV_DIAGNOSTICS_CONFIG_EXTENSION_NAME, 0, 78}; } ++template<> FeatureDesc makeFeatureDesc(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(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(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(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(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(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(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(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(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(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD, DECL_AMD_COHERENT_MEMORY_EXTENSION_NAME, 0, 92}; } +template<> FeatureDesc makeFeatureDesc(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(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(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(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(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(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(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(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(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(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(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(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(void) { return FeatureDesc{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV, DECL_NV_DIAGNOSTICS_CONFIG_EXTENSION_NAME, 0, 79}; } +template<> FeatureDesc makeFeatureDesc(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(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(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(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}; } diff --cc external/vulkancts/framework/vulkan/vkObjUtil.hpp index da70e2d,c8286fa..74ce14c --- a/external/vulkancts/framework/vulkan/vkObjUtil.hpp +++ b/external/vulkancts/framework/vulkan/vkObjUtil.hpp @@@ -77,9 -76,24 +77,25 @@@ Move 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 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& viewports, + const std::vector& 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 makeRenderPass (const DeviceInterface& vk, const VkDevice device, const VkFormat colorFormat = VK_FORMAT_UNDEFINED, diff --cc external/vulkancts/modules/vulkan/mesh_shader/vktMeshShaderMiscTests.cpp index 0000000,05efdf1..28b7d8e mode 000000,100644..100644 --- a/external/vulkancts/modules/vulkan/mesh_shader/vktMeshShaderMiscTests.cpp +++ b/external/vulkancts/modules/vulkan/mesh_shader/vktMeshShaderMiscTests.cpp @@@ -1,0 -1,2788 +1,2785 @@@ + /*------------------------------------------------------------------------ + * 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 + #include + #include + #include + #include + #include + + namespace vkt + { + namespace MeshShader + { + + namespace + { + + using GroupPtr = de::MovePtr; + + 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 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(taskCount); + } + + uint32_t drawCount () const + { + if (needsTaskShader()) + return taskCount.get(); + return meshCount; + } + }; + + using ParamsPtr = std::unique_ptr; + + 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 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& 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 m_referenceLevel; + }; + + void MeshShaderMiscInstance::generateSolidRefLevel (const tcu::Vec4& color, std::unique_ptr& output) + { + const auto format = getOutputFormat(); + const auto tcuFormat = mapVkFormat(format); + + const auto iWidth = static_cast(m_params->width); + const auto iHeight = static_cast(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(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 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 viewports (1u, makeViewport(imageExtent)); + const std::vector 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, ©Region); + 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(imageExtent.width), static_cast(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(m_params->width); + const auto iHeight = static_cast(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 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 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(m_params->width / 2u); + const auto halfHeight = static_cast(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(m_params->width); + const auto halfHeight = static_cast(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(m_params->width); + const float halfPixelY = 2.0f / static_cast(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(m_params->width / 2u); + const auto halfHeight = static_cast(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(m_params->width); + const auto iHeight = static_cast(m_params->height); + const auto fWidth = static_cast(m_params->width); + const auto fHeight = static_cast(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(x) + 0.5f) / fWidth), + ((static_cast(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(m_params->width); + const auto iHeight = static_cast(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(i) / static_cast(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(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(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 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 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 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. - constexpr auto Message = tcu::TestLog::Message; - constexpr auto EndMessage = tcu::TestLog::EndMessage; - + // Clarify what we are checking in the logs; otherwise, they could be confusing. + auto& log = m_context.getTestContext().getLog(); + const std::vector levels = { m_referenceLevel.get(), m_referenceLevel2.get() }; + + bool good = false; + for (size_t i = 0; i < levels.size(); ++i) + { - log << Message << "Comparing result with reference " << i << "..." << EndMessage; ++ log << tcu::TestLog::Message << "Comparing result with reference " << i << "..." << tcu::TestLog::EndMessage; + const auto success = MeshShaderMiscInstance::verifyResult(resultAccess, *levels[i]); + if (success) + { - log << Message << "Match! The test has passed" << EndMessage; ++ 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(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 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 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(m_params->width); + const auto iHeight = static_cast(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(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(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(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 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 viewports { makeViewport(imageExtent), topHalf }; + const std::vector 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, ©Region); + 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(imageExtent.width), static_cast(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::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(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 pcData { 0.25f, 0.25f, 0.75f, 0.75f }; + const auto pcSize = static_cast(de::dataSize(pcData)); + const auto pcHalfSize = pcSize / 2u; + + std::vector 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(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 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 viewports (1u, makeViewport(imageExtent)); + const std::vector 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(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, ©Region); + 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(imageExtent.width), static_cast(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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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 params (new NoPrimitivesParams); + params->taskCount = (extraWrites ? tcu::just(1u) : tcu::nothing()); + 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()); + 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 paramsPtr (new MemoryBarrierParams); + + paramsPtr->taskCount = (useTaskShader ? tcu::just(1u) : tcu::nothing()); + 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()); + 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()); + paramsPtr->meshCount = 1u; + paramsPtr->width = 16u; + paramsPtr->height = 16u; + + miscTests->addChild(new PushConstantCase(testCtx, name, desc, std::move(paramsPtr))); + } + } + + return miscTests.release(); + } + + } // MeshShader + } // vkt diff --cc external/vulkancts/modules/vulkan/multiview/vktMultiViewRenderTests.cpp index 6ea3c94,458f681..1e91bd5 --- a/external/vulkancts/modules/vulkan/multiview/vktMultiViewRenderTests.cpp +++ b/external/vulkancts/modules/vulkan/multiview/vktMultiViewRenderTests.cpp @@@ -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 diff --cc external/vulkancts/modules/vulkan/renderpass/vktRenderPassSubpassDependencyTests.cpp index 9780759,9de3bd2..140aa5b --- a/external/vulkancts/modules/vulkan/renderpass/vktRenderPassSubpassDependencyTests.cpp +++ b/external/vulkancts/modules/vulkan/renderpass/vktRenderPassSubpassDependencyTests.cpp @@@ -2559,8 -2559,15 +2559,15 @@@ tcu::TestStatus SeparateChannelsTestIns } const vector subpasses (1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, inputAttachmentReferences, colorAttachmentReferences, vector(), isDSFormat ? dsAttachmentReference : AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); + vector 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_renderPassType); ++ renderPass = createRenderPass(vkd, device, RenderPass(attachments, subpasses, subpassDependency), m_renderingType); - renderPass = createRenderPass(vkd, device, RenderPass(attachments, subpasses, vector()), m_renderingType); } // Create render pipeline. diff --cc external/vulkancts/scripts/src/extensions_data.txt index 301a7ec,24c87af..fcf1cfb --- a/external/vulkancts/scripts/src/extensions_data.txt +++ b/external/vulkancts/scripts/src/extensions_data.txt @@@ -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