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