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