1e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * OpenGL Conformance Tests
3e5c31af7Sopenharmony_ci * ------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright (c) 2017-2019 The Khronos Group Inc.
6e5c31af7Sopenharmony_ci * Copyright (c) 2017 Codeplay Software Ltd.
7e5c31af7Sopenharmony_ci * Copyright (c) 2019 NVIDIA Corporation.
8e5c31af7Sopenharmony_ci *
9e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
10e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
11e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
14e5c31af7Sopenharmony_ci *
15e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
16e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
17e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
19e5c31af7Sopenharmony_ci * limitations under the License.
20e5c31af7Sopenharmony_ci *
21e5c31af7Sopenharmony_ci */ /*!
22e5c31af7Sopenharmony_ci * \file
23e5c31af7Sopenharmony_ci * \brief Subgroups Tests
24e5c31af7Sopenharmony_ci */ /*--------------------------------------------------------------------*/
25e5c31af7Sopenharmony_ci
26e5c31af7Sopenharmony_ci#include "glcSubgroupsQuadTests.hpp"
27e5c31af7Sopenharmony_ci#include "glcSubgroupsTestsUtils.hpp"
28e5c31af7Sopenharmony_ci
29e5c31af7Sopenharmony_ci#include <string>
30e5c31af7Sopenharmony_ci#include <vector>
31e5c31af7Sopenharmony_ci
32e5c31af7Sopenharmony_ciusing namespace tcu;
33e5c31af7Sopenharmony_ciusing namespace std;
34e5c31af7Sopenharmony_ci
35e5c31af7Sopenharmony_cinamespace glc
36e5c31af7Sopenharmony_ci{
37e5c31af7Sopenharmony_cinamespace subgroups
38e5c31af7Sopenharmony_ci{
39e5c31af7Sopenharmony_cinamespace
40e5c31af7Sopenharmony_ci{
41e5c31af7Sopenharmony_cienum OpType
42e5c31af7Sopenharmony_ci{
43e5c31af7Sopenharmony_ci	OPTYPE_QUAD_BROADCAST = 0,
44e5c31af7Sopenharmony_ci	OPTYPE_QUAD_SWAP_HORIZONTAL,
45e5c31af7Sopenharmony_ci	OPTYPE_QUAD_SWAP_VERTICAL,
46e5c31af7Sopenharmony_ci	OPTYPE_QUAD_SWAP_DIAGONAL,
47e5c31af7Sopenharmony_ci	OPTYPE_LAST
48e5c31af7Sopenharmony_ci};
49e5c31af7Sopenharmony_ci
50e5c31af7Sopenharmony_cistatic bool checkVertexPipelineStages(std::vector<const void*> datas,
51e5c31af7Sopenharmony_ci									  deUint32 width, deUint32)
52e5c31af7Sopenharmony_ci{
53e5c31af7Sopenharmony_ci	return glc::subgroups::check(datas, width, 1);
54e5c31af7Sopenharmony_ci}
55e5c31af7Sopenharmony_ci
56e5c31af7Sopenharmony_cistatic bool checkComputeStage(std::vector<const void*> datas,
57e5c31af7Sopenharmony_ci						 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
58e5c31af7Sopenharmony_ci						 deUint32)
59e5c31af7Sopenharmony_ci{
60e5c31af7Sopenharmony_ci	return glc::subgroups::checkCompute(datas, numWorkgroups, localSize, 1);
61e5c31af7Sopenharmony_ci}
62e5c31af7Sopenharmony_ci
63e5c31af7Sopenharmony_cistd::string getOpTypeName(int opType)
64e5c31af7Sopenharmony_ci{
65e5c31af7Sopenharmony_ci	switch (opType)
66e5c31af7Sopenharmony_ci	{
67e5c31af7Sopenharmony_ci		default:
68e5c31af7Sopenharmony_ci			DE_FATAL("Unsupported op type");
69e5c31af7Sopenharmony_ci			return "";
70e5c31af7Sopenharmony_ci		case OPTYPE_QUAD_BROADCAST:
71e5c31af7Sopenharmony_ci			return "subgroupQuadBroadcast";
72e5c31af7Sopenharmony_ci		case OPTYPE_QUAD_SWAP_HORIZONTAL:
73e5c31af7Sopenharmony_ci			return "subgroupQuadSwapHorizontal";
74e5c31af7Sopenharmony_ci		case OPTYPE_QUAD_SWAP_VERTICAL:
75e5c31af7Sopenharmony_ci			return "subgroupQuadSwapVertical";
76e5c31af7Sopenharmony_ci		case OPTYPE_QUAD_SWAP_DIAGONAL:
77e5c31af7Sopenharmony_ci			return "subgroupQuadSwapDiagonal";
78e5c31af7Sopenharmony_ci	}
79e5c31af7Sopenharmony_ci}
80e5c31af7Sopenharmony_ci
81e5c31af7Sopenharmony_cistruct CaseDefinition
82e5c31af7Sopenharmony_ci{
83e5c31af7Sopenharmony_ci	int					opType;
84e5c31af7Sopenharmony_ci	ShaderStageFlags	shaderStage;
85e5c31af7Sopenharmony_ci	Format				format;
86e5c31af7Sopenharmony_ci	int					direction;
87e5c31af7Sopenharmony_ci};
88e5c31af7Sopenharmony_ci
89e5c31af7Sopenharmony_civoid initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
90e5c31af7Sopenharmony_ci{
91e5c31af7Sopenharmony_ci	std::string			swapTable[OPTYPE_LAST];
92e5c31af7Sopenharmony_ci
93e5c31af7Sopenharmony_ci	subgroups::setFragmentShaderFrameBuffer(programCollection);
94e5c31af7Sopenharmony_ci
95e5c31af7Sopenharmony_ci	if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
96e5c31af7Sopenharmony_ci		subgroups::setVertexShaderFrameBuffer(programCollection);
97e5c31af7Sopenharmony_ci
98e5c31af7Sopenharmony_ci	swapTable[OPTYPE_QUAD_BROADCAST] = "";
99e5c31af7Sopenharmony_ci	swapTable[OPTYPE_QUAD_SWAP_HORIZONTAL] = "  const uint swapTable[4] = uint[](1u, 0u, 3u, 2u);\n";
100e5c31af7Sopenharmony_ci	swapTable[OPTYPE_QUAD_SWAP_VERTICAL] = "  const uint swapTable[4] = uint[](2u, 3u, 0u, 1u);\n";
101e5c31af7Sopenharmony_ci	swapTable[OPTYPE_QUAD_SWAP_DIAGONAL] = "  const uint swapTable[4] = uint[](3u, 2u, 1u, 0u);\n";
102e5c31af7Sopenharmony_ci
103e5c31af7Sopenharmony_ci	if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
104e5c31af7Sopenharmony_ci	{
105e5c31af7Sopenharmony_ci		std::ostringstream	vertexSrc;
106e5c31af7Sopenharmony_ci		vertexSrc << "${VERSION_DECL}\n"
107e5c31af7Sopenharmony_ci			<< "#extension GL_KHR_shader_subgroup_quad: enable\n"
108e5c31af7Sopenharmony_ci			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
109e5c31af7Sopenharmony_ci			<< "layout(location = 0) in highp vec4 in_position;\n"
110e5c31af7Sopenharmony_ci			<< "layout(location = 0) out float result;\n"
111e5c31af7Sopenharmony_ci			<< "layout(binding = 0, std140) uniform Buffer0\n"
112e5c31af7Sopenharmony_ci			<< "{\n"
113e5c31af7Sopenharmony_ci			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
114e5c31af7Sopenharmony_ci			<< "};\n"
115e5c31af7Sopenharmony_ci			<< "\n"
116e5c31af7Sopenharmony_ci			<< "void main (void)\n"
117e5c31af7Sopenharmony_ci			<< "{\n"
118e5c31af7Sopenharmony_ci			<< "  uvec4 mask = subgroupBallot(true);\n"
119e5c31af7Sopenharmony_ci			<< swapTable[caseDef.opType];
120e5c31af7Sopenharmony_ci
121e5c31af7Sopenharmony_ci		if (OPTYPE_QUAD_BROADCAST == caseDef.opType)
122e5c31af7Sopenharmony_ci		{
123e5c31af7Sopenharmony_ci			vertexSrc << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
124e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID], " << caseDef.direction << "u);\n"
125e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + " << caseDef.direction << "u;\n";
126e5c31af7Sopenharmony_ci		}
127e5c31af7Sopenharmony_ci		else
128e5c31af7Sopenharmony_ci		{
129e5c31af7Sopenharmony_ci			vertexSrc << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
130e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID]);\n"
131e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + swapTable[gl_SubgroupInvocationID & 0x3u];\n";
132e5c31af7Sopenharmony_ci		}
133e5c31af7Sopenharmony_ci
134e5c31af7Sopenharmony_ci		vertexSrc << "  if (subgroupBallotBitExtract(mask, otherID))\n"
135e5c31af7Sopenharmony_ci			<< "  {\n"
136e5c31af7Sopenharmony_ci			<< "    result = (op == data[otherID]) ? 1.0f : 0.0f;\n"
137e5c31af7Sopenharmony_ci			<< "  }\n"
138e5c31af7Sopenharmony_ci			<< "  else\n"
139e5c31af7Sopenharmony_ci			<< "  {\n"
140e5c31af7Sopenharmony_ci			<< "    result = 1.0f;\n" // Invocation we read from was inactive, so we can't verify results!
141e5c31af7Sopenharmony_ci			<< "  }\n"
142e5c31af7Sopenharmony_ci			<< "  gl_Position = in_position;\n"
143e5c31af7Sopenharmony_ci			<< "  gl_PointSize = 1.0f;\n"
144e5c31af7Sopenharmony_ci			<< "}\n";
145e5c31af7Sopenharmony_ci		programCollection.add("vert") << glu::VertexSource(vertexSrc.str());
146e5c31af7Sopenharmony_ci	}
147e5c31af7Sopenharmony_ci	else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
148e5c31af7Sopenharmony_ci	{
149e5c31af7Sopenharmony_ci		std::ostringstream geometry;
150e5c31af7Sopenharmony_ci
151e5c31af7Sopenharmony_ci		geometry << "${VERSION_DECL}\n"
152e5c31af7Sopenharmony_ci			<< "#extension GL_KHR_shader_subgroup_quad: enable\n"
153e5c31af7Sopenharmony_ci			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
154e5c31af7Sopenharmony_ci			<< "layout(points) in;\n"
155e5c31af7Sopenharmony_ci			<< "layout(points, max_vertices = 1) out;\n"
156e5c31af7Sopenharmony_ci			<< "layout(location = 0) out float out_color;\n"
157e5c31af7Sopenharmony_ci			<< "layout(binding = 0, std140) uniform Buffer0\n"
158e5c31af7Sopenharmony_ci			<< "{\n"
159e5c31af7Sopenharmony_ci			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
160e5c31af7Sopenharmony_ci			<< "};\n"
161e5c31af7Sopenharmony_ci			<< "\n"
162e5c31af7Sopenharmony_ci			<< "void main (void)\n"
163e5c31af7Sopenharmony_ci			<< "{\n"
164e5c31af7Sopenharmony_ci			<< "  uvec4 mask = subgroupBallot(true);\n"
165e5c31af7Sopenharmony_ci			<< swapTable[caseDef.opType];
166e5c31af7Sopenharmony_ci
167e5c31af7Sopenharmony_ci		if (OPTYPE_QUAD_BROADCAST == caseDef.opType)
168e5c31af7Sopenharmony_ci		{
169e5c31af7Sopenharmony_ci			geometry << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
170e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID], " << caseDef.direction << "u);\n"
171e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + " << caseDef.direction << "u;\n";
172e5c31af7Sopenharmony_ci		}
173e5c31af7Sopenharmony_ci		else
174e5c31af7Sopenharmony_ci		{
175e5c31af7Sopenharmony_ci			geometry << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
176e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID]);\n"
177e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + swapTable[gl_SubgroupInvocationID & 0x3u];\n";
178e5c31af7Sopenharmony_ci		}
179e5c31af7Sopenharmony_ci
180e5c31af7Sopenharmony_ci		geometry << "  if (subgroupBallotBitExtract(mask, otherID))\n"
181e5c31af7Sopenharmony_ci			<< "  {\n"
182e5c31af7Sopenharmony_ci			<< "    out_color = (op == data[otherID]) ? 1.0 : 0.0;\n"
183e5c31af7Sopenharmony_ci			<< "  }\n"
184e5c31af7Sopenharmony_ci			<< "  else\n"
185e5c31af7Sopenharmony_ci			<< "  {\n"
186e5c31af7Sopenharmony_ci			<< "    out_color = 1.0;\n" // Invocation we read from was inactive, so we can't verify results!
187e5c31af7Sopenharmony_ci			<< "  }\n"
188e5c31af7Sopenharmony_ci			<< "  gl_Position = gl_in[0].gl_Position;\n"
189e5c31af7Sopenharmony_ci			<< "  EmitVertex();\n"
190e5c31af7Sopenharmony_ci			<< "  EndPrimitive();\n"
191e5c31af7Sopenharmony_ci			<< "}\n";
192e5c31af7Sopenharmony_ci
193e5c31af7Sopenharmony_ci		programCollection.add("geometry") << glu::GeometrySource(geometry.str());
194e5c31af7Sopenharmony_ci	}
195e5c31af7Sopenharmony_ci	else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
196e5c31af7Sopenharmony_ci	{
197e5c31af7Sopenharmony_ci		std::ostringstream controlSource;
198e5c31af7Sopenharmony_ci
199e5c31af7Sopenharmony_ci		controlSource << "${VERSION_DECL}\n"
200e5c31af7Sopenharmony_ci			<< "#extension GL_KHR_shader_subgroup_quad: enable\n"
201e5c31af7Sopenharmony_ci			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
202e5c31af7Sopenharmony_ci			<< "layout(vertices = 2) out;\n"
203e5c31af7Sopenharmony_ci			<< "layout(location = 0) out float out_color[];\n"
204e5c31af7Sopenharmony_ci			<< "layout(binding = 0, std140) uniform Buffer0\n"
205e5c31af7Sopenharmony_ci			<< "{\n"
206e5c31af7Sopenharmony_ci			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
207e5c31af7Sopenharmony_ci			<< "};\n"
208e5c31af7Sopenharmony_ci			<< "\n"
209e5c31af7Sopenharmony_ci			<< "void main (void)\n"
210e5c31af7Sopenharmony_ci			<< "{\n"
211e5c31af7Sopenharmony_ci			<< "  if (gl_InvocationID == 0)\n"
212e5c31af7Sopenharmony_ci			<<"  {\n"
213e5c31af7Sopenharmony_ci			<< "    gl_TessLevelOuter[0] = 1.0f;\n"
214e5c31af7Sopenharmony_ci			<< "    gl_TessLevelOuter[1] = 1.0f;\n"
215e5c31af7Sopenharmony_ci			<< "  }\n"
216e5c31af7Sopenharmony_ci			<< "  uvec4 mask = subgroupBallot(true);\n"
217e5c31af7Sopenharmony_ci			<< swapTable[caseDef.opType];
218e5c31af7Sopenharmony_ci
219e5c31af7Sopenharmony_ci		if (OPTYPE_QUAD_BROADCAST == caseDef.opType)
220e5c31af7Sopenharmony_ci		{
221e5c31af7Sopenharmony_ci			controlSource << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
222e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID], " << caseDef.direction << "u);\n"
223e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + " << caseDef.direction << "u;\n";
224e5c31af7Sopenharmony_ci		}
225e5c31af7Sopenharmony_ci		else
226e5c31af7Sopenharmony_ci		{
227e5c31af7Sopenharmony_ci			controlSource << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
228e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID]);\n"
229e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + swapTable[gl_SubgroupInvocationID & 0x3u];\n";
230e5c31af7Sopenharmony_ci		}
231e5c31af7Sopenharmony_ci
232e5c31af7Sopenharmony_ci		controlSource << "  if (subgroupBallotBitExtract(mask, otherID))\n"
233e5c31af7Sopenharmony_ci			<< "  {\n"
234e5c31af7Sopenharmony_ci			<< "    out_color[gl_InvocationID] = (op == data[otherID]) ? 1.0 : 0.0;\n"
235e5c31af7Sopenharmony_ci			<< "  }\n"
236e5c31af7Sopenharmony_ci			<< "  else\n"
237e5c31af7Sopenharmony_ci			<< "  {\n"
238e5c31af7Sopenharmony_ci			<< "    out_color[gl_InvocationID] = 1.0; \n"// Invocation we read from was inactive, so we can't verify results!
239e5c31af7Sopenharmony_ci			<< "  }\n"
240e5c31af7Sopenharmony_ci			<< "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
241e5c31af7Sopenharmony_ci			<< "}\n";
242e5c31af7Sopenharmony_ci
243e5c31af7Sopenharmony_ci		programCollection.add("tesc") << glu::TessellationControlSource(controlSource.str());
244e5c31af7Sopenharmony_ci		subgroups::setTesEvalShaderFrameBuffer(programCollection);
245e5c31af7Sopenharmony_ci	}
246e5c31af7Sopenharmony_ci	else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
247e5c31af7Sopenharmony_ci	{
248e5c31af7Sopenharmony_ci		ostringstream evaluationSource;
249e5c31af7Sopenharmony_ci		evaluationSource << "${VERSION_DECL}\n"
250e5c31af7Sopenharmony_ci			<< "#extension GL_KHR_shader_subgroup_quad: enable\n"
251e5c31af7Sopenharmony_ci			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
252e5c31af7Sopenharmony_ci			<< "layout(isolines, equal_spacing, ccw ) in;\n"
253e5c31af7Sopenharmony_ci			<< "layout(location = 0) out float out_color;\n"
254e5c31af7Sopenharmony_ci			<< "layout(binding = 0, std140) uniform Buffer0\n"
255e5c31af7Sopenharmony_ci			<< "{\n"
256e5c31af7Sopenharmony_ci			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
257e5c31af7Sopenharmony_ci			<< "};\n"
258e5c31af7Sopenharmony_ci			<< "\n"
259e5c31af7Sopenharmony_ci			<< "void main (void)\n"
260e5c31af7Sopenharmony_ci			<< "{\n"
261e5c31af7Sopenharmony_ci			<< "  uvec4 mask = subgroupBallot(true);\n"
262e5c31af7Sopenharmony_ci			<< swapTable[caseDef.opType];
263e5c31af7Sopenharmony_ci
264e5c31af7Sopenharmony_ci		if (OPTYPE_QUAD_BROADCAST == caseDef.opType)
265e5c31af7Sopenharmony_ci		{
266e5c31af7Sopenharmony_ci			evaluationSource << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
267e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID], " << caseDef.direction << "u);\n"
268e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + " << caseDef.direction << "u;\n";
269e5c31af7Sopenharmony_ci		}
270e5c31af7Sopenharmony_ci		else
271e5c31af7Sopenharmony_ci		{
272e5c31af7Sopenharmony_ci			evaluationSource << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
273e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID]);\n"
274e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + swapTable[gl_SubgroupInvocationID & 0x3u];\n";
275e5c31af7Sopenharmony_ci		}
276e5c31af7Sopenharmony_ci
277e5c31af7Sopenharmony_ci		evaluationSource << "  if (subgroupBallotBitExtract(mask, otherID))\n"
278e5c31af7Sopenharmony_ci			<< "  {\n"
279e5c31af7Sopenharmony_ci			<< "    out_color = (op == data[otherID]) ? 1.0 : 0.0;\n"
280e5c31af7Sopenharmony_ci			<< "  }\n"
281e5c31af7Sopenharmony_ci			<< "  else\n"
282e5c31af7Sopenharmony_ci			<< "  {\n"
283e5c31af7Sopenharmony_ci			<< "    out_color = 1.0;\n" // Invocation we read from was inactive, so we can't verify results!
284e5c31af7Sopenharmony_ci			<< "  }\n"
285e5c31af7Sopenharmony_ci			<< "  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
286e5c31af7Sopenharmony_ci			<< "}\n";
287e5c31af7Sopenharmony_ci
288e5c31af7Sopenharmony_ci		subgroups::setTesCtrlShaderFrameBuffer(programCollection);
289e5c31af7Sopenharmony_ci		programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSource.str());
290e5c31af7Sopenharmony_ci	}
291e5c31af7Sopenharmony_ci	else
292e5c31af7Sopenharmony_ci	{
293e5c31af7Sopenharmony_ci		DE_FATAL("Unsupported shader stage");
294e5c31af7Sopenharmony_ci	}
295e5c31af7Sopenharmony_ci}
296e5c31af7Sopenharmony_ci
297e5c31af7Sopenharmony_civoid initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
298e5c31af7Sopenharmony_ci{
299e5c31af7Sopenharmony_ci	std::string swapTable[OPTYPE_LAST];
300e5c31af7Sopenharmony_ci	swapTable[OPTYPE_QUAD_BROADCAST] = "";
301e5c31af7Sopenharmony_ci	swapTable[OPTYPE_QUAD_SWAP_HORIZONTAL] = "  const uint swapTable[4] = uint[](1u, 0u, 3u, 2u);\n";
302e5c31af7Sopenharmony_ci	swapTable[OPTYPE_QUAD_SWAP_VERTICAL] = "  const uint swapTable[4] = uint[](2u, 3u, 0u, 1u);\n";
303e5c31af7Sopenharmony_ci	swapTable[OPTYPE_QUAD_SWAP_DIAGONAL] = "  const uint swapTable[4] = uint[](3u, 2u, 1u, 0u);\n";
304e5c31af7Sopenharmony_ci
305e5c31af7Sopenharmony_ci	if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
306e5c31af7Sopenharmony_ci	{
307e5c31af7Sopenharmony_ci		std::ostringstream src;
308e5c31af7Sopenharmony_ci
309e5c31af7Sopenharmony_ci		src << "${VERSION_DECL}\n"
310e5c31af7Sopenharmony_ci			<< "#extension GL_KHR_shader_subgroup_quad: enable\n"
311e5c31af7Sopenharmony_ci			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
312e5c31af7Sopenharmony_ci			<< "layout (${LOCAL_SIZE_X}, ${LOCAL_SIZE_Y}, ${LOCAL_SIZE_Z}) in;\n"
313e5c31af7Sopenharmony_ci			<< "layout(binding = 0, std430) buffer Buffer0\n"
314e5c31af7Sopenharmony_ci			<< "{\n"
315e5c31af7Sopenharmony_ci			<< "  uint result[];\n"
316e5c31af7Sopenharmony_ci			<< "};\n"
317e5c31af7Sopenharmony_ci			<< "layout(binding = 1, std430) buffer Buffer1\n"
318e5c31af7Sopenharmony_ci			<< "{\n"
319e5c31af7Sopenharmony_ci			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[];\n"
320e5c31af7Sopenharmony_ci			<< "};\n"
321e5c31af7Sopenharmony_ci			<< "\n"
322e5c31af7Sopenharmony_ci			<< "void main (void)\n"
323e5c31af7Sopenharmony_ci			<< "{\n"
324e5c31af7Sopenharmony_ci			<< "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
325e5c31af7Sopenharmony_ci			<< "  highp uint offset = globalSize.x * ((globalSize.y * "
326e5c31af7Sopenharmony_ci			"gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
327e5c31af7Sopenharmony_ci			"gl_GlobalInvocationID.x;\n"
328e5c31af7Sopenharmony_ci			<< "  uvec4 mask = subgroupBallot(true);\n"
329e5c31af7Sopenharmony_ci			<< swapTable[caseDef.opType];
330e5c31af7Sopenharmony_ci
331e5c31af7Sopenharmony_ci
332e5c31af7Sopenharmony_ci		if (OPTYPE_QUAD_BROADCAST == caseDef.opType)
333e5c31af7Sopenharmony_ci		{
334e5c31af7Sopenharmony_ci			src << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
335e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID], " << caseDef.direction << "u);\n"
336e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + " << caseDef.direction << "u;\n";
337e5c31af7Sopenharmony_ci		}
338e5c31af7Sopenharmony_ci		else
339e5c31af7Sopenharmony_ci		{
340e5c31af7Sopenharmony_ci			src << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
341e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID]);\n"
342e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + swapTable[gl_SubgroupInvocationID & 0x3u];\n";
343e5c31af7Sopenharmony_ci		}
344e5c31af7Sopenharmony_ci
345e5c31af7Sopenharmony_ci		src << "  if (subgroupBallotBitExtract(mask, otherID))\n"
346e5c31af7Sopenharmony_ci			<< "  {\n"
347e5c31af7Sopenharmony_ci			<< "    result[offset] = (op == data[otherID]) ? 1u : 0u;\n"
348e5c31af7Sopenharmony_ci			<< "  }\n"
349e5c31af7Sopenharmony_ci			<< "  else\n"
350e5c31af7Sopenharmony_ci			<< "  {\n"
351e5c31af7Sopenharmony_ci			<< "    result[offset] = 1u; // Invocation we read from was inactive, so we can't verify results!\n"
352e5c31af7Sopenharmony_ci			<< "  }\n"
353e5c31af7Sopenharmony_ci			<< "}\n";
354e5c31af7Sopenharmony_ci
355e5c31af7Sopenharmony_ci		programCollection.add("comp") << glu::ComputeSource(src.str());
356e5c31af7Sopenharmony_ci	}
357e5c31af7Sopenharmony_ci	else
358e5c31af7Sopenharmony_ci	{
359e5c31af7Sopenharmony_ci		std::ostringstream src;
360e5c31af7Sopenharmony_ci		if (OPTYPE_QUAD_BROADCAST == caseDef.opType)
361e5c31af7Sopenharmony_ci		{
362e5c31af7Sopenharmony_ci			src << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
363e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID], " << caseDef.direction << "u);\n"
364e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + " << caseDef.direction << "u;\n";
365e5c31af7Sopenharmony_ci		}
366e5c31af7Sopenharmony_ci		else
367e5c31af7Sopenharmony_ci		{
368e5c31af7Sopenharmony_ci			src << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " op = "
369e5c31af7Sopenharmony_ci				<< getOpTypeName(caseDef.opType) << "(data[gl_SubgroupInvocationID]);\n"
370e5c31af7Sopenharmony_ci				<< "  uint otherID = (gl_SubgroupInvocationID & ~0x3u) + swapTable[gl_SubgroupInvocationID & 0x3u];\n";
371e5c31af7Sopenharmony_ci		}
372e5c31af7Sopenharmony_ci		const string sourceType = src.str();
373e5c31af7Sopenharmony_ci
374e5c31af7Sopenharmony_ci		{
375e5c31af7Sopenharmony_ci			const string vertex =
376e5c31af7Sopenharmony_ci				"${VERSION_DECL}\n"
377e5c31af7Sopenharmony_ci				"#extension GL_KHR_shader_subgroup_quad: enable\n"
378e5c31af7Sopenharmony_ci				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
379e5c31af7Sopenharmony_ci				"layout(binding = 0, std430) buffer Buffer0\n"
380e5c31af7Sopenharmony_ci				"{\n"
381e5c31af7Sopenharmony_ci				"  uint result[];\n"
382e5c31af7Sopenharmony_ci				"} b0;\n"
383e5c31af7Sopenharmony_ci				"layout(binding = 4, std430) readonly buffer Buffer4\n"
384e5c31af7Sopenharmony_ci				"{\n"
385e5c31af7Sopenharmony_ci				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " data[];\n"
386e5c31af7Sopenharmony_ci				"};\n"
387e5c31af7Sopenharmony_ci				"\n"
388e5c31af7Sopenharmony_ci				"void main (void)\n"
389e5c31af7Sopenharmony_ci				"{\n"
390e5c31af7Sopenharmony_ci				"  uvec4 mask = subgroupBallot(true);\n"
391e5c31af7Sopenharmony_ci				+ swapTable[caseDef.opType]
392e5c31af7Sopenharmony_ci				+ sourceType +
393e5c31af7Sopenharmony_ci				"  if (subgroupBallotBitExtract(mask, otherID))\n"
394e5c31af7Sopenharmony_ci				"  {\n"
395e5c31af7Sopenharmony_ci				"    b0.result[gl_VertexID] = (op == data[otherID]) ? 1u : 0u;\n"
396e5c31af7Sopenharmony_ci				"  }\n"
397e5c31af7Sopenharmony_ci				"  else\n"
398e5c31af7Sopenharmony_ci				"  {\n"
399e5c31af7Sopenharmony_ci				"    b0.result[gl_VertexID] = 1u; // Invocation we read from was inactive, so we can't verify results!\n"
400e5c31af7Sopenharmony_ci				"  }\n"
401e5c31af7Sopenharmony_ci				"  float pixelSize = 2.0f/1024.0f;\n"
402e5c31af7Sopenharmony_ci				"  float pixelPosition = pixelSize/2.0f - 1.0f;\n"
403e5c31af7Sopenharmony_ci				"  gl_Position = vec4(float(gl_VertexID) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
404e5c31af7Sopenharmony_ci				"}\n";
405e5c31af7Sopenharmony_ci			programCollection.add("vert") << glu::VertexSource(vertex);
406e5c31af7Sopenharmony_ci		}
407e5c31af7Sopenharmony_ci
408e5c31af7Sopenharmony_ci		{
409e5c31af7Sopenharmony_ci			const string tesc =
410e5c31af7Sopenharmony_ci				"${VERSION_DECL}\n"
411e5c31af7Sopenharmony_ci				"#extension GL_KHR_shader_subgroup_quad: enable\n"
412e5c31af7Sopenharmony_ci				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
413e5c31af7Sopenharmony_ci				"layout(vertices=1) out;\n"
414e5c31af7Sopenharmony_ci				"layout(binding = 1, std430) buffer Buffer1\n"
415e5c31af7Sopenharmony_ci				"{\n"
416e5c31af7Sopenharmony_ci				"  uint result[];\n"
417e5c31af7Sopenharmony_ci				"} b1;\n"
418e5c31af7Sopenharmony_ci				"layout(binding = 4, std430) readonly buffer Buffer4\n"
419e5c31af7Sopenharmony_ci				"{\n"
420e5c31af7Sopenharmony_ci				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " data[];\n"
421e5c31af7Sopenharmony_ci				"};\n"
422e5c31af7Sopenharmony_ci				"\n"
423e5c31af7Sopenharmony_ci				"void main (void)\n"
424e5c31af7Sopenharmony_ci				"{\n"
425e5c31af7Sopenharmony_ci				"  uvec4 mask = subgroupBallot(true);\n"
426e5c31af7Sopenharmony_ci				+ swapTable[caseDef.opType]
427e5c31af7Sopenharmony_ci				+ sourceType +
428e5c31af7Sopenharmony_ci				"  if (subgroupBallotBitExtract(mask, otherID))\n"
429e5c31af7Sopenharmony_ci				"  {\n"
430e5c31af7Sopenharmony_ci				"    b1.result[gl_PrimitiveID] = (op == data[otherID]) ? 1u : 0u;\n"
431e5c31af7Sopenharmony_ci				"  }\n"
432e5c31af7Sopenharmony_ci				"  else\n"
433e5c31af7Sopenharmony_ci				"  {\n"
434e5c31af7Sopenharmony_ci				"    b1.result[gl_PrimitiveID] = 1u; // Invocation we read from was inactive, so we can't verify results!\n"
435e5c31af7Sopenharmony_ci				"  }\n"
436e5c31af7Sopenharmony_ci				"  if (gl_InvocationID == 0)\n"
437e5c31af7Sopenharmony_ci				"  {\n"
438e5c31af7Sopenharmony_ci				"    gl_TessLevelOuter[0] = 1.0f;\n"
439e5c31af7Sopenharmony_ci				"    gl_TessLevelOuter[1] = 1.0f;\n"
440e5c31af7Sopenharmony_ci				"  }\n"
441e5c31af7Sopenharmony_ci				"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
442e5c31af7Sopenharmony_ci				"}\n";
443e5c31af7Sopenharmony_ci			programCollection.add("tesc") << glu::TessellationControlSource(tesc);
444e5c31af7Sopenharmony_ci		}
445e5c31af7Sopenharmony_ci
446e5c31af7Sopenharmony_ci		{
447e5c31af7Sopenharmony_ci			const string tese =
448e5c31af7Sopenharmony_ci				"${VERSION_DECL}\n"
449e5c31af7Sopenharmony_ci				"#extension GL_KHR_shader_subgroup_quad: enable\n"
450e5c31af7Sopenharmony_ci				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
451e5c31af7Sopenharmony_ci				"layout(isolines) in;\n"
452e5c31af7Sopenharmony_ci				"layout(binding = 2, std430)  buffer Buffer2\n"
453e5c31af7Sopenharmony_ci				"{\n"
454e5c31af7Sopenharmony_ci				"  uint result[];\n"
455e5c31af7Sopenharmony_ci				"} b2;\n"
456e5c31af7Sopenharmony_ci				"layout(binding = 4, std430) readonly buffer Buffer4\n"
457e5c31af7Sopenharmony_ci				"{\n"
458e5c31af7Sopenharmony_ci				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " data[];\n"
459e5c31af7Sopenharmony_ci				"};\n"
460e5c31af7Sopenharmony_ci				"\n"
461e5c31af7Sopenharmony_ci				"void main (void)\n"
462e5c31af7Sopenharmony_ci				"{\n"
463e5c31af7Sopenharmony_ci				"  uvec4 mask = subgroupBallot(true);\n"
464e5c31af7Sopenharmony_ci				+ swapTable[caseDef.opType]
465e5c31af7Sopenharmony_ci				+ sourceType +
466e5c31af7Sopenharmony_ci				"  if (subgroupBallotBitExtract(mask, otherID))\n"
467e5c31af7Sopenharmony_ci				"  {\n"
468e5c31af7Sopenharmony_ci				"    b2.result[gl_PrimitiveID * 2 + int(gl_TessCoord.x + 0.5)] = (op == data[otherID]) ? 1u : 0u;\n"
469e5c31af7Sopenharmony_ci				"  }\n"
470e5c31af7Sopenharmony_ci				"  else\n"
471e5c31af7Sopenharmony_ci				"  {\n"
472e5c31af7Sopenharmony_ci				"    b2.result[gl_PrimitiveID * 2 + int(gl_TessCoord.x + 0.5)] = 1u; // Invocation we read from was inactive, so we can't verify results!\n"
473e5c31af7Sopenharmony_ci				"  }\n"
474e5c31af7Sopenharmony_ci				"  float pixelSize = 2.0f/1024.0f;\n"
475e5c31af7Sopenharmony_ci				"  gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
476e5c31af7Sopenharmony_ci				"}\n";
477e5c31af7Sopenharmony_ci			programCollection.add("tese") << glu::TessellationEvaluationSource(tese);
478e5c31af7Sopenharmony_ci		}
479e5c31af7Sopenharmony_ci
480e5c31af7Sopenharmony_ci		{
481e5c31af7Sopenharmony_ci			const string geometry =
482e5c31af7Sopenharmony_ci				// version added by addGeometryShadersFromTemplate
483e5c31af7Sopenharmony_ci				"#extension GL_KHR_shader_subgroup_quad: enable\n"
484e5c31af7Sopenharmony_ci				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
485e5c31af7Sopenharmony_ci				"layout(${TOPOLOGY}) in;\n"
486e5c31af7Sopenharmony_ci				"layout(points, max_vertices = 1) out;\n"
487e5c31af7Sopenharmony_ci				"layout(binding = 3, std430) buffer Buffer3\n"
488e5c31af7Sopenharmony_ci				"{\n"
489e5c31af7Sopenharmony_ci				"  uint result[];\n"
490e5c31af7Sopenharmony_ci				"} b3;\n"
491e5c31af7Sopenharmony_ci				"layout(binding = 4, std430) readonly buffer Buffer4\n"
492e5c31af7Sopenharmony_ci				"{\n"
493e5c31af7Sopenharmony_ci				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " data[];\n"
494e5c31af7Sopenharmony_ci				"};\n"
495e5c31af7Sopenharmony_ci				"\n"
496e5c31af7Sopenharmony_ci				"void main (void)\n"
497e5c31af7Sopenharmony_ci				"{\n"
498e5c31af7Sopenharmony_ci				"  uvec4 mask = subgroupBallot(true);\n"
499e5c31af7Sopenharmony_ci				+ swapTable[caseDef.opType]
500e5c31af7Sopenharmony_ci				+ sourceType +
501e5c31af7Sopenharmony_ci				"  if (subgroupBallotBitExtract(mask, otherID))\n"
502e5c31af7Sopenharmony_ci				"  {\n"
503e5c31af7Sopenharmony_ci				"    b3.result[gl_PrimitiveIDIn] = (op == data[otherID]) ? 1u : 0u;\n"
504e5c31af7Sopenharmony_ci				"  }\n"
505e5c31af7Sopenharmony_ci				"  else\n"
506e5c31af7Sopenharmony_ci				"  {\n"
507e5c31af7Sopenharmony_ci				"    b3.result[gl_PrimitiveIDIn] = 1u; // Invocation we read from was inactive, so we can't verify results!\n"
508e5c31af7Sopenharmony_ci				"  }\n"
509e5c31af7Sopenharmony_ci				"  gl_Position = gl_in[0].gl_Position;\n"
510e5c31af7Sopenharmony_ci				"  EmitVertex();\n"
511e5c31af7Sopenharmony_ci				"  EndPrimitive();\n"
512e5c31af7Sopenharmony_ci				"}\n";
513e5c31af7Sopenharmony_ci			subgroups::addGeometryShadersFromTemplate(geometry, programCollection);
514e5c31af7Sopenharmony_ci		}
515e5c31af7Sopenharmony_ci
516e5c31af7Sopenharmony_ci		{
517e5c31af7Sopenharmony_ci			const string fragment =
518e5c31af7Sopenharmony_ci				"${VERSION_DECL}\n"
519e5c31af7Sopenharmony_ci				"#extension GL_KHR_shader_subgroup_quad: enable\n"
520e5c31af7Sopenharmony_ci				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
521e5c31af7Sopenharmony_ci				"precision highp int;\n"
522e5c31af7Sopenharmony_ci				"precision highp float;\n"
523e5c31af7Sopenharmony_ci				"layout(location = 0) out uint result;\n"
524e5c31af7Sopenharmony_ci				"layout(binding = 4, std430) readonly buffer Buffer4\n"
525e5c31af7Sopenharmony_ci				"{\n"
526e5c31af7Sopenharmony_ci				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " data[];\n"
527e5c31af7Sopenharmony_ci				"};\n"
528e5c31af7Sopenharmony_ci				"void main (void)\n"
529e5c31af7Sopenharmony_ci				"{\n"
530e5c31af7Sopenharmony_ci				"  uvec4 mask = subgroupBallot(true);\n"
531e5c31af7Sopenharmony_ci				+ swapTable[caseDef.opType]
532e5c31af7Sopenharmony_ci				+ sourceType +
533e5c31af7Sopenharmony_ci				"  if (subgroupBallotBitExtract(mask, otherID))\n"
534e5c31af7Sopenharmony_ci				"  {\n"
535e5c31af7Sopenharmony_ci				"    result = (op == data[otherID]) ? 1u : 0u;\n"
536e5c31af7Sopenharmony_ci				"  }\n"
537e5c31af7Sopenharmony_ci				"  else\n"
538e5c31af7Sopenharmony_ci				"  {\n"
539e5c31af7Sopenharmony_ci				"    result = 1u; // Invocation we read from was inactive, so we can't verify results!\n"
540e5c31af7Sopenharmony_ci				"  }\n"
541e5c31af7Sopenharmony_ci				"}\n";
542e5c31af7Sopenharmony_ci			programCollection.add("fragment") << glu::FragmentSource(fragment);
543e5c31af7Sopenharmony_ci		}
544e5c31af7Sopenharmony_ci		subgroups::addNoSubgroupShader(programCollection);
545e5c31af7Sopenharmony_ci	}
546e5c31af7Sopenharmony_ci}
547e5c31af7Sopenharmony_ci
548e5c31af7Sopenharmony_civoid supportedCheck (Context& context, CaseDefinition caseDef)
549e5c31af7Sopenharmony_ci{
550e5c31af7Sopenharmony_ci	if (!subgroups::isSubgroupSupported(context))
551e5c31af7Sopenharmony_ci		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
552e5c31af7Sopenharmony_ci
553e5c31af7Sopenharmony_ci	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, SUBGROUP_FEATURE_QUAD_BIT))
554e5c31af7Sopenharmony_ci		TCU_THROW(NotSupportedError, "Device does not support subgroup quad operations");
555e5c31af7Sopenharmony_ci
556e5c31af7Sopenharmony_ci
557e5c31af7Sopenharmony_ci	if (subgroups::isDoubleFormat(caseDef.format) &&
558e5c31af7Sopenharmony_ci			!subgroups::isDoubleSupportedForDevice(context))
559e5c31af7Sopenharmony_ci	{
560e5c31af7Sopenharmony_ci		TCU_THROW(NotSupportedError, "Device does not support subgroup double operations");
561e5c31af7Sopenharmony_ci	}
562e5c31af7Sopenharmony_ci}
563e5c31af7Sopenharmony_ci
564e5c31af7Sopenharmony_citcu::TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
565e5c31af7Sopenharmony_ci{
566e5c31af7Sopenharmony_ci	if (!subgroups::areSubgroupOperationsSupportedForStage(
567e5c31af7Sopenharmony_ci				context, caseDef.shaderStage))
568e5c31af7Sopenharmony_ci	{
569e5c31af7Sopenharmony_ci		if (subgroups::areSubgroupOperationsRequiredForStage(
570e5c31af7Sopenharmony_ci					caseDef.shaderStage))
571e5c31af7Sopenharmony_ci		{
572e5c31af7Sopenharmony_ci			return tcu::TestStatus::fail(
573e5c31af7Sopenharmony_ci					   "Shader stage " +
574e5c31af7Sopenharmony_ci					   subgroups::getShaderStageName(caseDef.shaderStage) +
575e5c31af7Sopenharmony_ci					   " is required to support subgroup operations!");
576e5c31af7Sopenharmony_ci		}
577e5c31af7Sopenharmony_ci		else
578e5c31af7Sopenharmony_ci		{
579e5c31af7Sopenharmony_ci			TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
580e5c31af7Sopenharmony_ci		}
581e5c31af7Sopenharmony_ci	}
582e5c31af7Sopenharmony_ci
583e5c31af7Sopenharmony_ci	subgroups::SSBOData inputData;
584e5c31af7Sopenharmony_ci	inputData.format = caseDef.format;
585e5c31af7Sopenharmony_ci	inputData.layout = subgroups::SSBOData::LayoutStd140;
586e5c31af7Sopenharmony_ci	inputData.numElements = subgroups::maxSupportedSubgroupSize();
587e5c31af7Sopenharmony_ci	inputData.initializeType = subgroups::SSBOData::InitializeNonZero;
588e5c31af7Sopenharmony_ci	inputData.binding = 0u;
589e5c31af7Sopenharmony_ci
590e5c31af7Sopenharmony_ci	if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
591e5c31af7Sopenharmony_ci		return subgroups::makeVertexFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages);
592e5c31af7Sopenharmony_ci	else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
593e5c31af7Sopenharmony_ci		return subgroups::makeGeometryFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages);
594e5c31af7Sopenharmony_ci	else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
595e5c31af7Sopenharmony_ci		return subgroups::makeTessellationEvaluationFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, SHADER_STAGE_TESS_CONTROL_BIT);
596e5c31af7Sopenharmony_ci	else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
597e5c31af7Sopenharmony_ci		return subgroups::makeTessellationEvaluationFrameBufferTest(context,  FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, SHADER_STAGE_TESS_EVALUATION_BIT);
598e5c31af7Sopenharmony_ci	else
599e5c31af7Sopenharmony_ci		TCU_THROW(InternalError, "Unhandled shader stage");
600e5c31af7Sopenharmony_ci}
601e5c31af7Sopenharmony_ci
602e5c31af7Sopenharmony_ci
603e5c31af7Sopenharmony_citcu::TestStatus test(Context& context, const CaseDefinition caseDef)
604e5c31af7Sopenharmony_ci{
605e5c31af7Sopenharmony_ci	if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
606e5c31af7Sopenharmony_ci	{
607e5c31af7Sopenharmony_ci		if (!subgroups::areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
608e5c31af7Sopenharmony_ci		{
609e5c31af7Sopenharmony_ci			return tcu::TestStatus::fail(
610e5c31af7Sopenharmony_ci					   "Shader stage " +
611e5c31af7Sopenharmony_ci					   subgroups::getShaderStageName(caseDef.shaderStage) +
612e5c31af7Sopenharmony_ci					   " is required to support subgroup operations!");
613e5c31af7Sopenharmony_ci		}
614e5c31af7Sopenharmony_ci		subgroups::SSBOData inputData;
615e5c31af7Sopenharmony_ci		inputData.format = caseDef.format;
616e5c31af7Sopenharmony_ci		inputData.layout = subgroups::SSBOData::LayoutStd430;
617e5c31af7Sopenharmony_ci		inputData.numElements = subgroups::maxSupportedSubgroupSize();
618e5c31af7Sopenharmony_ci		inputData.initializeType = subgroups::SSBOData::InitializeNonZero;
619e5c31af7Sopenharmony_ci		inputData.binding = 1u;
620e5c31af7Sopenharmony_ci
621e5c31af7Sopenharmony_ci		return subgroups::makeComputeTest(context, FORMAT_R32_UINT, &inputData, 1, checkComputeStage);
622e5c31af7Sopenharmony_ci	}
623e5c31af7Sopenharmony_ci	else
624e5c31af7Sopenharmony_ci	{
625e5c31af7Sopenharmony_ci		int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
626e5c31af7Sopenharmony_ci
627e5c31af7Sopenharmony_ci		ShaderStageFlags stages = (ShaderStageFlags)(caseDef.shaderStage & supportedStages);
628e5c31af7Sopenharmony_ci
629e5c31af7Sopenharmony_ci		if (SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
630e5c31af7Sopenharmony_ci		{
631e5c31af7Sopenharmony_ci			if ( (stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
632e5c31af7Sopenharmony_ci				TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
633e5c31af7Sopenharmony_ci			else
634e5c31af7Sopenharmony_ci				stages = SHADER_STAGE_FRAGMENT_BIT;
635e5c31af7Sopenharmony_ci		}
636e5c31af7Sopenharmony_ci
637e5c31af7Sopenharmony_ci		if ((ShaderStageFlags)0u == stages)
638e5c31af7Sopenharmony_ci			TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
639e5c31af7Sopenharmony_ci
640e5c31af7Sopenharmony_ci		subgroups::SSBOData inputData;
641e5c31af7Sopenharmony_ci		inputData.format			= caseDef.format;
642e5c31af7Sopenharmony_ci		inputData.layout			= subgroups::SSBOData::LayoutStd430;
643e5c31af7Sopenharmony_ci		inputData.numElements		= subgroups::maxSupportedSubgroupSize();
644e5c31af7Sopenharmony_ci		inputData.initializeType	= subgroups::SSBOData::InitializeNonZero;
645e5c31af7Sopenharmony_ci		inputData.binding			= 4u;
646e5c31af7Sopenharmony_ci		inputData.stages			= stages;
647e5c31af7Sopenharmony_ci
648e5c31af7Sopenharmony_ci		return subgroups::allStages(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, stages);
649e5c31af7Sopenharmony_ci	}
650e5c31af7Sopenharmony_ci}
651e5c31af7Sopenharmony_ci}
652e5c31af7Sopenharmony_ci
653e5c31af7Sopenharmony_cideqp::TestCaseGroup* createSubgroupsQuadTests(deqp::Context& testCtx)
654e5c31af7Sopenharmony_ci{
655e5c31af7Sopenharmony_ci	de::MovePtr<deqp::TestCaseGroup> graphicGroup(new deqp::TestCaseGroup(
656e5c31af7Sopenharmony_ci		testCtx, "graphics", "Subgroup arithmetic category tests: graphics"));
657e5c31af7Sopenharmony_ci	de::MovePtr<deqp::TestCaseGroup> computeGroup(new deqp::TestCaseGroup(
658e5c31af7Sopenharmony_ci		testCtx, "compute", "Subgroup arithmetic category tests: compute"));
659e5c31af7Sopenharmony_ci	de::MovePtr<deqp::TestCaseGroup> framebufferGroup(new deqp::TestCaseGroup(
660e5c31af7Sopenharmony_ci		testCtx, "framebuffer", "Subgroup arithmetic category tests: framebuffer"));
661e5c31af7Sopenharmony_ci
662e5c31af7Sopenharmony_ci	const Format formats[] =
663e5c31af7Sopenharmony_ci	{
664e5c31af7Sopenharmony_ci		FORMAT_R32_SINT, FORMAT_R32G32_SINT, FORMAT_R32G32B32_SINT,
665e5c31af7Sopenharmony_ci		FORMAT_R32G32B32A32_SINT, FORMAT_R32_UINT, FORMAT_R32G32_UINT,
666e5c31af7Sopenharmony_ci		FORMAT_R32G32B32_UINT, FORMAT_R32G32B32A32_UINT,
667e5c31af7Sopenharmony_ci		FORMAT_R32_SFLOAT, FORMAT_R32G32_SFLOAT,
668e5c31af7Sopenharmony_ci		FORMAT_R32G32B32_SFLOAT, FORMAT_R32G32B32A32_SFLOAT,
669e5c31af7Sopenharmony_ci		FORMAT_R64_SFLOAT, FORMAT_R64G64_SFLOAT,
670e5c31af7Sopenharmony_ci		FORMAT_R64G64B64_SFLOAT, FORMAT_R64G64B64A64_SFLOAT,
671e5c31af7Sopenharmony_ci		FORMAT_R32_BOOL, FORMAT_R32G32_BOOL,
672e5c31af7Sopenharmony_ci		FORMAT_R32G32B32_BOOL, FORMAT_R32G32B32A32_BOOL,
673e5c31af7Sopenharmony_ci	};
674e5c31af7Sopenharmony_ci
675e5c31af7Sopenharmony_ci	const ShaderStageFlags stages[] =
676e5c31af7Sopenharmony_ci	{
677e5c31af7Sopenharmony_ci		SHADER_STAGE_VERTEX_BIT,
678e5c31af7Sopenharmony_ci		SHADER_STAGE_TESS_EVALUATION_BIT,
679e5c31af7Sopenharmony_ci		SHADER_STAGE_TESS_CONTROL_BIT,
680e5c31af7Sopenharmony_ci		SHADER_STAGE_GEOMETRY_BIT,
681e5c31af7Sopenharmony_ci	};
682e5c31af7Sopenharmony_ci
683e5c31af7Sopenharmony_ci	for (int direction = 0; direction < 4; ++direction)
684e5c31af7Sopenharmony_ci	{
685e5c31af7Sopenharmony_ci		for (int formatIndex = 0; formatIndex < DE_LENGTH_OF_ARRAY(formats); ++formatIndex)
686e5c31af7Sopenharmony_ci		{
687e5c31af7Sopenharmony_ci			const Format format = formats[formatIndex];
688e5c31af7Sopenharmony_ci
689e5c31af7Sopenharmony_ci			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
690e5c31af7Sopenharmony_ci			{
691e5c31af7Sopenharmony_ci				const std::string op = de::toLower(getOpTypeName(opTypeIndex));
692e5c31af7Sopenharmony_ci				std::ostringstream name;
693e5c31af7Sopenharmony_ci				name << de::toLower(op);
694e5c31af7Sopenharmony_ci
695e5c31af7Sopenharmony_ci				if (OPTYPE_QUAD_BROADCAST == opTypeIndex)
696e5c31af7Sopenharmony_ci				{
697e5c31af7Sopenharmony_ci					name << "_" << direction;
698e5c31af7Sopenharmony_ci				}
699e5c31af7Sopenharmony_ci				else
700e5c31af7Sopenharmony_ci				{
701e5c31af7Sopenharmony_ci					if (0 != direction)
702e5c31af7Sopenharmony_ci					{
703e5c31af7Sopenharmony_ci						// We don't need direction for swap operations.
704e5c31af7Sopenharmony_ci						continue;
705e5c31af7Sopenharmony_ci					}
706e5c31af7Sopenharmony_ci				}
707e5c31af7Sopenharmony_ci
708e5c31af7Sopenharmony_ci				name << "_" << subgroups::getFormatNameForGLSL(format);
709e5c31af7Sopenharmony_ci
710e5c31af7Sopenharmony_ci				{
711e5c31af7Sopenharmony_ci					const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_COMPUTE_BIT, format, direction};
712e5c31af7Sopenharmony_ci					SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(computeGroup.get(), name.str(), "", supportedCheck, initPrograms, test, caseDef);
713e5c31af7Sopenharmony_ci				}
714e5c31af7Sopenharmony_ci
715e5c31af7Sopenharmony_ci				{
716e5c31af7Sopenharmony_ci					const CaseDefinition caseDef =
717e5c31af7Sopenharmony_ci					{
718e5c31af7Sopenharmony_ci						opTypeIndex,
719e5c31af7Sopenharmony_ci						SHADER_STAGE_ALL_GRAPHICS,
720e5c31af7Sopenharmony_ci						format,
721e5c31af7Sopenharmony_ci						direction
722e5c31af7Sopenharmony_ci					};
723e5c31af7Sopenharmony_ci					SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(graphicGroup.get(), name.str(), "", supportedCheck, initPrograms, test, caseDef);
724e5c31af7Sopenharmony_ci				}
725e5c31af7Sopenharmony_ci				for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
726e5c31af7Sopenharmony_ci				{
727e5c31af7Sopenharmony_ci					const CaseDefinition caseDef = {opTypeIndex, stages[stageIndex], format, direction};
728e5c31af7Sopenharmony_ci					SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(framebufferGroup.get(), name.str()+"_"+ getShaderStageName(caseDef.shaderStage), "",
729e5c31af7Sopenharmony_ci												supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
730e5c31af7Sopenharmony_ci				}
731e5c31af7Sopenharmony_ci
732e5c31af7Sopenharmony_ci			}
733e5c31af7Sopenharmony_ci		}
734e5c31af7Sopenharmony_ci	}
735e5c31af7Sopenharmony_ci
736e5c31af7Sopenharmony_ci	de::MovePtr<deqp::TestCaseGroup> group(new deqp::TestCaseGroup(
737e5c31af7Sopenharmony_ci		testCtx, "quad", "Subgroup quad category tests"));
738e5c31af7Sopenharmony_ci
739e5c31af7Sopenharmony_ci	group->addChild(graphicGroup.release());
740e5c31af7Sopenharmony_ci	group->addChild(computeGroup.release());
741e5c31af7Sopenharmony_ci	group->addChild(framebufferGroup.release());
742e5c31af7Sopenharmony_ci
743e5c31af7Sopenharmony_ci	return group.release();
744e5c31af7Sopenharmony_ci}
745e5c31af7Sopenharmony_ci} // subgroups
746e5c31af7Sopenharmony_ci} // glc
747