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