• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 The Android Open Source Project
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Compute Shader Built-in variable tests.
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktComputeShaderBuiltinVarTests.hpp"
28 #include "vktTestCaseUtil.hpp"
29 #include "vktComputeTestsUtil.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkRef.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkStrUtil.hpp"
36 #include "vkRefUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkBarrierUtil.hpp"
39 #include "vkMemUtil.hpp"
40 #include "vkDeviceUtil.hpp"
41 #include "vkTypeUtil.hpp"
42 #include "vkBuilderUtil.hpp"
43 #include "vkCmdUtil.hpp"
44 #include "vkObjUtil.hpp"
45 #include "vkBufferWithMemory.hpp"
46 
47 #include "tcuTestLog.hpp"
48 #include "tcuFormatUtil.hpp"
49 #include "tcuVectorUtil.hpp"
50 #include "tcuCommandLine.hpp"
51 
52 #include "gluShaderUtil.hpp"
53 
54 #include "deUniquePtr.hpp"
55 #include "deSharedPtr.hpp"
56 
57 #include <map>
58 #include <string>
59 #include <vector>
60 
61 namespace vkt
62 {
63 namespace compute
64 {
65 namespace
66 {
67 
68 using namespace vk;
69 using std::string;
70 using std::vector;
71 using std::map;
72 using tcu::TestLog;
73 using tcu::UVec3;
74 using tcu::IVec3;
75 
76 class ComputeBuiltinVarInstance;
77 class ComputeBuiltinVarCase;
78 
79 static const string s_prefixProgramName ="compute_";
80 
compareNumComponents(const UVec3 & a,const UVec3 & b,const int numComps)81 static inline bool compareNumComponents (const UVec3& a, const UVec3& b,const int numComps)
82 {
83 	DE_ASSERT(numComps == 1 || numComps == 3);
84 	return numComps == 3 ? tcu::allEqual(a, b) : a.x() == b.x();
85 }
86 
readResultVec(const deUint32 * ptr,const int numComps)87 static inline UVec3 readResultVec (const deUint32* ptr, const int numComps)
88 {
89 	UVec3 res;
90 	for (int ndx = 0; ndx < numComps; ndx++)
91 		res[ndx] = ptr[ndx];
92 	return res;
93 }
94 
95 struct LogComps
96 {
97 	const UVec3&	v;
98 	int				numComps;
99 
LogCompsvkt::compute::__anon39dc18470111::LogComps100 					LogComps	(const UVec3 &v_, int numComps_) : v(v_), numComps(numComps_) {}
101 };
102 
operator <<(std::ostream & str,const LogComps & c)103 static inline std::ostream& operator<< (std::ostream& str, const LogComps& c)
104 {
105 	DE_ASSERT(c.numComps == 1 || c.numComps == 3);
106 	return c.numComps == 3 ? str << c.v : str << c.v.x();
107 }
108 
109 class SubCase
110 {
111 public:
112 	// Use getters instead of public const members, because SubCase must be assignable
113 	// in order to be stored in a vector.
114 
localSize(void) const115 	const UVec3&	localSize		(void) const { return m_localSize; }
numWorkGroups(void) const116 	const UVec3&	numWorkGroups	(void) const { return m_numWorkGroups; }
117 
SubCase(void)118 					SubCase			(void) {}
SubCase(const UVec3 & localSize_,const UVec3 & numWorkGroups_)119 					SubCase			(const UVec3& localSize_, const UVec3& numWorkGroups_)
120 						: m_localSize		(localSize_)
121 						, m_numWorkGroups	(numWorkGroups_) {}
122 
123 private:
124 	UVec3	m_localSize;
125 	UVec3	m_numWorkGroups;
126 };
127 
128 
129 class ComputeBuiltinVarInstance : public vkt::TestInstance
130 {
131 public:
132 									ComputeBuiltinVarInstance	(Context&									context,
133 																 const vector<SubCase>&						subCases,
134 																 const glu::DataType						varType,
135 																 const ComputeBuiltinVarCase*				builtinVarCase,
136 																 const vk::ComputePipelineConstructionType	computePipelineConstructionType);
137 
138 	virtual tcu::TestStatus			iterate						(void);
139 
140 private:
141 	const VkDevice						m_device;
142 	const DeviceInterface&				m_vki;
143 	const VkQueue						m_queue;
144 	const deUint32						m_queueFamilyIndex;
145 	vector<SubCase>						m_subCases;
146 	const ComputeBuiltinVarCase*		m_builtin_var_case;
147 	int									m_subCaseNdx;
148 	const glu::DataType					m_varType;
149 	vk::ComputePipelineConstructionType m_computePipelineConstructionType;
150 };
151 
152 class ComputeBuiltinVarCase : public vkt::TestCase
153 {
154 public:
155 							ComputeBuiltinVarCase	(tcu::TestContext& context, const string& name, const char* varName, glu::DataType varType, bool readByComponent, const vk::ComputePipelineConstructionType computePipelineConstructionType);
156 							~ComputeBuiltinVarCase	(void);
157 
checkSupport(Context & context) const158 	virtual void			checkSupport			(Context& context) const
159 	{
160 		checkShaderObjectRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_computePipelineConstructionType);
161 	}
createInstance(Context & context) const162 	TestInstance*			createInstance			(Context& context) const
163 	{
164 		return new ComputeBuiltinVarInstance(context, m_subCases, m_varType, this, m_computePipelineConstructionType);
165 	}
166 
167 	virtual void			initPrograms			(SourceCollections& programCollection) const;
168 	virtual UVec3			computeReference		(const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const = 0;
169 
170 protected:
171 	string					genBuiltinVarSource		(const string& varName, glu::DataType varType, const UVec3& localSize, bool readByComponent) const;
172 	vector<SubCase>			m_subCases;
173 
174 private:
175 	deUint32				getProgram				(const tcu::UVec3& localSize);
176 
177 	const string						m_varName;
178 	const glu::DataType					m_varType;
179 	int									m_subCaseNdx;
180 	bool								m_readByComponent;
181 	vk::ComputePipelineConstructionType m_computePipelineConstructionType;
182 
183 	ComputeBuiltinVarCase (const ComputeBuiltinVarCase& other);
184 	ComputeBuiltinVarCase& operator= (const ComputeBuiltinVarCase& other);
185 };
186 
ComputeBuiltinVarCase(tcu::TestContext & context,const string & name,const char * varName,glu::DataType varType,bool readByComponent,const vk::ComputePipelineConstructionType computePipelineConstructionType)187 ComputeBuiltinVarCase::ComputeBuiltinVarCase (tcu::TestContext& context, const string& name, const char* varName, glu::DataType varType, bool readByComponent, const vk::ComputePipelineConstructionType computePipelineConstructionType)
188 	: TestCase							(context, name + (readByComponent ? "_component" : ""))
189 	, m_varName							(varName)
190 	, m_varType							(varType)
191 	, m_subCaseNdx						(0)
192 	, m_readByComponent					(readByComponent)
193 	, m_computePipelineConstructionType	(computePipelineConstructionType)
194 {
195 }
196 
~ComputeBuiltinVarCase(void)197 ComputeBuiltinVarCase::~ComputeBuiltinVarCase (void)
198 {
199 	ComputeBuiltinVarCase::deinit();
200 }
201 
initPrograms(SourceCollections & programCollection) const202 void ComputeBuiltinVarCase::initPrograms (SourceCollections& programCollection) const
203 {
204 	for (std::size_t i = 0; i < m_subCases.size(); i++)
205 	{
206 		const SubCase&	subCase = m_subCases[i];
207 		std::ostringstream name;
208 		name << s_prefixProgramName << i;
209 		programCollection.glslSources.add(name.str()) << glu::ComputeSource(genBuiltinVarSource(m_varName, m_varType, subCase.localSize(), m_readByComponent).c_str());
210 	}
211 }
212 
genBuiltinVarSource(const string & varName,glu::DataType varType,const UVec3 & localSize,bool readByComponent) const213 string ComputeBuiltinVarCase::genBuiltinVarSource (const string& varName, glu::DataType varType, const UVec3& localSize, bool readByComponent) const
214 {
215 	std::ostringstream src;
216 
217 	src << "#version 310 es\n"
218 		<< "layout (local_size_x = " << localSize.x() << ", local_size_y = " << localSize.y() << ", local_size_z = " << localSize.z() << ") in;\n";
219 
220 	// For the gl_WorkGroupSize case, force it to be specialized so that
221 	// Glslang can't just bypass the read of the builtin variable.
222 	// We will not override these spec constants.
223 	src << "layout (local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;\n";
224 
225 	src << "layout(set = 0, binding = 0) uniform Stride\n"
226 		<< "{\n"
227 		<< "	uvec2 u_stride;\n"
228 		<< "}stride;\n"
229 		<< "layout(set = 0, binding = 1, std430) buffer Output\n"
230 		<< "{\n"
231 		<< "	" << glu::getDataTypeName(varType) << " result[];\n"
232 		<< "} sb_out;\n"
233 		<< "\n"
234 		<< "void main (void)\n"
235 		<< "{\n"
236 		<< "	highp uint offset = stride.u_stride.x*gl_GlobalInvocationID.z + stride.u_stride.y*gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;\n";
237 
238 	if (readByComponent && varType != glu::TYPE_UINT) {
239 		switch(varType)
240 		{
241 			case glu::TYPE_UINT_VEC4:
242 				src << "	sb_out.result[offset].w = " << varName << ".w;\n";
243 				// Fall through
244 			case glu::TYPE_UINT_VEC3:
245 				src << "	sb_out.result[offset].z = " << varName << ".z;\n";
246 				// Fall through
247 			case glu::TYPE_UINT_VEC2:
248 				src << "	sb_out.result[offset].y = " << varName << ".y;\n"
249 					<< "	sb_out.result[offset].x = " << varName << ".x;\n";
250 				break;
251 			default:
252 				DE_FATAL("Illegal data type");
253 				break;
254 		}
255 	} else {
256 		src << "	sb_out.result[offset] = " << varName << ";\n";
257 	}
258 	src << "}\n";
259 
260 	return src.str();
261 }
262 
263 class NumWorkGroupsCase : public ComputeBuiltinVarCase
264 {
265 public:
NumWorkGroupsCase(tcu::TestContext & context,bool readByCompnent,const vk::ComputePipelineConstructionType computePipelineConstructionType)266 	NumWorkGroupsCase (tcu::TestContext& context, bool readByCompnent, const vk::ComputePipelineConstructionType computePipelineConstructionType)
267 		: ComputeBuiltinVarCase(context, "num_work_groups", "gl_NumWorkGroups", glu::TYPE_UINT_VEC3, readByCompnent, computePipelineConstructionType)
268 	{
269 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
270 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(52, 1, 1)));
271 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 39, 1)));
272 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 78)));
273 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(4, 7, 11)));
274 		m_subCases.push_back(SubCase(UVec3(2, 3, 4), UVec3(4, 7, 11)));
275 	}
276 
computeReference(const UVec3 & numWorkGroups,const UVec3 & workGroupSize,const UVec3 & workGroupID,const UVec3 & localInvocationID) const277 	UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
278 	{
279 		DE_UNREF(numWorkGroups);
280 		DE_UNREF(workGroupSize);
281 		DE_UNREF(workGroupID);
282 		DE_UNREF(localInvocationID);
283 		return numWorkGroups;
284 	}
285 };
286 
287 class WorkGroupSizeCase : public ComputeBuiltinVarCase
288 {
289 public:
WorkGroupSizeCase(tcu::TestContext & context,bool readByComponent,const vk::ComputePipelineConstructionType computePipelineConstructionType)290 	WorkGroupSizeCase (tcu::TestContext& context, bool readByComponent, const vk::ComputePipelineConstructionType computePipelineConstructionType)
291 		: ComputeBuiltinVarCase(context, "work_group_size", "gl_WorkGroupSize", glu::TYPE_UINT_VEC3, readByComponent, computePipelineConstructionType)
292 	{
293 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
294 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(2, 7, 3)));
295 		m_subCases.push_back(SubCase(UVec3(2, 1, 1), UVec3(1, 1, 1)));
296 		m_subCases.push_back(SubCase(UVec3(2, 1, 1), UVec3(1, 3, 5)));
297 		m_subCases.push_back(SubCase(UVec3(1, 3, 1), UVec3(1, 1, 1)));
298 		m_subCases.push_back(SubCase(UVec3(1, 1, 7), UVec3(1, 1, 1)));
299 		m_subCases.push_back(SubCase(UVec3(1, 1, 7), UVec3(3, 3, 1)));
300 		m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(1, 1, 1)));
301 		m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(3, 1, 2)));
302 	}
303 
computeReference(const UVec3 & numWorkGroups,const UVec3 & workGroupSize,const UVec3 & workGroupID,const UVec3 & localInvocationID) const304 	UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
305 	{
306 		DE_UNREF(numWorkGroups);
307 		DE_UNREF(workGroupID);
308 		DE_UNREF(localInvocationID);
309 		return workGroupSize;
310 	}
311 };
312 
313 //-----------------------------------------------------------------------
314 class WorkGroupIDCase : public ComputeBuiltinVarCase
315 {
316 public:
WorkGroupIDCase(tcu::TestContext & context,bool readbyComponent,const vk::ComputePipelineConstructionType computePipelineConstructionType)317 	WorkGroupIDCase (tcu::TestContext& context, bool readbyComponent, const vk::ComputePipelineConstructionType computePipelineConstructionType)
318 		: ComputeBuiltinVarCase(context, "work_group_id", "gl_WorkGroupID", glu::TYPE_UINT_VEC3, readbyComponent, computePipelineConstructionType)
319 	{
320 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
321 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(52, 1, 1)));
322 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 39, 1)));
323 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 78)));
324 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(4, 7, 11)));
325 		m_subCases.push_back(SubCase(UVec3(2, 3, 4), UVec3(4, 7, 11)));
326 	}
327 
computeReference(const UVec3 & numWorkGroups,const UVec3 & workGroupSize,const UVec3 & workGroupID,const UVec3 & localInvocationID) const328 	UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
329 	{
330 		DE_UNREF(numWorkGroups);
331 		DE_UNREF(workGroupSize);
332 		DE_UNREF(localInvocationID);
333 		return workGroupID;
334 	}
335 };
336 
337 class LocalInvocationIDCase : public ComputeBuiltinVarCase
338 {
339 public:
LocalInvocationIDCase(tcu::TestContext & context,bool readByComponent,const vk::ComputePipelineConstructionType computePipelineConstructionType)340 	LocalInvocationIDCase (tcu::TestContext& context, bool readByComponent, const vk::ComputePipelineConstructionType computePipelineConstructionType)
341 		: ComputeBuiltinVarCase(context, "local_invocation_id", "gl_LocalInvocationID", glu::TYPE_UINT_VEC3, readByComponent, computePipelineConstructionType)
342 	{
343 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
344 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(2, 7, 3)));
345 		m_subCases.push_back(SubCase(UVec3(2, 1, 1), UVec3(1, 1, 1)));
346 		m_subCases.push_back(SubCase(UVec3(2, 1, 1), UVec3(1, 3, 5)));
347 		m_subCases.push_back(SubCase(UVec3(1, 3, 1), UVec3(1, 1, 1)));
348 		m_subCases.push_back(SubCase(UVec3(1, 1, 7), UVec3(1, 1, 1)));
349 		m_subCases.push_back(SubCase(UVec3(1, 1, 7), UVec3(3, 3, 1)));
350 		m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(1, 1, 1)));
351 		m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(3, 1, 2)));
352 	}
353 
computeReference(const UVec3 & numWorkGroups,const UVec3 & workGroupSize,const UVec3 & workGroupID,const UVec3 & localInvocationID) const354 	UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
355 	{
356 		DE_UNREF(numWorkGroups);
357 		DE_UNREF(workGroupSize);
358 		DE_UNREF(workGroupID);
359 		return localInvocationID;
360 	}
361 };
362 
363 class GlobalInvocationIDCase : public ComputeBuiltinVarCase
364 {
365 public:
GlobalInvocationIDCase(tcu::TestContext & context,bool readByComponent,const vk::ComputePipelineConstructionType computePipelineConstructionType)366 	GlobalInvocationIDCase (tcu::TestContext& context, bool readByComponent, const vk::ComputePipelineConstructionType computePipelineConstructionType)
367 		: ComputeBuiltinVarCase(context, "global_invocation_id", "gl_GlobalInvocationID", glu::TYPE_UINT_VEC3, readByComponent, computePipelineConstructionType)
368 	{
369 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
370 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(52, 1, 1)));
371 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 39, 1)));
372 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 78)));
373 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(4, 7, 11)));
374 		m_subCases.push_back(SubCase(UVec3(2, 3, 4), UVec3(4, 7, 11)));
375 		m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(1, 1, 1)));
376 		m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(3, 1, 2)));
377 	}
378 
computeReference(const UVec3 & numWorkGroups,const UVec3 & workGroupSize,const UVec3 & workGroupID,const UVec3 & localInvocationID) const379 	UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
380 	{
381 		DE_UNREF(numWorkGroups);
382 		return workGroupID * workGroupSize + localInvocationID;
383 	}
384 };
385 
386 class LocalInvocationIndexCase : public ComputeBuiltinVarCase
387 {
388 public:
LocalInvocationIndexCase(tcu::TestContext & context,bool readByComponent,const vk::ComputePipelineConstructionType computePipelineConstructionType)389 	LocalInvocationIndexCase (tcu::TestContext& context, bool readByComponent, const vk::ComputePipelineConstructionType computePipelineConstructionType)
390 		: ComputeBuiltinVarCase(context, "local_invocation_index", "gl_LocalInvocationIndex", glu::TYPE_UINT, readByComponent, computePipelineConstructionType)
391 	{
392 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
393 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 39, 1)));
394 		m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(4, 7, 11)));
395 		m_subCases.push_back(SubCase(UVec3(2, 3, 4), UVec3(4, 7, 11)));
396 		m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(1, 1, 1)));
397 		m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(3, 1, 2)));
398 	}
399 
computeReference(const UVec3 & numWorkGroups,const UVec3 & workGroupSize,const UVec3 & workGroupID,const UVec3 & localInvocationID) const400 	UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
401 	{
402 		DE_UNREF(workGroupID);
403 		DE_UNREF(numWorkGroups);
404 		return UVec3(localInvocationID.z()*workGroupSize.x()*workGroupSize.y() + localInvocationID.y()*workGroupSize.x() + localInvocationID.x(), 0, 0);
405 	}
406 };
407 
ComputeBuiltinVarInstance(Context & context,const vector<SubCase> & subCases,const glu::DataType varType,const ComputeBuiltinVarCase * builtinVarCase,const vk::ComputePipelineConstructionType computePipelineConstructionType)408 ComputeBuiltinVarInstance::ComputeBuiltinVarInstance (Context&									context,
409 													  const vector<SubCase>&					subCases,
410 													  const glu::DataType						varType,
411 													  const ComputeBuiltinVarCase*				builtinVarCase,
412 													  const vk::ComputePipelineConstructionType	computePipelineConstructionType)
413 	: vkt::TestInstance					(context)
414 	, m_device							(m_context.getDevice())
415 	, m_vki								(m_context.getDeviceInterface())
416 	, m_queue							(context.getUniversalQueue())
417 	, m_queueFamilyIndex				(context.getUniversalQueueFamilyIndex())
418 	, m_subCases						(subCases)
419 	, m_builtin_var_case				(builtinVarCase)
420 	, m_subCaseNdx						(0)
421 	, m_varType							(varType)
422 	, m_computePipelineConstructionType	(computePipelineConstructionType)
423 {
424 }
425 
iterate(void)426 tcu::TestStatus	ComputeBuiltinVarInstance::iterate (void)
427 {
428 	std::ostringstream program_name;
429 	program_name << s_prefixProgramName << m_subCaseNdx;
430 
431 	const SubCase&				subCase				= m_subCases[m_subCaseNdx];
432 	const tcu::UVec3			globalSize			= subCase.localSize()*subCase.numWorkGroups();
433 	const tcu::UVec2			stride				(globalSize[0] * globalSize[1], globalSize[0]);
434 	const deUint32				sizeOfUniformBuffer	= sizeof(stride);
435 	const int					numScalars			= glu::getDataTypeScalarSize(m_varType);
436 	const deUint32				numInvocations		= subCase.localSize()[0] * subCase.localSize()[1] * subCase.localSize()[2] * subCase.numWorkGroups()[0] * subCase.numWorkGroups()[1] * subCase.numWorkGroups()[2];
437 
438 	deUint32					resultBufferStride = 0;
439 	switch (m_varType)
440 	{
441 		case glu::TYPE_UINT:
442 			resultBufferStride = sizeof(deUint32);
443 			break;
444 		case glu::TYPE_UINT_VEC2:
445 			resultBufferStride = sizeof(tcu::UVec2);
446 			break;
447 		case glu::TYPE_UINT_VEC3:
448 		case glu::TYPE_UINT_VEC4:
449 			resultBufferStride = sizeof(tcu::UVec4);
450 			break;
451 		default:
452 			DE_FATAL("Illegal data type");
453 	}
454 
455 	const deUint32				resultBufferSize	= numInvocations * resultBufferStride;
456 
457 	// Create result buffer
458 	vk::BufferWithMemory uniformBuffer(m_vki, m_device, m_context.getDefaultAllocator(), makeBufferCreateInfo(sizeOfUniformBuffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT), MemoryRequirement::HostVisible);
459 	vk::BufferWithMemory resultBuffer(m_vki, m_device, m_context.getDefaultAllocator(), makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
460 
461 	{
462 		const Allocation& alloc = uniformBuffer.getAllocation();
463 		memcpy(alloc.getHostPtr(), &stride, sizeOfUniformBuffer);
464 		flushAlloc(m_vki, m_device, alloc);
465 	}
466 
467 	// Create descriptorSetLayout
468 	const Unique<VkDescriptorSetLayout>	descriptorSetLayout(
469 		DescriptorSetLayoutBuilder()
470 		.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
471 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
472 		.build(m_vki, m_device));
473 
474 	ComputePipelineWrapper			pipeline(m_vki, m_device, m_computePipelineConstructionType, m_context.getBinaryCollection().get(program_name.str()));
475 	pipeline.setDescriptorSetLayout(descriptorSetLayout.get());
476 	pipeline.buildPipeline();
477 
478 	const Unique<VkDescriptorPool> descriptorPool(
479 		DescriptorPoolBuilder()
480 		.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
481 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
482 		.build(m_vki, m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
483 
484 	const VkBufferMemoryBarrier bufferBarrier = makeBufferMemoryBarrier(
485 		VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSize);
486 
487 	const Unique<VkCommandPool> cmdPool(makeCommandPool(m_vki, m_device, m_queueFamilyIndex));
488 	const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(m_vki, m_device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
489 
490 	// Start recording commands
491 	beginCommandBuffer(m_vki, *cmdBuffer);
492 
493 	pipeline.bind(*cmdBuffer);
494 
495 	// Create descriptor set
496 	const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(m_vki, m_device, *descriptorPool, *descriptorSetLayout));
497 
498 	const VkDescriptorBufferInfo resultDescriptorInfo = makeDescriptorBufferInfo(*resultBuffer, 0ull, resultBufferSize);
499 	const VkDescriptorBufferInfo uniformDescriptorInfo = makeDescriptorBufferInfo(*uniformBuffer, 0ull, sizeOfUniformBuffer);
500 
501 	DescriptorSetUpdateBuilder()
502 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uniformDescriptorInfo)
503 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultDescriptorInfo)
504 		.update(m_vki, m_device);
505 
506 	m_vki.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.getPipelineLayout(), 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
507 
508 	// Dispatch indirect compute command
509 	m_vki.cmdDispatch(*cmdBuffer, subCase.numWorkGroups()[0], subCase.numWorkGroups()[1], subCase.numWorkGroups()[2]);
510 
511 	m_vki.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
512 							 0, (const VkMemoryBarrier*)DE_NULL,
513 							 1, &bufferBarrier,
514 							 0, (const VkImageMemoryBarrier*)DE_NULL);
515 
516 	// End recording commands
517 	endCommandBuffer(m_vki, *cmdBuffer);
518 
519 	// Wait for command buffer execution finish
520 	submitCommandsAndWait(m_vki, m_device, m_queue, *cmdBuffer);
521 
522 	const Allocation& resultAlloc = resultBuffer.getAllocation();
523 	invalidateAlloc(m_vki, m_device, resultAlloc);
524 
525 	const deUint8*	 ptr = reinterpret_cast<deUint8*>(resultAlloc.getHostPtr());
526 
527 	int			numFailed		= 0;
528 	const int	maxLogPrints	= 10;
529 
530 	tcu::TestContext& testCtx	= m_context.getTestContext();
531 
532 #ifdef CTS_USES_VULKANSC
533 	if(testCtx.getCommandLine().isSubProcess())
534 #endif // CTS_USES_VULKANSC
535 	{
536 		for (deUint32 groupZ = 0; groupZ < subCase.numWorkGroups().z(); groupZ++)
537 		for (deUint32 groupY = 0; groupY < subCase.numWorkGroups().y(); groupY++)
538 		for (deUint32 groupX = 0; groupX < subCase.numWorkGroups().x(); groupX++)
539 		for (deUint32 localZ = 0; localZ < subCase.localSize().z(); localZ++)
540 		for (deUint32 localY = 0; localY < subCase.localSize().y(); localY++)
541 		for (deUint32 localX = 0; localX < subCase.localSize().x(); localX++)
542 		{
543 			const UVec3			refGroupID(groupX, groupY, groupZ);
544 			const UVec3			refLocalID(localX, localY, localZ);
545 			const UVec3			refGlobalID = refGroupID * subCase.localSize() + refLocalID;
546 
547 			const deUint32		refOffset = stride.x()*refGlobalID.z() + stride.y()*refGlobalID.y() + refGlobalID.x();
548 
549 			const UVec3			refValue = m_builtin_var_case->computeReference(subCase.numWorkGroups(), subCase.localSize(), refGroupID, refLocalID);
550 
551 			const deUint32*		resPtr = (const deUint32*)(ptr + refOffset * resultBufferStride);
552 			const UVec3			resValue = readResultVec(resPtr, numScalars);
553 
554 			if (!compareNumComponents(refValue, resValue, numScalars))
555 			{
556 				if (numFailed < maxLogPrints)
557 					testCtx.getLog()
558 					<< TestLog::Message
559 					<< "ERROR: comparison failed at offset " << refOffset
560 					<< ": expected " << LogComps(refValue, numScalars)
561 					<< ", got " << LogComps(resValue, numScalars)
562 					<< TestLog::EndMessage;
563 				else if (numFailed == maxLogPrints)
564 					testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
565 
566 				numFailed += 1;
567 			}
568 		}
569 	}
570 
571 	testCtx.getLog() << TestLog::Message << (numInvocations - numFailed) << " / " << numInvocations << " values passed" << TestLog::EndMessage;
572 
573 	if (numFailed > 0)
574 		return tcu::TestStatus::fail("Comparison failed");
575 
576 	m_subCaseNdx += 1;
577 	return (m_subCaseNdx < (int)m_subCases.size()) ? tcu::TestStatus::incomplete() :tcu::TestStatus::pass("Comparison succeeded");
578 }
579 
580 class ComputeShaderBuiltinVarTests : public tcu::TestCaseGroup
581 {
582 public:
583 			ComputeShaderBuiltinVarTests	(tcu::TestContext& context, vk::ComputePipelineConstructionType computePipelineConstructionType);
584 
585 	void	init							(void);
586 
587 private:
588 	ComputeShaderBuiltinVarTests (const ComputeShaderBuiltinVarTests& other);
589 	ComputeShaderBuiltinVarTests& operator= (const ComputeShaderBuiltinVarTests& other);
590 
591 	vk::ComputePipelineConstructionType m_computePipelineConstructionType;
592 };
593 
ComputeShaderBuiltinVarTests(tcu::TestContext & context,vk::ComputePipelineConstructionType computePipelineConstructionType)594 ComputeShaderBuiltinVarTests::ComputeShaderBuiltinVarTests (tcu::TestContext& context, vk::ComputePipelineConstructionType computePipelineConstructionType)
595 	: TestCaseGroup						(context, "builtin_var", "Shader builtin var tests")
596 	, m_computePipelineConstructionType	(computePipelineConstructionType)
597 {
598 }
599 
init(void)600 void ComputeShaderBuiltinVarTests::init (void)
601 {
602 	// Builtin variables with vector values should be read whole and by component.
603 	for (int i = 0; i < 2; i++)
604 	{
605 		const bool readByComponent = (i != 0);
606 		addChild(new NumWorkGroupsCase(this->getTestContext(), readByComponent, m_computePipelineConstructionType));
607 		addChild(new WorkGroupSizeCase(this->getTestContext(), readByComponent, m_computePipelineConstructionType));
608 		addChild(new WorkGroupIDCase(this->getTestContext(), readByComponent, m_computePipelineConstructionType));
609 		addChild(new LocalInvocationIDCase(this->getTestContext(), readByComponent, m_computePipelineConstructionType));
610 		addChild(new GlobalInvocationIDCase(this->getTestContext(), readByComponent, m_computePipelineConstructionType));
611 	}
612 	// Local invocation index is already just a scalar.
613 	addChild(new LocalInvocationIndexCase(this->getTestContext(), false, m_computePipelineConstructionType));
614 }
615 
616 } // anonymous
617 
createComputeShaderBuiltinVarTests(tcu::TestContext & testCtx,vk::ComputePipelineConstructionType computePipelineConstructionType)618 tcu::TestCaseGroup* createComputeShaderBuiltinVarTests (tcu::TestContext& testCtx, vk::ComputePipelineConstructionType computePipelineConstructionType)
619 {
620 	return new ComputeShaderBuiltinVarTests(testCtx, computePipelineConstructionType);
621 }
622 
623 } // compute
624 } // vkt
625