1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2016 The Android Open Source Project
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Compute Shader Built-in variable tests.
23 *//*--------------------------------------------------------------------*/
25 #include "vktComputeShaderBuiltinVarTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktComputeTestsUtil.hpp"
30 #include "vkPlatform.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"
41 #include "tcuTestLog.hpp"
42 #include "tcuFormatUtil.hpp"
43 #include "tcuVectorUtil.hpp"
45 #include "gluShaderUtil.hpp"
47 #include "deUniquePtr.hpp"
48 #include "deSharedPtr.hpp"
69 class ComputeBuiltinVarInstance;
70 class ComputeBuiltinVarCase;
72 static const string s_prefixProgramName ="compute_";
74 static inline bool compareNumComponents (const UVec3& a, const UVec3& b,const int numComps)
76 DE_ASSERT(numComps == 1 || numComps == 3);
77 return numComps == 3 ? tcu::allEqual(a, b) : a.x() == b.x();
80 static inline UVec3 readResultVec (const deUint32* ptr, const int numComps)
83 for (int ndx = 0; ndx < numComps; ndx++)
93 LogComps (const UVec3 &v_, int numComps_) : v(v_), numComps(numComps_) {}
96 static inline std::ostream& operator<< (std::ostream& str, const LogComps& c)
98 DE_ASSERT(c.numComps == 1 || c.numComps == 3);
99 return c.numComps == 3 ? str << c.v : str << c.v.x();
105 // Use getters instead of public const members, because SubCase must be assignable
106 // in order to be stored in a vector.
108 const UVec3& localSize (void) const { return m_localSize; }
109 const UVec3& numWorkGroups (void) const { return m_numWorkGroups; }
112 SubCase (const UVec3& localSize_, const UVec3& numWorkGroups_)
113 : m_localSize (localSize_)
114 , m_numWorkGroups (numWorkGroups_) {}
118 UVec3 m_numWorkGroups;
122 class ComputeBuiltinVarInstance : public vkt::TestInstance
125 ComputeBuiltinVarInstance (Context& context,
126 const vector<SubCase>& subCases,
127 const glu::DataType varType,
128 const ComputeBuiltinVarCase* builtinVarCase);
130 virtual tcu::TestStatus iterate (void);
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;
140 const glu::DataType m_varType;
143 class ComputeBuiltinVarCase : public vkt::TestCase
146 ComputeBuiltinVarCase (tcu::TestContext& context, const char* name, const char* varName, glu::DataType varType);
147 ~ComputeBuiltinVarCase (void);
149 TestInstance* createInstance (Context& context) const
151 return new ComputeBuiltinVarInstance(context, m_subCases, m_varType, this);
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;
158 string genBuiltinVarSource (const string& varName, glu::DataType varType, const UVec3& localSize) const;
159 vector<SubCase> m_subCases;
162 deUint32 getProgram (const tcu::UVec3& localSize);
164 const string m_varName;
165 const glu::DataType m_varType;
168 ComputeBuiltinVarCase (const ComputeBuiltinVarCase& other);
169 ComputeBuiltinVarCase& operator= (const ComputeBuiltinVarCase& other);
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)
180 ComputeBuiltinVarCase::~ComputeBuiltinVarCase (void)
182 ComputeBuiltinVarCase::deinit();
185 void ComputeBuiltinVarCase::initPrograms (SourceCollections& programCollection) const
187 for (std::size_t i = 0; i < m_subCases.size(); i++)
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());
196 string ComputeBuiltinVarCase::genBuiltinVarSource (const string& varName, glu::DataType varType, const UVec3& localSize) const
198 std::ostringstream src;
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"
204 << " uvec2 u_stride;\n"
206 << "layout(set = 0, binding = 1, std430) buffer Output\n"
208 << " " << glu::getDataTypeName(varType) << " result[];\n"
211 << "void main (void)\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"
220 class NumWorkGroupsCase : public ComputeBuiltinVarCase
223 NumWorkGroupsCase (tcu::TestContext& context)
224 : ComputeBuiltinVarCase(context, "num_work_groups", "gl_NumWorkGroups", glu::TYPE_UINT_VEC3)
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)));
234 UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
236 DE_UNREF(numWorkGroups);
237 DE_UNREF(workGroupSize);
238 DE_UNREF(workGroupID);
239 DE_UNREF(localInvocationID);
240 return numWorkGroups;
244 class WorkGroupSizeCase : public ComputeBuiltinVarCase
247 WorkGroupSizeCase (tcu::TestContext& context)
248 : ComputeBuiltinVarCase(context, "work_group_size", "gl_WorkGroupSize", glu::TYPE_UINT_VEC3)
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)));
261 UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
263 DE_UNREF(numWorkGroups);
264 DE_UNREF(workGroupID);
265 DE_UNREF(localInvocationID);
266 return workGroupSize;
270 //-----------------------------------------------------------------------
271 class WorkGroupIDCase : public ComputeBuiltinVarCase
274 WorkGroupIDCase (tcu::TestContext& context)
275 : ComputeBuiltinVarCase(context, "work_group_id", "gl_WorkGroupID", glu::TYPE_UINT_VEC3)
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)));
285 UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
287 DE_UNREF(numWorkGroups);
288 DE_UNREF(workGroupSize);
289 DE_UNREF(localInvocationID);
294 class LocalInvocationIDCase : public ComputeBuiltinVarCase
297 LocalInvocationIDCase (tcu::TestContext& context)
298 : ComputeBuiltinVarCase(context, "local_invocation_id", "gl_LocalInvocationID", glu::TYPE_UINT_VEC3)
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)));
311 UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
313 DE_UNREF(numWorkGroups);
314 DE_UNREF(workGroupSize);
315 DE_UNREF(workGroupID);
316 return localInvocationID;
320 class GlobalInvocationIDCase : public ComputeBuiltinVarCase
323 GlobalInvocationIDCase (tcu::TestContext& context)
324 : ComputeBuiltinVarCase(context, "global_invocation_id", "gl_GlobalInvocationID", glu::TYPE_UINT_VEC3)
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)));
336 UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
338 DE_UNREF(numWorkGroups);
339 return workGroupID * workGroupSize + localInvocationID;
343 class LocalInvocationIndexCase : public ComputeBuiltinVarCase
346 LocalInvocationIndexCase (tcu::TestContext& context)
347 : ComputeBuiltinVarCase(context, "local_invocation_index", "gl_LocalInvocationIndex", glu::TYPE_UINT)
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)));
357 UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
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);
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)
377 , m_varType (varType)
381 tcu::TestStatus ComputeBuiltinVarInstance::iterate (void)
383 std::ostringstream program_name;
384 program_name << s_prefixProgramName << m_subCaseNdx;
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];
393 deUint32 resultBufferStride = 0;
397 resultBufferStride = sizeof(deUint32);
399 case glu::TYPE_UINT_VEC2:
400 resultBufferStride = sizeof(tcu::UVec2);
402 case glu::TYPE_UINT_VEC3:
403 case glu::TYPE_UINT_VEC4:
404 resultBufferStride = sizeof(tcu::UVec4);
407 DE_ASSERT("Illegal data type");
410 const deUint32 resultBufferSize = numInvocations * resultBufferStride;
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);
417 const Allocation& alloc = uniformBuffer.getAllocation();
418 memcpy(alloc.getHostPtr(), &stride, sizeOfUniformBuffer);
419 flushMappedMemoryRange(m_vki, m_device, alloc.getMemory(), alloc.getOffset(), sizeOfUniformBuffer);
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));
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));
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));
439 const VkBufferMemoryBarrier bufferBarrier = makeBufferMemoryBarrier(
440 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSize);
442 const Unique<VkCommandPool> cmdPool(makeCommandPool(m_vki, m_device, m_queueFamilyIndex));
443 const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(m_vki, m_device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
445 // Start recording commands
446 beginCommandBuffer(m_vki, *cmdBuffer);
448 m_vki.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
450 // Create descriptor set
451 const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(m_vki, m_device, *descriptorPool, *descriptorSetLayout));
453 const VkDescriptorBufferInfo resultDescriptorInfo = makeDescriptorBufferInfo(*resultBuffer, 0ull, resultBufferSize);
454 const VkDescriptorBufferInfo uniformDescriptorInfo = makeDescriptorBufferInfo(*uniformBuffer, 0ull, sizeOfUniformBuffer);
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);
461 m_vki.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
463 // Dispatch indirect compute command
464 m_vki.cmdDispatch(*cmdBuffer, subCase.numWorkGroups()[0], subCase.numWorkGroups()[1], subCase.numWorkGroups()[2]);
466 m_vki.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
467 0, (const VkMemoryBarrier*)DE_NULL,
469 0, (const VkImageMemoryBarrier*)DE_NULL);
471 // End recording commands
472 endCommandBuffer(m_vki, *cmdBuffer);
474 // Wait for command buffer execution finish
475 submitCommandsAndWait(m_vki, m_device, m_queue, *cmdBuffer);
477 const Allocation& resultAlloc = resultBuffer.getAllocation();
478 invalidateMappedMemoryRange(m_vki, m_device, resultAlloc.getMemory(), resultAlloc.getOffset(), resultBufferSize);
480 const deUint8* ptr = reinterpret_cast<deUint8*>(resultAlloc.getHostPtr());
483 const int maxLogPrints = 10;
485 tcu::TestContext& testCtx = m_context.getTestContext();
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++)
494 const UVec3 refGroupID(groupX, groupY, groupZ);
495 const UVec3 refLocalID(localX, localY, localZ);
496 const UVec3 refGlobalID = refGroupID * subCase.localSize() + refLocalID;
498 const deUint32 refOffset = stride.x()*refGlobalID.z() + stride.y()*refGlobalID.y() + refGlobalID.x();
500 const UVec3 refValue = m_builtin_var_case->computeReference(subCase.numWorkGroups(), subCase.localSize(), refGroupID, refLocalID);
502 const deUint32* resPtr = (const deUint32*)(ptr + refOffset * resultBufferStride);
503 const UVec3 resValue = readResultVec(resPtr, numScalars);
505 if (!compareNumComponents(refValue, resValue, numScalars))
507 if (numFailed < maxLogPrints)
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;
521 testCtx.getLog() << TestLog::Message << (numInvocations - numFailed) << " / " << numInvocations << " values passed" << TestLog::EndMessage;
524 return tcu::TestStatus::fail("Comparison failed");
527 return (m_subCaseNdx < (int)m_subCases.size()) ? tcu::TestStatus::incomplete() :tcu::TestStatus::pass("Comparison succeeded");
530 class ComputeShaderBuiltinVarTests : public tcu::TestCaseGroup
533 ComputeShaderBuiltinVarTests (tcu::TestContext& context);
538 ComputeShaderBuiltinVarTests (const ComputeShaderBuiltinVarTests& other);
539 ComputeShaderBuiltinVarTests& operator= (const ComputeShaderBuiltinVarTests& other);
542 ComputeShaderBuiltinVarTests::ComputeShaderBuiltinVarTests (tcu::TestContext& context)
543 : TestCaseGroup(context, "builtin_var", "Shader builtin var tests")
547 void ComputeShaderBuiltinVarTests::init (void)
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()));
559 tcu::TestCaseGroup* createComputeShaderBuiltinVarTests (tcu::TestContext& testCtx)
561 return new ComputeShaderBuiltinVarTests(testCtx);