diff options
Diffstat (limited to 'modules/gles31/functional/es31fComputeShaderBuiltinVarTests.cpp')
-rw-r--r-- | modules/gles31/functional/es31fComputeShaderBuiltinVarTests.cpp | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/modules/gles31/functional/es31fComputeShaderBuiltinVarTests.cpp b/modules/gles31/functional/es31fComputeShaderBuiltinVarTests.cpp new file mode 100644 index 000000000..d074306da --- /dev/null +++ b/modules/gles31/functional/es31fComputeShaderBuiltinVarTests.cpp @@ -0,0 +1,456 @@ +/*------------------------------------------------------------------------- + * drawElements Quality Program OpenGL ES 3.1 Module + * ------------------------------------------------- + * + * Copyright 2014 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 "es31fComputeShaderBuiltinVarTests.hpp" +#include "gluShaderProgram.hpp" +#include "gluShaderUtil.hpp" +#include "gluRenderContext.hpp" +#include "gluObjectWrapper.hpp" +#include "gluProgramInterfaceQuery.hpp" +#include "tcuVector.hpp" +#include "tcuTestLog.hpp" +#include "tcuVectorUtil.hpp" +#include "deSharedPtr.hpp" +#include "deStringUtil.hpp" +#include "glwFunctions.hpp" +#include "glwEnums.hpp" + +#include <map> + +namespace deqp +{ +namespace gles31 +{ +namespace Functional +{ + +using std::string; +using std::vector; +using std::map; +using tcu::TestLog; +using tcu::UVec3; +using tcu::IVec3; + +using namespace glu; + +template<typename T, int Size> +struct LexicalCompareVec +{ + inline bool operator() (const tcu::Vector<T, Size>& a, const tcu::Vector<T, Size>& b) const + { + for (int ndx = 0; ndx < Size; ndx++) + { + if (a[ndx] < b[ndx]) + return true; + else if (a[ndx] > b[ndx]) + return false; + } + return false; + } +}; + +typedef de::SharedPtr<glu::ShaderProgram> ShaderProgramSp; +typedef std::map<tcu::UVec3, ShaderProgramSp, LexicalCompareVec<deUint32, 3> > LocalSizeProgramMap; + +class ComputeBuiltinVarCase : public TestCase +{ +public: + ComputeBuiltinVarCase (Context& context, const char* name, const char* varName, DataType varType); + ~ComputeBuiltinVarCase (void); + + void init (void); + void deinit (void); + IterateResult iterate (void); + + virtual UVec3 computeReference (const UVec3& numWorkGroups, const UVec3& workGroupSize, const UVec3& workGroupID, const UVec3& localInvocationID) const = 0; + +protected: + struct SubCase + { + UVec3 localSize; + UVec3 numWorkGroups; + + SubCase (void) {} + SubCase (const UVec3& localSize_, const UVec3& numWorkGroups_) : localSize(localSize_), numWorkGroups(numWorkGroups_) {} + }; + + vector<SubCase> m_subCases; + +private: + ComputeBuiltinVarCase (const ComputeBuiltinVarCase& other); + ComputeBuiltinVarCase& operator= (const ComputeBuiltinVarCase& other); + + deUint32 getProgram (const UVec3& localSize); + + const string m_varName; + const DataType m_varType; + + LocalSizeProgramMap m_progMap; + int m_subCaseNdx; +}; + +ComputeBuiltinVarCase::ComputeBuiltinVarCase (Context& context, const char* name, const char* varName, DataType varType) + : TestCase (context, name, varName) + , m_varName (varName) + , m_varType (varType) + , m_subCaseNdx (0) +{ +} + +ComputeBuiltinVarCase::~ComputeBuiltinVarCase (void) +{ + ComputeBuiltinVarCase::deinit(); +} + +void ComputeBuiltinVarCase::init (void) +{ + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + m_subCaseNdx = 0; +} + +void ComputeBuiltinVarCase::deinit (void) +{ + m_progMap.clear(); +} + +static string genBuiltinVarSource (const string& varName, DataType varType, const UVec3& localSize) +{ + 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" + << "uniform highp uvec2 u_stride;\n" + << "layout(binding = 0) buffer Output\n" + << "{\n" + << " " << glu::getDataTypeName(varType) << " result[];\n" + << "} sb_out;\n" + << "\n" + << "void main (void)\n" + << "{\n" + << " highp uint offset = u_stride.x*gl_GlobalInvocationID.z + u_stride.y*gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;\n" + << " sb_out.result[offset] = " << varName << ";\n" + << "}\n"; + + return src.str(); +} + +deUint32 ComputeBuiltinVarCase::getProgram (const UVec3& localSize) +{ + LocalSizeProgramMap::const_iterator cachePos = m_progMap.find(localSize); + if (cachePos != m_progMap.end()) + return cachePos->second->getProgram(); + else + { + ShaderProgramSp program(new ShaderProgram(m_context.getRenderContext(), + ProgramSources() << ComputeSource(genBuiltinVarSource(m_varName, m_varType, localSize)))); + + // Log all compiled programs. + m_testCtx.getLog() << *program; + if (!program->isOk()) + throw tcu::TestError("Compile failed"); + + m_progMap[localSize] = program; + return program->getProgram(); + } +} + +static inline UVec3 readResultVec (const deUint32* ptr, int numComps) +{ + UVec3 res; + for (int ndx = 0; ndx < numComps; ndx++) + res[ndx] = ptr[ndx]; + return res; +} + +static inline bool compareComps (const UVec3& a, const UVec3& b, int numComps) +{ + DE_ASSERT(numComps == 1 || numComps == 3); + return numComps == 3 ? tcu::allEqual(a, b) : a.x() == b.x(); +} + +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(); +} + +ComputeBuiltinVarCase::IterateResult ComputeBuiltinVarCase::iterate (void) +{ + const tcu::ScopedLogSection section (m_testCtx.getLog(), string("Iteration") + de::toString(m_subCaseNdx), string("Iteration ") + de::toString(m_subCaseNdx)); + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + const SubCase& subCase = m_subCases[m_subCaseNdx]; + const deUint32 program = getProgram(subCase.localSize); + + const tcu::UVec3 globalSize = subCase.localSize*subCase.numWorkGroups; + const tcu::UVec2 stride (globalSize[0]*globalSize[1], globalSize[0]); + const deUint32 numInvocations = subCase.localSize[0]*subCase.localSize[1]*subCase.localSize[2]*subCase.numWorkGroups[0]*subCase.numWorkGroups[1]*subCase.numWorkGroups[2]; + + const deUint32 outVarIndex = gl.getProgramResourceIndex(program, GL_BUFFER_VARIABLE, "Output.result"); + const InterfaceVariableInfo outVarInfo = getProgramInterfaceVariableInfo(gl, program, GL_BUFFER_VARIABLE, outVarIndex); + const deUint32 bufferSize = numInvocations*outVarInfo.arrayStride; + Buffer outputBuffer (m_context.getRenderContext()); + + TCU_CHECK(outVarInfo.arraySize == 0); // Unsized variable. + + m_testCtx.getLog() << TestLog::Message << "Number of work groups = " << subCase.numWorkGroups << TestLog::EndMessage + << TestLog::Message << "Work group size = " << subCase.localSize << TestLog::EndMessage; + + gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); + gl.bufferData(GL_SHADER_STORAGE_BUFFER, (glw::GLsizeiptr)bufferSize, DE_NULL, GL_STREAM_READ); + gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer); + GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer setup failed"); + + gl.useProgram(program); + gl.uniform2uiv(gl.getUniformLocation(program, "u_stride"), 1, stride.getPtr()); + GLU_EXPECT_NO_ERROR(gl.getError(), "Program setup failed"); + + gl.dispatchCompute(subCase.numWorkGroups[0], subCase.numWorkGroups[1], subCase.numWorkGroups[2]); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() failed"); + + { + const void* ptr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, bufferSize, GL_MAP_READ_BIT); + int numFailed = 0; + const int numScalars = getDataTypeScalarSize(m_varType); + const int maxLogPrints = 10; + + GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed"); + TCU_CHECK(ptr); + + 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 = computeReference(subCase.numWorkGroups, subCase.localSize, refGroupID, refLocalID); + + const deUint32* resPtr = (const deUint32*)((const deUint8*)ptr + refOffset*outVarInfo.arrayStride); + const UVec3 resValue = readResultVec(resPtr, numScalars); + + if (!compareComps(refValue, resValue, numScalars)) + { + if (numFailed < maxLogPrints) + m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed at offset " << refOffset + << ": expected " << LogComps(refValue, numScalars) + << ", got " << LogComps(resValue, numScalars) + << TestLog::EndMessage; + else if (numFailed == maxLogPrints) + m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; + + numFailed += 1; + } + } + + m_testCtx.getLog() << TestLog::Message << (numInvocations-numFailed) << " / " << numInvocations << " values passed" << TestLog::EndMessage; + + if (numFailed > 0) + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Comparison failed"); + + gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); + } + + m_subCaseNdx += 1; + return (m_subCaseNdx < (int)m_subCases.size() && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS) ? CONTINUE : STOP; +} + +// Test cases + +class NumWorkGroupsCase : public ComputeBuiltinVarCase +{ +public: + NumWorkGroupsCase (Context& context) + : ComputeBuiltinVarCase(context, "num_work_groups", "gl_NumWorkGroups", 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 (Context& context) + : ComputeBuiltinVarCase(context, "work_group_size", "gl_WorkGroupSize", 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(11,3,8), UVec3(1,1,1))); + m_subCases.push_back(SubCase(UVec3(11,3,8), 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 (Context& context) + : ComputeBuiltinVarCase(context, "work_group_id", "gl_WorkGroupID", 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 (Context& context) + : ComputeBuiltinVarCase(context, "local_invocation_id", "gl_LocalInvocationID", 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(11,3,8), UVec3(1,1,1))); + m_subCases.push_back(SubCase(UVec3(11,3,8), 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 (Context& context) + : ComputeBuiltinVarCase(context, "global_invocation_id", "gl_GlobalInvocationID", 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(11,3,8), UVec3(1,1,1))); + m_subCases.push_back(SubCase(UVec3(11,3,8), 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 (Context& context) + : ComputeBuiltinVarCase(context, "local_invocation_index", "gl_LocalInvocationIndex", 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(11,3,8), UVec3(1,1,1))); + m_subCases.push_back(SubCase(UVec3(11,3,8), 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); + } +}; + +ComputeShaderBuiltinVarTests::ComputeShaderBuiltinVarTests (Context& context) + : TestCaseGroup(context, "compute", "Compute Shader Builtin Variables") +{ +} + +ComputeShaderBuiltinVarTests::~ComputeShaderBuiltinVarTests (void) +{ +} + +void ComputeShaderBuiltinVarTests::init (void) +{ + addChild(new NumWorkGroupsCase (m_context)); + addChild(new WorkGroupSizeCase (m_context)); + addChild(new WorkGroupIDCase (m_context)); + addChild(new LocalInvocationIDCase (m_context)); + addChild(new GlobalInvocationIDCase (m_context)); + addChild(new LocalInvocationIndexCase (m_context)); +} + +} // Functional +} // gles31 +} // deqp |