| /*------------------------------------------------------------------------ |
| * 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 |