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