/*------------------------------------------------------------------------ * 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 "vktMeshShaderUtil.hpp" #include "vktTestCase.hpp" #include "vktTestCaseUtil.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 "deRandom.hpp" #include #include #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) { checkTaskMeshShaderSupportNV(context, requireTaskShader, true); if (requireVertexStores) { context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS); } } struct MiscTestParams { tcu::Maybe taskCount; uint32_t meshCount; uint32_t width; uint32_t height; MiscTestParams (const tcu::Maybe& taskCount_, uint32_t meshCount_, uint32_t width_, uint32_t height_) : taskCount (taskCount_) , meshCount (meshCount_) , width (width_) , height (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)); // Color blending. const auto colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT); const VkPipelineColorBlendAttachmentState blendAttState = { VK_TRUE, // VkBool32 blendEnable; VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; VK_BLEND_FACTOR_ONE, // VkBlendFactor dstColorBlendFactor; VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp; VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor; VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp; colorWriteMask, // VkColorComponentFlags colorWriteMask; }; const VkPipelineColorBlendStateCreateInfo colorBlendInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; nullptr, // const void* pNext; 0u, // VkPipelineColorBlendStateCreateFlags flags; VK_FALSE, // VkBool32 logicOpEnable; VK_LOGIC_OP_OR, // VkLogicOp logicOp; 1u, // uint32_t attachmentCount; &blendAttState, // const VkPipelineColorBlendAttachmentState* pAttachments; { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4]; }; const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(), taskShader.get(), meshShader.get(), fragShader.get(), renderPass.get(), viewports, scissors, 0u/*subpass*/, nullptr, nullptr, nullptr, &colorBlendInfo); // 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 { NoPrimitivesParams (const tcu::Maybe& taskCount_, uint32_t meshCount_, uint32_t width_, uint32_t height_, PrimitiveType primitiveType_) : MiscTestParams (taskCount_, meshCount_, width_, height_) , primitiveType (primitiveType_) {} 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" << " memoryBarrierShared();\n" << " barrier();\n" << " atomicAdd(sumOfIds, td.localInvocations[gl_LocalInvocationID.x]);\n" << " memoryBarrierShared();\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" << "memoryBarrierShared();\n" << "barrier();\n" << "atomicAdd(counter, 1u);\n" << "memoryBarrierShared();\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 { MemoryBarrierParams (const tcu::Maybe& taskCount_, uint32_t meshCount_, uint32_t width_, uint32_t height_, MemoryBarrierType memBarrierType_) : MiscTestParams (taskCount_, meshCount_, width_, height_) , memBarrierType (memBarrierType_) {} 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. // 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 << tcu::TestLog::Message << "Comparing result with reference " << i << "..." << tcu::TestLog::EndMessage; const auto success = MeshShaderMiscInstance::verifyResult(resultAccess, *levels[i]); if (success) { log << tcu::TestLog::Message << "Match! The test has passed" << tcu::TestLog::EndMessage; good = true; break; } } return good; } void MemoryBarrierCase::initPrograms (vk::SourceCollections& programCollection) const { const auto params = dynamic_cast(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"); } // Use large work group size, large number of vertices and large number of primitives. struct MaximizeThreadsParams : public MiscTestParams { MaximizeThreadsParams (const tcu::Maybe& taskCount_, uint32_t meshCount_, uint32_t width_, uint32_t height_, uint32_t localSize_, uint32_t numVertices_, uint32_t numPrimitives_) : MiscTestParams (taskCount_, meshCount_, width_, height_) , localSize (localSize_) , numVertices (numVertices_) , numPrimitives (numPrimitives_) {} uint32_t localSize; uint32_t numVertices; uint32_t numPrimitives; void checkSupport (Context& context) const { const auto& properties = context.getMeshShaderProperties(); if (localSize > properties.maxMeshWorkGroupSize[0]) TCU_THROW(NotSupportedError, "Required local size not supported"); if (numVertices > properties.maxMeshOutputVertices) TCU_THROW(NotSupportedError, "Required number of output vertices not supported"); if (numPrimitives > properties.maxMeshOutputPrimitives) TCU_THROW(NotSupportedError, "Required number of output primitives not supported"); } }; // Focus on the number of primitives. class MaximizePrimitivesCase : public MeshShaderMiscCase { public: MaximizePrimitivesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params) : MeshShaderMiscCase (testCtx, name, description, std::move(params)) { const auto mtParams = dynamic_cast(m_params.get()); DE_ASSERT(mtParams); DE_UNREF(mtParams); // For release builds. } void initPrograms (vk::SourceCollections& programCollection) const override; void checkSupport (Context& context) const override; TestInstance* createInstance (Context& context) const override; }; class MaximizePrimitivesInstance : public MeshShaderMiscInstance { public: MaximizePrimitivesInstance (Context& context, const MiscTestParams* params) : MeshShaderMiscInstance (context, params) {} void generateReferenceLevel () override; }; TestInstance* MaximizePrimitivesCase::createInstance (Context& context) const { return new MaximizePrimitivesInstance (context, m_params.get()); } void MaximizePrimitivesCase::checkSupport (Context& context) const { MeshShaderMiscCase::checkSupport(context); const auto params = dynamic_cast(m_params.get()); params->checkSupport(context); } void MaximizePrimitivesCase::initPrograms (vk::SourceCollections& programCollection) const { const auto params = dynamic_cast(m_params.get()); DE_ASSERT(!params->needsTaskShader()); MeshShaderMiscCase::initPrograms(programCollection); // Idea behind the test: generate 128 vertices, 1 per each pixel in a 128x1 image. Then, use each vertex to generate two points, // adding the colors of each point using color blending to make sure every point is properly generated. DE_ASSERT(params->numPrimitives == params->numVertices * 2u); DE_ASSERT(params->numVertices == params->width); const auto verticesPerInvocation = params->numVertices / params->localSize; const auto primitivesPerVertex = params->numPrimitives / params->numVertices; std::ostringstream mesh; mesh << "#version 450\n" << "#extension GL_NV_mesh_shader : enable\n" << "\n" << "layout(local_size_x=" << params->localSize << ") in;\n" << "layout(points) out;\n" << "layout(max_vertices=" << params->numVertices << ", max_primitives=" << params->numPrimitives << ") out;\n" << "\n" << "layout (location=0) out perprimitiveNV vec4 pointColor[];\n" << "\n" << "const uint verticesPerInvocation = " << verticesPerInvocation << ";\n" << "const uint primitivesPerVertex = " << primitivesPerVertex << ";\n" << "\n" << "vec4 colors[primitivesPerVertex] = vec4[](\n" << " vec4(0.0, 0.0, 1.0, 1.0),\n" << " vec4(1.0, 0.0, 0.0, 1.0)\n" << ");\n" << "void main ()\n" << "{\n" << " gl_PrimitiveCountNV = " << params->numPrimitives << ";\n" << " const uint firstVertex = gl_LocalInvocationIndex * verticesPerInvocation;\n" << " for (uint i = 0u; i < verticesPerInvocation; ++i)\n" << " {\n" << " const uint vertexNumber = firstVertex + i;\n" << " const float xCoord = ((float(vertexNumber) + 0.5) / " << params->width << ".0) * 2.0 - 1.0;\n" << " const float yCoord = 0.0;\n" << " gl_MeshVerticesNV[vertexNumber].gl_Position = vec4(xCoord, yCoord, 0.0f, 1.0f);\n" << " gl_MeshVerticesNV[vertexNumber].gl_PointSize = 1.0f;\n" << " for (uint j = 0u; j < primitivesPerVertex; ++j)\n" << " {\n" << " const uint primitiveNumber = vertexNumber * primitivesPerVertex + j;\n" << " gl_PrimitiveIndicesNV[primitiveNumber] = vertexNumber;\n" << " pointColor[primitiveNumber] = colors[j];\n" << " }\n" << " }\n" << "}\n" ; programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()); } void MaximizePrimitivesInstance::generateReferenceLevel () { generateSolidRefLevel(tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel); } // Focus on the number of vertices. class MaximizeVerticesCase : public MeshShaderMiscCase { public: MaximizeVerticesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params) : MeshShaderMiscCase (testCtx, name, description, std::move(params)) { const auto mtParams = dynamic_cast(m_params.get()); DE_ASSERT(mtParams); DE_UNREF(mtParams); // For release builds. } void initPrograms (vk::SourceCollections& programCollection) const override; void checkSupport (Context& context) const override; TestInstance* createInstance (Context& context) const override; }; class MaximizeVerticesInstance : public MeshShaderMiscInstance { public: MaximizeVerticesInstance (Context& context, const MiscTestParams* params) : MeshShaderMiscInstance (context, params) {} void generateReferenceLevel () override; }; TestInstance* MaximizeVerticesCase::createInstance (Context& context) const { return new MaximizeVerticesInstance (context, m_params.get()); } void MaximizeVerticesCase::checkSupport (Context& context) const { MeshShaderMiscCase::checkSupport(context); const auto params = dynamic_cast(m_params.get()); params->checkSupport(context); } void MaximizeVerticesCase::initPrograms (vk::SourceCollections& programCollection) const { const auto params = dynamic_cast(m_params.get()); DE_ASSERT(!params->needsTaskShader()); MeshShaderMiscCase::initPrograms(programCollection); // Idea behind the test: cover a framebuffer using a triangle quad per pixel (4 vertices, 2 triangles). DE_ASSERT(params->numVertices == params->numPrimitives * 2u); DE_ASSERT(params->numPrimitives == params->width * 2u); const auto pixelsPerInvocation = params->width / params->localSize; const auto verticesPerPixel = 4u; const auto primitivesPerPixel = 2u; const auto verticesPerInvocation = pixelsPerInvocation * verticesPerPixel; const auto primitivesPerInvocation = pixelsPerInvocation * primitivesPerPixel; std::ostringstream mesh; mesh << "#version 450\n" << "#extension GL_NV_mesh_shader : enable\n" << "\n" << "layout(local_size_x=" << params->localSize << ") in;\n" << "layout(triangles) out;\n" << "layout(max_vertices=" << params->numVertices << ", max_primitives=" << params->numPrimitives << ") out;\n" << "\n" << "layout (location=0) out perprimitiveNV vec4 triangleColor[];\n" << "\n" << "const uint pixelsPerInvocation = " << pixelsPerInvocation << ";\n" << "const uint verticesPerInvocation = " << verticesPerInvocation << ";\n" << "const uint primitivesPerInvocation = " << primitivesPerInvocation << ";\n" << "const uint indicesPerInvocation = primitivesPerInvocation * 3u;\n" << "const uint verticesPerPixel = " << verticesPerPixel << ";\n" << "const uint primitivesPerPixel = " << primitivesPerPixel << ";\n" << "const uint indicesPerPixel = primitivesPerPixel * 3u;\n" << "\n" << "void main ()\n" << "{\n" << " gl_PrimitiveCountNV = " << params->numPrimitives << ";\n" << "\n" << " const uint firstPixel = gl_LocalInvocationIndex * pixelsPerInvocation;\n" << " const float pixelWidth = 2.0 / float(" << params->width << ");\n" << " const float quarterWidth = pixelWidth / 4.0;\n" << "\n" << " for (uint pixelIdx = 0u; pixelIdx < pixelsPerInvocation; ++pixelIdx)\n" << " {\n" << " const uint pixelId = firstPixel + pixelIdx;\n" << " const float pixelCenter = (float(pixelId) + 0.5) / float(" << params->width << ") * 2.0 - 1.0;\n" << " const float left = pixelCenter - quarterWidth;\n" << " const float right = pixelCenter + quarterWidth;\n" << "\n" << " const uint firstVertex = gl_LocalInvocationIndex * verticesPerInvocation + pixelIdx * verticesPerPixel;\n" << " gl_MeshVerticesNV[firstVertex + 0].gl_Position = vec4(left, -1.0, 0.0f, 1.0f);\n" << " gl_MeshVerticesNV[firstVertex + 1].gl_Position = vec4(left, 1.0, 0.0f, 1.0f);\n" << " gl_MeshVerticesNV[firstVertex + 2].gl_Position = vec4(right, -1.0, 0.0f, 1.0f);\n" << " gl_MeshVerticesNV[firstVertex + 3].gl_Position = vec4(right, 1.0, 0.0f, 1.0f);\n" << "\n" << " const uint firstPrimitive = gl_LocalInvocationIndex * primitivesPerInvocation + pixelIdx * primitivesPerPixel;\n" << " triangleColor[firstPrimitive + 0] = vec4(0.0, 0.0, 1.0, 1.0);\n" << " triangleColor[firstPrimitive + 1] = vec4(0.0, 0.0, 1.0, 1.0);\n" << "\n" << " const uint firstIndex = gl_LocalInvocationIndex * indicesPerInvocation + pixelIdx * indicesPerPixel;\n" << " gl_PrimitiveIndicesNV[firstIndex + 0] = firstVertex + 0;\n" << " gl_PrimitiveIndicesNV[firstIndex + 1] = firstVertex + 1;\n" << " gl_PrimitiveIndicesNV[firstIndex + 2] = firstVertex + 2;\n" << " gl_PrimitiveIndicesNV[firstIndex + 3] = firstVertex + 1;\n" << " gl_PrimitiveIndicesNV[firstIndex + 4] = firstVertex + 3;\n" << " gl_PrimitiveIndicesNV[firstIndex + 5] = firstVertex + 2;\n" << " }\n" << "}\n" ; programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()); } void MaximizeVerticesInstance::generateReferenceLevel () { generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel); } // Focus on the number of invocations. class MaximizeInvocationsCase : public MeshShaderMiscCase { public: MaximizeInvocationsCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params) : MeshShaderMiscCase (testCtx, name, description, std::move(params)) { const auto mtParams = dynamic_cast(m_params.get()); DE_ASSERT(mtParams); DE_UNREF(mtParams); // For release builds. } void initPrograms (vk::SourceCollections& programCollection) const override; void checkSupport (Context& context) const override; TestInstance* createInstance (Context& context) const override; }; class MaximizeInvocationsInstance : public MeshShaderMiscInstance { public: MaximizeInvocationsInstance (Context& context, const MiscTestParams* params) : MeshShaderMiscInstance (context, params) {} void generateReferenceLevel () override; }; TestInstance* MaximizeInvocationsCase::createInstance (Context& context) const { return new MaximizeInvocationsInstance (context, m_params.get()); } void MaximizeInvocationsCase::checkSupport (Context& context) const { MeshShaderMiscCase::checkSupport(context); const auto params = dynamic_cast(m_params.get()); params->checkSupport(context); } void MaximizeInvocationsCase::initPrograms (vk::SourceCollections& programCollection) const { const auto params = dynamic_cast(m_params.get()); DE_ASSERT(!params->needsTaskShader()); MeshShaderMiscCase::initPrograms(programCollection); // Idea behind the test: use two invocations to generate one point per framebuffer pixel. DE_ASSERT(params->localSize == params->width * 2u); DE_ASSERT(params->localSize == params->numPrimitives * 2u); DE_ASSERT(params->localSize == params->numVertices * 2u); std::ostringstream mesh; mesh << "#version 450\n" << "#extension GL_NV_mesh_shader : enable\n" << "\n" << "layout(local_size_x=" << params->localSize << ") in;\n" << "layout(points) out;\n" << "layout(max_vertices=" << params->numVertices << ", max_primitives=" << params->numPrimitives << ") out;\n" << "\n" << "layout (location=0) out perprimitiveNV vec4 pointColor[];\n" << "\n" << "void main ()\n" << "{\n" << " gl_PrimitiveCountNV = " << params->numPrimitives << ";\n" << " const uint pixelId = gl_LocalInvocationIndex / 2u;\n" << " if (gl_LocalInvocationIndex % 2u == 0u)\n" << " {\n" << " const float xCoord = (float(pixelId) + 0.5) / float(" << params->width << ") * 2.0 - 1.0;\n" << " gl_MeshVerticesNV[pixelId].gl_Position = vec4(xCoord, 0.0, 0.0f, 1.0f);\n" << " gl_MeshVerticesNV[pixelId].gl_PointSize = 1.0f;\n" << " }\n" << " else\n" << " {\n" << " gl_PrimitiveIndicesNV[pixelId] = pixelId;\n" << " pointColor[pixelId] = vec4(0.0, 0.0, 1.0, 1.0);\n" << " }\n" << "}\n" ; programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()); } void MaximizeInvocationsInstance::generateReferenceLevel () { generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel); } // Tests checking varied interfaces between task, mesh and frag. enum class Owner { VERTEX = 0, PRIMITIVE, }; enum class DataType { INTEGER = 0, FLOAT, }; // Note: 8-bit variables not available for Input/Output. enum class BitWidth { B64 = 64, B32 = 32, B16 = 16, }; enum class DataDim { SCALAR = 1, VEC2 = 2, VEC3 = 3, VEC4 = 4, }; enum class Interpolation { NORMAL = 0, FLAT, }; enum class Direction { IN = 0, OUT, }; // Interface variable. struct IfaceVar { static constexpr uint32_t kNumVertices = 4u; static constexpr uint32_t kNumPrimitives = 2u; static constexpr uint32_t kVarsPerType = 2u; IfaceVar (Owner owner_, DataType dataType_, BitWidth bitWidth_, DataDim dataDim_, Interpolation interpolation_, uint32_t index_) : owner (owner_) , dataType (dataType_) , bitWidth (bitWidth_) , dataDim (dataDim_) , interpolation (interpolation_) , index (index_) { DE_ASSERT(!(dataType == DataType::INTEGER && interpolation == Interpolation::NORMAL)); DE_ASSERT(!(owner == Owner::PRIMITIVE && interpolation == Interpolation::NORMAL)); DE_ASSERT(!(dataType == DataType::FLOAT && bitWidth == BitWidth::B64 && interpolation == Interpolation::NORMAL)); DE_ASSERT(index < kVarsPerType); } // This constructor needs to be defined for the code to compile, but it should never be actually called. // To make sure it's not used, the index is defined to be very large, which should trigger the assertion in getName() below. IfaceVar () : owner (Owner::VERTEX) , dataType (DataType::FLOAT) , bitWidth (BitWidth::B32) , dataDim (DataDim::VEC4) , interpolation (Interpolation::NORMAL) , index (std::numeric_limits::max()) { } Owner owner; DataType dataType; BitWidth bitWidth; DataDim dataDim; Interpolation interpolation; uint32_t index; // In case there are several variables matching this type. // The variable name will be unique and depend on its type. std::string getName () const { DE_ASSERT(index < kVarsPerType); std::ostringstream name; name << ((owner == Owner::VERTEX) ? "vert" : "prim") << "_" << ((dataType == DataType::INTEGER) ? "i" : "f") << static_cast(bitWidth) << "d" << static_cast(dataDim) << "_" << ((interpolation == Interpolation::NORMAL) ? "inter" : "flat") << "_" << index ; return name.str(); } // Get location size according to the type. uint32_t getLocationSize () const { return ((bitWidth == BitWidth::B64 && dataDim >= DataDim::VEC3) ? 2u : 1u); } // Get the variable type in GLSL. std::string getGLSLType () const { const auto widthStr = std::to_string(static_cast(bitWidth)); const auto dimStr = std::to_string(static_cast(dataDim)); const auto shortTypeStr = ((dataType == DataType::INTEGER) ? "i" : "f"); const auto typeStr = ((dataType == DataType::INTEGER) ? "int" : "float"); if (dataDim == DataDim::SCALAR) return typeStr + widthStr + "_t"; // e.g. int32_t or float16_t return shortTypeStr + widthStr + "vec" + dimStr; // e.g. i16vec2 or f64vec4. } // Get a simple declaration of type and name. This can be reused for several things. std::string getTypeAndName () const { return getGLSLType() + " " + getName(); } std::string getTypeAndNameDecl (bool arrayDecl = false) const { std::ostringstream decl; decl << " " << getTypeAndName(); if (arrayDecl) decl << "[" << ((owner == Owner::PRIMITIVE) ? IfaceVar::kNumPrimitives : IfaceVar::kNumVertices) << "]"; decl << ";\n"; return decl.str(); } // Variable declaration statement given its location and direction. std::string getLocationDecl (size_t location, Direction direction) const { std::ostringstream decl; decl << "layout (location=" << location << ") " << ((direction == Direction::IN) ? "in" : "out") << " " << ((owner == Owner::PRIMITIVE) ? "perprimitiveNV " : "") << ((interpolation == Interpolation::FLAT) ? "flat " : "") << getTypeAndName() << ((direction == Direction::OUT) ? "[]" : "") << ";\n" ; return decl.str(); } // Get the name of the source data for this variable. Tests will use a storage buffer for the per-vertex data and a uniform // buffer for the per-primitive data. The names in those will match. std::string getDataSourceName () const { // per-primitive data or per-vertex data buffers. return ((owner == Owner::PRIMITIVE) ? "ppd" : "pvd") + ("." + getName()); } // Get the boolean check variable name (see below). std::string getCheckName () const { return "good_" + getName(); } // Get the check statement that would be used in the fragment shader. std::string getCheckStatement () const { std::ostringstream check; const auto sourceName = getDataSourceName(); const auto glslType = getGLSLType(); const auto name = getName(); check << " bool " << getCheckName() << " = "; if (owner == Owner::VERTEX) { // There will be 4 values in the buffers. std::ostringstream maxElem; std::ostringstream minElem; maxElem << glslType << "(max(max(max(" << sourceName << "[0], " << sourceName << "[1]), " << sourceName << "[2]), " << sourceName << "[3]))"; minElem << glslType << "(min(min(min(" << sourceName << "[0], " << sourceName << "[1]), " << sourceName << "[2]), " << sourceName << "[3]))"; if (dataDim == DataDim::SCALAR) { check << "(" << name << " <= " << maxElem.str() << ") && (" << name << " >= " << minElem.str() << ")"; } else { check << "all(lessThanEqual(" << name << ", " << maxElem.str() << ")) && " << "all(greaterThanEqual(" << name << ", " << minElem.str() << "))"; } } else if (owner == Owner::PRIMITIVE) { // There will be 2 values in the buffers. check << "((gl_PrimitiveID == 0 || gl_PrimitiveID == 1) && (" << "(gl_PrimitiveID == 0 && " << name << " == " << sourceName << "[0]) || " << "(gl_PrimitiveID == 1 && " << name << " == " << sourceName << "[1])))"; } check << ";\n"; return check.str(); } // Get an assignment statement for an out variable. std::string getAssignmentStatement (size_t arrayIndex, const std::string& leftPrefix, const std::string& rightPrefix) const { const auto name = getName(); const auto typeStr = getGLSLType(); std::ostringstream stmt; stmt << " " << leftPrefix << (leftPrefix.empty() ? "" : ".") << name << "[" << arrayIndex << "] = " << typeStr << "(" << rightPrefix << (rightPrefix.empty() ? "" : ".") << name << "[" << arrayIndex << "]);\n"; return stmt.str(); } // Get the corresponding array size based on the owner (vertex or primitive) uint32_t getArraySize () const { return ((owner == Owner::PRIMITIVE) ? IfaceVar::kNumPrimitives : IfaceVar::kNumVertices); } }; using IfaceVarVec = std::vector; using IfaceVarVecPtr = std::unique_ptr; struct InterfaceVariableParams : public MiscTestParams { InterfaceVariableParams (const tcu::Maybe& taskCount_, uint32_t meshCount_, uint32_t width_, uint32_t height_, bool useInt64_, bool useFloat64_, bool useInt16_, bool useFloat16_, IfaceVarVecPtr vars_) : MiscTestParams (taskCount_, meshCount_, width_, height_) , useInt64 (useInt64_) , useFloat64 (useFloat64_) , useInt16 (useInt16_) , useFloat16 (useFloat16_) , ifaceVars (std::move(vars_)) {} // These need to match the list of interface variables. bool useInt64; bool useFloat64; bool useInt16; bool useFloat16; IfaceVarVecPtr ifaceVars; }; class InterfaceVariablesCase : public MeshShaderMiscCase { public: InterfaceVariablesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, ParamsPtr params) : MeshShaderMiscCase(testCtx, name, description, std::move(params)) { } virtual ~InterfaceVariablesCase (void) {} TestInstance* createInstance (Context& context) const override; void checkSupport (Context& context) const override; void initPrograms (vk::SourceCollections& programCollection) const override; // Note data types in the input buffers are always plain floats or ints. They will be converted to the appropriate type when // copying them in or out of output variables. Note we have two variables per type, as per IfaceVar::kVarsPerType. struct PerVertexData { // Interpolated floats. tcu::Vec4 vert_f64d4_inter_0[IfaceVar::kNumVertices]; tcu::Vec4 vert_f64d4_inter_1[IfaceVar::kNumVertices]; tcu::Vec3 vert_f64d3_inter_0[IfaceVar::kNumVertices]; tcu::Vec3 vert_f64d3_inter_1[IfaceVar::kNumVertices]; tcu::Vec2 vert_f64d2_inter_0[IfaceVar::kNumVertices]; tcu::Vec2 vert_f64d2_inter_1[IfaceVar::kNumVertices]; float vert_f64d1_inter_0[IfaceVar::kNumVertices]; float vert_f64d1_inter_1[IfaceVar::kNumVertices]; tcu::Vec4 vert_f32d4_inter_0[IfaceVar::kNumVertices]; tcu::Vec4 vert_f32d4_inter_1[IfaceVar::kNumVertices]; tcu::Vec3 vert_f32d3_inter_0[IfaceVar::kNumVertices]; tcu::Vec3 vert_f32d3_inter_1[IfaceVar::kNumVertices]; tcu::Vec2 vert_f32d2_inter_0[IfaceVar::kNumVertices]; tcu::Vec2 vert_f32d2_inter_1[IfaceVar::kNumVertices]; float vert_f32d1_inter_0[IfaceVar::kNumVertices]; float vert_f32d1_inter_1[IfaceVar::kNumVertices]; tcu::Vec4 vert_f16d4_inter_0[IfaceVar::kNumVertices]; tcu::Vec4 vert_f16d4_inter_1[IfaceVar::kNumVertices]; tcu::Vec3 vert_f16d3_inter_0[IfaceVar::kNumVertices]; tcu::Vec3 vert_f16d3_inter_1[IfaceVar::kNumVertices]; tcu::Vec2 vert_f16d2_inter_0[IfaceVar::kNumVertices]; tcu::Vec2 vert_f16d2_inter_1[IfaceVar::kNumVertices]; float vert_f16d1_inter_0[IfaceVar::kNumVertices]; float vert_f16d1_inter_1[IfaceVar::kNumVertices]; // Flat floats. tcu::Vec4 vert_f64d4_flat_0[IfaceVar::kNumVertices]; tcu::Vec4 vert_f64d4_flat_1[IfaceVar::kNumVertices]; tcu::Vec3 vert_f64d3_flat_0[IfaceVar::kNumVertices]; tcu::Vec3 vert_f64d3_flat_1[IfaceVar::kNumVertices]; tcu::Vec2 vert_f64d2_flat_0[IfaceVar::kNumVertices]; tcu::Vec2 vert_f64d2_flat_1[IfaceVar::kNumVertices]; float vert_f64d1_flat_0[IfaceVar::kNumVertices]; float vert_f64d1_flat_1[IfaceVar::kNumVertices]; tcu::Vec4 vert_f32d4_flat_0[IfaceVar::kNumVertices]; tcu::Vec4 vert_f32d4_flat_1[IfaceVar::kNumVertices]; tcu::Vec3 vert_f32d3_flat_0[IfaceVar::kNumVertices]; tcu::Vec3 vert_f32d3_flat_1[IfaceVar::kNumVertices]; tcu::Vec2 vert_f32d2_flat_0[IfaceVar::kNumVertices]; tcu::Vec2 vert_f32d2_flat_1[IfaceVar::kNumVertices]; float vert_f32d1_flat_0[IfaceVar::kNumVertices]; float vert_f32d1_flat_1[IfaceVar::kNumVertices]; tcu::Vec4 vert_f16d4_flat_0[IfaceVar::kNumVertices]; tcu::Vec4 vert_f16d4_flat_1[IfaceVar::kNumVertices]; tcu::Vec3 vert_f16d3_flat_0[IfaceVar::kNumVertices]; tcu::Vec3 vert_f16d3_flat_1[IfaceVar::kNumVertices]; tcu::Vec2 vert_f16d2_flat_0[IfaceVar::kNumVertices]; tcu::Vec2 vert_f16d2_flat_1[IfaceVar::kNumVertices]; float vert_f16d1_flat_0[IfaceVar::kNumVertices]; float vert_f16d1_flat_1[IfaceVar::kNumVertices]; // Flat ints. tcu::IVec4 vert_i64d4_flat_0[IfaceVar::kNumVertices]; tcu::IVec4 vert_i64d4_flat_1[IfaceVar::kNumVertices]; tcu::IVec3 vert_i64d3_flat_0[IfaceVar::kNumVertices]; tcu::IVec3 vert_i64d3_flat_1[IfaceVar::kNumVertices]; tcu::IVec2 vert_i64d2_flat_0[IfaceVar::kNumVertices]; tcu::IVec2 vert_i64d2_flat_1[IfaceVar::kNumVertices]; int32_t vert_i64d1_flat_0[IfaceVar::kNumVertices]; int32_t vert_i64d1_flat_1[IfaceVar::kNumVertices]; tcu::IVec4 vert_i32d4_flat_0[IfaceVar::kNumVertices]; tcu::IVec4 vert_i32d4_flat_1[IfaceVar::kNumVertices]; tcu::IVec3 vert_i32d3_flat_0[IfaceVar::kNumVertices]; tcu::IVec3 vert_i32d3_flat_1[IfaceVar::kNumVertices]; tcu::IVec2 vert_i32d2_flat_0[IfaceVar::kNumVertices]; tcu::IVec2 vert_i32d2_flat_1[IfaceVar::kNumVertices]; int32_t vert_i32d1_flat_0[IfaceVar::kNumVertices]; int32_t vert_i32d1_flat_1[IfaceVar::kNumVertices]; tcu::IVec4 vert_i16d4_flat_0[IfaceVar::kNumVertices]; tcu::IVec4 vert_i16d4_flat_1[IfaceVar::kNumVertices]; tcu::IVec3 vert_i16d3_flat_0[IfaceVar::kNumVertices]; tcu::IVec3 vert_i16d3_flat_1[IfaceVar::kNumVertices]; tcu::IVec2 vert_i16d2_flat_0[IfaceVar::kNumVertices]; tcu::IVec2 vert_i16d2_flat_1[IfaceVar::kNumVertices]; int32_t vert_i16d1_flat_0[IfaceVar::kNumVertices]; int32_t vert_i16d1_flat_1[IfaceVar::kNumVertices]; }; struct PerPrimitiveData { // Flat floats. tcu::Vec4 prim_f64d4_flat_0[IfaceVar::kNumPrimitives]; tcu::Vec4 prim_f64d4_flat_1[IfaceVar::kNumPrimitives]; tcu::Vec3 prim_f64d3_flat_0[IfaceVar::kNumPrimitives]; tcu::Vec3 prim_f64d3_flat_1[IfaceVar::kNumPrimitives]; tcu::Vec2 prim_f64d2_flat_0[IfaceVar::kNumPrimitives]; tcu::Vec2 prim_f64d2_flat_1[IfaceVar::kNumPrimitives]; float prim_f64d1_flat_0[IfaceVar::kNumPrimitives]; float prim_f64d1_flat_1[IfaceVar::kNumPrimitives]; tcu::Vec4 prim_f32d4_flat_0[IfaceVar::kNumPrimitives]; tcu::Vec4 prim_f32d4_flat_1[IfaceVar::kNumPrimitives]; tcu::Vec3 prim_f32d3_flat_0[IfaceVar::kNumPrimitives]; tcu::Vec3 prim_f32d3_flat_1[IfaceVar::kNumPrimitives]; tcu::Vec2 prim_f32d2_flat_0[IfaceVar::kNumPrimitives]; tcu::Vec2 prim_f32d2_flat_1[IfaceVar::kNumPrimitives]; float prim_f32d1_flat_0[IfaceVar::kNumPrimitives]; float prim_f32d1_flat_1[IfaceVar::kNumPrimitives]; tcu::Vec4 prim_f16d4_flat_0[IfaceVar::kNumPrimitives]; tcu::Vec4 prim_f16d4_flat_1[IfaceVar::kNumPrimitives]; tcu::Vec3 prim_f16d3_flat_0[IfaceVar::kNumPrimitives]; tcu::Vec3 prim_f16d3_flat_1[IfaceVar::kNumPrimitives]; tcu::Vec2 prim_f16d2_flat_0[IfaceVar::kNumPrimitives]; tcu::Vec2 prim_f16d2_flat_1[IfaceVar::kNumPrimitives]; float prim_f16d1_flat_0[IfaceVar::kNumPrimitives]; float prim_f16d1_flat_1[IfaceVar::kNumPrimitives]; // Flat ints. tcu::IVec4 prim_i64d4_flat_0[IfaceVar::kNumPrimitives]; tcu::IVec4 prim_i64d4_flat_1[IfaceVar::kNumPrimitives]; tcu::IVec3 prim_i64d3_flat_0[IfaceVar::kNumPrimitives]; tcu::IVec3 prim_i64d3_flat_1[IfaceVar::kNumPrimitives]; tcu::IVec2 prim_i64d2_flat_0[IfaceVar::kNumPrimitives]; tcu::IVec2 prim_i64d2_flat_1[IfaceVar::kNumPrimitives]; int32_t prim_i64d1_flat_0[IfaceVar::kNumPrimitives]; int32_t prim_i64d1_flat_1[IfaceVar::kNumPrimitives]; tcu::IVec4 prim_i32d4_flat_0[IfaceVar::kNumPrimitives]; tcu::IVec4 prim_i32d4_flat_1[IfaceVar::kNumPrimitives]; tcu::IVec3 prim_i32d3_flat_0[IfaceVar::kNumPrimitives]; tcu::IVec3 prim_i32d3_flat_1[IfaceVar::kNumPrimitives]; tcu::IVec2 prim_i32d2_flat_0[IfaceVar::kNumPrimitives]; tcu::IVec2 prim_i32d2_flat_1[IfaceVar::kNumPrimitives]; int32_t prim_i32d1_flat_0[IfaceVar::kNumPrimitives]; int32_t prim_i32d1_flat_1[IfaceVar::kNumPrimitives]; tcu::IVec4 prim_i16d4_flat_0[IfaceVar::kNumPrimitives]; tcu::IVec4 prim_i16d4_flat_1[IfaceVar::kNumPrimitives]; tcu::IVec3 prim_i16d3_flat_0[IfaceVar::kNumPrimitives]; tcu::IVec3 prim_i16d3_flat_1[IfaceVar::kNumPrimitives]; tcu::IVec2 prim_i16d2_flat_0[IfaceVar::kNumPrimitives]; tcu::IVec2 prim_i16d2_flat_1[IfaceVar::kNumPrimitives]; int32_t prim_i16d1_flat_0[IfaceVar::kNumPrimitives]; int32_t prim_i16d1_flat_1[IfaceVar::kNumPrimitives]; }; static constexpr uint32_t kGlslangBuiltInCount = 11u; static constexpr uint32_t kMaxLocations = 16u; }; class InterfaceVariablesInstance : public MeshShaderMiscInstance { public: InterfaceVariablesInstance (Context& context, const MiscTestParams* params) : MeshShaderMiscInstance(context, params) {} virtual ~InterfaceVariablesInstance (void) {} void generateReferenceLevel () override; tcu::TestStatus iterate (void) override; }; TestInstance* InterfaceVariablesCase::createInstance (Context& context) const { return new InterfaceVariablesInstance(context, m_params.get()); } void InterfaceVariablesCase::checkSupport (Context& context) const { const auto params = dynamic_cast(m_params.get()); DE_ASSERT(params); MeshShaderMiscCase::checkSupport(context); if (params->useFloat64) context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_FLOAT64); if (params->useInt64) context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_INT64); if (params->useInt16) context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_INT16); if (params->useFloat16) { const auto& features = context.getShaderFloat16Int8Features(); if (!features.shaderFloat16) TCU_THROW(NotSupportedError, "shaderFloat16 feature not supported"); } if (params->useInt16 || params->useFloat16) { const auto& features = context.get16BitStorageFeatures(); if (!features.storageInputOutput16) TCU_THROW(NotSupportedError, "storageInputOutput16 feature not supported"); } // glslang will use several built-ins in the generated mesh code, which count against the location and component limits. { const auto neededComponents = (kGlslangBuiltInCount + kMaxLocations) * 4u; const auto& properties = context.getDeviceProperties(); if (neededComponents > properties.limits.maxFragmentInputComponents) TCU_THROW(NotSupportedError, "maxFragmentInputComponents too low to run this test"); } } void InterfaceVariablesCase::initPrograms (vk::SourceCollections& programCollection) const { // Bindings needs to match the PerVertexData and PerPrimitiveData structures. std::ostringstream bindings; bindings << "layout(set=0, binding=0, std430) readonly buffer PerVertexBlock {\n" << " vec4 vert_f64d4_inter_0[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f64d4_inter_1[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f64d3_inter_0[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f64d3_inter_1[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f64d2_inter_0[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f64d2_inter_1[" << IfaceVar::kNumVertices << "];\n" << " float vert_f64d1_inter_0[" << IfaceVar::kNumVertices << "];\n" << " float vert_f64d1_inter_1[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f32d4_inter_0[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f32d4_inter_1[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f32d3_inter_0[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f32d3_inter_1[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f32d2_inter_0[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f32d2_inter_1[" << IfaceVar::kNumVertices << "];\n" << " float vert_f32d1_inter_0[" << IfaceVar::kNumVertices << "];\n" << " float vert_f32d1_inter_1[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f16d4_inter_0[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f16d4_inter_1[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f16d3_inter_0[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f16d3_inter_1[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f16d2_inter_0[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f16d2_inter_1[" << IfaceVar::kNumVertices << "];\n" << " float vert_f16d1_inter_0[" << IfaceVar::kNumVertices << "];\n" << " float vert_f16d1_inter_1[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f64d4_flat_0[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f64d4_flat_1[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f64d3_flat_0[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f64d3_flat_1[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f64d2_flat_0[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f64d2_flat_1[" << IfaceVar::kNumVertices << "];\n" << " float vert_f64d1_flat_0[" << IfaceVar::kNumVertices << "];\n" << " float vert_f64d1_flat_1[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f32d4_flat_0[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f32d4_flat_1[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f32d3_flat_0[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f32d3_flat_1[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f32d2_flat_0[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f32d2_flat_1[" << IfaceVar::kNumVertices << "];\n" << " float vert_f32d1_flat_0[" << IfaceVar::kNumVertices << "];\n" << " float vert_f32d1_flat_1[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f16d4_flat_0[" << IfaceVar::kNumVertices << "];\n" << " vec4 vert_f16d4_flat_1[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f16d3_flat_0[" << IfaceVar::kNumVertices << "];\n" << " vec3 vert_f16d3_flat_1[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f16d2_flat_0[" << IfaceVar::kNumVertices << "];\n" << " vec2 vert_f16d2_flat_1[" << IfaceVar::kNumVertices << "];\n" << " float vert_f16d1_flat_0[" << IfaceVar::kNumVertices << "];\n" << " float vert_f16d1_flat_1[" << IfaceVar::kNumVertices << "];\n" << " ivec4 vert_i64d4_flat_0[" << IfaceVar::kNumVertices << "];\n" << " ivec4 vert_i64d4_flat_1[" << IfaceVar::kNumVertices << "];\n" << " ivec3 vert_i64d3_flat_0[" << IfaceVar::kNumVertices << "];\n" << " ivec3 vert_i64d3_flat_1[" << IfaceVar::kNumVertices << "];\n" << " ivec2 vert_i64d2_flat_0[" << IfaceVar::kNumVertices << "];\n" << " ivec2 vert_i64d2_flat_1[" << IfaceVar::kNumVertices << "];\n" << " int vert_i64d1_flat_0[" << IfaceVar::kNumVertices << "];\n" << " int vert_i64d1_flat_1[" << IfaceVar::kNumVertices << "];\n" << " ivec4 vert_i32d4_flat_0[" << IfaceVar::kNumVertices << "];\n" << " ivec4 vert_i32d4_flat_1[" << IfaceVar::kNumVertices << "];\n" << " ivec3 vert_i32d3_flat_0[" << IfaceVar::kNumVertices << "];\n" << " ivec3 vert_i32d3_flat_1[" << IfaceVar::kNumVertices << "];\n" << " ivec2 vert_i32d2_flat_0[" << IfaceVar::kNumVertices << "];\n" << " ivec2 vert_i32d2_flat_1[" << IfaceVar::kNumVertices << "];\n" << " int vert_i32d1_flat_0[" << IfaceVar::kNumVertices << "];\n" << " int vert_i32d1_flat_1[" << IfaceVar::kNumVertices << "];\n" << " ivec4 vert_i16d4_flat_0[" << IfaceVar::kNumVertices << "];\n" << " ivec4 vert_i16d4_flat_1[" << IfaceVar::kNumVertices << "];\n" << " ivec3 vert_i16d3_flat_0[" << IfaceVar::kNumVertices << "];\n" << " ivec3 vert_i16d3_flat_1[" << IfaceVar::kNumVertices << "];\n" << " ivec2 vert_i16d2_flat_0[" << IfaceVar::kNumVertices << "];\n" << " ivec2 vert_i16d2_flat_1[" << IfaceVar::kNumVertices << "];\n" << " int vert_i16d1_flat_0[" << IfaceVar::kNumVertices << "];\n" << " int vert_i16d1_flat_1[" << IfaceVar::kNumVertices << "];\n" << " } pvd;\n" << "\n" << "layout(set=0, binding=1, std430) readonly buffer PerPrimitiveBlock {\n" << " vec4 prim_f64d4_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " vec4 prim_f64d4_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " vec3 prim_f64d3_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " vec3 prim_f64d3_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " vec2 prim_f64d2_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " vec2 prim_f64d2_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " float prim_f64d1_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " float prim_f64d1_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " vec4 prim_f32d4_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " vec4 prim_f32d4_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " vec3 prim_f32d3_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " vec3 prim_f32d3_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " vec2 prim_f32d2_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " vec2 prim_f32d2_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " float prim_f32d1_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " float prim_f32d1_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " vec4 prim_f16d4_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " vec4 prim_f16d4_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " vec3 prim_f16d3_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " vec3 prim_f16d3_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " vec2 prim_f16d2_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " vec2 prim_f16d2_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " float prim_f16d1_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " float prim_f16d1_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " ivec4 prim_i64d4_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " ivec4 prim_i64d4_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " ivec3 prim_i64d3_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " ivec3 prim_i64d3_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " ivec2 prim_i64d2_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " ivec2 prim_i64d2_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " int prim_i64d1_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " int prim_i64d1_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " ivec4 prim_i32d4_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " ivec4 prim_i32d4_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " ivec3 prim_i32d3_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " ivec3 prim_i32d3_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " ivec2 prim_i32d2_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " ivec2 prim_i32d2_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " int prim_i32d1_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " int prim_i32d1_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " ivec4 prim_i16d4_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " ivec4 prim_i16d4_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " ivec3 prim_i16d3_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " ivec3 prim_i16d3_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " ivec2 prim_i16d2_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " ivec2 prim_i16d2_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " int prim_i16d1_flat_0[" << IfaceVar::kNumPrimitives << "];\n" << " int prim_i16d1_flat_1[" << IfaceVar::kNumPrimitives << "];\n" << " } ppd;\n" << "\n" ; const auto bindingsDecl = bindings.str(); const auto params = dynamic_cast(m_params.get()); DE_ASSERT(params); const auto& varVec = *(params->ifaceVars); std::ostringstream frag; frag << "#version 450\n" << "#extension GL_NV_mesh_shader : enable\n" << "#extension GL_EXT_shader_explicit_arithmetic_types : enable\n" << "\n" << bindingsDecl ; // Declare interface variables as Input in the fragment shader. { uint32_t usedLocations = 0u; for (const auto& var : varVec) { frag << var.getLocationDecl(usedLocations, Direction::IN); usedLocations += var.getLocationSize(); } } frag << "\n" << "layout (location=0) out vec4 outColor;\n" << "\n" << "void main ()\n" << "{\n" ; // Emit checks for each variable value in the fragment shader. std::ostringstream allConditions; for (size_t i = 0; i < varVec.size(); ++i) { frag << varVec[i].getCheckStatement(); allConditions << ((i == 0) ? "" : " && ") << varVec[i].getCheckName(); } // Emit final check. frag << " if (" << allConditions.str() << ") {\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 taskDataStream; taskDataStream << "taskNV TaskData {\n"; for (size_t i = 0; i < varVec.size(); ++i) taskDataStream << varVec[i].getTypeAndNameDecl(/*arrayDecl*/true); taskDataStream << "} td;\n\n"; const auto taskShader = m_params->needsTaskShader(); const auto taskDataDecl = taskDataStream.str(); 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" << "#extension GL_EXT_shader_explicit_arithmetic_types : enable\n" << "\n" << "layout (local_size_x=1) in;\n" << "layout (max_primitives=" << IfaceVar::kNumPrimitives << ", max_vertices=" << IfaceVar::kNumVertices << ") out;\n" << "layout (triangles) out;\n" << "\n" ; // Declare interface variables as Output variables. { uint32_t usedLocations = 0u; for (const auto& var : varVec) { mesh << var.getLocationDecl(usedLocations, Direction::OUT); usedLocations += var.getLocationSize(); } } mesh << "out gl_MeshPerVertexNV {\n" << " vec4 gl_Position;\n" << "} gl_MeshVerticesNV[];\n" << "out perprimitiveNV gl_MeshPerPrimitiveNV {\n" << " int gl_PrimitiveID;\n" << "} gl_MeshPrimitivesNV[];\n" << "\n" << (taskShader ? "in " + taskDataDecl : bindingsDecl) << "vec4 positions[" << IfaceVar::kNumVertices << "] = vec4[](\n" << " vec4(-1.0, -1.0, 0.0, 1.0),\n" << " vec4( 1.0, -1.0, 0.0, 1.0),\n" << " vec4(-1.0, 1.0, 0.0, 1.0),\n" << " vec4( 1.0, 1.0, 0.0, 1.0)\n" << ");\n" << "\n" << "int indices[" << (IfaceVar::kNumPrimitives * 3u) << "] = int[](\n" << " 0, 1, 2, 2, 3, 1\n" << ");\n" << "\n" << "void main ()\n" << "{\n" << " gl_PrimitiveCountNV = " << IfaceVar::kNumPrimitives << ";\n" << "\n" ; // Emit positions, indices and primitive IDs. for (uint32_t i = 0; i < IfaceVar::kNumVertices; ++i) mesh << " gl_MeshVerticesNV[" << i << "].gl_Position = positions[" << i << "];\n"; mesh << "\n"; for (uint32_t i = 0; i < IfaceVar::kNumPrimitives; ++i) for (uint32_t j = 0; j < 3u; ++j) // 3 vertices per triangle { const auto arrayPos = i*3u + j; mesh << " gl_PrimitiveIndicesNV[" << arrayPos << "] = indices[" << arrayPos << "];\n"; } mesh << "\n"; for (uint32_t i = 0; i < IfaceVar::kNumPrimitives; ++i) mesh << " gl_MeshPrimitivesNV[" << i << "].gl_PrimitiveID = " << i << ";\n"; mesh << "\n"; // Copy data to output variables, either from the task data or the bindings. for (size_t i = 0; i < varVec.size(); ++i) { const auto arraySize = varVec[i].getArraySize(); const auto prefix = ((varVec[i].owner == Owner::VERTEX) ? meshPvdPrefix : meshPpdPrefix); for (uint32_t arrayIndex = 0u; arrayIndex < arraySize; ++arrayIndex) mesh << varVec[i].getAssignmentStatement(arrayIndex, "", prefix); } mesh << "\n" << "}\n" ; programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()); // Task shader if needed. if (taskShader) { const auto& meshCount = m_params->meshCount; const auto taskPvdPrefix = "pvd"; const auto taskPpdPrefix = "ppd"; std::ostringstream task; task << "#version 450\n" << "#extension GL_NV_mesh_shader : enable\n" << "#extension GL_EXT_shader_explicit_arithmetic_types : enable\n" << "\n" << "out " << taskDataDecl << bindingsDecl << "void main ()\n" << "{\n" << " gl_TaskCountNV = " << meshCount << ";\n" << "\n" ; // Copy data from bindings to the task data structure. for (size_t i = 0; i < varVec.size(); ++i) { const auto arraySize = varVec[i].getArraySize(); const auto prefix = ((varVec[i].owner == Owner::VERTEX) ? taskPvdPrefix : taskPpdPrefix); for (uint32_t arrayIndex = 0u; arrayIndex < arraySize; ++arrayIndex) task << varVec[i].getAssignmentStatement(arrayIndex, "td", prefix); } task << "}\n"; programCollection.glslSources.add("task") << glu::TaskSource(task.str()); } } void InterfaceVariablesInstance::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(); const auto blueColor = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f); tcu::clear(access, blueColor); } tcu::TestStatus InterfaceVariablesInstance::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 auto bufStages = (VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_MESH_BIT_NV | (hasTask ? VK_SHADER_STAGE_TASK_BIT_NV : 0)); 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(); // Bindings data. // The initialization statements below were generated automatically with a Python script. // Note: it works with stdin/stdout. #if 0 import re import sys # Lines look like: tcu::Vec4 vert_f64d4_inter_0[IfaceVar::kNumVertices]; lineRE = re.compile(r'^\s*(\S+)\s+(\w+)\[(\S+)\];.*$') vecRE = re.compile(r'^.*Vec(\d)$') floatSuffixes = ( (0.25, 0.50, 0.875, 0.0), (0.25, 0.75, 0.875, 0.0), (0.50, 0.50, 0.875, 0.0), (0.50, 0.75, 0.875, 0.0), ) lineCounter = 0 for line in sys.stdin: match = lineRE.search(line) if not match: continue varType = match.group(1) varName = match.group(2) varSize = match.group(3) arraySize = (4 if varSize == 'IfaceVar::kNumVertices' else 2) vecMatch = vecRE.match(varType) numComponents = (1 if not vecMatch else vecMatch.group(1)) isFlat = '_flat_' in varName lineCounter += 1 varBaseVal = 1000 + 10 * lineCounter valueTemplate = ('%s' if numComponents == 1 else '%s(%%s)' % (varType,)) for index in range(arraySize): valueStr = '' for comp in range(numComponents): compValue = varBaseVal + comp + 1 if not isFlat: compValue += floatSuffixes[index][comp] valueStr += ('' if comp == 0 else ', ') + str(compValue) value = valueTemplate % (valueStr,) statement = '%s[%s] = %s;' % (varName, index, value) print('%s' % (statement,)) #endif InterfaceVariablesCase::PerVertexData perVertexData; { perVertexData.vert_f64d4_inter_0[0] = tcu::Vec4(1011.25, 1012.5, 1013.875, 1014.0); perVertexData.vert_f64d4_inter_0[1] = tcu::Vec4(1011.25, 1012.75, 1013.875, 1014.0); perVertexData.vert_f64d4_inter_0[2] = tcu::Vec4(1011.5, 1012.5, 1013.875, 1014.0); perVertexData.vert_f64d4_inter_0[3] = tcu::Vec4(1011.5, 1012.75, 1013.875, 1014.0); perVertexData.vert_f64d4_inter_1[0] = tcu::Vec4(1021.25, 1022.5, 1023.875, 1024.0); perVertexData.vert_f64d4_inter_1[1] = tcu::Vec4(1021.25, 1022.75, 1023.875, 1024.0); perVertexData.vert_f64d4_inter_1[2] = tcu::Vec4(1021.5, 1022.5, 1023.875, 1024.0); perVertexData.vert_f64d4_inter_1[3] = tcu::Vec4(1021.5, 1022.75, 1023.875, 1024.0); perVertexData.vert_f64d3_inter_0[0] = tcu::Vec3(1031.25, 1032.5, 1033.875); perVertexData.vert_f64d3_inter_0[1] = tcu::Vec3(1031.25, 1032.75, 1033.875); perVertexData.vert_f64d3_inter_0[2] = tcu::Vec3(1031.5, 1032.5, 1033.875); perVertexData.vert_f64d3_inter_0[3] = tcu::Vec3(1031.5, 1032.75, 1033.875); perVertexData.vert_f64d3_inter_1[0] = tcu::Vec3(1041.25, 1042.5, 1043.875); perVertexData.vert_f64d3_inter_1[1] = tcu::Vec3(1041.25, 1042.75, 1043.875); perVertexData.vert_f64d3_inter_1[2] = tcu::Vec3(1041.5, 1042.5, 1043.875); perVertexData.vert_f64d3_inter_1[3] = tcu::Vec3(1041.5, 1042.75, 1043.875); perVertexData.vert_f64d2_inter_0[0] = tcu::Vec2(1051.25, 1052.5); perVertexData.vert_f64d2_inter_0[1] = tcu::Vec2(1051.25, 1052.75); perVertexData.vert_f64d2_inter_0[2] = tcu::Vec2(1051.5, 1052.5); perVertexData.vert_f64d2_inter_0[3] = tcu::Vec2(1051.5, 1052.75); perVertexData.vert_f64d2_inter_1[0] = tcu::Vec2(1061.25, 1062.5); perVertexData.vert_f64d2_inter_1[1] = tcu::Vec2(1061.25, 1062.75); perVertexData.vert_f64d2_inter_1[2] = tcu::Vec2(1061.5, 1062.5); perVertexData.vert_f64d2_inter_1[3] = tcu::Vec2(1061.5, 1062.75); perVertexData.vert_f64d1_inter_0[0] = 1071.25; perVertexData.vert_f64d1_inter_0[1] = 1071.25; perVertexData.vert_f64d1_inter_0[2] = 1071.5; perVertexData.vert_f64d1_inter_0[3] = 1071.5; perVertexData.vert_f64d1_inter_1[0] = 1081.25; perVertexData.vert_f64d1_inter_1[1] = 1081.25; perVertexData.vert_f64d1_inter_1[2] = 1081.5; perVertexData.vert_f64d1_inter_1[3] = 1081.5; perVertexData.vert_f32d4_inter_0[0] = tcu::Vec4(1091.25, 1092.5, 1093.875, 1094.0); perVertexData.vert_f32d4_inter_0[1] = tcu::Vec4(1091.25, 1092.75, 1093.875, 1094.0); perVertexData.vert_f32d4_inter_0[2] = tcu::Vec4(1091.5, 1092.5, 1093.875, 1094.0); perVertexData.vert_f32d4_inter_0[3] = tcu::Vec4(1091.5, 1092.75, 1093.875, 1094.0); perVertexData.vert_f32d4_inter_1[0] = tcu::Vec4(1101.25, 1102.5, 1103.875, 1104.0); perVertexData.vert_f32d4_inter_1[1] = tcu::Vec4(1101.25, 1102.75, 1103.875, 1104.0); perVertexData.vert_f32d4_inter_1[2] = tcu::Vec4(1101.5, 1102.5, 1103.875, 1104.0); perVertexData.vert_f32d4_inter_1[3] = tcu::Vec4(1101.5, 1102.75, 1103.875, 1104.0); perVertexData.vert_f32d3_inter_0[0] = tcu::Vec3(1111.25, 1112.5, 1113.875); perVertexData.vert_f32d3_inter_0[1] = tcu::Vec3(1111.25, 1112.75, 1113.875); perVertexData.vert_f32d3_inter_0[2] = tcu::Vec3(1111.5, 1112.5, 1113.875); perVertexData.vert_f32d3_inter_0[3] = tcu::Vec3(1111.5, 1112.75, 1113.875); perVertexData.vert_f32d3_inter_1[0] = tcu::Vec3(1121.25, 1122.5, 1123.875); perVertexData.vert_f32d3_inter_1[1] = tcu::Vec3(1121.25, 1122.75, 1123.875); perVertexData.vert_f32d3_inter_1[2] = tcu::Vec3(1121.5, 1122.5, 1123.875); perVertexData.vert_f32d3_inter_1[3] = tcu::Vec3(1121.5, 1122.75, 1123.875); perVertexData.vert_f32d2_inter_0[0] = tcu::Vec2(1131.25, 1132.5); perVertexData.vert_f32d2_inter_0[1] = tcu::Vec2(1131.25, 1132.75); perVertexData.vert_f32d2_inter_0[2] = tcu::Vec2(1131.5, 1132.5); perVertexData.vert_f32d2_inter_0[3] = tcu::Vec2(1131.5, 1132.75); perVertexData.vert_f32d2_inter_1[0] = tcu::Vec2(1141.25, 1142.5); perVertexData.vert_f32d2_inter_1[1] = tcu::Vec2(1141.25, 1142.75); perVertexData.vert_f32d2_inter_1[2] = tcu::Vec2(1141.5, 1142.5); perVertexData.vert_f32d2_inter_1[3] = tcu::Vec2(1141.5, 1142.75); perVertexData.vert_f32d1_inter_0[0] = 1151.25; perVertexData.vert_f32d1_inter_0[1] = 1151.25; perVertexData.vert_f32d1_inter_0[2] = 1151.5; perVertexData.vert_f32d1_inter_0[3] = 1151.5; perVertexData.vert_f32d1_inter_1[0] = 1161.25; perVertexData.vert_f32d1_inter_1[1] = 1161.25; perVertexData.vert_f32d1_inter_1[2] = 1161.5; perVertexData.vert_f32d1_inter_1[3] = 1161.5; perVertexData.vert_f16d4_inter_0[0] = tcu::Vec4(1171.25, 1172.5, 1173.875, 1174.0); perVertexData.vert_f16d4_inter_0[1] = tcu::Vec4(1171.25, 1172.75, 1173.875, 1174.0); perVertexData.vert_f16d4_inter_0[2] = tcu::Vec4(1171.5, 1172.5, 1173.875, 1174.0); perVertexData.vert_f16d4_inter_0[3] = tcu::Vec4(1171.5, 1172.75, 1173.875, 1174.0); perVertexData.vert_f16d4_inter_1[0] = tcu::Vec4(1181.25, 1182.5, 1183.875, 1184.0); perVertexData.vert_f16d4_inter_1[1] = tcu::Vec4(1181.25, 1182.75, 1183.875, 1184.0); perVertexData.vert_f16d4_inter_1[2] = tcu::Vec4(1181.5, 1182.5, 1183.875, 1184.0); perVertexData.vert_f16d4_inter_1[3] = tcu::Vec4(1181.5, 1182.75, 1183.875, 1184.0); perVertexData.vert_f16d3_inter_0[0] = tcu::Vec3(1191.25, 1192.5, 1193.875); perVertexData.vert_f16d3_inter_0[1] = tcu::Vec3(1191.25, 1192.75, 1193.875); perVertexData.vert_f16d3_inter_0[2] = tcu::Vec3(1191.5, 1192.5, 1193.875); perVertexData.vert_f16d3_inter_0[3] = tcu::Vec3(1191.5, 1192.75, 1193.875); perVertexData.vert_f16d3_inter_1[0] = tcu::Vec3(1201.25, 1202.5, 1203.875); perVertexData.vert_f16d3_inter_1[1] = tcu::Vec3(1201.25, 1202.75, 1203.875); perVertexData.vert_f16d3_inter_1[2] = tcu::Vec3(1201.5, 1202.5, 1203.875); perVertexData.vert_f16d3_inter_1[3] = tcu::Vec3(1201.5, 1202.75, 1203.875); perVertexData.vert_f16d2_inter_0[0] = tcu::Vec2(1211.25, 1212.5); perVertexData.vert_f16d2_inter_0[1] = tcu::Vec2(1211.25, 1212.75); perVertexData.vert_f16d2_inter_0[2] = tcu::Vec2(1211.5, 1212.5); perVertexData.vert_f16d2_inter_0[3] = tcu::Vec2(1211.5, 1212.75); perVertexData.vert_f16d2_inter_1[0] = tcu::Vec2(1221.25, 1222.5); perVertexData.vert_f16d2_inter_1[1] = tcu::Vec2(1221.25, 1222.75); perVertexData.vert_f16d2_inter_1[2] = tcu::Vec2(1221.5, 1222.5); perVertexData.vert_f16d2_inter_1[3] = tcu::Vec2(1221.5, 1222.75); perVertexData.vert_f16d1_inter_0[0] = 1231.25; perVertexData.vert_f16d1_inter_0[1] = 1231.25; perVertexData.vert_f16d1_inter_0[2] = 1231.5; perVertexData.vert_f16d1_inter_0[3] = 1231.5; perVertexData.vert_f16d1_inter_1[0] = 1241.25; perVertexData.vert_f16d1_inter_1[1] = 1241.25; perVertexData.vert_f16d1_inter_1[2] = 1241.5; perVertexData.vert_f16d1_inter_1[3] = 1241.5; perVertexData.vert_f64d4_flat_0[0] = tcu::Vec4(1251, 1252, 1253, 1254); perVertexData.vert_f64d4_flat_0[1] = tcu::Vec4(1251, 1252, 1253, 1254); perVertexData.vert_f64d4_flat_0[2] = tcu::Vec4(1251, 1252, 1253, 1254); perVertexData.vert_f64d4_flat_0[3] = tcu::Vec4(1251, 1252, 1253, 1254); perVertexData.vert_f64d4_flat_1[0] = tcu::Vec4(1261, 1262, 1263, 1264); perVertexData.vert_f64d4_flat_1[1] = tcu::Vec4(1261, 1262, 1263, 1264); perVertexData.vert_f64d4_flat_1[2] = tcu::Vec4(1261, 1262, 1263, 1264); perVertexData.vert_f64d4_flat_1[3] = tcu::Vec4(1261, 1262, 1263, 1264); perVertexData.vert_f64d3_flat_0[0] = tcu::Vec3(1271, 1272, 1273); perVertexData.vert_f64d3_flat_0[1] = tcu::Vec3(1271, 1272, 1273); perVertexData.vert_f64d3_flat_0[2] = tcu::Vec3(1271, 1272, 1273); perVertexData.vert_f64d3_flat_0[3] = tcu::Vec3(1271, 1272, 1273); perVertexData.vert_f64d3_flat_1[0] = tcu::Vec3(1281, 1282, 1283); perVertexData.vert_f64d3_flat_1[1] = tcu::Vec3(1281, 1282, 1283); perVertexData.vert_f64d3_flat_1[2] = tcu::Vec3(1281, 1282, 1283); perVertexData.vert_f64d3_flat_1[3] = tcu::Vec3(1281, 1282, 1283); perVertexData.vert_f64d2_flat_0[0] = tcu::Vec2(1291, 1292); perVertexData.vert_f64d2_flat_0[1] = tcu::Vec2(1291, 1292); perVertexData.vert_f64d2_flat_0[2] = tcu::Vec2(1291, 1292); perVertexData.vert_f64d2_flat_0[3] = tcu::Vec2(1291, 1292); perVertexData.vert_f64d2_flat_1[0] = tcu::Vec2(1301, 1302); perVertexData.vert_f64d2_flat_1[1] = tcu::Vec2(1301, 1302); perVertexData.vert_f64d2_flat_1[2] = tcu::Vec2(1301, 1302); perVertexData.vert_f64d2_flat_1[3] = tcu::Vec2(1301, 1302); perVertexData.vert_f64d1_flat_0[0] = 1311; perVertexData.vert_f64d1_flat_0[1] = 1311; perVertexData.vert_f64d1_flat_0[2] = 1311; perVertexData.vert_f64d1_flat_0[3] = 1311; perVertexData.vert_f64d1_flat_1[0] = 1321; perVertexData.vert_f64d1_flat_1[1] = 1321; perVertexData.vert_f64d1_flat_1[2] = 1321; perVertexData.vert_f64d1_flat_1[3] = 1321; perVertexData.vert_f32d4_flat_0[0] = tcu::Vec4(1331, 1332, 1333, 1334); perVertexData.vert_f32d4_flat_0[1] = tcu::Vec4(1331, 1332, 1333, 1334); perVertexData.vert_f32d4_flat_0[2] = tcu::Vec4(1331, 1332, 1333, 1334); perVertexData.vert_f32d4_flat_0[3] = tcu::Vec4(1331, 1332, 1333, 1334); perVertexData.vert_f32d4_flat_1[0] = tcu::Vec4(1341, 1342, 1343, 1344); perVertexData.vert_f32d4_flat_1[1] = tcu::Vec4(1341, 1342, 1343, 1344); perVertexData.vert_f32d4_flat_1[2] = tcu::Vec4(1341, 1342, 1343, 1344); perVertexData.vert_f32d4_flat_1[3] = tcu::Vec4(1341, 1342, 1343, 1344); perVertexData.vert_f32d3_flat_0[0] = tcu::Vec3(1351, 1352, 1353); perVertexData.vert_f32d3_flat_0[1] = tcu::Vec3(1351, 1352, 1353); perVertexData.vert_f32d3_flat_0[2] = tcu::Vec3(1351, 1352, 1353); perVertexData.vert_f32d3_flat_0[3] = tcu::Vec3(1351, 1352, 1353); perVertexData.vert_f32d3_flat_1[0] = tcu::Vec3(1361, 1362, 1363); perVertexData.vert_f32d3_flat_1[1] = tcu::Vec3(1361, 1362, 1363); perVertexData.vert_f32d3_flat_1[2] = tcu::Vec3(1361, 1362, 1363); perVertexData.vert_f32d3_flat_1[3] = tcu::Vec3(1361, 1362, 1363); perVertexData.vert_f32d2_flat_0[0] = tcu::Vec2(1371, 1372); perVertexData.vert_f32d2_flat_0[1] = tcu::Vec2(1371, 1372); perVertexData.vert_f32d2_flat_0[2] = tcu::Vec2(1371, 1372); perVertexData.vert_f32d2_flat_0[3] = tcu::Vec2(1371, 1372); perVertexData.vert_f32d2_flat_1[0] = tcu::Vec2(1381, 1382); perVertexData.vert_f32d2_flat_1[1] = tcu::Vec2(1381, 1382); perVertexData.vert_f32d2_flat_1[2] = tcu::Vec2(1381, 1382); perVertexData.vert_f32d2_flat_1[3] = tcu::Vec2(1381, 1382); perVertexData.vert_f32d1_flat_0[0] = 1391; perVertexData.vert_f32d1_flat_0[1] = 1391; perVertexData.vert_f32d1_flat_0[2] = 1391; perVertexData.vert_f32d1_flat_0[3] = 1391; perVertexData.vert_f32d1_flat_1[0] = 1401; perVertexData.vert_f32d1_flat_1[1] = 1401; perVertexData.vert_f32d1_flat_1[2] = 1401; perVertexData.vert_f32d1_flat_1[3] = 1401; perVertexData.vert_f16d4_flat_0[0] = tcu::Vec4(1411, 1412, 1413, 1414); perVertexData.vert_f16d4_flat_0[1] = tcu::Vec4(1411, 1412, 1413, 1414); perVertexData.vert_f16d4_flat_0[2] = tcu::Vec4(1411, 1412, 1413, 1414); perVertexData.vert_f16d4_flat_0[3] = tcu::Vec4(1411, 1412, 1413, 1414); perVertexData.vert_f16d4_flat_1[0] = tcu::Vec4(1421, 1422, 1423, 1424); perVertexData.vert_f16d4_flat_1[1] = tcu::Vec4(1421, 1422, 1423, 1424); perVertexData.vert_f16d4_flat_1[2] = tcu::Vec4(1421, 1422, 1423, 1424); perVertexData.vert_f16d4_flat_1[3] = tcu::Vec4(1421, 1422, 1423, 1424); perVertexData.vert_f16d3_flat_0[0] = tcu::Vec3(1431, 1432, 1433); perVertexData.vert_f16d3_flat_0[1] = tcu::Vec3(1431, 1432, 1433); perVertexData.vert_f16d3_flat_0[2] = tcu::Vec3(1431, 1432, 1433); perVertexData.vert_f16d3_flat_0[3] = tcu::Vec3(1431, 1432, 1433); perVertexData.vert_f16d3_flat_1[0] = tcu::Vec3(1441, 1442, 1443); perVertexData.vert_f16d3_flat_1[1] = tcu::Vec3(1441, 1442, 1443); perVertexData.vert_f16d3_flat_1[2] = tcu::Vec3(1441, 1442, 1443); perVertexData.vert_f16d3_flat_1[3] = tcu::Vec3(1441, 1442, 1443); perVertexData.vert_f16d2_flat_0[0] = tcu::Vec2(1451, 1452); perVertexData.vert_f16d2_flat_0[1] = tcu::Vec2(1451, 1452); perVertexData.vert_f16d2_flat_0[2] = tcu::Vec2(1451, 1452); perVertexData.vert_f16d2_flat_0[3] = tcu::Vec2(1451, 1452); perVertexData.vert_f16d2_flat_1[0] = tcu::Vec2(1461, 1462); perVertexData.vert_f16d2_flat_1[1] = tcu::Vec2(1461, 1462); perVertexData.vert_f16d2_flat_1[2] = tcu::Vec2(1461, 1462); perVertexData.vert_f16d2_flat_1[3] = tcu::Vec2(1461, 1462); perVertexData.vert_f16d1_flat_0[0] = 1471; perVertexData.vert_f16d1_flat_0[1] = 1471; perVertexData.vert_f16d1_flat_0[2] = 1471; perVertexData.vert_f16d1_flat_0[3] = 1471; perVertexData.vert_f16d1_flat_1[0] = 1481; perVertexData.vert_f16d1_flat_1[1] = 1481; perVertexData.vert_f16d1_flat_1[2] = 1481; perVertexData.vert_f16d1_flat_1[3] = 1481; perVertexData.vert_i64d4_flat_0[0] = tcu::IVec4(1491, 1492, 1493, 1494); perVertexData.vert_i64d4_flat_0[1] = tcu::IVec4(1491, 1492, 1493, 1494); perVertexData.vert_i64d4_flat_0[2] = tcu::IVec4(1491, 1492, 1493, 1494); perVertexData.vert_i64d4_flat_0[3] = tcu::IVec4(1491, 1492, 1493, 1494); perVertexData.vert_i64d4_flat_1[0] = tcu::IVec4(1501, 1502, 1503, 1504); perVertexData.vert_i64d4_flat_1[1] = tcu::IVec4(1501, 1502, 1503, 1504); perVertexData.vert_i64d4_flat_1[2] = tcu::IVec4(1501, 1502, 1503, 1504); perVertexData.vert_i64d4_flat_1[3] = tcu::IVec4(1501, 1502, 1503, 1504); perVertexData.vert_i64d3_flat_0[0] = tcu::IVec3(1511, 1512, 1513); perVertexData.vert_i64d3_flat_0[1] = tcu::IVec3(1511, 1512, 1513); perVertexData.vert_i64d3_flat_0[2] = tcu::IVec3(1511, 1512, 1513); perVertexData.vert_i64d3_flat_0[3] = tcu::IVec3(1511, 1512, 1513); perVertexData.vert_i64d3_flat_1[0] = tcu::IVec3(1521, 1522, 1523); perVertexData.vert_i64d3_flat_1[1] = tcu::IVec3(1521, 1522, 1523); perVertexData.vert_i64d3_flat_1[2] = tcu::IVec3(1521, 1522, 1523); perVertexData.vert_i64d3_flat_1[3] = tcu::IVec3(1521, 1522, 1523); perVertexData.vert_i64d2_flat_0[0] = tcu::IVec2(1531, 1532); perVertexData.vert_i64d2_flat_0[1] = tcu::IVec2(1531, 1532); perVertexData.vert_i64d2_flat_0[2] = tcu::IVec2(1531, 1532); perVertexData.vert_i64d2_flat_0[3] = tcu::IVec2(1531, 1532); perVertexData.vert_i64d2_flat_1[0] = tcu::IVec2(1541, 1542); perVertexData.vert_i64d2_flat_1[1] = tcu::IVec2(1541, 1542); perVertexData.vert_i64d2_flat_1[2] = tcu::IVec2(1541, 1542); perVertexData.vert_i64d2_flat_1[3] = tcu::IVec2(1541, 1542); perVertexData.vert_i64d1_flat_0[0] = 1551; perVertexData.vert_i64d1_flat_0[1] = 1551; perVertexData.vert_i64d1_flat_0[2] = 1551; perVertexData.vert_i64d1_flat_0[3] = 1551; perVertexData.vert_i64d1_flat_1[0] = 1561; perVertexData.vert_i64d1_flat_1[1] = 1561; perVertexData.vert_i64d1_flat_1[2] = 1561; perVertexData.vert_i64d1_flat_1[3] = 1561; perVertexData.vert_i32d4_flat_0[0] = tcu::IVec4(1571, 1572, 1573, 1574); perVertexData.vert_i32d4_flat_0[1] = tcu::IVec4(1571, 1572, 1573, 1574); perVertexData.vert_i32d4_flat_0[2] = tcu::IVec4(1571, 1572, 1573, 1574); perVertexData.vert_i32d4_flat_0[3] = tcu::IVec4(1571, 1572, 1573, 1574); perVertexData.vert_i32d4_flat_1[0] = tcu::IVec4(1581, 1582, 1583, 1584); perVertexData.vert_i32d4_flat_1[1] = tcu::IVec4(1581, 1582, 1583, 1584); perVertexData.vert_i32d4_flat_1[2] = tcu::IVec4(1581, 1582, 1583, 1584); perVertexData.vert_i32d4_flat_1[3] = tcu::IVec4(1581, 1582, 1583, 1584); perVertexData.vert_i32d3_flat_0[0] = tcu::IVec3(1591, 1592, 1593); perVertexData.vert_i32d3_flat_0[1] = tcu::IVec3(1591, 1592, 1593); perVertexData.vert_i32d3_flat_0[2] = tcu::IVec3(1591, 1592, 1593); perVertexData.vert_i32d3_flat_0[3] = tcu::IVec3(1591, 1592, 1593); perVertexData.vert_i32d3_flat_1[0] = tcu::IVec3(1601, 1602, 1603); perVertexData.vert_i32d3_flat_1[1] = tcu::IVec3(1601, 1602, 1603); perVertexData.vert_i32d3_flat_1[2] = tcu::IVec3(1601, 1602, 1603); perVertexData.vert_i32d3_flat_1[3] = tcu::IVec3(1601, 1602, 1603); perVertexData.vert_i32d2_flat_0[0] = tcu::IVec2(1611, 1612); perVertexData.vert_i32d2_flat_0[1] = tcu::IVec2(1611, 1612); perVertexData.vert_i32d2_flat_0[2] = tcu::IVec2(1611, 1612); perVertexData.vert_i32d2_flat_0[3] = tcu::IVec2(1611, 1612); perVertexData.vert_i32d2_flat_1[0] = tcu::IVec2(1621, 1622); perVertexData.vert_i32d2_flat_1[1] = tcu::IVec2(1621, 1622); perVertexData.vert_i32d2_flat_1[2] = tcu::IVec2(1621, 1622); perVertexData.vert_i32d2_flat_1[3] = tcu::IVec2(1621, 1622); perVertexData.vert_i32d1_flat_0[0] = 1631; perVertexData.vert_i32d1_flat_0[1] = 1631; perVertexData.vert_i32d1_flat_0[2] = 1631; perVertexData.vert_i32d1_flat_0[3] = 1631; perVertexData.vert_i32d1_flat_1[0] = 1641; perVertexData.vert_i32d1_flat_1[1] = 1641; perVertexData.vert_i32d1_flat_1[2] = 1641; perVertexData.vert_i32d1_flat_1[3] = 1641; perVertexData.vert_i16d4_flat_0[0] = tcu::IVec4(1651, 1652, 1653, 1654); perVertexData.vert_i16d4_flat_0[1] = tcu::IVec4(1651, 1652, 1653, 1654); perVertexData.vert_i16d4_flat_0[2] = tcu::IVec4(1651, 1652, 1653, 1654); perVertexData.vert_i16d4_flat_0[3] = tcu::IVec4(1651, 1652, 1653, 1654); perVertexData.vert_i16d4_flat_1[0] = tcu::IVec4(1661, 1662, 1663, 1664); perVertexData.vert_i16d4_flat_1[1] = tcu::IVec4(1661, 1662, 1663, 1664); perVertexData.vert_i16d4_flat_1[2] = tcu::IVec4(1661, 1662, 1663, 1664); perVertexData.vert_i16d4_flat_1[3] = tcu::IVec4(1661, 1662, 1663, 1664); perVertexData.vert_i16d3_flat_0[0] = tcu::IVec3(1671, 1672, 1673); perVertexData.vert_i16d3_flat_0[1] = tcu::IVec3(1671, 1672, 1673); perVertexData.vert_i16d3_flat_0[2] = tcu::IVec3(1671, 1672, 1673); perVertexData.vert_i16d3_flat_0[3] = tcu::IVec3(1671, 1672, 1673); perVertexData.vert_i16d3_flat_1[0] = tcu::IVec3(1681, 1682, 1683); perVertexData.vert_i16d3_flat_1[1] = tcu::IVec3(1681, 1682, 1683); perVertexData.vert_i16d3_flat_1[2] = tcu::IVec3(1681, 1682, 1683); perVertexData.vert_i16d3_flat_1[3] = tcu::IVec3(1681, 1682, 1683); perVertexData.vert_i16d2_flat_0[0] = tcu::IVec2(1691, 1692); perVertexData.vert_i16d2_flat_0[1] = tcu::IVec2(1691, 1692); perVertexData.vert_i16d2_flat_0[2] = tcu::IVec2(1691, 1692); perVertexData.vert_i16d2_flat_0[3] = tcu::IVec2(1691, 1692); perVertexData.vert_i16d2_flat_1[0] = tcu::IVec2(1701, 1702); perVertexData.vert_i16d2_flat_1[1] = tcu::IVec2(1701, 1702); perVertexData.vert_i16d2_flat_1[2] = tcu::IVec2(1701, 1702); perVertexData.vert_i16d2_flat_1[3] = tcu::IVec2(1701, 1702); perVertexData.vert_i16d1_flat_0[0] = 1711; perVertexData.vert_i16d1_flat_0[1] = 1711; perVertexData.vert_i16d1_flat_0[2] = 1711; perVertexData.vert_i16d1_flat_0[3] = 1711; perVertexData.vert_i16d1_flat_1[0] = 1721; perVertexData.vert_i16d1_flat_1[1] = 1721; perVertexData.vert_i16d1_flat_1[2] = 1721; perVertexData.vert_i16d1_flat_1[3] = 1721; } InterfaceVariablesCase::PerPrimitiveData perPrimitiveData; { perPrimitiveData.prim_f64d4_flat_0[0] = tcu::Vec4(1011, 1012, 1013, 1014); perPrimitiveData.prim_f64d4_flat_0[1] = tcu::Vec4(1011, 1012, 1013, 1014); perPrimitiveData.prim_f64d4_flat_1[0] = tcu::Vec4(1021, 1022, 1023, 1024); perPrimitiveData.prim_f64d4_flat_1[1] = tcu::Vec4(1021, 1022, 1023, 1024); perPrimitiveData.prim_f64d3_flat_0[0] = tcu::Vec3(1031, 1032, 1033); perPrimitiveData.prim_f64d3_flat_0[1] = tcu::Vec3(1031, 1032, 1033); perPrimitiveData.prim_f64d3_flat_1[0] = tcu::Vec3(1041, 1042, 1043); perPrimitiveData.prim_f64d3_flat_1[1] = tcu::Vec3(1041, 1042, 1043); perPrimitiveData.prim_f64d2_flat_0[0] = tcu::Vec2(1051, 1052); perPrimitiveData.prim_f64d2_flat_0[1] = tcu::Vec2(1051, 1052); perPrimitiveData.prim_f64d2_flat_1[0] = tcu::Vec2(1061, 1062); perPrimitiveData.prim_f64d2_flat_1[1] = tcu::Vec2(1061, 1062); perPrimitiveData.prim_f64d1_flat_0[0] = 1071; perPrimitiveData.prim_f64d1_flat_0[1] = 1071; perPrimitiveData.prim_f64d1_flat_1[0] = 1081; perPrimitiveData.prim_f64d1_flat_1[1] = 1081; perPrimitiveData.prim_f32d4_flat_0[0] = tcu::Vec4(1091, 1092, 1093, 1094); perPrimitiveData.prim_f32d4_flat_0[1] = tcu::Vec4(1091, 1092, 1093, 1094); perPrimitiveData.prim_f32d4_flat_1[0] = tcu::Vec4(1101, 1102, 1103, 1104); perPrimitiveData.prim_f32d4_flat_1[1] = tcu::Vec4(1101, 1102, 1103, 1104); perPrimitiveData.prim_f32d3_flat_0[0] = tcu::Vec3(1111, 1112, 1113); perPrimitiveData.prim_f32d3_flat_0[1] = tcu::Vec3(1111, 1112, 1113); perPrimitiveData.prim_f32d3_flat_1[0] = tcu::Vec3(1121, 1122, 1123); perPrimitiveData.prim_f32d3_flat_1[1] = tcu::Vec3(1121, 1122, 1123); perPrimitiveData.prim_f32d2_flat_0[0] = tcu::Vec2(1131, 1132); perPrimitiveData.prim_f32d2_flat_0[1] = tcu::Vec2(1131, 1132); perPrimitiveData.prim_f32d2_flat_1[0] = tcu::Vec2(1141, 1142); perPrimitiveData.prim_f32d2_flat_1[1] = tcu::Vec2(1141, 1142); perPrimitiveData.prim_f32d1_flat_0[0] = 1151; perPrimitiveData.prim_f32d1_flat_0[1] = 1151; perPrimitiveData.prim_f32d1_flat_1[0] = 1161; perPrimitiveData.prim_f32d1_flat_1[1] = 1161; perPrimitiveData.prim_f16d4_flat_0[0] = tcu::Vec4(1171, 1172, 1173, 1174); perPrimitiveData.prim_f16d4_flat_0[1] = tcu::Vec4(1171, 1172, 1173, 1174); perPrimitiveData.prim_f16d4_flat_1[0] = tcu::Vec4(1181, 1182, 1183, 1184); perPrimitiveData.prim_f16d4_flat_1[1] = tcu::Vec4(1181, 1182, 1183, 1184); perPrimitiveData.prim_f16d3_flat_0[0] = tcu::Vec3(1191, 1192, 1193); perPrimitiveData.prim_f16d3_flat_0[1] = tcu::Vec3(1191, 1192, 1193); perPrimitiveData.prim_f16d3_flat_1[0] = tcu::Vec3(1201, 1202, 1203); perPrimitiveData.prim_f16d3_flat_1[1] = tcu::Vec3(1201, 1202, 1203); perPrimitiveData.prim_f16d2_flat_0[0] = tcu::Vec2(1211, 1212); perPrimitiveData.prim_f16d2_flat_0[1] = tcu::Vec2(1211, 1212); perPrimitiveData.prim_f16d2_flat_1[0] = tcu::Vec2(1221, 1222); perPrimitiveData.prim_f16d2_flat_1[1] = tcu::Vec2(1221, 1222); perPrimitiveData.prim_f16d1_flat_0[0] = 1231; perPrimitiveData.prim_f16d1_flat_0[1] = 1231; perPrimitiveData.prim_f16d1_flat_1[0] = 1241; perPrimitiveData.prim_f16d1_flat_1[1] = 1241; perPrimitiveData.prim_i64d4_flat_0[0] = tcu::IVec4(1251, 1252, 1253, 1254); perPrimitiveData.prim_i64d4_flat_0[1] = tcu::IVec4(1251, 1252, 1253, 1254); perPrimitiveData.prim_i64d4_flat_1[0] = tcu::IVec4(1261, 1262, 1263, 1264); perPrimitiveData.prim_i64d4_flat_1[1] = tcu::IVec4(1261, 1262, 1263, 1264); perPrimitiveData.prim_i64d3_flat_0[0] = tcu::IVec3(1271, 1272, 1273); perPrimitiveData.prim_i64d3_flat_0[1] = tcu::IVec3(1271, 1272, 1273); perPrimitiveData.prim_i64d3_flat_1[0] = tcu::IVec3(1281, 1282, 1283); perPrimitiveData.prim_i64d3_flat_1[1] = tcu::IVec3(1281, 1282, 1283); perPrimitiveData.prim_i64d2_flat_0[0] = tcu::IVec2(1291, 1292); perPrimitiveData.prim_i64d2_flat_0[1] = tcu::IVec2(1291, 1292); perPrimitiveData.prim_i64d2_flat_1[0] = tcu::IVec2(1301, 1302); perPrimitiveData.prim_i64d2_flat_1[1] = tcu::IVec2(1301, 1302); perPrimitiveData.prim_i64d1_flat_0[0] = 1311; perPrimitiveData.prim_i64d1_flat_0[1] = 1311; perPrimitiveData.prim_i64d1_flat_1[0] = 1321; perPrimitiveData.prim_i64d1_flat_1[1] = 1321; perPrimitiveData.prim_i32d4_flat_0[0] = tcu::IVec4(1331, 1332, 1333, 1334); perPrimitiveData.prim_i32d4_flat_0[1] = tcu::IVec4(1331, 1332, 1333, 1334); perPrimitiveData.prim_i32d4_flat_1[0] = tcu::IVec4(1341, 1342, 1343, 1344); perPrimitiveData.prim_i32d4_flat_1[1] = tcu::IVec4(1341, 1342, 1343, 1344); perPrimitiveData.prim_i32d3_flat_0[0] = tcu::IVec3(1351, 1352, 1353); perPrimitiveData.prim_i32d3_flat_0[1] = tcu::IVec3(1351, 1352, 1353); perPrimitiveData.prim_i32d3_flat_1[0] = tcu::IVec3(1361, 1362, 1363); perPrimitiveData.prim_i32d3_flat_1[1] = tcu::IVec3(1361, 1362, 1363); perPrimitiveData.prim_i32d2_flat_0[0] = tcu::IVec2(1371, 1372); perPrimitiveData.prim_i32d2_flat_0[1] = tcu::IVec2(1371, 1372); perPrimitiveData.prim_i32d2_flat_1[0] = tcu::IVec2(1381, 1382); perPrimitiveData.prim_i32d2_flat_1[1] = tcu::IVec2(1381, 1382); perPrimitiveData.prim_i32d1_flat_0[0] = 1391; perPrimitiveData.prim_i32d1_flat_0[1] = 1391; perPrimitiveData.prim_i32d1_flat_1[0] = 1401; perPrimitiveData.prim_i32d1_flat_1[1] = 1401; perPrimitiveData.prim_i16d4_flat_0[0] = tcu::IVec4(1411, 1412, 1413, 1414); perPrimitiveData.prim_i16d4_flat_0[1] = tcu::IVec4(1411, 1412, 1413, 1414); perPrimitiveData.prim_i16d4_flat_1[0] = tcu::IVec4(1421, 1422, 1423, 1424); perPrimitiveData.prim_i16d4_flat_1[1] = tcu::IVec4(1421, 1422, 1423, 1424); perPrimitiveData.prim_i16d3_flat_0[0] = tcu::IVec3(1431, 1432, 1433); perPrimitiveData.prim_i16d3_flat_0[1] = tcu::IVec3(1431, 1432, 1433); perPrimitiveData.prim_i16d3_flat_1[0] = tcu::IVec3(1441, 1442, 1443); perPrimitiveData.prim_i16d3_flat_1[1] = tcu::IVec3(1441, 1442, 1443); perPrimitiveData.prim_i16d2_flat_0[0] = tcu::IVec2(1451, 1452); perPrimitiveData.prim_i16d2_flat_0[1] = tcu::IVec2(1451, 1452); perPrimitiveData.prim_i16d2_flat_1[0] = tcu::IVec2(1461, 1462); perPrimitiveData.prim_i16d2_flat_1[1] = tcu::IVec2(1461, 1462); perPrimitiveData.prim_i16d1_flat_0[0] = 1471; perPrimitiveData.prim_i16d1_flat_0[1] = 1471; perPrimitiveData.prim_i16d1_flat_1[0] = 1481; perPrimitiveData.prim_i16d1_flat_1[1] = 1481; } // 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_STORAGE_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_STORAGE_BUFFER, bufStages); const auto setLayout = setLayoutBuilder.build(vkd, device); // Create and update descriptor set. DescriptorPoolBuilder descriptorPoolBuilder; descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u); 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 pvdBufferInfo = makeDescriptorBufferInfo(pvdData.get(), 0ull, pvdSize); const auto ppdBufferInfo = makeDescriptorBufferInfo(ppdData.get(), 0ull, ppdSize); updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &pvdBufferInfo); updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ppdBufferInfo); 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); const auto drawCount = m_params->drawCount(); 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, 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"); } void checkMeshSupport (Context& context) { checkTaskMeshShaderSupportNV(context, false, true); } void initMixedPipelinesPrograms (vk::SourceCollections& programCollection) { std::ostringstream frag; frag << "#version 450\n" << "\n" << "layout (location=0) in vec4 inColor;\n" << "layout (location=0) out vec4 outColor;\n" << "\n" << "void main ()\n" << "{\n" << " outColor = inColor;\n" << "}\n" ; programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()); const std::string pushConstantDecl = "layout (push_constant, std430) uniform PushConstantBlock {\n" " vec4 color;\n" " uint firstVertex;\n" "} pc;\n" ; // The normal pipeline will have a binding with the vertex position and will take the vertex color from the push constants. std::ostringstream vert; vert << "#version 450\n" << "\n" << pushConstantDecl << "layout (location=0) out vec4 outColor;\n" << "layout (location=0) in vec4 inPos;\n" << "\n" << "void main ()\n" << "{\n" << " gl_Position = inPos;\n" << " outColor = pc.color;\n" << "}\n" ; programCollection.glslSources.add("vert") << glu::VertexSource(vert.str()); // The mesh pipeline will emit a quad based on the first vertex as indicated by the push constants, using the push constant color as well. std::ostringstream mesh; mesh << "#version 450\n" << "#extension GL_NV_mesh_shader : enable\n" << "\n" << pushConstantDecl << "\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 vec4 outColor[];\n" << "\n" << "layout (set=0, binding=0) readonly buffer VertexBlock {\n" << " vec4 positions[];\n" << "} vertexData;\n" << "\n" << "void main ()\n" << "{\n" << " // Emit 4 vertices starting at firstVertex, 2 per invocation.\n" << " gl_PrimitiveCountNV = 2u;\n" << " \n" << " const uint localVertexOffset = 2u * gl_LocalInvocationIndex;\n" << " const uint firstLocalVertex = pc.firstVertex + localVertexOffset;\n" << " const uint localIndexOffset = 3u * gl_LocalInvocationIndex;\n" << "\n" << " for (uint i = 0; i < 2; ++i)\n" << " {\n" << " gl_MeshVerticesNV[localVertexOffset + i].gl_Position = vertexData.positions[firstLocalVertex + i];\n" << " outColor[localVertexOffset + i] = pc.color;\n" << " }\n" << "\n" << " // Emit 2 primitives, 1 per invocation.\n" << " const uint indices[] = uint[](0, 1, 2, 2, 1, 3);\n" << "\n" << " for (uint i = 0; i < 3; ++i)\n" << " {\n" << " const uint pos = localIndexOffset + i;\n" << " gl_PrimitiveIndicesNV[pos] = indices[pos];\n" << " }\n" << "}\n" ; programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()); } tcu::TestStatus testMixedPipelines (Context& context) { const auto& vkd = context.getDeviceInterface(); const auto device = context.getDevice(); auto& alloc = context.getDefaultAllocator(); const auto queue = context.getUniversalQueue(); const auto qIndex = context.getUniversalQueueFamilyIndex(); const auto colorFormat = getOutputFormat(); const auto colorExtent = makeExtent3D(32u, 32u, 1u); const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); const auto tcuFormat = mapVkFormat(colorFormat); const tcu::IVec3 iExtent (static_cast(colorExtent.width), static_cast(colorExtent.height), static_cast(colorExtent.depth)); const tcu::Vec4 clearValue (0.0f, 0.0f, 0.0f, 1.0f); // Divide the image in 4 quadrants and emit a "full-screen" quad (2 triangles) in each quadrant, using a mesh or normal pipeline. // Replicate a standard quad 4 times with different offsets in X and Y for each quadrant. // Triangle vertices for a single full-screen quad. const std::vector stdQuad { tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), }; // Offsets for each quadrant. const std::vector quadrantOffsets { tcu::Vec4(-1.0f, -1.0f, 0.0f, 0.0f), // Top left. tcu::Vec4( 0.0f, -1.0f, 0.0f, 0.0f), // Top right. tcu::Vec4(-1.0f, 0.0f, 0.0f, 0.0f), // Bottom left. tcu::Vec4( 0.0f, 0.0f, 0.0f, 0.0f), // Bottom right. }; // Colors for each quadrant. const std::vector quadrantColors { tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f), tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), }; DE_ASSERT(quadrantOffsets.size() == quadrantColors.size()); // Fill the vertex buffer. const auto numVertices = stdQuad.size() * quadrantOffsets.size(); std::vector vertexBufferSrc; vertexBufferSrc.reserve(numVertices); for (size_t quadrantIdx = 0; quadrantIdx < quadrantOffsets.size(); ++quadrantIdx) { const auto& quadrantOffset = quadrantOffsets[quadrantIdx]; for (size_t vertexIdx = 0; vertexIdx < stdQuad.size(); ++vertexIdx) { const tcu::Vec4 pos = stdQuad[vertexIdx] + quadrantOffset; vertexBufferSrc.push_back(pos); } } const auto vertexBufferSize = de::dataSize(vertexBufferSrc); const auto vertexBufferUsage = (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, vertexBufferUsage); BufferWithMemory vertexBuffer (vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible); auto& vertexBufferAlloc = vertexBuffer.getAllocation(); tcu::Vec4* vertexBufferData = reinterpret_cast(vertexBufferAlloc.getHostPtr()); deMemcpy(vertexBufferData, vertexBufferSrc.data(), vertexBufferSize); flushAlloc(vkd, device, vertexBufferAlloc); // Index buffer, only used for the classic pipeline. const std::vector vertexIndices {0u, 1u, 2u, 2u, 1u, 3u}; const auto indexBufferSize = de::dataSize(vertexIndices); const auto indexBufferUsage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; const auto indexBufferInfo = makeBufferCreateInfo(indexBufferSize, indexBufferUsage); BufferWithMemory indexBuffer (vkd, device, alloc, indexBufferInfo, MemoryRequirement::HostVisible); auto& indexBufferAlloc = indexBuffer.getAllocation(); void* indexBufferData = indexBufferAlloc.getHostPtr(); deMemcpy(indexBufferData, vertexIndices.data(), indexBufferSize); flushAlloc(vkd, device, indexBufferAlloc); // Color attachment. const VkImageCreateInfo colorAttachmentInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; nullptr, // const void* pNext; 0u, // VkImageCreateFlags flags; VK_IMAGE_TYPE_2D, // VkImageType imageType; colorFormat, // VkFormat format; colorExtent, // VkExtent3D extent; 1u, // uint32_t mipLevels; 1u, // uint32_t arrayLayers; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; colorUsage, // VkImageUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 0u, // uint32_t queueFamilyIndexCount; nullptr, // const uint32_t* pQueueFamilyIndices; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; }; ImageWithMemory colorAttachment (vkd, device, alloc, colorAttachmentInfo, MemoryRequirement::Any); const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); const auto colorView = makeImageView(vkd, device, colorAttachment.get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR); // Verification buffer. const auto verificationBufferSize = tcu::getPixelSize(tcuFormat) * iExtent.x() * iExtent.y() * iExtent.z(); const auto verificationBufferSizeSz = static_cast(verificationBufferSize); const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSizeSz, VK_BUFFER_USAGE_TRANSFER_DST_BIT); BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible); auto& verificationBufferAlloc = verificationBuffer.getAllocation(); void* verificationBufferData = verificationBufferAlloc.getHostPtr(); // Render pass and framebuffer. const auto renderPass = makeRenderPass(vkd, device, colorFormat); const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorView.get(), colorExtent.width, colorExtent.height); // Push constant range. struct PushConstantBlock { tcu::Vec4 color; uint32_t firstVertex; }; const auto pcSize = static_cast(sizeof(PushConstantBlock)); const auto pcStages = (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_MESH_BIT_EXT); const auto pcRange = makePushConstantRange(pcStages, 0u, pcSize); // No descriptor set layout for the classic pipeline. // Descriptor set layout for the mesh pipeline using the vertex buffer. DescriptorSetLayoutBuilder dsLayoutBuilder; dsLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_MESH_BIT_EXT); const auto meshDSLayout = dsLayoutBuilder.build(vkd, device); // Pipeline layout for the classic pipeline. const auto classicPipelineLayout = makePipelineLayout(vkd, device, 0u, nullptr, 1u, &pcRange); // Pipeline layout for the mesh pipeline. const auto meshPipelineLayout = makePipelineLayout(vkd, device, 1u, &meshDSLayout.get(), 1u, &pcRange); // Descriptor pool and set with the vertex buffer. DescriptorPoolBuilder poolBuilder; poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); const auto meshDescriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), meshDSLayout.get()); DescriptorSetUpdateBuilder updateBuilder; const auto vertexBufferDescInfo = makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertexBufferSize); updateBuilder.writeSingle(meshDescriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &vertexBufferDescInfo); updateBuilder.update(vkd, device); // Shaders and pipelines. const auto& binaries = context.getBinaryCollection(); const auto vertModule = createShaderModule(vkd, device, binaries.get("vert")); const auto meshModule = createShaderModule(vkd, device, binaries.get("mesh")); const auto fragModule = createShaderModule(vkd, device, binaries.get("frag")); const std::vector viewports (1u, makeViewport(colorExtent)); const std::vector scissors (1u, makeRect2D(colorExtent)); const auto classicPipeline = makeGraphicsPipeline(vkd, device, classicPipelineLayout.get(), vertModule.get(), DE_NULL, DE_NULL, DE_NULL, fragModule.get(), renderPass.get(), viewports, scissors); const auto meshPipeline = makeGraphicsPipeline(vkd, device, meshPipelineLayout.get(), DE_NULL, meshModule.get(), fragModule.get(), renderPass.get(), viewports, scissors); // Command pool and buffer. const auto cmdPool = makeCommandPool(vkd, device, qIndex); const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY); const auto cmdBuffer = cmdBufferPtr.get(); beginCommandBuffer(vkd, cmdBuffer); beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), clearValue); // Draw a triangle quad in each of the 4 image quadrants. PushConstantBlock pcData; for (size_t quadrantIdx = 0; quadrantIdx < quadrantColors.size(); ++quadrantIdx) { pcData.color = quadrantColors[quadrantIdx]; pcData.firstVertex = static_cast(quadrantIdx * stdQuad.size()); const auto vOffset = static_cast(pcData.firstVertex * sizeof(tcu::Vec4)); const bool isMeshQuadrant = (quadrantIdx % 2u == 0u); if (isMeshQuadrant) { vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, meshPipeline.get()); vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, meshPipelineLayout.get(), 0u, 1u, &meshDescriptorSet.get(), 0u, nullptr); vkd.cmdPushConstants(cmdBuffer, meshPipelineLayout.get(), pcStages, 0u, pcSize, &pcData); vkd.cmdDrawMeshTasksNV(cmdBuffer, 1u, 0u); } else { vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, classicPipeline.get()); vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vOffset); vkd.cmdBindIndexBuffer(cmdBuffer, indexBuffer.get(), 0ull, VK_INDEX_TYPE_UINT32); vkd.cmdPushConstants(cmdBuffer, classicPipelineLayout.get(), pcStages, 0u, pcSize, &pcData); vkd.cmdDrawIndexed(cmdBuffer, static_cast(vertexIndices.size()), 1u, 0u, 0, 0u); } } endRenderPass(vkd, cmdBuffer); copyImageToBuffer(vkd, cmdBuffer, colorAttachment.get(), verificationBuffer.get(), tcu::IVec2(iExtent.x(), iExtent.y())); endCommandBuffer(vkd, cmdBuffer); submitCommandsAndWait(vkd, device, queue, cmdBuffer); invalidateAlloc(vkd, device, verificationBufferAlloc); // Prepare a reference image with the quadrant colors. tcu::TextureLevel refLevel (tcuFormat, iExtent.x(), iExtent.y(), iExtent.z()); auto refAccess = refLevel.getAccess(); const tcu::Vec4 halfSize (static_cast(iExtent.x()) / 2.0f, static_cast(iExtent.y()) / 2.0f, 0, 0); const tcu::Vec4 fbOffset (-1.0f, -1.0f, 0.0f, 0.0f); for (size_t quadrantIdx = 0; quadrantIdx < quadrantOffsets.size(); ++quadrantIdx) { const auto& offset = quadrantOffsets[quadrantIdx]; const auto absOffset = (offset - fbOffset) * halfSize; const auto subregion = tcu::getSubregion(refAccess, static_cast(absOffset.x()), static_cast(absOffset.y()), static_cast(halfSize.x()), static_cast(halfSize.y())); tcu::clear(subregion, quadrantColors.at(quadrantIdx)); } auto& log = context.getTestContext().getLog(); const tcu::ConstPixelBufferAccess resAccess (tcuFormat, iExtent, verificationBufferData); const tcu::Vec4 threshold (0.0f, 0.0f, 0.0f, 0.0f); // The chosen colors should need no threshold. They can be represented exactly. if (!tcu::floatThresholdCompare(log, "TestResult", "", refAccess, resAccess, threshold, tcu::COMPARE_LOG_ON_ERROR)) TCU_FAIL("Check log for details"); return tcu::TestStatus::pass("Pass"); } // Test reading the gl_TaskCountNV and gl_PrimitiveCountNV built-ins from several invocations. class CountReadCase : public MeshShaderMiscCase { public: CountReadCase (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 kLocalSize = 32u; }; class CountReadInstance : public MeshShaderMiscInstance { public: CountReadInstance (Context& context, const MiscTestParams* params) : MeshShaderMiscInstance (context, params) {} void generateReferenceLevel () override; }; TestInstance* CountReadCase::createInstance (Context& context) const { return new CountReadInstance(context, m_params.get()); } void CountReadInstance::generateReferenceLevel () { generateSolidRefLevel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), m_referenceLevel); } void CountReadCase::initPrograms (vk::SourceCollections& programCollection) const { DE_ASSERT(m_params->needsTaskShader()); DE_ASSERT(m_params->height == m_params->meshCount); DE_ASSERT(m_params->width == kLocalSize); std::ostringstream taskDataDeclStream; taskDataDeclStream << "taskNV TaskData {\n" << " vec4 color[" << kLocalSize << "];\n" << "} td;\n" ; const auto taskDataDecl = taskDataDeclStream.str(); std::ostringstream task; task << "#version 450\n" << "#extension GL_NV_mesh_shader : enable\n" << "\n" << "layout(local_size_x=" << kLocalSize << ") in;\n" << "\n" << "out " << taskDataDecl << "void main ()\n" << "{\n" << " gl_TaskCountNV = 0u;\n" << " if (gl_LocalInvocationIndex == 0u) {\n" << " gl_TaskCountNV = " << m_params->meshCount << ";\n" << " }\n" << " memoryBarrierShared();\n" << " barrier();\n" << " td.color[gl_LocalInvocationIndex] = ((gl_TaskCountNV == " << m_params->meshCount << ") ? vec4(0.0, 0.0, 1.0, 1.0) : vec4(0.0, 0.0, 0.0, 1.0));\n" << "}\n" ; programCollection.glslSources.add("task") << glu::TaskSource(task.str()); std::ostringstream mesh; mesh << "#version 450\n" << "#extension GL_NV_mesh_shader : enable\n" << "\n" << "in " << taskDataDecl << "\n" << "layout (local_size_x=" << kLocalSize << ") in;\n" << "layout (points) out;\n" << "layout (max_vertices=" << kLocalSize << ", max_primitives=" << kLocalSize << ") out;\n" << "\n" << "layout (location=0) out perprimitiveNV vec4 pointColor[];\n" << "\n" << "void main ()\n" << "{\n" << " gl_PrimitiveCountNV = 0u;\n" << " if (gl_LocalInvocationIndex == 0u) {\n" << " gl_PrimitiveCountNV = " << kLocalSize << ";\n" << " }\n" << " memoryBarrierShared();\n" << " barrier();\n" << "\n" << " const vec4 color = ((gl_PrimitiveCountNV == " << kLocalSize << ") ? td.color[gl_LocalInvocationIndex] : vec4(0.0, 0.0, 0.0, 1.0));\n" << " const float xCoord = (((float(gl_LocalInvocationIndex) + 0.5) / " << m_params->width << ") * 2.0 - 1.0);\n" << " const float yCoord = (((float(gl_WorkGroupID.x) + 0.5) / " << m_params->height << ") * 2.0 - 1.0);\n" << "\n" << " gl_MeshVerticesNV[gl_LocalInvocationIndex].gl_Position = vec4(xCoord, yCoord, 0.0, 1.0);\n" << " gl_PrimitiveIndicesNV[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;\n" << " pointColor[gl_LocalInvocationIndex] = color;\n" << "}\n" ; programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()); // Default fragment shader. MeshShaderMiscCase::initPrograms(programCollection); } } // anonymous namespace tcu::TestCaseGroup* createMeshShaderMiscTests (tcu::TestContext& testCtx) { GroupPtr miscTests (new tcu::TestCaseGroup(testCtx, "misc", "Mesh Shader Misc Tests")); { ParamsPtr paramsPtr (new MiscTestParams( /*taskCount*/ tcu::just(2u), /*meshCount*/ 2u, /*width*/ 8u, /*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( /*taskCount*/ tcu::Nothing, /*meshCount*/ 1u, /*width*/ 5u, // Use an odd value so there's a pixel in the exact center. /*height*/ 7u)); // Idem. miscTests->addChild(new SinglePointCase(testCtx, "single_point", "Draw a single point", std::move(paramsPtr))); } { ParamsPtr paramsPtr (new MiscTestParams( /*taskCount*/ tcu::Nothing, /*meshCount*/ 1u, /*width*/ 8u, /*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( /*taskCount*/ tcu::Nothing, /*meshCount*/ 1u, /*width*/ 5u, // Use an odd value so there's a pixel in the exact center. /*height*/ 7u)); // Idem. miscTests->addChild(new SingleTriangleCase(testCtx, "single_triangle", "Draw a single triangle", std::move(paramsPtr))); } { ParamsPtr paramsPtr (new MiscTestParams( /*taskCount*/ tcu::Nothing, /*meshCount*/ 1u, /*width*/ 16u, /*height*/ 16u)); miscTests->addChild(new MaxPointsCase(testCtx, "max_points", "Draw the maximum number of points", std::move(paramsPtr))); } { ParamsPtr paramsPtr (new MiscTestParams( /*taskCount*/ tcu::Nothing, /*meshCount*/ 1u, /*width*/ 1u, /*height*/ 1020u)); miscTests->addChild(new MaxLinesCase(testCtx, "max_lines", "Draw the maximum number of lines", std::move(paramsPtr))); } { ParamsPtr paramsPtr (new MiscTestParams( /*taskCount*/ tcu::Nothing, /*meshCount*/ 1u, /*width*/ 512u, /*height*/ 512u)); miscTests->addChild(new MaxTrianglesCase(testCtx, "max_triangles", "Draw the maximum number of triangles", std::move(paramsPtr))); } { ParamsPtr paramsPtr (new MiscTestParams( /*taskCount*/ tcu::just(65535u), /*meshCount*/ 1u, /*width*/ 1360u, /*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( /*taskCount*/ tcu::Nothing, /*meshCount*/ 65535u, /*width*/ 1360u, /*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( /*taskCount*/ tcu::just(512u), /*meshCount*/ 512u, /*width*/ 4096u, /*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( /*taskCount*/ (extraWrites ? tcu::just(1u) : tcu::Nothing), /*meshCount*/ 1u, /*width*/ 16u, /*height*/ 16u, /*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( /*taskCount*/ (useTaskShader ? tcu::just(1u) : tcu::Nothing), /*meshCount*/ 1u, /*width*/ 1u, /*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( /*taskCount*/ (useTaskShader ? tcu::just(1u) : tcu::Nothing), /*meshCount*/ 1u, /*width*/ 1u, /*height*/ 1u, /*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( /*taskCount*/ (useTaskShader ? tcu::just(1u) : tcu::Nothing), /*meshCount*/ 1u, /*width*/ 32u, /*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( /*taskCount*/ (useTaskShader ? tcu::just(1u) : tcu::Nothing), /*meshCount*/ 1u, /*width*/ 16u, /*height*/ 16u)); miscTests->addChild(new PushConstantCase(testCtx, name, desc, std::move(paramsPtr))); } } { ParamsPtr paramsPtr (new MaximizeThreadsParams( /*taskCount*/ tcu::Nothing, /*meshCount*/ 1u, /*width*/ 128u, /*height*/ 1u, /*localSize*/ 32u, /*numVertices*/ 128u, /*numPrimitives*/ 256u)); miscTests->addChild(new MaximizePrimitivesCase(testCtx, "maximize_primitives", "Use a large number of primitives compared to other sizes", std::move(paramsPtr))); } { ParamsPtr paramsPtr (new MaximizeThreadsParams( /*taskCount*/ tcu::Nothing, /*meshCount*/ 1u, /*width*/ 64u, /*height*/ 1u, /*localSize*/ 32u, /*numVertices*/ 256u, /*numPrimitives*/ 128u)); miscTests->addChild(new MaximizeVerticesCase(testCtx, "maximize_vertices", "Use a large number of vertices compared to other sizes", std::move(paramsPtr))); } { const uint32_t kInvocationCases[] = { 32u, 64u, 128u, 256u }; for (const auto& invocationCase : kInvocationCases) { const auto invsStr = std::to_string(invocationCase); const auto numPixels = invocationCase / 2u; ParamsPtr paramsPtr (new MaximizeThreadsParams( /*taskCount*/ tcu::Nothing, /*meshCount*/ 1u, /*width*/ numPixels, /*height*/ 1u, /*localSize*/ invocationCase, /*numVertices*/ numPixels, /*numPrimitives*/ numPixels)); miscTests->addChild(new MaximizeInvocationsCase(testCtx, "maximize_invocations_" + invsStr, "Use a large number of invocations compared to other sizes: " + invsStr, std::move(paramsPtr))); } } if (false) // This test does not work and the spec is not clear that it should. { ParamsPtr paramsPtr (new MiscTestParams( /*taskCount*/ tcu::just(1u), /*meshCount*/ 128u, /*width*/ 32u, /*height*/ 128u)); miscTests->addChild(new CountReadCase(testCtx, "count_reads", "Attempt to read gl_TaskCountNV and gl_PrimitiveCountNV from multiple invocations", std::move(paramsPtr))); } addFunctionCaseWithPrograms(miscTests.get(), "mixed_pipelines", "Mix classic and mesh shader pipelines in the same render pass", checkMeshSupport, initMixedPipelinesPrograms, testMixedPipelines); return miscTests.release(); } tcu::TestCaseGroup* createMeshShaderInOutTests (tcu::TestContext& testCtx) { GroupPtr inOutTests (new tcu::TestCaseGroup(testCtx, "in_out", "Mesh Shader Tests checking Input/Output interfaces")); const struct { bool i64; bool f64; bool i16; bool f16; const char* name; } requiredFeatures[] = { // Restrict the number of combinations to avoid creating too many tests. // i64 f64 i16 f16 name { false, false, false, false, "32_bits_only" }, { true, false, false, false, "with_i64" }, { false, true, false, false, "with_f64" }, { true, true, false, false, "all_but_16_bits" }, { false, false, true, false, "with_i16" }, { false, false, false, true, "with_f16" }, { true, true, true, true, "all_types" }, }; Owner ownerCases[] = { Owner::VERTEX, Owner::PRIMITIVE }; DataType dataTypeCases[] = { DataType::FLOAT, DataType::INTEGER }; BitWidth bitWidthCases[] = { BitWidth::B64, BitWidth::B32, BitWidth::B16 }; DataDim dataDimCases[] = { DataDim::SCALAR, DataDim::VEC2, DataDim::VEC3, DataDim::VEC4 }; Interpolation interpolationCases[] = { Interpolation::NORMAL, Interpolation::FLAT }; de::Random rnd(1636723398u); for (const auto& reqs : requiredFeatures) { GroupPtr reqsGroup (new tcu::TestCaseGroup(testCtx, reqs.name, "")); // Generate the variable list according to the group requirements. IfaceVarVecPtr varsPtr(new IfaceVarVec); for (const auto& ownerCase : ownerCases) for (const auto& dataTypeCase : dataTypeCases) for (const auto& bitWidthCase : bitWidthCases) for (const auto& dataDimCase : dataDimCases) for (const auto& interpolationCase : interpolationCases) { if (dataTypeCase == DataType::FLOAT) { if (bitWidthCase == BitWidth::B64 && !reqs.f64) continue; if (bitWidthCase == BitWidth::B16 && !reqs.f16) continue; } else if (dataTypeCase == DataType::INTEGER) { if (bitWidthCase == BitWidth::B64 && !reqs.i64) continue; if (bitWidthCase == BitWidth::B16 && !reqs.i16) continue; } if (dataTypeCase == DataType::INTEGER && interpolationCase == Interpolation::NORMAL) continue; if (ownerCase == Owner::PRIMITIVE && interpolationCase == Interpolation::NORMAL) continue; if (dataTypeCase == DataType::FLOAT && bitWidthCase == BitWidth::B64 && interpolationCase == Interpolation::NORMAL) continue; for (uint32_t idx = 0u; idx < IfaceVar::kVarsPerType; ++idx) varsPtr->push_back(IfaceVar(ownerCase, dataTypeCase, bitWidthCase, dataDimCase, interpolationCase, idx)); } // Generating all permutations of the variables above would mean millions of tests, so we just generate some pseudorandom permutations. constexpr uint32_t kPermutations = 40u; for (uint32_t combIdx = 0; combIdx < kPermutations; ++combIdx) { const auto caseName = "permutation_" + std::to_string(combIdx); GroupPtr rndGroup(new tcu::TestCaseGroup(testCtx, caseName.c_str(), "")); // Duplicate and shuffle vector. IfaceVarVecPtr permutVec (new IfaceVarVec(*varsPtr)); rnd.shuffle(begin(*permutVec), end(*permutVec)); // Cut the vector short to the usable number of locations. { uint32_t usedLocations = 0u; size_t vectorEnd = 0u; auto& varVec = *permutVec; for (size_t i = 0; i < varVec.size(); ++i) { vectorEnd = i; const auto varSize = varVec[i].getLocationSize(); if (usedLocations + varSize > InterfaceVariablesCase::kMaxLocations) break; usedLocations += varSize; } varVec.resize(vectorEnd); } for (int i = 0; i < 2; ++i) { const bool useTaskShader = (i > 0); const auto name = (useTaskShader ? "task_mesh" : "mesh_only"); // Duplicate vector for this particular case so both variants have the same shuffle. IfaceVarVecPtr paramsVec(new IfaceVarVec(*permutVec)); ParamsPtr paramsPtr (new InterfaceVariableParams( /*taskCount*/ (useTaskShader ? tcu::just(1u) : tcu::Nothing), /*meshCount*/ 1u, /*width*/ 8u, /*height*/ 8u, /*useInt64*/ reqs.i64, /*useFloat64*/ reqs.f64, /*useInt16*/ reqs.i16, /*useFloat16*/ reqs.f16, /*vars*/ std::move(paramsVec))); rndGroup->addChild(new InterfaceVariablesCase(testCtx, name, "", std::move(paramsPtr))); } reqsGroup->addChild(rndGroup.release()); } inOutTests->addChild(reqsGroup.release()); } return inOutTests.release(); } } // MeshShader } // vkt