blob: b5b949b25977b4991519f887129bda7495693139 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2016 The Khronos Group Inc.
* Copyright (c) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Compute Shader Built-in variable tests.
*//*--------------------------------------------------------------------*/
#include "vktComputeShaderBuiltinVarTests.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktComputeTestsUtil.hpp"
#include "vkDefs.hpp"
#include "vkPlatform.hpp"
#include "vkRef.hpp"
#include "vkPrograms.hpp"
#include "vkStrUtil.hpp"
#include "vkRefUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkDeviceUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuFormatUtil.hpp"
#include "tcuVectorUtil.hpp"
#include "gluShaderUtil.hpp"
#include "deUniquePtr.hpp"
#include "deSharedPtr.hpp"
#include <map>
#include <string>
#include <vector>
namespace vkt
{
namespace compute
{
namespace
{
using namespace vk;
using std::string;
using std::vector;
using std::map;
using tcu::TestLog;
using tcu::UVec3;
using tcu::IVec3;
class ComputeBuiltinVarInstance;
class ComputeBuiltinVarCase;
static const string s_prefixProgramName ="compute_";
static inline bool compareNumComponents (const UVec3& a, const UVec3& b,const int numComps)
{
DE_ASSERT(numComps == 1 || numComps == 3);
return numComps == 3 ? tcu::allEqual(a, b) : a.x() == b.x();
}
static inline UVec3 readResultVec (const deUint32* ptr, const int numComps)
{
UVec3 res;
for (int ndx = 0; ndx < numComps; ndx++)
res[ndx] = ptr[ndx];
return res;
}
struct LogComps
{
const UVec3& v;
int numComps;
LogComps (const UVec3 &v_, int numComps_) : v(v_), numComps(numComps_) {}
};
static inline std::ostream& operator<< (std::ostream& str, const LogComps& c)
{
DE_ASSERT(c.numComps == 1 || c.numComps == 3);
return c.numComps == 3 ? str << c.v : str << c.v.x();
}
class SubCase
{
public:
// Use getters instead of public const members, because SubCase must be assignable
// in order to be stored in a vector.
const UVec3& localSize (void) const { return m_localSize; }
const UVec3& numWorkGroups (void) const { return m_numWorkGroups; }
SubCase (void) {}
SubCase (const UVec3& localSize_, const UVec3& numWorkGroups_)
: m_localSize (localSize_)
, m_numWorkGroups (numWorkGroups_) {}
private:
UVec3 m_localSize;
UVec3 m_numWorkGroups;
};
class ComputeBuiltinVarInstance : public vkt::TestInstance
{
public:
ComputeBuiltinVarInstance (Context& context,
const vector<SubCase>& subCases,
const glu::DataType varType,
const ComputeBuiltinVarCase* builtinVarCase);
virtual tcu::TestStatus iterate (void);
private:
const VkDevice m_device;
const DeviceInterface& m_vki;
const VkQueue m_queue;
const deUint32 m_queueFamilyIndex;
vector<SubCase> m_subCases;
const ComputeBuiltinVarCase* m_builtin_var_case;
int m_subCaseNdx;
const glu::DataType m_varType;
};
class ComputeBuiltinVarCase : public vkt::TestCase
{
public:
ComputeBuiltinVarCase (tcu::TestContext& context, const char* name, const char* varName, glu::DataType varType);
~ComputeBuiltinVarCase (void);
TestInstance* createInstance (Context& context) const
{
return new ComputeBuiltinVarInstance(context, m_subCases, m_varType, this);
};
virtual void initPrograms (SourceCollections& programCollection) const;
virtual UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const = 0;
protected:
string genBuiltinVarSource (const string& varName, glu::DataType varType, const UVec3& localSize) const;
vector<SubCase> m_subCases;
private:
deUint32 getProgram (const tcu::UVec3& localSize);
const string m_varName;
const glu::DataType m_varType;
int m_subCaseNdx;
ComputeBuiltinVarCase (const ComputeBuiltinVarCase& other);
ComputeBuiltinVarCase& operator= (const ComputeBuiltinVarCase& other);
};
ComputeBuiltinVarCase::ComputeBuiltinVarCase (tcu::TestContext& context, const char* name, const char* varName, glu::DataType varType)
: TestCase (context, name, varName)
, m_varName (varName)
, m_varType (varType)
, m_subCaseNdx (0)
{
}
ComputeBuiltinVarCase::~ComputeBuiltinVarCase (void)
{
ComputeBuiltinVarCase::deinit();
}
void ComputeBuiltinVarCase::initPrograms (SourceCollections& programCollection) const
{
for (std::size_t i = 0; i < m_subCases.size(); i++)
{
const SubCase& subCase = m_subCases[i];
std::ostringstream name;
name << s_prefixProgramName << i;
programCollection.glslSources.add(name.str()) << glu::ComputeSource(genBuiltinVarSource(m_varName, m_varType, subCase.localSize()).c_str());
}
}
string ComputeBuiltinVarCase::genBuiltinVarSource (const string& varName, glu::DataType varType, const UVec3& localSize) const
{
std::ostringstream src;
src << "#version 310 es\n"
<< "layout (local_size_x = " << localSize.x() << ", local_size_y = " << localSize.y() << ", local_size_z = " << localSize.z() << ") in;\n"
<< "layout(set = 0, binding = 0) uniform Stride\n"
<< "{\n"
<< " uvec2 u_stride;\n"
<< "}stride;\n"
<< "layout(set = 0, binding = 1, std430) buffer Output\n"
<< "{\n"
<< " " << glu::getDataTypeName(varType) << " result[];\n"
<< "} sb_out;\n"
<< "\n"
<< "void main (void)\n"
<< "{\n"
<< " highp uint offset = stride.u_stride.x*gl_GlobalInvocationID.z + stride.u_stride.y*gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;\n"
<< " sb_out.result[offset] = " << varName << ";\n"
<< "}\n";
return src.str();
}
class NumWorkGroupsCase : public ComputeBuiltinVarCase
{
public:
NumWorkGroupsCase (tcu::TestContext& context)
: ComputeBuiltinVarCase(context, "num_work_groups", "gl_NumWorkGroups", glu::TYPE_UINT_VEC3)
{
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(52, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 39, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 78)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(4, 7, 11)));
m_subCases.push_back(SubCase(UVec3(2, 3, 4), UVec3(4, 7, 11)));
}
UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
{
DE_UNREF(numWorkGroups);
DE_UNREF(workGroupSize);
DE_UNREF(workGroupID);
DE_UNREF(localInvocationID);
return numWorkGroups;
}
};
class WorkGroupSizeCase : public ComputeBuiltinVarCase
{
public:
WorkGroupSizeCase (tcu::TestContext& context)
: ComputeBuiltinVarCase(context, "work_group_size", "gl_WorkGroupSize", glu::TYPE_UINT_VEC3)
{
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(2, 7, 3)));
m_subCases.push_back(SubCase(UVec3(2, 1, 1), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(2, 1, 1), UVec3(1, 3, 5)));
m_subCases.push_back(SubCase(UVec3(1, 3, 1), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 7), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 7), UVec3(3, 3, 1)));
m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(3, 1, 2)));
}
UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
{
DE_UNREF(numWorkGroups);
DE_UNREF(workGroupID);
DE_UNREF(localInvocationID);
return workGroupSize;
}
};
//-----------------------------------------------------------------------
class WorkGroupIDCase : public ComputeBuiltinVarCase
{
public:
WorkGroupIDCase (tcu::TestContext& context)
: ComputeBuiltinVarCase(context, "work_group_id", "gl_WorkGroupID", glu::TYPE_UINT_VEC3)
{
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(52, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 39, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 78)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(4, 7, 11)));
m_subCases.push_back(SubCase(UVec3(2, 3, 4), UVec3(4, 7, 11)));
}
UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
{
DE_UNREF(numWorkGroups);
DE_UNREF(workGroupSize);
DE_UNREF(localInvocationID);
return workGroupID;
}
};
class LocalInvocationIDCase : public ComputeBuiltinVarCase
{
public:
LocalInvocationIDCase (tcu::TestContext& context)
: ComputeBuiltinVarCase(context, "local_invocation_id", "gl_LocalInvocationID", glu::TYPE_UINT_VEC3)
{
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(2, 7, 3)));
m_subCases.push_back(SubCase(UVec3(2, 1, 1), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(2, 1, 1), UVec3(1, 3, 5)));
m_subCases.push_back(SubCase(UVec3(1, 3, 1), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 7), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 7), UVec3(3, 3, 1)));
m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(3, 1, 2)));
}
UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
{
DE_UNREF(numWorkGroups);
DE_UNREF(workGroupSize);
DE_UNREF(workGroupID);
return localInvocationID;
}
};
class GlobalInvocationIDCase : public ComputeBuiltinVarCase
{
public:
GlobalInvocationIDCase (tcu::TestContext& context)
: ComputeBuiltinVarCase(context, "global_invocation_id", "gl_GlobalInvocationID", glu::TYPE_UINT_VEC3)
{
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(52, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 39, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 78)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(4, 7, 11)));
m_subCases.push_back(SubCase(UVec3(2, 3, 4), UVec3(4, 7, 11)));
m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(3, 1, 2)));
}
UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
{
DE_UNREF(numWorkGroups);
return workGroupID * workGroupSize + localInvocationID;
}
};
class LocalInvocationIndexCase : public ComputeBuiltinVarCase
{
public:
LocalInvocationIndexCase (tcu::TestContext& context)
: ComputeBuiltinVarCase(context, "local_invocation_index", "gl_LocalInvocationIndex", glu::TYPE_UINT)
{
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(1, 39, 1)));
m_subCases.push_back(SubCase(UVec3(1, 1, 1), UVec3(4, 7, 11)));
m_subCases.push_back(SubCase(UVec3(2, 3, 4), UVec3(4, 7, 11)));
m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(1, 1, 1)));
m_subCases.push_back(SubCase(UVec3(10, 3, 4), UVec3(3, 1, 2)));
}
UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const
{
DE_UNREF(workGroupID);
DE_UNREF(numWorkGroups);
return UVec3(localInvocationID.z()*workGroupSize.x()*workGroupSize.y() + localInvocationID.y()*workGroupSize.x() + localInvocationID.x(), 0, 0);
}
};
ComputeBuiltinVarInstance::ComputeBuiltinVarInstance (Context& context,
const vector<SubCase>& subCases,
const glu::DataType varType,
const ComputeBuiltinVarCase* builtinVarCase)
: vkt::TestInstance (context)
, m_device (m_context.getDevice())
, m_vki (m_context.getDeviceInterface())
, m_queue (context.getUniversalQueue())
, m_queueFamilyIndex (context.getUniversalQueueFamilyIndex())
, m_subCases (subCases)
, m_builtin_var_case (builtinVarCase)
, m_subCaseNdx (0)
, m_varType (varType)
{
}
tcu::TestStatus ComputeBuiltinVarInstance::iterate (void)
{
std::ostringstream program_name;
program_name << s_prefixProgramName << m_subCaseNdx;
const SubCase& subCase = m_subCases[m_subCaseNdx];
const tcu::UVec3 globalSize = subCase.localSize()*subCase.numWorkGroups();
const tcu::UVec2 stride (globalSize[0] * globalSize[1], globalSize[0]);
const deUint32 sizeOfUniformBuffer = sizeof(stride);
const int numScalars = glu::getDataTypeScalarSize(m_varType);
const deUint32 numInvocations = subCase.localSize()[0] * subCase.localSize()[1] * subCase.localSize()[2] * subCase.numWorkGroups()[0] * subCase.numWorkGroups()[1] * subCase.numWorkGroups()[2];
deUint32 resultBufferStride = 0;
switch (m_varType)
{
case glu::TYPE_UINT:
resultBufferStride = sizeof(deUint32);
break;
case glu::TYPE_UINT_VEC2:
resultBufferStride = sizeof(tcu::UVec2);
break;
case glu::TYPE_UINT_VEC3:
case glu::TYPE_UINT_VEC4:
resultBufferStride = sizeof(tcu::UVec4);
break;
default:
DE_ASSERT("Illegal data type");
}
const deUint32 resultBufferSize = numInvocations * resultBufferStride;
// Create result buffer
Buffer uniformBuffer(m_vki, m_device, m_context.getDefaultAllocator(), makeBufferCreateInfo(sizeOfUniformBuffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT), MemoryRequirement::HostVisible);
Buffer resultBuffer(m_vki, m_device, m_context.getDefaultAllocator(), makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
{
const Allocation& alloc = uniformBuffer.getAllocation();
memcpy(alloc.getHostPtr(), &stride, sizeOfUniformBuffer);
flushMappedMemoryRange(m_vki, m_device, alloc.getMemory(), alloc.getOffset(), sizeOfUniformBuffer);
}
// Create descriptorSetLayout
const Unique<VkDescriptorSetLayout> descriptorSetLayout(
DescriptorSetLayoutBuilder()
.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
.build(m_vki, m_device));
const Unique<VkShaderModule> shaderModule(createShaderModule(m_vki, m_device, m_context.getBinaryCollection().get(program_name.str()), 0u));
const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(m_vki, m_device, *descriptorSetLayout));
const Unique<VkPipeline> pipeline(makeComputePipeline(m_vki, m_device, *pipelineLayout, *shaderModule));
const Unique<VkDescriptorPool> descriptorPool(
DescriptorPoolBuilder()
.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
.build(m_vki, m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
const VkBufferMemoryBarrier bufferBarrier = makeBufferMemoryBarrier(
VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSize);
const Unique<VkCommandPool> cmdPool(makeCommandPool(m_vki, m_device, m_queueFamilyIndex));
const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(m_vki, m_device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
// Start recording commands
beginCommandBuffer(m_vki, *cmdBuffer);
m_vki.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
// Create descriptor set
const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(m_vki, m_device, *descriptorPool, *descriptorSetLayout));
const VkDescriptorBufferInfo resultDescriptorInfo = makeDescriptorBufferInfo(*resultBuffer, 0ull, resultBufferSize);
const VkDescriptorBufferInfo uniformDescriptorInfo = makeDescriptorBufferInfo(*uniformBuffer, 0ull, sizeOfUniformBuffer);
DescriptorSetUpdateBuilder()
.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uniformDescriptorInfo)
.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultDescriptorInfo)
.update(m_vki, m_device);
m_vki.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
// Dispatch indirect compute command
m_vki.cmdDispatch(*cmdBuffer, subCase.numWorkGroups()[0], subCase.numWorkGroups()[1], subCase.numWorkGroups()[2]);
m_vki.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
0, (const VkMemoryBarrier*)DE_NULL,
1, &bufferBarrier,
0, (const VkImageMemoryBarrier*)DE_NULL);
// End recording commands
endCommandBuffer(m_vki, *cmdBuffer);
// Wait for command buffer execution finish
submitCommandsAndWait(m_vki, m_device, m_queue, *cmdBuffer);
const Allocation& resultAlloc = resultBuffer.getAllocation();
invalidateMappedMemoryRange(m_vki, m_device, resultAlloc.getMemory(), resultAlloc.getOffset(), resultBufferSize);
const deUint8* ptr = reinterpret_cast<deUint8*>(resultAlloc.getHostPtr());
int numFailed = 0;
const int maxLogPrints = 10;
tcu::TestContext& testCtx = m_context.getTestContext();
for (deUint32 groupZ = 0; groupZ < subCase.numWorkGroups().z(); groupZ++)
for (deUint32 groupY = 0; groupY < subCase.numWorkGroups().y(); groupY++)
for (deUint32 groupX = 0; groupX < subCase.numWorkGroups().x(); groupX++)
for (deUint32 localZ = 0; localZ < subCase.localSize().z(); localZ++)
for (deUint32 localY = 0; localY < subCase.localSize().y(); localY++)
for (deUint32 localX = 0; localX < subCase.localSize().x(); localX++)
{
const UVec3 refGroupID(groupX, groupY, groupZ);
const UVec3 refLocalID(localX, localY, localZ);
const UVec3 refGlobalID = refGroupID * subCase.localSize() + refLocalID;
const deUint32 refOffset = stride.x()*refGlobalID.z() + stride.y()*refGlobalID.y() + refGlobalID.x();
const UVec3 refValue = m_builtin_var_case->computeReference(subCase.numWorkGroups(), subCase.localSize(), refGroupID, refLocalID);
const deUint32* resPtr = (const deUint32*)(ptr + refOffset * resultBufferStride);
const UVec3 resValue = readResultVec(resPtr, numScalars);
if (!compareNumComponents(refValue, resValue, numScalars))
{
if (numFailed < maxLogPrints)
testCtx.getLog()
<< TestLog::Message
<< "ERROR: comparison failed at offset " << refOffset
<< ": expected " << LogComps(refValue, numScalars)
<< ", got " << LogComps(resValue, numScalars)
<< TestLog::EndMessage;
else if (numFailed == maxLogPrints)
testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
numFailed += 1;
}
}
testCtx.getLog() << TestLog::Message << (numInvocations - numFailed) << " / " << numInvocations << " values passed" << TestLog::EndMessage;
if (numFailed > 0)
return tcu::TestStatus::fail("Comparison failed");
m_subCaseNdx += 1;
return (m_subCaseNdx < (int)m_subCases.size()) ? tcu::TestStatus::incomplete() :tcu::TestStatus::pass("Comparison succeeded");
}
class ComputeShaderBuiltinVarTests : public tcu::TestCaseGroup
{
public:
ComputeShaderBuiltinVarTests (tcu::TestContext& context);
void init (void);
private:
ComputeShaderBuiltinVarTests (const ComputeShaderBuiltinVarTests& other);
ComputeShaderBuiltinVarTests& operator= (const ComputeShaderBuiltinVarTests& other);
};
ComputeShaderBuiltinVarTests::ComputeShaderBuiltinVarTests (tcu::TestContext& context)
: TestCaseGroup(context, "builtin_var", "Shader builtin var tests")
{
}
void ComputeShaderBuiltinVarTests::init (void)
{
addChild(new NumWorkGroupsCase(this->getTestContext()));
addChild(new WorkGroupSizeCase(this->getTestContext()));
addChild(new WorkGroupIDCase(this->getTestContext()));
addChild(new LocalInvocationIDCase(this->getTestContext()));
addChild(new GlobalInvocationIDCase(this->getTestContext()));
addChild(new LocalInvocationIndexCase(this->getTestContext()));
}
} // anonymous
tcu::TestCaseGroup* createComputeShaderBuiltinVarTests (tcu::TestContext& testCtx)
{
return new ComputeShaderBuiltinVarTests(testCtx);
}
} // compute
} // vkt