1e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------ 2e5c31af7Sopenharmony_ci * Vulkan Conformance Tests 3e5c31af7Sopenharmony_ci * ------------------------ 4e5c31af7Sopenharmony_ci * 5e5c31af7Sopenharmony_ci * Copyright (c) 2021 The Khronos Group Inc. 6e5c31af7Sopenharmony_ci * Copyright (c) 2021 Valve Corporation. 7e5c31af7Sopenharmony_ci * 8e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 9e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License. 10e5c31af7Sopenharmony_ci * You may obtain a copy of the License at 11e5c31af7Sopenharmony_ci * 12e5c31af7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 13e5c31af7Sopenharmony_ci * 14e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 15e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 16e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and 18e5c31af7Sopenharmony_ci * limitations under the License. 19e5c31af7Sopenharmony_ci * 20e5c31af7Sopenharmony_ci *//*! 21e5c31af7Sopenharmony_ci * \file 22e5c31af7Sopenharmony_ci * \brief Mesh Shader API Tests 23e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/ 24e5c31af7Sopenharmony_ci 25e5c31af7Sopenharmony_ci#include "vktMeshShaderApiTests.hpp" 26e5c31af7Sopenharmony_ci#include "vktMeshShaderUtil.hpp" 27e5c31af7Sopenharmony_ci#include "vktTestCase.hpp" 28e5c31af7Sopenharmony_ci 29e5c31af7Sopenharmony_ci#include "vkTypeUtil.hpp" 30e5c31af7Sopenharmony_ci#include "vkImageWithMemory.hpp" 31e5c31af7Sopenharmony_ci#include "vkBufferWithMemory.hpp" 32e5c31af7Sopenharmony_ci#include "vkObjUtil.hpp" 33e5c31af7Sopenharmony_ci#include "vkBuilderUtil.hpp" 34e5c31af7Sopenharmony_ci#include "vkCmdUtil.hpp" 35e5c31af7Sopenharmony_ci#include "vkImageUtil.hpp" 36e5c31af7Sopenharmony_ci 37e5c31af7Sopenharmony_ci#include "tcuMaybe.hpp" 38e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp" 39e5c31af7Sopenharmony_ci#include "tcuImageCompare.hpp" 40e5c31af7Sopenharmony_ci 41e5c31af7Sopenharmony_ci#include "deRandom.hpp" 42e5c31af7Sopenharmony_ci 43e5c31af7Sopenharmony_ci#include <iostream> 44e5c31af7Sopenharmony_ci#include <sstream> 45e5c31af7Sopenharmony_ci#include <vector> 46e5c31af7Sopenharmony_ci#include <algorithm> 47e5c31af7Sopenharmony_ci#include <iterator> 48e5c31af7Sopenharmony_ci#include <limits> 49e5c31af7Sopenharmony_ci 50e5c31af7Sopenharmony_cinamespace vkt 51e5c31af7Sopenharmony_ci{ 52e5c31af7Sopenharmony_cinamespace MeshShader 53e5c31af7Sopenharmony_ci{ 54e5c31af7Sopenharmony_ci 55e5c31af7Sopenharmony_cinamespace 56e5c31af7Sopenharmony_ci{ 57e5c31af7Sopenharmony_ci 58e5c31af7Sopenharmony_ciusing namespace vk; 59e5c31af7Sopenharmony_ci 60e5c31af7Sopenharmony_ciusing GroupPtr = de::MovePtr<tcu::TestCaseGroup>; 61e5c31af7Sopenharmony_ciusing ImageWithMemoryPtr = de::MovePtr<ImageWithMemory>; 62e5c31af7Sopenharmony_ciusing BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>; 63e5c31af7Sopenharmony_ci 64e5c31af7Sopenharmony_cienum class DrawType 65e5c31af7Sopenharmony_ci{ 66e5c31af7Sopenharmony_ci DRAW = 0, 67e5c31af7Sopenharmony_ci DRAW_INDIRECT, 68e5c31af7Sopenharmony_ci DRAW_INDIRECT_COUNT, 69e5c31af7Sopenharmony_ci}; 70e5c31af7Sopenharmony_ci 71e5c31af7Sopenharmony_cistd::ostream& operator<< (std::ostream& stream, DrawType drawType) 72e5c31af7Sopenharmony_ci{ 73e5c31af7Sopenharmony_ci switch (drawType) 74e5c31af7Sopenharmony_ci { 75e5c31af7Sopenharmony_ci case DrawType::DRAW: stream << "draw"; break; 76e5c31af7Sopenharmony_ci case DrawType::DRAW_INDIRECT: stream << "draw_indirect"; break; 77e5c31af7Sopenharmony_ci case DrawType::DRAW_INDIRECT_COUNT: stream << "draw_indirect_count"; break; 78e5c31af7Sopenharmony_ci default: DE_ASSERT(false); break; 79e5c31af7Sopenharmony_ci } 80e5c31af7Sopenharmony_ci return stream; 81e5c31af7Sopenharmony_ci} 82e5c31af7Sopenharmony_ci 83e5c31af7Sopenharmony_ci 84e5c31af7Sopenharmony_ci// This helps test the maxDrawCount rule for the DRAW_INDIRECT_COUNT case. 85e5c31af7Sopenharmony_cienum class IndirectCountLimitType 86e5c31af7Sopenharmony_ci{ 87e5c31af7Sopenharmony_ci BUFFER_VALUE = 0, // The actual count will be given by the count buffer. 88e5c31af7Sopenharmony_ci MAX_COUNT, // The actual count will be given by the maxDrawCount argument passed to the draw command. 89e5c31af7Sopenharmony_ci}; 90e5c31af7Sopenharmony_ci 91e5c31af7Sopenharmony_cistruct IndirectArgs 92e5c31af7Sopenharmony_ci{ 93e5c31af7Sopenharmony_ci uint32_t offset; 94e5c31af7Sopenharmony_ci uint32_t stride; 95e5c31af7Sopenharmony_ci}; 96e5c31af7Sopenharmony_ci 97e5c31af7Sopenharmony_cistruct TestParams 98e5c31af7Sopenharmony_ci{ 99e5c31af7Sopenharmony_ci DrawType drawType; 100e5c31af7Sopenharmony_ci uint32_t seed; 101e5c31af7Sopenharmony_ci uint32_t drawCount; // Equivalent to taskCount or drawCount. 102e5c31af7Sopenharmony_ci uint32_t firstTask; // Equivalent to firstTask in every call. 103e5c31af7Sopenharmony_ci tcu::Maybe<IndirectArgs> indirectArgs; // Only used for DRAW_INDIRECT*. 104e5c31af7Sopenharmony_ci tcu::Maybe<IndirectCountLimitType> indirectCountLimit; // Only used for DRAW_INDIRECT_COUNT. 105e5c31af7Sopenharmony_ci tcu::Maybe<uint32_t> indirectCountOffset; // Only used for DRAW_INDIRECT_COUNT. 106e5c31af7Sopenharmony_ci bool useTask; 107e5c31af7Sopenharmony_ci}; 108e5c31af7Sopenharmony_ci 109e5c31af7Sopenharmony_ci// The framebuffer will have a number of rows and 32 columns. Each mesh shader workgroup will generate geometry to fill a single 110e5c31af7Sopenharmony_ci// framebuffer row, using a triangle list with 32 triangles of different colors, each covering a framebuffer pixel. 111e5c31af7Sopenharmony_ci// 112e5c31af7Sopenharmony_ci// Note: the total framebuffer rows is called "full" below (e.g. 64). When using a task shader to generate work, each workgroup will 113e5c31af7Sopenharmony_ci// generate a single mesh workgroup using a push constant instead of a compile-time constant. 114e5c31af7Sopenharmony_ci// 115e5c31af7Sopenharmony_ci// When using DRAW, the task count will tell us how many rows of pixels will be filled in the framebuffer. 116e5c31af7Sopenharmony_ci// 117e5c31af7Sopenharmony_ci// When using indirect draws, the full framebuffer will always be drawn into by using multiple draw command structures, except in 118e5c31af7Sopenharmony_ci// the case of drawCount==0. Each draw will spawn the needed number of tasks to fill the whole framebuffer. In addition, in order to 119e5c31af7Sopenharmony_ci// make all argument structures different, the number of tasks in each draw count will be slightly different and assigned 120e5c31af7Sopenharmony_ci// pseudorandomly. 121e5c31af7Sopenharmony_ci// 122e5c31af7Sopenharmony_ci// DRAW: taskCount=0, taskCount=1, taskCount=2, taskCount=half, taskCount=full 123e5c31af7Sopenharmony_ci// 124e5c31af7Sopenharmony_ci// DRAW_INDIRECT: drawCount=0, drawCount=1, drawCount=2, drawCount=half, drawCount=full. 125e5c31af7Sopenharmony_ci// * With offset 0 and pseudorandom (multiples of 4). 126e5c31af7Sopenharmony_ci// * With stride adding a padding of 0 and pseudorandom (multiples of 4). 127e5c31af7Sopenharmony_ci// 128e5c31af7Sopenharmony_ci// DRAW_INDIRECT_COUNT: same as indirect in two variants: 129e5c31af7Sopenharmony_ci// 1. Passing the count in a buffer with a large maximum. 130e5c31af7Sopenharmony_ci// 2. Passing a large value in the buffer and limiting it with the maximum. 131e5c31af7Sopenharmony_ci 132e5c31af7Sopenharmony_ciclass MeshApiCase : public vkt::TestCase 133e5c31af7Sopenharmony_ci{ 134e5c31af7Sopenharmony_cipublic: 135e5c31af7Sopenharmony_ci MeshApiCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params) 136e5c31af7Sopenharmony_ci : vkt::TestCase (testCtx, name) 137e5c31af7Sopenharmony_ci , m_params (params) 138e5c31af7Sopenharmony_ci {} 139e5c31af7Sopenharmony_ci virtual ~MeshApiCase (void) {} 140e5c31af7Sopenharmony_ci 141e5c31af7Sopenharmony_ci void initPrograms (vk::SourceCollections& programCollection) const override; 142e5c31af7Sopenharmony_ci void checkSupport (Context& context) const override; 143e5c31af7Sopenharmony_ci TestInstance* createInstance (Context& context) const override; 144e5c31af7Sopenharmony_ci 145e5c31af7Sopenharmony_ciprotected: 146e5c31af7Sopenharmony_ci TestParams m_params; 147e5c31af7Sopenharmony_ci}; 148e5c31af7Sopenharmony_ci 149e5c31af7Sopenharmony_ciclass MeshApiInstance : public vkt::TestInstance 150e5c31af7Sopenharmony_ci{ 151e5c31af7Sopenharmony_cipublic: 152e5c31af7Sopenharmony_ci MeshApiInstance (Context& context, const TestParams& params) 153e5c31af7Sopenharmony_ci : vkt::TestInstance (context) 154e5c31af7Sopenharmony_ci , m_params (params) 155e5c31af7Sopenharmony_ci {} 156e5c31af7Sopenharmony_ci virtual ~MeshApiInstance (void) {} 157e5c31af7Sopenharmony_ci 158e5c31af7Sopenharmony_ci tcu::TestStatus iterate (void) override; 159e5c31af7Sopenharmony_ci 160e5c31af7Sopenharmony_ciprotected: 161e5c31af7Sopenharmony_ci TestParams m_params; 162e5c31af7Sopenharmony_ci}; 163e5c31af7Sopenharmony_ci 164e5c31af7Sopenharmony_ciTestInstance* MeshApiCase::createInstance (Context& context) const 165e5c31af7Sopenharmony_ci{ 166e5c31af7Sopenharmony_ci return new MeshApiInstance(context, m_params); 167e5c31af7Sopenharmony_ci} 168e5c31af7Sopenharmony_ci 169e5c31af7Sopenharmony_cistruct PushConstantData 170e5c31af7Sopenharmony_ci{ 171e5c31af7Sopenharmony_ci uint32_t width; 172e5c31af7Sopenharmony_ci uint32_t height; 173e5c31af7Sopenharmony_ci uint32_t firstTaskMesh; 174e5c31af7Sopenharmony_ci uint32_t one; 175e5c31af7Sopenharmony_ci uint32_t firstTaskTask; 176e5c31af7Sopenharmony_ci 177e5c31af7Sopenharmony_ci std::vector<VkPushConstantRange> getRanges (bool includeTask) const 178e5c31af7Sopenharmony_ci { 179e5c31af7Sopenharmony_ci constexpr uint32_t offsetMesh = 0u; 180e5c31af7Sopenharmony_ci constexpr uint32_t offsetTask = static_cast<uint32_t>(offsetof(PushConstantData, one)); 181e5c31af7Sopenharmony_ci constexpr uint32_t sizeMesh = offsetTask; 182e5c31af7Sopenharmony_ci constexpr uint32_t sizeTask = static_cast<uint32_t>(sizeof(PushConstantData)) - offsetTask; 183e5c31af7Sopenharmony_ci 184e5c31af7Sopenharmony_ci const VkPushConstantRange meshRange = 185e5c31af7Sopenharmony_ci { 186e5c31af7Sopenharmony_ci VK_SHADER_STAGE_MESH_BIT_NV, // VkShaderStageFlags stageFlags; 187e5c31af7Sopenharmony_ci offsetMesh, // uint32_t offset; 188e5c31af7Sopenharmony_ci sizeMesh, // uint32_t size; 189e5c31af7Sopenharmony_ci }; 190e5c31af7Sopenharmony_ci const VkPushConstantRange taskRange = 191e5c31af7Sopenharmony_ci { 192e5c31af7Sopenharmony_ci VK_SHADER_STAGE_TASK_BIT_NV, // VkShaderStageFlags stageFlags; 193e5c31af7Sopenharmony_ci offsetTask, // uint32_t offset; 194e5c31af7Sopenharmony_ci sizeTask, // uint32_t size; 195e5c31af7Sopenharmony_ci }; 196e5c31af7Sopenharmony_ci 197e5c31af7Sopenharmony_ci std::vector<VkPushConstantRange> ranges (1u, meshRange); 198e5c31af7Sopenharmony_ci if (includeTask) 199e5c31af7Sopenharmony_ci ranges.push_back(taskRange); 200e5c31af7Sopenharmony_ci return ranges; 201e5c31af7Sopenharmony_ci } 202e5c31af7Sopenharmony_ci}; 203e5c31af7Sopenharmony_ci 204e5c31af7Sopenharmony_civoid MeshApiCase::initPrograms (vk::SourceCollections& programCollection) const 205e5c31af7Sopenharmony_ci{ 206e5c31af7Sopenharmony_ci const std::string taskDataDecl = 207e5c31af7Sopenharmony_ci "taskNV TaskData {\n" 208e5c31af7Sopenharmony_ci " uint blockNumber;\n" 209e5c31af7Sopenharmony_ci " uint blockRow;\n" 210e5c31af7Sopenharmony_ci "} td;\n" 211e5c31af7Sopenharmony_ci ; 212e5c31af7Sopenharmony_ci 213e5c31af7Sopenharmony_ci // Task shader if needed. 214e5c31af7Sopenharmony_ci if (m_params.useTask) 215e5c31af7Sopenharmony_ci { 216e5c31af7Sopenharmony_ci std::ostringstream task; 217e5c31af7Sopenharmony_ci task 218e5c31af7Sopenharmony_ci << "#version 460\n" 219e5c31af7Sopenharmony_ci << "#extension GL_NV_mesh_shader : enable\n" 220e5c31af7Sopenharmony_ci << "\n" 221e5c31af7Sopenharmony_ci << "layout (local_size_x=1) in;\n" 222e5c31af7Sopenharmony_ci << "\n" 223e5c31af7Sopenharmony_ci << "layout (push_constant, std430) uniform TaskPushConstantBlock {\n" 224e5c31af7Sopenharmony_ci << " layout (offset=12) uint one;\n" 225e5c31af7Sopenharmony_ci << " layout (offset=16) uint firstTask;\n" 226e5c31af7Sopenharmony_ci << "} pc;\n" 227e5c31af7Sopenharmony_ci << "\n" 228e5c31af7Sopenharmony_ci << "out " << taskDataDecl 229e5c31af7Sopenharmony_ci << "\n" 230e5c31af7Sopenharmony_ci << "void main ()\n" 231e5c31af7Sopenharmony_ci << "{\n" 232e5c31af7Sopenharmony_ci << " gl_TaskCountNV = pc.one;\n" 233e5c31af7Sopenharmony_ci << " td.blockNumber = uint(gl_DrawID);\n" 234e5c31af7Sopenharmony_ci << " td.blockRow = gl_WorkGroupID.x - pc.firstTask;\n" 235e5c31af7Sopenharmony_ci << "}\n" 236e5c31af7Sopenharmony_ci ; 237e5c31af7Sopenharmony_ci programCollection.glslSources.add("task") << glu::TaskSource(task.str()); 238e5c31af7Sopenharmony_ci } 239e5c31af7Sopenharmony_ci 240e5c31af7Sopenharmony_ci // Mesh shader. 241e5c31af7Sopenharmony_ci { 242e5c31af7Sopenharmony_ci std::ostringstream mesh; 243e5c31af7Sopenharmony_ci mesh 244e5c31af7Sopenharmony_ci << "#version 460\n" 245e5c31af7Sopenharmony_ci << "#extension GL_NV_mesh_shader : enable\n" 246e5c31af7Sopenharmony_ci << "\n" 247e5c31af7Sopenharmony_ci << "layout (local_size_x=32) in;\n" 248e5c31af7Sopenharmony_ci << "layout (triangles) out;\n" 249e5c31af7Sopenharmony_ci << "layout (max_vertices=96, max_primitives=32) out;\n" 250e5c31af7Sopenharmony_ci << "\n" 251e5c31af7Sopenharmony_ci << "layout (push_constant, std430) uniform MeshPushConstantBlock {\n" 252e5c31af7Sopenharmony_ci << " uint width;\n" 253e5c31af7Sopenharmony_ci << " uint height;\n" 254e5c31af7Sopenharmony_ci << " uint firstTask;\n" 255e5c31af7Sopenharmony_ci << "} pc;\n" 256e5c31af7Sopenharmony_ci << "\n" 257e5c31af7Sopenharmony_ci << "layout (location=0) perprimitiveNV out vec4 primitiveColor[];\n" 258e5c31af7Sopenharmony_ci << "\n" 259e5c31af7Sopenharmony_ci << (m_params.useTask ? ("in " + taskDataDecl): "") 260e5c31af7Sopenharmony_ci << "\n" 261e5c31af7Sopenharmony_ci << "layout (set=0, binding=0, std430) readonly buffer BlockSizes {\n" 262e5c31af7Sopenharmony_ci << " uint blockSize[];\n" 263e5c31af7Sopenharmony_ci << "} bsz;\n" 264e5c31af7Sopenharmony_ci << "\n" 265e5c31af7Sopenharmony_ci << "uint startOfBlock (uint blockNumber)\n" 266e5c31af7Sopenharmony_ci << "{\n" 267e5c31af7Sopenharmony_ci << " uint start = 0;\n" 268e5c31af7Sopenharmony_ci << " for (uint i = 0; i < blockNumber; i++)\n" 269e5c31af7Sopenharmony_ci << " start += bsz.blockSize[i];\n" 270e5c31af7Sopenharmony_ci << " return start;\n" 271e5c31af7Sopenharmony_ci << "}\n" 272e5c31af7Sopenharmony_ci << "\n" 273e5c31af7Sopenharmony_ci << "void main ()\n" 274e5c31af7Sopenharmony_ci << "{\n" 275e5c31af7Sopenharmony_ci << " const uint blockNumber = " << (m_params.useTask ? "td.blockNumber" : "uint(gl_DrawID)") << ";\n" 276e5c31af7Sopenharmony_ci << " const uint blockRow = " << (m_params.useTask ? "td.blockRow" : "(gl_WorkGroupID.x - pc.firstTask)") << ";\n" 277e5c31af7Sopenharmony_ci << "\n" 278e5c31af7Sopenharmony_ci << " // Each workgroup will fill one row, and each invocation will generate a\n" 279e5c31af7Sopenharmony_ci << " // triangle around the pixel center in each column.\n" 280e5c31af7Sopenharmony_ci << " const uint row = startOfBlock(blockNumber) + blockRow;\n" 281e5c31af7Sopenharmony_ci << " const uint col = gl_LocalInvocationID.x;\n" 282e5c31af7Sopenharmony_ci << "\n" 283e5c31af7Sopenharmony_ci << " const float fHeight = float(pc.height);\n" 284e5c31af7Sopenharmony_ci << " const float fWidth = float(pc.width);\n" 285e5c31af7Sopenharmony_ci << "\n" 286e5c31af7Sopenharmony_ci << " // Pixel coordinates, normalized.\n" 287e5c31af7Sopenharmony_ci << " const float rowNorm = (float(row) + 0.5) / fHeight;\n" 288e5c31af7Sopenharmony_ci << " const float colNorm = (float(col) + 0.5) / fWidth;\n" 289e5c31af7Sopenharmony_ci << "\n" 290e5c31af7Sopenharmony_ci << " // Framebuffer coordinates.\n" 291e5c31af7Sopenharmony_ci << " const float coordX = (colNorm * 2.0) - 1.0;\n" 292e5c31af7Sopenharmony_ci << " const float coordY = (rowNorm * 2.0) - 1.0;\n" 293e5c31af7Sopenharmony_ci << "\n" 294e5c31af7Sopenharmony_ci << " const float pixelWidth = 2.0 / fWidth;\n" 295e5c31af7Sopenharmony_ci << " const float pixelHeight = 2.0 / fHeight;\n" 296e5c31af7Sopenharmony_ci << "\n" 297e5c31af7Sopenharmony_ci << " const float offsetX = pixelWidth / 2.0;\n" 298e5c31af7Sopenharmony_ci << " const float offsetY = pixelHeight / 2.0;\n" 299e5c31af7Sopenharmony_ci << "\n" 300e5c31af7Sopenharmony_ci << " const uint baseIndex = col*3;\n" 301e5c31af7Sopenharmony_ci << " const uvec3 indices = uvec3(baseIndex, baseIndex + 1, baseIndex + 2);\n" 302e5c31af7Sopenharmony_ci << "\n" 303e5c31af7Sopenharmony_ci << " gl_PrimitiveCountNV = 32u;\n" 304e5c31af7Sopenharmony_ci << " primitiveColor[col] = vec4(rowNorm, colNorm, 0.0, 1.0);\n" 305e5c31af7Sopenharmony_ci << "\n" 306e5c31af7Sopenharmony_ci << " gl_PrimitiveIndicesNV[indices.x] = indices.x;\n" 307e5c31af7Sopenharmony_ci << " gl_PrimitiveIndicesNV[indices.y] = indices.y;\n" 308e5c31af7Sopenharmony_ci << " gl_PrimitiveIndicesNV[indices.z] = indices.z;\n" 309e5c31af7Sopenharmony_ci << "\n" 310e5c31af7Sopenharmony_ci << " gl_MeshVerticesNV[indices.x].gl_Position = vec4(coordX - offsetX, coordY + offsetY, 0.0, 1.0);\n" 311e5c31af7Sopenharmony_ci << " gl_MeshVerticesNV[indices.y].gl_Position = vec4(coordX + offsetX, coordY + offsetY, 0.0, 1.0);\n" 312e5c31af7Sopenharmony_ci << " gl_MeshVerticesNV[indices.z].gl_Position = vec4(coordX, coordY - offsetY, 0.0, 1.0);\n" 313e5c31af7Sopenharmony_ci << "}\n" 314e5c31af7Sopenharmony_ci ; 315e5c31af7Sopenharmony_ci programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()); 316e5c31af7Sopenharmony_ci } 317e5c31af7Sopenharmony_ci 318e5c31af7Sopenharmony_ci // Frag shader. 319e5c31af7Sopenharmony_ci { 320e5c31af7Sopenharmony_ci std::ostringstream frag; 321e5c31af7Sopenharmony_ci frag 322e5c31af7Sopenharmony_ci << "#version 460\n" 323e5c31af7Sopenharmony_ci << "#extension GL_NV_mesh_shader : enable\n" 324e5c31af7Sopenharmony_ci << "\n" 325e5c31af7Sopenharmony_ci << "layout (location=0) perprimitiveNV in vec4 primitiveColor;\n" 326e5c31af7Sopenharmony_ci << "layout (location=0) out vec4 outColor;\n" 327e5c31af7Sopenharmony_ci << "\n" 328e5c31af7Sopenharmony_ci << "void main ()\n" 329e5c31af7Sopenharmony_ci << "{\n" 330e5c31af7Sopenharmony_ci << " outColor = primitiveColor;\n" 331e5c31af7Sopenharmony_ci << "}\n" 332e5c31af7Sopenharmony_ci ; 333e5c31af7Sopenharmony_ci programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()); 334e5c31af7Sopenharmony_ci } 335e5c31af7Sopenharmony_ci} 336e5c31af7Sopenharmony_ci 337e5c31af7Sopenharmony_civoid MeshApiCase::checkSupport (Context& context) const 338e5c31af7Sopenharmony_ci{ 339e5c31af7Sopenharmony_ci checkTaskMeshShaderSupportNV(context, m_params.useTask, true); 340e5c31af7Sopenharmony_ci 341e5c31af7Sopenharmony_ci // VUID-vkCmdDrawMeshTasksIndirectNV-drawCount-02718 342e5c31af7Sopenharmony_ci if (m_params.drawType == DrawType::DRAW_INDIRECT && m_params.drawCount > 1u) 343e5c31af7Sopenharmony_ci { 344e5c31af7Sopenharmony_ci context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_DRAW_INDIRECT); 345e5c31af7Sopenharmony_ci } 346e5c31af7Sopenharmony_ci 347e5c31af7Sopenharmony_ci // VUID-vkCmdDrawMeshTasksIndirectCountNV-None-04445 348e5c31af7Sopenharmony_ci if (m_params.drawType == DrawType::DRAW_INDIRECT_COUNT) 349e5c31af7Sopenharmony_ci context.requireDeviceFunctionality("VK_KHR_draw_indirect_count"); 350e5c31af7Sopenharmony_ci} 351e5c31af7Sopenharmony_ci 352e5c31af7Sopenharmony_citemplate <typename T> 353e5c31af7Sopenharmony_ciBufferWithMemoryPtr makeStridedBuffer(const DeviceInterface& vkd, VkDevice device, Allocator& alloc, const std::vector<T>& elements, uint32_t offset, uint32_t stride, VkBufferUsageFlags usage, uint32_t endPadding) 354e5c31af7Sopenharmony_ci{ 355e5c31af7Sopenharmony_ci const auto elementSize = static_cast<uint32_t>(sizeof(T)); 356e5c31af7Sopenharmony_ci const auto actualStride = std::max(elementSize, stride); 357e5c31af7Sopenharmony_ci const auto bufferSize = static_cast<size_t>(offset) + static_cast<size_t>(actualStride) * elements.size() + static_cast<size_t>(endPadding); 358e5c31af7Sopenharmony_ci const auto bufferInfo = makeBufferCreateInfo(static_cast<VkDeviceSize>(bufferSize), usage); 359e5c31af7Sopenharmony_ci 360e5c31af7Sopenharmony_ci BufferWithMemoryPtr buffer(new BufferWithMemory(vkd, device, alloc, bufferInfo, MemoryRequirement::HostVisible)); 361e5c31af7Sopenharmony_ci auto& bufferAlloc = buffer->getAllocation(); 362e5c31af7Sopenharmony_ci char* bufferDataPtr = reinterpret_cast<char*>(bufferAlloc.getHostPtr()); 363e5c31af7Sopenharmony_ci 364e5c31af7Sopenharmony_ci char* itr = bufferDataPtr + offset; 365e5c31af7Sopenharmony_ci for (const auto& elem : elements) 366e5c31af7Sopenharmony_ci { 367e5c31af7Sopenharmony_ci deMemcpy(itr, &elem, sizeof(elem)); 368e5c31af7Sopenharmony_ci itr += actualStride; 369e5c31af7Sopenharmony_ci } 370e5c31af7Sopenharmony_ci if (endPadding > 0u) 371e5c31af7Sopenharmony_ci deMemset(itr, 0xFF, endPadding); 372e5c31af7Sopenharmony_ci 373e5c31af7Sopenharmony_ci flushAlloc(vkd, device, bufferAlloc); 374e5c31af7Sopenharmony_ci 375e5c31af7Sopenharmony_ci return buffer; 376e5c31af7Sopenharmony_ci} 377e5c31af7Sopenharmony_ci 378e5c31af7Sopenharmony_ciVkExtent3D getExtent () 379e5c31af7Sopenharmony_ci{ 380e5c31af7Sopenharmony_ci return makeExtent3D(32u, 64u, 1u); 381e5c31af7Sopenharmony_ci} 382e5c31af7Sopenharmony_ci 383e5c31af7Sopenharmony_citcu::TestStatus MeshApiInstance::iterate (void) 384e5c31af7Sopenharmony_ci{ 385e5c31af7Sopenharmony_ci const auto& vkd = m_context.getDeviceInterface(); 386e5c31af7Sopenharmony_ci const auto device = m_context.getDevice(); 387e5c31af7Sopenharmony_ci auto& alloc = m_context.getDefaultAllocator(); 388e5c31af7Sopenharmony_ci const auto queueIndex = m_context.getUniversalQueueFamilyIndex(); 389e5c31af7Sopenharmony_ci const auto queue = m_context.getUniversalQueue(); 390e5c31af7Sopenharmony_ci 391e5c31af7Sopenharmony_ci const auto extent = getExtent(); 392e5c31af7Sopenharmony_ci const auto iExtent3D = tcu::IVec3(static_cast<int>(extent.width), static_cast<int>(extent.height), static_cast<int>(extent.depth)); 393e5c31af7Sopenharmony_ci const auto iExtent2D = tcu::IVec2(iExtent3D.x(), iExtent3D.y()); 394e5c31af7Sopenharmony_ci const auto format = VK_FORMAT_R8G8B8A8_UNORM; 395e5c31af7Sopenharmony_ci const auto tcuFormat = mapVkFormat(format); 396e5c31af7Sopenharmony_ci const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); 397e5c31af7Sopenharmony_ci const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); 398e5c31af7Sopenharmony_ci const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f); 399e5c31af7Sopenharmony_ci const float colorThres = 0.005f; // 1/255 < 0.005 < 2/255 400e5c31af7Sopenharmony_ci const tcu::Vec4 threshold (colorThres, colorThres, 0.0f, 0.0f); 401e5c31af7Sopenharmony_ci 402e5c31af7Sopenharmony_ci ImageWithMemoryPtr colorBuffer; 403e5c31af7Sopenharmony_ci Move<VkImageView> colorBufferView; 404e5c31af7Sopenharmony_ci { 405e5c31af7Sopenharmony_ci const VkImageCreateInfo colorBufferInfo = 406e5c31af7Sopenharmony_ci { 407e5c31af7Sopenharmony_ci VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; 408e5c31af7Sopenharmony_ci nullptr, // const void* pNext; 409e5c31af7Sopenharmony_ci 0u, // VkImageCreateFlags flags; 410e5c31af7Sopenharmony_ci VK_IMAGE_TYPE_2D, // VkImageType imageType; 411e5c31af7Sopenharmony_ci format, // VkFormat format; 412e5c31af7Sopenharmony_ci extent, // VkExtent3D extent; 413e5c31af7Sopenharmony_ci 1u, // uint32_t mipLevels; 414e5c31af7Sopenharmony_ci 1u, // uint32_t arrayLayers; 415e5c31af7Sopenharmony_ci VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 416e5c31af7Sopenharmony_ci VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; 417e5c31af7Sopenharmony_ci colorUsage, // VkImageUsageFlags usage; 418e5c31af7Sopenharmony_ci VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 419e5c31af7Sopenharmony_ci 0u, // uint32_t queueFamilyIndexCount; 420e5c31af7Sopenharmony_ci nullptr, // const uint32_t* pQueueFamilyIndices; 421e5c31af7Sopenharmony_ci VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 422e5c31af7Sopenharmony_ci }; 423e5c31af7Sopenharmony_ci colorBuffer = ImageWithMemoryPtr(new ImageWithMemory(vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any)); 424e5c31af7Sopenharmony_ci colorBufferView = makeImageView(vkd, device, colorBuffer->get(), VK_IMAGE_VIEW_TYPE_2D, format, colorSRR); 425e5c31af7Sopenharmony_ci } 426e5c31af7Sopenharmony_ci 427e5c31af7Sopenharmony_ci // Prepare buffer containing the array of block sizes. 428e5c31af7Sopenharmony_ci de::Random rnd (m_params.seed); 429e5c31af7Sopenharmony_ci std::vector<uint32_t> blockSizes; 430e5c31af7Sopenharmony_ci 431e5c31af7Sopenharmony_ci const uint32_t vectorSize = std::max(1u, m_params.drawCount); 432e5c31af7Sopenharmony_ci const uint32_t largeDrawCount = vectorSize + 1u; // The indirect buffer needs to have some padding at the end. See below. 433e5c31af7Sopenharmony_ci const uint32_t evenBlockSize = extent.height / vectorSize; 434e5c31af7Sopenharmony_ci uint32_t remainingRows = extent.height; 435e5c31af7Sopenharmony_ci 436e5c31af7Sopenharmony_ci blockSizes.reserve(vectorSize); 437e5c31af7Sopenharmony_ci for (uint32_t i = 0; i < vectorSize - 1u; ++i) 438e5c31af7Sopenharmony_ci { 439e5c31af7Sopenharmony_ci const auto blockSize = static_cast<uint32_t>(rnd.getInt(1, evenBlockSize)); 440e5c31af7Sopenharmony_ci remainingRows -= blockSize; 441e5c31af7Sopenharmony_ci blockSizes.push_back(blockSize); 442e5c31af7Sopenharmony_ci } 443e5c31af7Sopenharmony_ci blockSizes.push_back(remainingRows); 444e5c31af7Sopenharmony_ci 445e5c31af7Sopenharmony_ci const auto blockSizesBufferSize = static_cast<VkDeviceSize>(de::dataSize(blockSizes)); 446e5c31af7Sopenharmony_ci BufferWithMemoryPtr blockSizesBuffer = makeStridedBuffer(vkd, device, alloc, blockSizes, 0u, 0u, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, 0u); 447e5c31af7Sopenharmony_ci 448e5c31af7Sopenharmony_ci // Descriptor set layout, pool and set. 449e5c31af7Sopenharmony_ci DescriptorSetLayoutBuilder layoutBuilder; 450e5c31af7Sopenharmony_ci layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_MESH_BIT_NV); 451e5c31af7Sopenharmony_ci const auto setLayout = layoutBuilder.build(vkd, device); 452e5c31af7Sopenharmony_ci 453e5c31af7Sopenharmony_ci DescriptorPoolBuilder poolBuilder; 454e5c31af7Sopenharmony_ci poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); 455e5c31af7Sopenharmony_ci const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); 456e5c31af7Sopenharmony_ci 457e5c31af7Sopenharmony_ci const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get()); 458e5c31af7Sopenharmony_ci 459e5c31af7Sopenharmony_ci // Update descriptor set. 460e5c31af7Sopenharmony_ci { 461e5c31af7Sopenharmony_ci DescriptorSetUpdateBuilder updateBuilder; 462e5c31af7Sopenharmony_ci 463e5c31af7Sopenharmony_ci const auto location = DescriptorSetUpdateBuilder::Location::binding(0u); 464e5c31af7Sopenharmony_ci const auto descriptorBufferInfo = makeDescriptorBufferInfo(blockSizesBuffer->get(), 0ull, blockSizesBufferSize); 465e5c31af7Sopenharmony_ci 466e5c31af7Sopenharmony_ci updateBuilder.writeSingle(descriptorSet.get(), location, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo); 467e5c31af7Sopenharmony_ci updateBuilder.update(vkd, device); 468e5c31af7Sopenharmony_ci } 469e5c31af7Sopenharmony_ci 470e5c31af7Sopenharmony_ci // Pipeline layout. 471e5c31af7Sopenharmony_ci PushConstantData pcData; 472e5c31af7Sopenharmony_ci const auto pcRanges = pcData.getRanges(m_params.useTask); 473e5c31af7Sopenharmony_ci const auto pipelineLayout = makePipelineLayout(vkd, device, 1u, &setLayout.get(), static_cast<uint32_t>(pcRanges.size()), de::dataOrNull(pcRanges)); 474e5c31af7Sopenharmony_ci 475e5c31af7Sopenharmony_ci // Push constants. 476e5c31af7Sopenharmony_ci pcData.width = extent.width; 477e5c31af7Sopenharmony_ci pcData.height = extent.height; 478e5c31af7Sopenharmony_ci pcData.firstTaskMesh = m_params.firstTask; 479e5c31af7Sopenharmony_ci pcData.one = 1u; 480e5c31af7Sopenharmony_ci pcData.firstTaskTask = m_params.firstTask; 481e5c31af7Sopenharmony_ci 482e5c31af7Sopenharmony_ci // Render pass and framebuffer. 483e5c31af7Sopenharmony_ci const auto renderPass = makeRenderPass(vkd, device, format); 484e5c31af7Sopenharmony_ci const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), extent.width, extent.height); 485e5c31af7Sopenharmony_ci 486e5c31af7Sopenharmony_ci // Pipeline. 487e5c31af7Sopenharmony_ci Move<VkShaderModule> taskModule; 488e5c31af7Sopenharmony_ci Move<VkShaderModule> meshModule; 489e5c31af7Sopenharmony_ci Move<VkShaderModule> fragModule; 490e5c31af7Sopenharmony_ci 491e5c31af7Sopenharmony_ci const auto& binaries = m_context.getBinaryCollection(); 492e5c31af7Sopenharmony_ci if (m_params.useTask) 493e5c31af7Sopenharmony_ci taskModule = createShaderModule(vkd, device, binaries.get("task")); 494e5c31af7Sopenharmony_ci meshModule = createShaderModule(vkd, device, binaries.get("mesh")); 495e5c31af7Sopenharmony_ci fragModule = createShaderModule(vkd, device, binaries.get("frag")); 496e5c31af7Sopenharmony_ci 497e5c31af7Sopenharmony_ci const std::vector<VkViewport> viewports (1u, makeViewport(extent)); 498e5c31af7Sopenharmony_ci const std::vector<VkRect2D> scissors (1u, makeRect2D(extent)); 499e5c31af7Sopenharmony_ci 500e5c31af7Sopenharmony_ci const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(), 501e5c31af7Sopenharmony_ci taskModule.get(), meshModule.get(), fragModule.get(), 502e5c31af7Sopenharmony_ci renderPass.get(), viewports, scissors); 503e5c31af7Sopenharmony_ci 504e5c31af7Sopenharmony_ci // Command pool and buffer. 505e5c31af7Sopenharmony_ci const auto cmdPool = makeCommandPool(vkd, device, queueIndex); 506e5c31af7Sopenharmony_ci const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY); 507e5c31af7Sopenharmony_ci const auto cmdBuffer = cmdBufferPtr.get(); 508e5c31af7Sopenharmony_ci 509e5c31af7Sopenharmony_ci // Indirect and count buffers if needed. 510e5c31af7Sopenharmony_ci BufferWithMemoryPtr indirectBuffer; 511e5c31af7Sopenharmony_ci BufferWithMemoryPtr countBuffer; 512e5c31af7Sopenharmony_ci 513e5c31af7Sopenharmony_ci if (m_params.drawType != DrawType::DRAW) 514e5c31af7Sopenharmony_ci { 515e5c31af7Sopenharmony_ci // Indirect draws. 516e5c31af7Sopenharmony_ci DE_ASSERT(static_cast<bool>(m_params.indirectArgs)); 517e5c31af7Sopenharmony_ci const auto& indirectArgs = m_params.indirectArgs.get(); 518e5c31af7Sopenharmony_ci 519e5c31af7Sopenharmony_ci // Check stride and offset validity. 520e5c31af7Sopenharmony_ci DE_ASSERT(indirectArgs.offset % 4u == 0u); 521e5c31af7Sopenharmony_ci DE_ASSERT(indirectArgs.stride % 4u == 0u && (indirectArgs.stride == 0u || indirectArgs.stride >= static_cast<uint32_t>(sizeof(VkDrawMeshTasksIndirectCommandNV)))); 522e5c31af7Sopenharmony_ci 523e5c31af7Sopenharmony_ci // Prepare struct vector, which will be converted to a buffer with the proper stride and offset later. 524e5c31af7Sopenharmony_ci std::vector<VkDrawMeshTasksIndirectCommandNV> commands; 525e5c31af7Sopenharmony_ci commands.reserve(blockSizes.size()); 526e5c31af7Sopenharmony_ci 527e5c31af7Sopenharmony_ci std::transform(begin(blockSizes), end(blockSizes), std::back_inserter(commands), 528e5c31af7Sopenharmony_ci [this](uint32_t blockSize) { return VkDrawMeshTasksIndirectCommandNV{blockSize, this->m_params.firstTask}; }); 529e5c31af7Sopenharmony_ci 530e5c31af7Sopenharmony_ci const auto padding = static_cast<uint32_t>(sizeof(VkDrawMeshTasksIndirectCommandNV)); 531e5c31af7Sopenharmony_ci indirectBuffer = makeStridedBuffer(vkd, device, alloc, commands, indirectArgs.offset, indirectArgs.stride, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, padding); 532e5c31af7Sopenharmony_ci 533e5c31af7Sopenharmony_ci // Prepare count buffer if needed. 534e5c31af7Sopenharmony_ci if (m_params.drawType == DrawType::DRAW_INDIRECT_COUNT) 535e5c31af7Sopenharmony_ci { 536e5c31af7Sopenharmony_ci DE_ASSERT(static_cast<bool>(m_params.indirectCountLimit)); 537e5c31af7Sopenharmony_ci DE_ASSERT(static_cast<bool>(m_params.indirectCountOffset)); 538e5c31af7Sopenharmony_ci 539e5c31af7Sopenharmony_ci const auto countBufferValue = ((m_params.indirectCountLimit.get() == IndirectCountLimitType::BUFFER_VALUE) 540e5c31af7Sopenharmony_ci ? m_params.drawCount 541e5c31af7Sopenharmony_ci : largeDrawCount); 542e5c31af7Sopenharmony_ci 543e5c31af7Sopenharmony_ci const std::vector<uint32_t> singleCount (1u, countBufferValue); 544e5c31af7Sopenharmony_ci countBuffer = makeStridedBuffer(vkd, device, alloc, singleCount, m_params.indirectCountOffset.get(), static_cast<uint32_t>(sizeof(uint32_t)), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, 0u); 545e5c31af7Sopenharmony_ci } 546e5c31af7Sopenharmony_ci } 547e5c31af7Sopenharmony_ci 548e5c31af7Sopenharmony_ci // Submit commands. 549e5c31af7Sopenharmony_ci beginCommandBuffer(vkd, cmdBuffer); 550e5c31af7Sopenharmony_ci beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), clearColor); 551e5c31af7Sopenharmony_ci 552e5c31af7Sopenharmony_ci vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr); 553e5c31af7Sopenharmony_ci { 554e5c31af7Sopenharmony_ci const char* pcDataPtr = reinterpret_cast<const char*>(&pcData); 555e5c31af7Sopenharmony_ci for (const auto& range : pcRanges) 556e5c31af7Sopenharmony_ci vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), range.stageFlags, range.offset, range.size, pcDataPtr + range.offset); 557e5c31af7Sopenharmony_ci } 558e5c31af7Sopenharmony_ci vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get()); 559e5c31af7Sopenharmony_ci 560e5c31af7Sopenharmony_ci if (m_params.drawType == DrawType::DRAW) 561e5c31af7Sopenharmony_ci { 562e5c31af7Sopenharmony_ci vkd.cmdDrawMeshTasksNV(cmdBuffer, m_params.drawCount, m_params.firstTask); 563e5c31af7Sopenharmony_ci } 564e5c31af7Sopenharmony_ci else if (m_params.drawType == DrawType::DRAW_INDIRECT) 565e5c31af7Sopenharmony_ci { 566e5c31af7Sopenharmony_ci const auto& indirectArgs = m_params.indirectArgs.get(); 567e5c31af7Sopenharmony_ci vkd.cmdDrawMeshTasksIndirectNV(cmdBuffer, indirectBuffer->get(), indirectArgs.offset, m_params.drawCount, indirectArgs.stride); 568e5c31af7Sopenharmony_ci } 569e5c31af7Sopenharmony_ci else if (m_params.drawType == DrawType::DRAW_INDIRECT_COUNT) 570e5c31af7Sopenharmony_ci { 571e5c31af7Sopenharmony_ci const auto& indirectArgs = m_params.indirectArgs.get(); 572e5c31af7Sopenharmony_ci const auto& indirectCountOffset = m_params.indirectCountOffset.get(); 573e5c31af7Sopenharmony_ci const auto& indirectCountLimit = m_params.indirectCountLimit.get(); 574e5c31af7Sopenharmony_ci 575e5c31af7Sopenharmony_ci const auto maxCount = ((indirectCountLimit == IndirectCountLimitType::MAX_COUNT) 576e5c31af7Sopenharmony_ci ? m_params.drawCount 577e5c31af7Sopenharmony_ci : largeDrawCount); 578e5c31af7Sopenharmony_ci vkd.cmdDrawMeshTasksIndirectCountNV(cmdBuffer, indirectBuffer->get(), indirectArgs.offset, countBuffer->get(), indirectCountOffset, maxCount, indirectArgs.stride); 579e5c31af7Sopenharmony_ci } 580e5c31af7Sopenharmony_ci else 581e5c31af7Sopenharmony_ci DE_ASSERT(false); 582e5c31af7Sopenharmony_ci 583e5c31af7Sopenharmony_ci endRenderPass(vkd, cmdBuffer); 584e5c31af7Sopenharmony_ci 585e5c31af7Sopenharmony_ci // Output buffer to extract the color buffer. 586e5c31af7Sopenharmony_ci BufferWithMemoryPtr outBuffer; 587e5c31af7Sopenharmony_ci void* outBufferData = nullptr; 588e5c31af7Sopenharmony_ci { 589e5c31af7Sopenharmony_ci const auto outBufferSize = static_cast<VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * extent.width * extent.height); 590e5c31af7Sopenharmony_ci const auto outBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; 591e5c31af7Sopenharmony_ci const auto outBufferInfo = makeBufferCreateInfo(outBufferSize, outBufferUsage); 592e5c31af7Sopenharmony_ci 593e5c31af7Sopenharmony_ci outBuffer = BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, outBufferInfo, MemoryRequirement::HostVisible)); 594e5c31af7Sopenharmony_ci outBufferData = outBuffer->getAllocation().getHostPtr(); 595e5c31af7Sopenharmony_ci } 596e5c31af7Sopenharmony_ci 597e5c31af7Sopenharmony_ci copyImageToBuffer(vkd, cmdBuffer, colorBuffer->get(), outBuffer->get(), iExtent2D); 598e5c31af7Sopenharmony_ci endCommandBuffer(vkd, cmdBuffer); 599e5c31af7Sopenharmony_ci submitCommandsAndWait(vkd, device, queue, cmdBuffer); 600e5c31af7Sopenharmony_ci 601e5c31af7Sopenharmony_ci // Generate reference image and compare. 602e5c31af7Sopenharmony_ci { 603e5c31af7Sopenharmony_ci auto& log = m_context.getTestContext().getLog(); 604e5c31af7Sopenharmony_ci auto& outBufferAlloc = outBuffer->getAllocation(); 605e5c31af7Sopenharmony_ci tcu::ConstPixelBufferAccess result (tcuFormat, iExtent3D, outBufferData); 606e5c31af7Sopenharmony_ci tcu::TextureLevel referenceLevel (tcuFormat, iExtent3D.x(), iExtent3D.y()); 607e5c31af7Sopenharmony_ci const auto reference = referenceLevel.getAccess(); 608e5c31af7Sopenharmony_ci const auto setName = de::toString(m_params.drawType) + "_draw_count_" + de::toString(m_params.drawCount) + (m_params.useTask ? "_with_task" : "_no_task"); 609e5c31af7Sopenharmony_ci const auto fHeight = static_cast<float>(extent.height); 610e5c31af7Sopenharmony_ci const auto fWidth = static_cast<float>(extent.width); 611e5c31af7Sopenharmony_ci 612e5c31af7Sopenharmony_ci invalidateAlloc(vkd, device, outBufferAlloc); 613e5c31af7Sopenharmony_ci 614e5c31af7Sopenharmony_ci for (int y = 0; y < iExtent3D.y(); ++y) 615e5c31af7Sopenharmony_ci for (int x = 0; x < iExtent3D.x(); ++x) 616e5c31af7Sopenharmony_ci { 617e5c31af7Sopenharmony_ci const tcu::Vec4 refColor = ((m_params.drawCount == 0u || (m_params.drawType == DrawType::DRAW && y >= static_cast<int>(m_params.drawCount))) 618e5c31af7Sopenharmony_ci ? clearColor 619e5c31af7Sopenharmony_ci : tcu::Vec4( 620e5c31af7Sopenharmony_ci // These match the per-primitive color set by the mesh shader. 621e5c31af7Sopenharmony_ci (static_cast<float>(y) + 0.5f) / fHeight, 622e5c31af7Sopenharmony_ci (static_cast<float>(x) + 0.5f) / fWidth, 623e5c31af7Sopenharmony_ci 0.0f, 624e5c31af7Sopenharmony_ci 1.0f)); 625e5c31af7Sopenharmony_ci reference.setPixel(refColor, x, y); 626e5c31af7Sopenharmony_ci } 627e5c31af7Sopenharmony_ci 628e5c31af7Sopenharmony_ci if (!tcu::floatThresholdCompare(log, setName.c_str(), "", reference, result, threshold, tcu::COMPARE_LOG_ON_ERROR)) 629e5c31af7Sopenharmony_ci return tcu::TestStatus::fail("Image comparison failed; check log for details"); 630e5c31af7Sopenharmony_ci } 631e5c31af7Sopenharmony_ci 632e5c31af7Sopenharmony_ci return tcu::TestStatus::pass("Pass"); 633e5c31af7Sopenharmony_ci} 634e5c31af7Sopenharmony_ci 635e5c31af7Sopenharmony_ci} // anonymous 636e5c31af7Sopenharmony_ci 637e5c31af7Sopenharmony_citcu::TestCaseGroup* createMeshShaderApiTests (tcu::TestContext& testCtx) 638e5c31af7Sopenharmony_ci{ 639e5c31af7Sopenharmony_ci GroupPtr mainGroup (new tcu::TestCaseGroup(testCtx, "api")); 640e5c31af7Sopenharmony_ci 641e5c31af7Sopenharmony_ci const DrawType drawCases[] = 642e5c31af7Sopenharmony_ci { 643e5c31af7Sopenharmony_ci DrawType::DRAW, 644e5c31af7Sopenharmony_ci DrawType::DRAW_INDIRECT, 645e5c31af7Sopenharmony_ci DrawType::DRAW_INDIRECT_COUNT, 646e5c31af7Sopenharmony_ci }; 647e5c31af7Sopenharmony_ci 648e5c31af7Sopenharmony_ci const auto extent = getExtent(); 649e5c31af7Sopenharmony_ci const uint32_t drawCountCases[] = { 0u, 1u, 2u, extent.height / 2u, extent.height }; 650e5c31af7Sopenharmony_ci 651e5c31af7Sopenharmony_ci const uint32_t normalStride = static_cast<uint32_t>(sizeof(VkDrawMeshTasksIndirectCommandNV)); 652e5c31af7Sopenharmony_ci const uint32_t largeStride = 2u * normalStride + 4u; 653e5c31af7Sopenharmony_ci const uint32_t altOffset = 20u; 654e5c31af7Sopenharmony_ci 655e5c31af7Sopenharmony_ci const struct 656e5c31af7Sopenharmony_ci { 657e5c31af7Sopenharmony_ci tcu::Maybe<IndirectArgs> indirectArgs; 658e5c31af7Sopenharmony_ci const char* name; 659e5c31af7Sopenharmony_ci } indirectArgsCases[] = 660e5c31af7Sopenharmony_ci { 661e5c31af7Sopenharmony_ci { tcu::nothing<IndirectArgs>(), "no_indirect_args" }, 662e5c31af7Sopenharmony_ci 663e5c31af7Sopenharmony_ci // Offset 0, varying strides. 664e5c31af7Sopenharmony_ci { tcu::just(IndirectArgs{ 0u, 0u }), "offset_0_stride_0" }, 665e5c31af7Sopenharmony_ci { tcu::just(IndirectArgs{ 0u, normalStride }), "offset_0_stride_normal" }, 666e5c31af7Sopenharmony_ci { tcu::just(IndirectArgs{ 0u, largeStride }), "offset_0_stride_large" }, 667e5c31af7Sopenharmony_ci 668e5c31af7Sopenharmony_ci // Nonzero offset, varying strides. 669e5c31af7Sopenharmony_ci { tcu::just(IndirectArgs{ altOffset, 0u }), "offset_alt_stride_0" }, 670e5c31af7Sopenharmony_ci { tcu::just(IndirectArgs{ altOffset, normalStride }), "offset_alt_stride_normal" }, 671e5c31af7Sopenharmony_ci { tcu::just(IndirectArgs{ altOffset, largeStride }), "offset_alt_stride_large" }, 672e5c31af7Sopenharmony_ci }; 673e5c31af7Sopenharmony_ci 674e5c31af7Sopenharmony_ci const struct 675e5c31af7Sopenharmony_ci { 676e5c31af7Sopenharmony_ci tcu::Maybe<IndirectCountLimitType> limitType; 677e5c31af7Sopenharmony_ci const char* name; 678e5c31af7Sopenharmony_ci } countLimitCases[] = 679e5c31af7Sopenharmony_ci { 680e5c31af7Sopenharmony_ci { tcu::nothing<IndirectCountLimitType>(), "no_count_limit" }, 681e5c31af7Sopenharmony_ci { tcu::just(IndirectCountLimitType::BUFFER_VALUE), "count_limit_buffer" }, 682e5c31af7Sopenharmony_ci { tcu::just(IndirectCountLimitType::MAX_COUNT), "count_limit_max_count" }, 683e5c31af7Sopenharmony_ci }; 684e5c31af7Sopenharmony_ci 685e5c31af7Sopenharmony_ci const struct 686e5c31af7Sopenharmony_ci { 687e5c31af7Sopenharmony_ci tcu::Maybe<uint32_t> countOffset; 688e5c31af7Sopenharmony_ci const char* name; 689e5c31af7Sopenharmony_ci } countOffsetCases[] = 690e5c31af7Sopenharmony_ci { 691e5c31af7Sopenharmony_ci { tcu::nothing<uint32_t>(), "no_count_offset" }, 692e5c31af7Sopenharmony_ci { tcu::just(uint32_t{0u}), "count_offset_0" }, 693e5c31af7Sopenharmony_ci { tcu::just(altOffset), "count_offset_alt" }, 694e5c31af7Sopenharmony_ci }; 695e5c31af7Sopenharmony_ci 696e5c31af7Sopenharmony_ci const struct 697e5c31af7Sopenharmony_ci { 698e5c31af7Sopenharmony_ci bool useTask; 699e5c31af7Sopenharmony_ci const char* name; 700e5c31af7Sopenharmony_ci } taskCases[] = 701e5c31af7Sopenharmony_ci { 702e5c31af7Sopenharmony_ci { false, "no_task_shader" }, 703e5c31af7Sopenharmony_ci { true, "with_task_shader" }, 704e5c31af7Sopenharmony_ci }; 705e5c31af7Sopenharmony_ci 706e5c31af7Sopenharmony_ci const struct 707e5c31af7Sopenharmony_ci { 708e5c31af7Sopenharmony_ci uint32_t firstTask; 709e5c31af7Sopenharmony_ci const char* name; 710e5c31af7Sopenharmony_ci } firstTaskCases[] = 711e5c31af7Sopenharmony_ci { 712e5c31af7Sopenharmony_ci { 0u, "first_task_zero" }, 713e5c31af7Sopenharmony_ci { 1001u, "first_task_nonzero" }, 714e5c31af7Sopenharmony_ci }; 715e5c31af7Sopenharmony_ci 716e5c31af7Sopenharmony_ci uint32_t seed = 1628678795u; 717e5c31af7Sopenharmony_ci 718e5c31af7Sopenharmony_ci for (const auto& drawCase : drawCases) 719e5c31af7Sopenharmony_ci { 720e5c31af7Sopenharmony_ci const auto drawCaseName = de::toString(drawCase); 721e5c31af7Sopenharmony_ci const bool isIndirect = (drawCase != DrawType::DRAW); 722e5c31af7Sopenharmony_ci const bool isIndirectNoCount = (drawCase == DrawType::DRAW_INDIRECT); 723e5c31af7Sopenharmony_ci const bool isIndirectCount = (drawCase == DrawType::DRAW_INDIRECT_COUNT); 724e5c31af7Sopenharmony_ci 725e5c31af7Sopenharmony_ci GroupPtr drawGroup(new tcu::TestCaseGroup(testCtx, drawCaseName.c_str())); 726e5c31af7Sopenharmony_ci 727e5c31af7Sopenharmony_ci for (const auto& drawCountCase : drawCountCases) 728e5c31af7Sopenharmony_ci { 729e5c31af7Sopenharmony_ci const auto drawCountName = "draw_count_" + de::toString(drawCountCase); 730e5c31af7Sopenharmony_ci GroupPtr drawCountGroup(new tcu::TestCaseGroup(testCtx, drawCountName.c_str())); 731e5c31af7Sopenharmony_ci 732e5c31af7Sopenharmony_ci for (const auto& indirectArgsCase : indirectArgsCases) 733e5c31af7Sopenharmony_ci { 734e5c31af7Sopenharmony_ci const bool hasIndirectArgs = static_cast<bool>(indirectArgsCase.indirectArgs); 735e5c31af7Sopenharmony_ci const bool strideZero = (hasIndirectArgs && indirectArgsCase.indirectArgs.get().stride == 0u); 736e5c31af7Sopenharmony_ci 737e5c31af7Sopenharmony_ci if (isIndirect != hasIndirectArgs) 738e5c31af7Sopenharmony_ci continue; 739e5c31af7Sopenharmony_ci 740e5c31af7Sopenharmony_ci // VUID-vkCmdDrawMeshTasksIndirectNV-drawCount-02146 and VUID-vkCmdDrawMeshTasksIndirectCountNV-stride-02182. 741e5c31af7Sopenharmony_ci if (((isIndirectNoCount && drawCountCase > 1u) || isIndirectCount) && strideZero) 742e5c31af7Sopenharmony_ci continue; 743e5c31af7Sopenharmony_ci 744e5c31af7Sopenharmony_ci GroupPtr indirectArgsGroup(new tcu::TestCaseGroup(testCtx, indirectArgsCase.name)); 745e5c31af7Sopenharmony_ci 746e5c31af7Sopenharmony_ci for (const auto& countLimitCase : countLimitCases) 747e5c31af7Sopenharmony_ci { 748e5c31af7Sopenharmony_ci const bool hasCountLimit = static_cast<bool>(countLimitCase.limitType); 749e5c31af7Sopenharmony_ci 750e5c31af7Sopenharmony_ci if (isIndirectCount != hasCountLimit) 751e5c31af7Sopenharmony_ci continue; 752e5c31af7Sopenharmony_ci 753e5c31af7Sopenharmony_ci GroupPtr countLimitGroup(new tcu::TestCaseGroup(testCtx, countLimitCase.name)); 754e5c31af7Sopenharmony_ci 755e5c31af7Sopenharmony_ci for (const auto& countOffsetCase : countOffsetCases) 756e5c31af7Sopenharmony_ci { 757e5c31af7Sopenharmony_ci const bool hasCountOffsetType = static_cast<bool>(countOffsetCase.countOffset); 758e5c31af7Sopenharmony_ci 759e5c31af7Sopenharmony_ci if (isIndirectCount != hasCountOffsetType) 760e5c31af7Sopenharmony_ci continue; 761e5c31af7Sopenharmony_ci 762e5c31af7Sopenharmony_ci GroupPtr countOffsetGroup(new tcu::TestCaseGroup(testCtx, countOffsetCase.name)); 763e5c31af7Sopenharmony_ci 764e5c31af7Sopenharmony_ci for (const auto& taskCase : taskCases) 765e5c31af7Sopenharmony_ci { 766e5c31af7Sopenharmony_ci GroupPtr taskCaseGrp(new tcu::TestCaseGroup(testCtx, taskCase.name)); 767e5c31af7Sopenharmony_ci 768e5c31af7Sopenharmony_ci for (const auto& firstTaskCase : firstTaskCases) 769e5c31af7Sopenharmony_ci { 770e5c31af7Sopenharmony_ci const TestParams params = 771e5c31af7Sopenharmony_ci { 772e5c31af7Sopenharmony_ci drawCase, // DrawType drawType; 773e5c31af7Sopenharmony_ci seed++, // uint32_t seed; 774e5c31af7Sopenharmony_ci drawCountCase, // uint32_t drawCount; 775e5c31af7Sopenharmony_ci firstTaskCase.firstTask, // uint32_t firstTask; 776e5c31af7Sopenharmony_ci indirectArgsCase.indirectArgs, // tcu::Maybe<IndirectArgs> indirectArgs; 777e5c31af7Sopenharmony_ci countLimitCase.limitType, // tcu::Maybe<IndirectCountLimitType> indirectCountLimit; 778e5c31af7Sopenharmony_ci countOffsetCase.countOffset, // tcu::Maybe<uint32_t> indirectCountOffset; 779e5c31af7Sopenharmony_ci taskCase.useTask, // bool useTask; 780e5c31af7Sopenharmony_ci }; 781e5c31af7Sopenharmony_ci 782e5c31af7Sopenharmony_ci taskCaseGrp->addChild(new MeshApiCase(testCtx, firstTaskCase.name, params)); 783e5c31af7Sopenharmony_ci } 784e5c31af7Sopenharmony_ci 785e5c31af7Sopenharmony_ci countOffsetGroup->addChild(taskCaseGrp.release()); 786e5c31af7Sopenharmony_ci } 787e5c31af7Sopenharmony_ci 788e5c31af7Sopenharmony_ci countLimitGroup->addChild(countOffsetGroup.release()); 789e5c31af7Sopenharmony_ci } 790e5c31af7Sopenharmony_ci 791e5c31af7Sopenharmony_ci indirectArgsGroup->addChild(countLimitGroup.release()); 792e5c31af7Sopenharmony_ci } 793e5c31af7Sopenharmony_ci 794e5c31af7Sopenharmony_ci drawCountGroup->addChild(indirectArgsGroup.release()); 795e5c31af7Sopenharmony_ci } 796e5c31af7Sopenharmony_ci 797e5c31af7Sopenharmony_ci drawGroup->addChild(drawCountGroup.release()); 798e5c31af7Sopenharmony_ci } 799e5c31af7Sopenharmony_ci 800e5c31af7Sopenharmony_ci mainGroup->addChild(drawGroup.release()); 801e5c31af7Sopenharmony_ci } 802e5c31af7Sopenharmony_ci 803e5c31af7Sopenharmony_ci return mainGroup.release(); 804e5c31af7Sopenharmony_ci} 805e5c31af7Sopenharmony_ci 806e5c31af7Sopenharmony_ci} // MeshShader 807e5c31af7Sopenharmony_ci} // vkt 808