| /*------------------------------------------------------------------------- |
| * 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 Basic Compute Shader Tests. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es31fBasicComputeShaderTests.hpp" |
| #include "gluShaderProgram.hpp" |
| #include "gluObjectWrapper.hpp" |
| #include "gluRenderContext.hpp" |
| #include "gluProgramInterfaceQuery.hpp" |
| #include "gluContextInfo.hpp" |
| #include "glwFunctions.hpp" |
| #include "glwEnums.hpp" |
| #include "tcuTestLog.hpp" |
| #include "deRandom.hpp" |
| #include "deStringUtil.hpp" |
| #include "deMemory.h" |
| |
| namespace deqp |
| { |
| namespace gles31 |
| { |
| namespace Functional |
| { |
| |
| using std::string; |
| using std::vector; |
| using tcu::TestLog; |
| using namespace glu; |
| |
| //! Utility for mapping buffers. |
| class BufferMemMap |
| { |
| public: |
| BufferMemMap(const glw::Functions &gl, uint32_t target, int offset, int size, uint32_t access) |
| : m_gl(gl) |
| , m_target(target) |
| , m_ptr(DE_NULL) |
| { |
| m_ptr = gl.mapBufferRange(target, offset, size, access); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()"); |
| TCU_CHECK(m_ptr); |
| } |
| |
| ~BufferMemMap(void) |
| { |
| m_gl.unmapBuffer(m_target); |
| } |
| |
| void *getPtr(void) const |
| { |
| return m_ptr; |
| } |
| void *operator*(void) const |
| { |
| return m_ptr; |
| } |
| |
| private: |
| BufferMemMap(const BufferMemMap &other); |
| BufferMemMap &operator=(const BufferMemMap &other); |
| |
| const glw::Functions &m_gl; |
| const uint32_t m_target; |
| void *m_ptr; |
| }; |
| |
| namespace |
| { |
| |
| class EmptyComputeShaderCase : public TestCase |
| { |
| public: |
| EmptyComputeShaderCase(Context &context) : TestCase(context, "empty", "Empty shader") |
| { |
| } |
| |
| IterateResult iterate(void) |
| { |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = 1) in;\n" |
| "void main (void) {}\n"; |
| |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() |
| << ShaderSource(SHADERTYPE_COMPUTE, src.str())); |
| |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| gl.useProgram(program.getProgram()); |
| gl.dispatchCompute(1, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| }; |
| |
| class UBOToSSBOInvertCase : public TestCase |
| { |
| public: |
| UBOToSSBOInvertCase(Context &context, const char *name, const char *description, int numValues, |
| const tcu::IVec3 &localSize, const tcu::IVec3 &workSize) |
| : TestCase(context, name, description) |
| , m_numValues(numValues) |
| , m_localSize(localSize) |
| , m_workSize(workSize) |
| { |
| DE_ASSERT(m_numValues % (m_workSize[0] * m_workSize[1] * m_workSize[2] * m_localSize[0] * m_localSize[1] * |
| m_localSize[2]) == |
| 0); |
| } |
| |
| IterateResult iterate(void) |
| { |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = " << m_localSize[0] << ", local_size_y = " << m_localSize[1] |
| << ", local_size_z = " << m_localSize[2] << ") in;\n" |
| << "uniform Input {\n" |
| << " uint values[" << m_numValues << "];\n" |
| << "} ub_in;\n" |
| << "layout(binding = 1) buffer Output {\n" |
| << " uint values[" << m_numValues << "];\n" |
| << "} sb_out;\n" |
| << "void main (void) {\n" |
| << " uvec3 size = gl_NumWorkGroups * gl_WorkGroupSize;\n" |
| << " uint numValuesPerInv = uint(ub_in.values.length()) / (size.x*size.y*size.z);\n" |
| << " uint groupNdx = size.x*size.y*gl_GlobalInvocationID.z + size.x*gl_GlobalInvocationID.y + " |
| "gl_GlobalInvocationID.x;\n" |
| << " uint offset = numValuesPerInv*groupNdx;\n" |
| << "\n" |
| << " for (uint ndx = 0u; ndx < numValuesPerInv; ndx++)\n" |
| << " sb_out.values[offset + ndx] = ~ub_in.values[offset + ndx];\n" |
| << "}\n"; |
| |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() |
| << ShaderSource(SHADERTYPE_COMPUTE, src.str())); |
| const Buffer inputBuffer(m_context.getRenderContext()); |
| const Buffer outputBuffer(m_context.getRenderContext()); |
| std::vector<uint32_t> inputValues(m_numValues); |
| |
| // Compute input values. |
| { |
| de::Random rnd(0x111223f); |
| for (int ndx = 0; ndx < (int)inputValues.size(); ndx++) |
| inputValues[ndx] = rnd.getUint32(); |
| } |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_workSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Input buffer setup |
| { |
| const uint32_t blockIndex = gl.getProgramResourceIndex(program.getProgram(), GL_UNIFORM_BLOCK, "Input"); |
| const InterfaceBlockInfo blockInfo = |
| getProgramInterfaceBlockInfo(gl, program.getProgram(), GL_UNIFORM_BLOCK, blockIndex); |
| const uint32_t valueIndex = gl.getProgramResourceIndex(program.getProgram(), GL_UNIFORM, "Input.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_UNIFORM, valueIndex); |
| |
| gl.bindBuffer(GL_UNIFORM_BUFFER, *inputBuffer); |
| gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)blockInfo.dataSize, DE_NULL, GL_STATIC_DRAW); |
| |
| { |
| const BufferMemMap bufMap(gl, GL_UNIFORM_BUFFER, 0, (int)blockInfo.dataSize, GL_MAP_WRITE_BIT); |
| |
| for (uint32_t ndx = 0; ndx < de::min(valueInfo.arraySize, (uint32_t)inputValues.size()); ndx++) |
| *(uint32_t *)((uint8_t *)bufMap.getPtr() + valueInfo.offset + ndx * valueInfo.arrayStride) = |
| inputValues[ndx]; |
| } |
| |
| gl.uniformBlockBinding(program.getProgram(), blockIndex, 0); |
| gl.bindBufferBase(GL_UNIFORM_BUFFER, 0, *inputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Input buffer setup failed"); |
| } |
| |
| // Output buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ); |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, *outputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], m_workSize[2]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Output.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); |
| |
| TCU_CHECK(valueInfo.arraySize == (uint32_t)inputValues.size()); |
| for (uint32_t ndx = 0; ndx < valueInfo.arraySize; ndx++) |
| { |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + valueInfo.offset + |
| valueInfo.arrayStride * ndx)); |
| const uint32_t ref = ~inputValues[ndx]; |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for Output.values[") + de::toString(ndx) + "]"); |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const int m_numValues; |
| const tcu::IVec3 m_localSize; |
| const tcu::IVec3 m_workSize; |
| }; |
| |
| class CopyInvertSSBOCase : public TestCase |
| { |
| public: |
| CopyInvertSSBOCase(Context &context, const char *name, const char *description, int numValues, |
| const tcu::IVec3 &localSize, const tcu::IVec3 &workSize) |
| : TestCase(context, name, description) |
| , m_numValues(numValues) |
| , m_localSize(localSize) |
| , m_workSize(workSize) |
| { |
| DE_ASSERT(m_numValues % (m_workSize[0] * m_workSize[1] * m_workSize[2] * m_localSize[0] * m_localSize[1] * |
| m_localSize[2]) == |
| 0); |
| } |
| |
| IterateResult iterate(void) |
| { |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = " << m_localSize[0] << ", local_size_y = " << m_localSize[1] |
| << ", local_size_z = " << m_localSize[2] << ") in;\n" |
| << "layout(binding = 0) buffer Input {\n" |
| << " uint values[" << m_numValues << "];\n" |
| << "} sb_in;\n" |
| << "layout (binding = 1) buffer Output {\n" |
| << " uint values[" << m_numValues << "];\n" |
| << "} sb_out;\n" |
| << "void main (void) {\n" |
| << " uvec3 size = gl_NumWorkGroups * gl_WorkGroupSize;\n" |
| << " uint numValuesPerInv = uint(sb_in.values.length()) / (size.x*size.y*size.z);\n" |
| << " uint groupNdx = size.x*size.y*gl_GlobalInvocationID.z + size.x*gl_GlobalInvocationID.y + " |
| "gl_GlobalInvocationID.x;\n" |
| << " uint offset = numValuesPerInv*groupNdx;\n" |
| << "\n" |
| << " for (uint ndx = 0u; ndx < numValuesPerInv; ndx++)\n" |
| << " sb_out.values[offset + ndx] = ~sb_in.values[offset + ndx];\n" |
| << "}\n"; |
| |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() |
| << ShaderSource(SHADERTYPE_COMPUTE, src.str())); |
| const Buffer inputBuffer(m_context.getRenderContext()); |
| const Buffer outputBuffer(m_context.getRenderContext()); |
| std::vector<uint32_t> inputValues(m_numValues); |
| |
| // Compute input values. |
| { |
| de::Random rnd(0x124fef); |
| for (int ndx = 0; ndx < (int)inputValues.size(); ndx++) |
| inputValues[ndx] = rnd.getUint32(); |
| } |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_workSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Input buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Input"); |
| const InterfaceBlockInfo blockInfo = |
| getProgramInterfaceBlockInfo(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Input.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *inputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, (glw::GLsizeiptr)blockInfo.dataSize, DE_NULL, GL_STATIC_DRAW); |
| |
| TCU_CHECK(valueInfo.arraySize == (uint32_t)inputValues.size()); |
| |
| { |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, (int)blockInfo.dataSize, GL_MAP_WRITE_BIT); |
| |
| for (uint32_t ndx = 0; ndx < (uint32_t)inputValues.size(); ndx++) |
| *(uint32_t *)((uint8_t *)bufMap.getPtr() + valueInfo.offset + ndx * valueInfo.arrayStride) = |
| inputValues[ndx]; |
| } |
| |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, blockInfo.bufferBinding, *inputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Input buffer setup failed"); |
| } |
| |
| // Output buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const InterfaceBlockInfo blockInfo = |
| getProgramInterfaceBlockInfo(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockInfo.dataSize, DE_NULL, GL_STREAM_READ); |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, blockInfo.bufferBinding, *outputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], m_workSize[2]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Output.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); |
| |
| TCU_CHECK(valueInfo.arraySize == (uint32_t)inputValues.size()); |
| for (uint32_t ndx = 0; ndx < valueInfo.arraySize; ndx++) |
| { |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + valueInfo.offset + |
| valueInfo.arrayStride * ndx)); |
| const uint32_t ref = ~inputValues[ndx]; |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for Output.values[") + de::toString(ndx) + "]"); |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const int m_numValues; |
| const tcu::IVec3 m_localSize; |
| const tcu::IVec3 m_workSize; |
| }; |
| |
| class InvertSSBOInPlaceCase : public TestCase |
| { |
| public: |
| InvertSSBOInPlaceCase(Context &context, const char *name, const char *description, int numValues, bool isSized, |
| const tcu::IVec3 &localSize, const tcu::IVec3 &workSize) |
| : TestCase(context, name, description) |
| , m_numValues(numValues) |
| , m_isSized(isSized) |
| , m_localSize(localSize) |
| , m_workSize(workSize) |
| { |
| DE_ASSERT(m_numValues % (m_workSize[0] * m_workSize[1] * m_workSize[2] * m_localSize[0] * m_localSize[1] * |
| m_localSize[2]) == |
| 0); |
| } |
| |
| IterateResult iterate(void) |
| { |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = " << m_localSize[0] << ", local_size_y = " << m_localSize[1] |
| << ", local_size_z = " << m_localSize[2] << ") in;\n" |
| << "layout(binding = 0) buffer InOut {\n" |
| << " uint values[" << (m_isSized ? de::toString(m_numValues) : string("")) << "];\n" |
| << "} sb_inout;\n" |
| << "void main (void) {\n" |
| << " uvec3 size = gl_NumWorkGroups * gl_WorkGroupSize;\n" |
| << " uint numValuesPerInv = uint(sb_inout.values.length()) / (size.x*size.y*size.z);\n" |
| << " uint groupNdx = size.x*size.y*gl_GlobalInvocationID.z + size.x*gl_GlobalInvocationID.y + " |
| "gl_GlobalInvocationID.x;\n" |
| << " uint offset = numValuesPerInv*groupNdx;\n" |
| << "\n" |
| << " for (uint ndx = 0u; ndx < numValuesPerInv; ndx++)\n" |
| << " sb_inout.values[offset + ndx] = ~sb_inout.values[offset + ndx];\n" |
| << "}\n"; |
| |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() |
| << ShaderSource(SHADERTYPE_COMPUTE, src.str())); |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| const Buffer outputBuffer(m_context.getRenderContext()); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "InOut.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const uint32_t blockSize = valueInfo.arrayStride * (uint32_t)m_numValues; |
| std::vector<uint32_t> inputValues(m_numValues); |
| |
| // Compute input values. |
| { |
| de::Random rnd(0x82ce7f); |
| for (int ndx = 0; ndx < (int)inputValues.size(); ndx++) |
| inputValues[ndx] = rnd.getUint32(); |
| } |
| |
| TCU_CHECK(valueInfo.arraySize == (uint32_t)(m_isSized ? m_numValues : 0)); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_workSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Output buffer setup |
| { |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_DRAW); |
| |
| { |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, (int)blockSize, GL_MAP_WRITE_BIT); |
| |
| for (uint32_t ndx = 0; ndx < (uint32_t)inputValues.size(); ndx++) |
| *(uint32_t *)((uint8_t *)bufMap.getPtr() + valueInfo.offset + ndx * valueInfo.arrayStride) = |
| inputValues[ndx]; |
| } |
| |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], m_workSize[2]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare |
| { |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); |
| |
| for (uint32_t ndx = 0; ndx < (uint32_t)inputValues.size(); ndx++) |
| { |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + valueInfo.offset + |
| valueInfo.arrayStride * ndx)); |
| const uint32_t ref = ~inputValues[ndx]; |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for InOut.values[") + de::toString(ndx) + "]"); |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const int m_numValues; |
| const bool m_isSized; |
| const tcu::IVec3 m_localSize; |
| const tcu::IVec3 m_workSize; |
| }; |
| |
| class WriteToMultipleSSBOCase : public TestCase |
| { |
| public: |
| WriteToMultipleSSBOCase(Context &context, const char *name, const char *description, int numValues, bool isSized, |
| const tcu::IVec3 &localSize, const tcu::IVec3 &workSize) |
| : TestCase(context, name, description) |
| , m_numValues(numValues) |
| , m_isSized(isSized) |
| , m_localSize(localSize) |
| , m_workSize(workSize) |
| { |
| DE_ASSERT(m_numValues % (m_workSize[0] * m_workSize[1] * m_workSize[2] * m_localSize[0] * m_localSize[1] * |
| m_localSize[2]) == |
| 0); |
| } |
| |
| IterateResult iterate(void) |
| { |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = " << m_localSize[0] << ", local_size_y = " << m_localSize[1] |
| << ", local_size_z = " << m_localSize[2] << ") in;\n" |
| << "layout(binding = 0) buffer Out0 {\n" |
| << " uint values[" << (m_isSized ? de::toString(m_numValues) : string("")) << "];\n" |
| << "} sb_out0;\n" |
| << "layout(binding = 1) buffer Out1 {\n" |
| << " uint values[" << (m_isSized ? de::toString(m_numValues) : string("")) << "];\n" |
| << "} sb_out1;\n" |
| << "void main (void) {\n" |
| << " uvec3 size = gl_NumWorkGroups * gl_WorkGroupSize;\n" |
| << " uint groupNdx = size.x*size.y*gl_GlobalInvocationID.z + size.x*gl_GlobalInvocationID.y + " |
| "gl_GlobalInvocationID.x;\n" |
| << "\n" |
| << " {\n" |
| << " uint numValuesPerInv = uint(sb_out0.values.length()) / (size.x*size.y*size.z);\n" |
| << " uint offset = numValuesPerInv*groupNdx;\n" |
| << "\n" |
| << " for (uint ndx = 0u; ndx < numValuesPerInv; ndx++)\n" |
| << " sb_out0.values[offset + ndx] = offset + ndx;\n" |
| << " }\n" |
| << " {\n" |
| << " uint numValuesPerInv = uint(sb_out1.values.length()) / (size.x*size.y*size.z);\n" |
| << " uint offset = numValuesPerInv*groupNdx;\n" |
| << "\n" |
| << " for (uint ndx = 0u; ndx < numValuesPerInv; ndx++)\n" |
| << " sb_out1.values[offset + ndx] = uint(sb_out1.values.length()) - offset - ndx;\n" |
| << " }\n" |
| << "}\n"; |
| |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() |
| << ShaderSource(SHADERTYPE_COMPUTE, src.str())); |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| const Buffer outputBuffer0(m_context.getRenderContext()); |
| const uint32_t value0Index = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Out0.values"); |
| const InterfaceVariableInfo value0Info = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, value0Index); |
| const uint32_t block0Size = value0Info.arrayStride * (uint32_t)m_numValues; |
| |
| const Buffer outputBuffer1(m_context.getRenderContext()); |
| const uint32_t value1Index = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Out1.values"); |
| const InterfaceVariableInfo value1Info = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, value1Index); |
| const uint32_t block1Size = value1Info.arrayStride * (uint32_t)m_numValues; |
| |
| TCU_CHECK(value0Info.arraySize == (uint32_t)(m_isSized ? m_numValues : 0)); |
| TCU_CHECK(value1Info.arraySize == (uint32_t)(m_isSized ? m_numValues : 0)); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_workSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Output buffer setup |
| { |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer0); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, block0Size, DE_NULL, GL_STREAM_DRAW); |
| |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer setup failed"); |
| } |
| { |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer1); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, block1Size, DE_NULL, GL_STREAM_DRAW); |
| |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, *outputBuffer1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], m_workSize[2]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer0); |
| { |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, block0Size, GL_MAP_READ_BIT); |
| |
| for (uint32_t ndx = 0; ndx < (uint32_t)m_numValues; ndx++) |
| { |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + value0Info.offset + |
| value0Info.arrayStride * ndx)); |
| const uint32_t ref = ndx; |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for Out0.values[") + de::toString(ndx) + |
| "] res=" + de::toString(res) + " ref=" + de::toString(ref)); |
| } |
| } |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer1); |
| { |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, block1Size, GL_MAP_READ_BIT); |
| |
| for (uint32_t ndx = 0; ndx < (uint32_t)m_numValues; ndx++) |
| { |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + value1Info.offset + |
| value1Info.arrayStride * ndx)); |
| const uint32_t ref = m_numValues - ndx; |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for Out1.values[") + de::toString(ndx) + |
| "] res=" + de::toString(res) + " ref=" + de::toString(ref)); |
| } |
| } |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const int m_numValues; |
| const bool m_isSized; |
| const tcu::IVec3 m_localSize; |
| const tcu::IVec3 m_workSize; |
| }; |
| |
| class SSBOLocalBarrierCase : public TestCase |
| { |
| public: |
| SSBOLocalBarrierCase(Context &context, const char *name, const char *description, const tcu::IVec3 &localSize, |
| const tcu::IVec3 &workSize) |
| : TestCase(context, name, description) |
| , m_localSize(localSize) |
| , m_workSize(workSize) |
| { |
| } |
| |
| IterateResult iterate(void) |
| { |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const Buffer outputBuffer(m_context.getRenderContext()); |
| const int workGroupSize = m_localSize[0] * m_localSize[1] * m_localSize[2]; |
| const int workGroupCount = m_workSize[0] * m_workSize[1] * m_workSize[2]; |
| const int numValues = workGroupSize * workGroupCount; |
| |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = " << m_localSize[0] << ", local_size_y = " << m_localSize[1] |
| << ", local_size_z = " << m_localSize[2] << ") in;\n" |
| << "layout(binding = 0) buffer Output {\n" |
| << " coherent uint values[" << numValues << "];\n" |
| << "} sb_out;\n\n" |
| << "shared uint offsets[" << workGroupSize << "];\n\n" |
| << "void main (void) {\n" |
| << " uint localSize = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z;\n" |
| << " uint globalNdx = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + " |
| "gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n" |
| << " uint globalOffs = localSize*globalNdx;\n" |
| << " uint localOffs = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_LocalInvocationID.z + " |
| "gl_WorkGroupSize.x*gl_LocalInvocationID.y + gl_LocalInvocationID.x;\n" |
| << "\n" |
| << " sb_out.values[globalOffs + localOffs] = globalOffs;\n" |
| << " memoryBarrierBuffer();\n" |
| << " barrier();\n" |
| << " sb_out.values[globalOffs + ((localOffs+1u)%localSize)] += localOffs;\n" |
| << " memoryBarrierBuffer();\n" |
| << " barrier();\n" |
| << " sb_out.values[globalOffs + ((localOffs+2u)%localSize)] += localOffs;\n" |
| << "}\n"; |
| |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() << ComputeSource(src.str())); |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_workSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Output buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ); |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], m_workSize[2]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Output.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); |
| |
| for (int groupNdx = 0; groupNdx < workGroupCount; groupNdx++) |
| { |
| for (int localOffs = 0; localOffs < workGroupSize; localOffs++) |
| { |
| const int globalOffs = groupNdx * workGroupSize; |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + valueInfo.offset + |
| valueInfo.arrayStride * (globalOffs + localOffs))); |
| const int offs0 = localOffs - 1 < 0 ? ((localOffs + workGroupSize - 1) % workGroupSize) : |
| ((localOffs - 1) % workGroupSize); |
| const int offs1 = localOffs - 2 < 0 ? ((localOffs + workGroupSize - 2) % workGroupSize) : |
| ((localOffs - 2) % workGroupSize); |
| const uint32_t ref = (uint32_t)(globalOffs + offs0 + offs1); |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for Output.values[") + |
| de::toString(globalOffs + localOffs) + "]"); |
| } |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const tcu::IVec3 m_localSize; |
| const tcu::IVec3 m_workSize; |
| }; |
| |
| class SSBOBarrierCase : public TestCase |
| { |
| public: |
| SSBOBarrierCase(Context &context, const char *name, const char *description, const tcu::IVec3 &workSize) |
| : TestCase(context, name, description) |
| , m_workSize(workSize) |
| { |
| } |
| |
| IterateResult iterate(void) |
| { |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| const char *const glslVersionDeclaration = getGLSLVersionDeclaration(glslVersion); |
| |
| std::ostringstream src0; |
| src0 << glslVersionDeclaration << "\n" |
| << "layout (local_size_x = 1) in;\n" |
| "uniform uint u_baseVal;\n" |
| "layout(binding = 1) buffer Output {\n" |
| " uint values[];\n" |
| "};\n" |
| "void main (void) {\n" |
| " uint offset = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + " |
| "gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n" |
| " values[offset] = u_baseVal+offset;\n" |
| "}\n"; |
| |
| std::ostringstream src1; |
| src1 << glslVersionDeclaration << "\n" |
| << "layout (local_size_x = 1) in;\n" |
| "uniform uint u_baseVal;\n" |
| "layout(binding = 1) buffer Input {\n" |
| " uint values[];\n" |
| "};\n" |
| "layout(binding = 0) buffer Output {\n" |
| " coherent uint sum;\n" |
| "};\n" |
| "void main (void) {\n" |
| " uint offset = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + " |
| "gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n" |
| " uint value = values[offset];\n" |
| " atomicAdd(sum, value);\n" |
| "}\n"; |
| |
| const ShaderProgram program0(m_context.getRenderContext(), ProgramSources() << ComputeSource(src0.str())); |
| const ShaderProgram program1(m_context.getRenderContext(), ProgramSources() << ComputeSource(src1.str())); |
| |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const Buffer tempBuffer(m_context.getRenderContext()); |
| const Buffer outputBuffer(m_context.getRenderContext()); |
| const uint32_t baseValue = 127; |
| |
| m_testCtx.getLog() << program0 << program1; |
| if (!program0.isOk() || !program1.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_workSize << TestLog::EndMessage; |
| |
| // Temp buffer setup |
| { |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program0.getProgram(), GL_BUFFER_VARIABLE, "values[0]"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program0.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const uint32_t bufferSize = valueInfo.arrayStride * m_workSize[0] * m_workSize[1] * m_workSize[2]; |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *tempBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, (glw::GLsizeiptr)bufferSize, DE_NULL, GL_STATIC_DRAW); |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, *tempBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Temp buffer setup failed"); |
| } |
| |
| // Output buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program1.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program1.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ); |
| |
| { |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_WRITE_BIT); |
| deMemset(bufMap.getPtr(), 0, blockSize); |
| } |
| |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.useProgram(program0.getProgram()); |
| gl.uniform1ui(gl.getUniformLocation(program0.getProgram(), "u_baseVal"), baseValue); |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], m_workSize[2]); |
| gl.memoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); |
| gl.useProgram(program1.getProgram()); |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], m_workSize[2]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to dispatch commands"); |
| |
| // Read back and compare |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program1.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program1.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| const uint32_t valueIndex = gl.getProgramResourceIndex(program1.getProgram(), GL_BUFFER_VARIABLE, "sum"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program1.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); |
| |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + valueInfo.offset)); |
| uint32_t ref = 0; |
| |
| for (int ndx = 0; ndx < m_workSize[0] * m_workSize[1] * m_workSize[2]; ndx++) |
| ref += baseValue + (uint32_t)ndx; |
| |
| if (res != ref) |
| { |
| m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed, expected " << ref << ", got " |
| << res << TestLog::EndMessage; |
| throw tcu::TestError("Comparison failed"); |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const tcu::IVec3 m_workSize; |
| }; |
| |
| class BasicSharedVarCase : public TestCase |
| { |
| public: |
| BasicSharedVarCase(Context &context, const char *name, const char *description, const tcu::IVec3 &localSize, |
| const tcu::IVec3 &workSize) |
| : TestCase(context, name, description) |
| , m_localSize(localSize) |
| , m_workSize(workSize) |
| { |
| } |
| |
| IterateResult iterate(void) |
| { |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const Buffer outputBuffer(m_context.getRenderContext()); |
| const int workGroupSize = m_localSize[0] * m_localSize[1] * m_localSize[2]; |
| const int workGroupCount = m_workSize[0] * m_workSize[1] * m_workSize[2]; |
| const int numValues = workGroupSize * workGroupCount; |
| |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = " << m_localSize[0] << ", local_size_y = " << m_localSize[1] |
| << ", local_size_z = " << m_localSize[2] << ") in;\n" |
| << "layout(binding = 0) buffer Output {\n" |
| << " uint values[" << numValues << "];\n" |
| << "} sb_out;\n\n" |
| << "shared uint offsets[" << workGroupSize << "];\n\n" |
| << "void main (void) {\n" |
| << " uint localSize = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z;\n" |
| << " uint globalNdx = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + " |
| "gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n" |
| << " uint globalOffs = localSize*globalNdx;\n" |
| << " uint localOffs = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_LocalInvocationID.z + " |
| "gl_WorkGroupSize.x*gl_LocalInvocationID.y + gl_LocalInvocationID.x;\n" |
| << "\n" |
| << " offsets[localSize-localOffs-1u] = globalOffs + localOffs*localOffs;\n" |
| << " barrier();\n" |
| << " sb_out.values[globalOffs + localOffs] = offsets[localOffs];\n" |
| << "}\n"; |
| |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() |
| << ShaderSource(SHADERTYPE_COMPUTE, src.str())); |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_workSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Output buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ); |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], m_workSize[2]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Output.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); |
| |
| for (int groupNdx = 0; groupNdx < workGroupCount; groupNdx++) |
| { |
| for (int localOffs = 0; localOffs < workGroupSize; localOffs++) |
| { |
| const int globalOffs = groupNdx * workGroupSize; |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + valueInfo.offset + |
| valueInfo.arrayStride * (globalOffs + localOffs))); |
| const uint32_t ref = |
| (uint32_t)(globalOffs + (workGroupSize - localOffs - 1) * (workGroupSize - localOffs - 1)); |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for Output.values[") + |
| de::toString(globalOffs + localOffs) + "]"); |
| } |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const tcu::IVec3 m_localSize; |
| const tcu::IVec3 m_workSize; |
| }; |
| |
| class SharedVarAtomicOpCase : public TestCase |
| { |
| public: |
| SharedVarAtomicOpCase(Context &context, const char *name, const char *description, const tcu::IVec3 &localSize, |
| const tcu::IVec3 &workSize) |
| : TestCase(context, name, description) |
| , m_localSize(localSize) |
| , m_workSize(workSize) |
| { |
| } |
| |
| IterateResult iterate(void) |
| { |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const Buffer outputBuffer(m_context.getRenderContext()); |
| const int workGroupSize = m_localSize[0] * m_localSize[1] * m_localSize[2]; |
| const int workGroupCount = m_workSize[0] * m_workSize[1] * m_workSize[2]; |
| const int numValues = workGroupSize * workGroupCount; |
| |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = " << m_localSize[0] << ", local_size_y = " << m_localSize[1] |
| << ", local_size_z = " << m_localSize[2] << ") in;\n" |
| << "layout(binding = 0) buffer Output {\n" |
| << " uint values[" << numValues << "];\n" |
| << "} sb_out;\n\n" |
| << "shared uint count;\n\n" |
| << "void main (void) {\n" |
| << " uint localSize = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z;\n" |
| << " uint globalNdx = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + " |
| "gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n" |
| << " uint globalOffs = localSize*globalNdx;\n" |
| << "\n" |
| << " count = 0u;\n" |
| << " barrier();\n" |
| << " uint oldVal = atomicAdd(count, 1u);\n" |
| << " sb_out.values[globalOffs+oldVal] = oldVal+1u;\n" |
| << "}\n"; |
| |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() |
| << ShaderSource(SHADERTYPE_COMPUTE, src.str())); |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_workSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Output buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ); |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], m_workSize[2]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Output.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); |
| |
| for (int groupNdx = 0; groupNdx < workGroupCount; groupNdx++) |
| { |
| for (int localOffs = 0; localOffs < workGroupSize; localOffs++) |
| { |
| const int globalOffs = groupNdx * workGroupSize; |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + valueInfo.offset + |
| valueInfo.arrayStride * (globalOffs + localOffs))); |
| const uint32_t ref = (uint32_t)(localOffs + 1); |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for Output.values[") + |
| de::toString(globalOffs + localOffs) + "]"); |
| } |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const tcu::IVec3 m_localSize; |
| const tcu::IVec3 m_workSize; |
| }; |
| |
| class CopyImageToSSBOCase : public TestCase |
| { |
| public: |
| CopyImageToSSBOCase(Context &context, const char *name, const char *description, const tcu::IVec2 &localSize, |
| const tcu::IVec2 &imageSize) |
| : TestCase(context, name, description) |
| , m_localSize(localSize) |
| , m_imageSize(imageSize) |
| { |
| DE_ASSERT(m_imageSize[0] % m_localSize[0] == 0); |
| DE_ASSERT(m_imageSize[1] % m_localSize[1] == 0); |
| } |
| |
| IterateResult iterate(void) |
| { |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = " << m_localSize[0] << ", local_size_y = " << m_localSize[1] << ") in;\n" |
| << "layout(r32ui, binding = 1) readonly uniform highp uimage2D u_srcImg;\n" |
| << "layout(binding = 0) buffer Output {\n" |
| << " uint values[" << (m_imageSize[0] * m_imageSize[1]) << "];\n" |
| << "} sb_out;\n\n" |
| << "void main (void) {\n" |
| << " uint stride = gl_NumWorkGroups.x*gl_WorkGroupSize.x;\n" |
| << " uint value = imageLoad(u_srcImg, ivec2(gl_GlobalInvocationID.xy)).x;\n" |
| << " sb_out.values[gl_GlobalInvocationID.y*stride + gl_GlobalInvocationID.x] = value;\n" |
| << "}\n"; |
| |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const Buffer outputBuffer(m_context.getRenderContext()); |
| const Texture inputTexture(m_context.getRenderContext()); |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() |
| << ShaderSource(SHADERTYPE_COMPUTE, src.str())); |
| const tcu::IVec2 workSize = m_imageSize / m_localSize; |
| de::Random rnd(0xab2c7); |
| vector<uint32_t> inputValues(m_imageSize[0] * m_imageSize[1]); |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << workSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Input values |
| for (vector<uint32_t>::iterator i = inputValues.begin(); i != inputValues.end(); ++i) |
| *i = rnd.getUint32(); |
| |
| // Input image setup |
| gl.bindTexture(GL_TEXTURE_2D, *inputTexture); |
| gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, m_imageSize[0], m_imageSize[1]); |
| gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_imageSize[0], m_imageSize[1], GL_RED_INTEGER, GL_UNSIGNED_INT, |
| &inputValues[0]); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed"); |
| |
| // Bind to unit 1 |
| gl.bindImageTexture(1, *inputTexture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Image setup failed"); |
| |
| // Output buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ); |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(workSize[0], workSize[1], 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Output.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); |
| |
| TCU_CHECK(valueInfo.arraySize == (uint32_t)inputValues.size()); |
| |
| for (uint32_t ndx = 0; ndx < valueInfo.arraySize; ndx++) |
| { |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + valueInfo.offset + |
| valueInfo.arrayStride * ndx)); |
| const uint32_t ref = inputValues[ndx]; |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for Output.values[") + de::toString(ndx) + "]"); |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const tcu::IVec2 m_localSize; |
| const tcu::IVec2 m_imageSize; |
| }; |
| |
| class CopySSBOToImageCase : public TestCase |
| { |
| public: |
| CopySSBOToImageCase(Context &context, const char *name, const char *description, const tcu::IVec2 &localSize, |
| const tcu::IVec2 &imageSize) |
| : TestCase(context, name, description) |
| , m_localSize(localSize) |
| , m_imageSize(imageSize) |
| { |
| DE_ASSERT(m_imageSize[0] % m_localSize[0] == 0); |
| DE_ASSERT(m_imageSize[1] % m_localSize[1] == 0); |
| } |
| |
| IterateResult iterate(void) |
| { |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = " << m_localSize[0] << ", local_size_y = " << m_localSize[1] << ") in;\n" |
| << "layout(r32ui, binding = 1) writeonly uniform highp uimage2D u_dstImg;\n" |
| << "buffer Input {\n" |
| << " uint values[" << (m_imageSize[0] * m_imageSize[1]) << "];\n" |
| << "} sb_in;\n\n" |
| << "void main (void) {\n" |
| << " uint stride = gl_NumWorkGroups.x*gl_WorkGroupSize.x;\n" |
| << " uint value = sb_in.values[gl_GlobalInvocationID.y*stride + gl_GlobalInvocationID.x];\n" |
| << " imageStore(u_dstImg, ivec2(gl_GlobalInvocationID.xy), uvec4(value, 0, 0, 0));\n" |
| << "}\n"; |
| |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const Buffer inputBuffer(m_context.getRenderContext()); |
| const Texture outputTexture(m_context.getRenderContext()); |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() |
| << ShaderSource(SHADERTYPE_COMPUTE, src.str())); |
| const tcu::IVec2 workSize = m_imageSize / m_localSize; |
| de::Random rnd(0x77238ac2); |
| vector<uint32_t> inputValues(m_imageSize[0] * m_imageSize[1]); |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << workSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Input values |
| for (vector<uint32_t>::iterator i = inputValues.begin(); i != inputValues.end(); ++i) |
| *i = rnd.getUint32(); |
| |
| // Input buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Input"); |
| const InterfaceBlockInfo blockInfo = |
| getProgramInterfaceBlockInfo(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Input.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *inputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, (glw::GLsizeiptr)blockInfo.dataSize, DE_NULL, GL_STATIC_DRAW); |
| |
| TCU_CHECK(valueInfo.arraySize == (uint32_t)inputValues.size()); |
| |
| { |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, (int)blockInfo.dataSize, GL_MAP_WRITE_BIT); |
| |
| for (uint32_t ndx = 0; ndx < (uint32_t)inputValues.size(); ndx++) |
| *(uint32_t *)((uint8_t *)bufMap.getPtr() + valueInfo.offset + ndx * valueInfo.arrayStride) = |
| inputValues[ndx]; |
| } |
| |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, blockInfo.bufferBinding, *inputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Input buffer setup failed"); |
| } |
| |
| // Output image setup |
| gl.bindTexture(GL_TEXTURE_2D, *outputTexture); |
| gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, m_imageSize[0], m_imageSize[1]); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed"); |
| |
| // Bind to unit 1 |
| gl.bindImageTexture(1, *outputTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Image setup failed"); |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(workSize[0], workSize[1], 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare |
| { |
| Framebuffer fbo(m_context.getRenderContext()); |
| vector<uint32_t> pixels(inputValues.size() * 4); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo); |
| gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *outputTexture, 0); |
| TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); |
| |
| // \note In ES3 we have to use GL_RGBA_INTEGER |
| gl.readBuffer(GL_COLOR_ATTACHMENT0); |
| gl.readPixels(0, 0, m_imageSize[0], m_imageSize[1], GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed"); |
| |
| for (uint32_t ndx = 0; ndx < (uint32_t)inputValues.size(); ndx++) |
| { |
| const uint32_t res = pixels[ndx * 4]; |
| const uint32_t ref = inputValues[ndx]; |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for pixel ") + de::toString(ndx)); |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const tcu::IVec2 m_localSize; |
| const tcu::IVec2 m_imageSize; |
| }; |
| |
| class ImageAtomicOpCase : public TestCase |
| { |
| public: |
| ImageAtomicOpCase(Context &context, const char *name, const char *description, int localSize, |
| const tcu::IVec2 &imageSize) |
| : TestCase(context, name, description) |
| , m_localSize(localSize) |
| , m_imageSize(imageSize) |
| { |
| } |
| |
| void init(void) |
| { |
| auto contextType = m_context.getRenderContext().getType(); |
| if (!glu::contextSupports(contextType, glu::ApiType::es(3, 2)) && |
| !glu::contextSupports(contextType, glu::ApiType::core(4, 5)) && |
| !m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic")) |
| TCU_THROW(NotSupportedError, "Test requires OES_shader_image_atomic extension"); |
| } |
| |
| IterateResult iterate(void) |
| { |
| glu::ContextType contextType = m_context.getRenderContext().getType(); |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(contextType); |
| const bool supportsES32orGL45 = glu::contextSupports(contextType, glu::ApiType::es(3, 2)) || |
| glu::contextSupports(contextType, glu::ApiType::core(4, 5)); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << (supportsES32orGL45 ? "\n" : "#extension GL_OES_shader_image_atomic : require\n") |
| << "layout (local_size_x = " << m_localSize << ") in;\n" |
| << "layout(r32ui, binding = 1) uniform highp uimage2D u_dstImg;\n" |
| << "buffer Input {\n" |
| << " uint values[" << (m_imageSize[0] * m_imageSize[1] * m_localSize) << "];\n" |
| << "} sb_in;\n\n" |
| << "void main (void) {\n" |
| << " uint stride = gl_NumWorkGroups.x*gl_WorkGroupSize.x;\n" |
| << " uint value = sb_in.values[gl_GlobalInvocationID.y*stride + gl_GlobalInvocationID.x];\n" |
| << "\n" |
| << " if (gl_LocalInvocationIndex == 0u)\n" |
| << " imageStore(u_dstImg, ivec2(gl_WorkGroupID.xy), uvec4(0));\n" |
| << " barrier();\n" |
| << " imageAtomicAdd(u_dstImg, ivec2(gl_WorkGroupID.xy), value);\n" |
| << "}\n"; |
| |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const Buffer inputBuffer(m_context.getRenderContext()); |
| const Texture outputTexture(m_context.getRenderContext()); |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() |
| << ShaderSource(SHADERTYPE_COMPUTE, src.str())); |
| de::Random rnd(0x77238ac2); |
| vector<uint32_t> inputValues(m_imageSize[0] * m_imageSize[1] * m_localSize); |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_imageSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Input values |
| for (vector<uint32_t>::iterator i = inputValues.begin(); i != inputValues.end(); ++i) |
| *i = rnd.getUint32(); |
| |
| // Input buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Input"); |
| const InterfaceBlockInfo blockInfo = |
| getProgramInterfaceBlockInfo(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Input.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *inputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, (glw::GLsizeiptr)blockInfo.dataSize, DE_NULL, GL_STATIC_DRAW); |
| |
| TCU_CHECK(valueInfo.arraySize == (uint32_t)inputValues.size()); |
| |
| { |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, (int)blockInfo.dataSize, GL_MAP_WRITE_BIT); |
| |
| for (uint32_t ndx = 0; ndx < (uint32_t)inputValues.size(); ndx++) |
| *(uint32_t *)((uint8_t *)bufMap.getPtr() + valueInfo.offset + ndx * valueInfo.arrayStride) = |
| inputValues[ndx]; |
| } |
| |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, blockInfo.bufferBinding, *inputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Input buffer setup failed"); |
| } |
| |
| // Output image setup |
| gl.bindTexture(GL_TEXTURE_2D, *outputTexture); |
| gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, m_imageSize[0], m_imageSize[1]); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed"); |
| |
| // Bind to unit 1 |
| gl.bindImageTexture(1, *outputTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Image setup failed"); |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(m_imageSize[0], m_imageSize[1], 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare |
| { |
| Framebuffer fbo(m_context.getRenderContext()); |
| vector<uint32_t> pixels(m_imageSize[0] * m_imageSize[1] * 4); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo); |
| gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *outputTexture, 0); |
| TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); |
| |
| // \note In ES3 we have to use GL_RGBA_INTEGER |
| gl.readBuffer(GL_COLOR_ATTACHMENT0); |
| gl.readPixels(0, 0, m_imageSize[0], m_imageSize[1], GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed"); |
| |
| for (int pixelNdx = 0; pixelNdx < (int)inputValues.size() / m_localSize; pixelNdx++) |
| { |
| const uint32_t res = pixels[pixelNdx * 4]; |
| uint32_t ref = 0; |
| |
| for (int offs = 0; offs < m_localSize; offs++) |
| ref += inputValues[pixelNdx * m_localSize + offs]; |
| |
| if (res != ref) |
| throw tcu::TestError(string("Comparison failed for pixel ") + de::toString(pixelNdx)); |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const int m_localSize; |
| const tcu::IVec2 m_imageSize; |
| }; |
| |
| class ImageBarrierCase : public TestCase |
| { |
| public: |
| ImageBarrierCase(Context &context, const char *name, const char *description, const tcu::IVec2 &workSize) |
| : TestCase(context, name, description) |
| , m_workSize(workSize) |
| { |
| } |
| |
| IterateResult iterate(void) |
| { |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| const char *const glslVersionDeclaration = getGLSLVersionDeclaration(glslVersion); |
| |
| std::ostringstream src0; |
| src0 << glslVersionDeclaration << "\n" |
| << "layout (local_size_x = 1) in;\n" |
| "uniform uint u_baseVal;\n" |
| "layout(r32ui, binding = 2) writeonly uniform highp uimage2D u_img;\n" |
| "void main (void) {\n" |
| " uint offset = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + " |
| "gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n" |
| " imageStore(u_img, ivec2(gl_WorkGroupID.xy), uvec4(offset+u_baseVal, 0, 0, 0));\n" |
| "}\n"; |
| |
| std::ostringstream src1; |
| src1 << glslVersionDeclaration << "\n" |
| << "layout (local_size_x = 1) in;\n" |
| "layout(r32ui, binding = 2) readonly uniform highp uimage2D u_img;\n" |
| "layout(binding = 0) buffer Output {\n" |
| " coherent uint sum;\n" |
| "};\n" |
| "void main (void) {\n" |
| " uint value = imageLoad(u_img, ivec2(gl_WorkGroupID.xy)).x;\n" |
| " atomicAdd(sum, value);\n" |
| "}\n"; |
| |
| const ShaderProgram program0(m_context.getRenderContext(), ProgramSources() << ComputeSource(src0.str())); |
| const ShaderProgram program1(m_context.getRenderContext(), ProgramSources() << ComputeSource(src1.str())); |
| |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const Texture tempTexture(m_context.getRenderContext()); |
| const Buffer outputBuffer(m_context.getRenderContext()); |
| const uint32_t baseValue = 127; |
| |
| m_testCtx.getLog() << program0 << program1; |
| if (!program0.isOk() || !program1.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_workSize << TestLog::EndMessage; |
| |
| // Temp texture setup |
| gl.bindTexture(GL_TEXTURE_2D, *tempTexture); |
| gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, m_workSize[0], m_workSize[1]); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed"); |
| |
| // Bind to unit 2 |
| gl.bindImageTexture(2, *tempTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Image setup failed"); |
| |
| // Output buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program1.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program1.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ); |
| |
| { |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_WRITE_BIT); |
| deMemset(bufMap.getPtr(), 0, blockSize); |
| } |
| |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.useProgram(program0.getProgram()); |
| gl.uniform1ui(gl.getUniformLocation(program0.getProgram(), "u_baseVal"), baseValue); |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], 1); |
| gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); |
| gl.useProgram(program1.getProgram()); |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to dispatch commands"); |
| |
| // Read back and compare |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program1.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program1.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| const uint32_t valueIndex = gl.getProgramResourceIndex(program1.getProgram(), GL_BUFFER_VARIABLE, "sum"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program1.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); |
| |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + valueInfo.offset)); |
| uint32_t ref = 0; |
| |
| for (int ndx = 0; ndx < m_workSize[0] * m_workSize[1]; ndx++) |
| ref += baseValue + (uint32_t)ndx; |
| |
| if (res != ref) |
| { |
| m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed, expected " << ref << ", got " |
| << res << TestLog::EndMessage; |
| throw tcu::TestError("Comparison failed"); |
| } |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const tcu::IVec2 m_workSize; |
| }; |
| |
| class AtomicCounterCase : public TestCase |
| { |
| public: |
| AtomicCounterCase(Context &context, const char *name, const char *description, const tcu::IVec3 &localSize, |
| const tcu::IVec3 &workSize) |
| : TestCase(context, name, description) |
| , m_localSize(localSize) |
| , m_workSize(workSize) |
| { |
| } |
| |
| IterateResult iterate(void) |
| { |
| const glw::Functions &gl = m_context.getRenderContext().getFunctions(); |
| const Buffer outputBuffer(m_context.getRenderContext()); |
| const Buffer counterBuffer(m_context.getRenderContext()); |
| const int workGroupSize = m_localSize[0] * m_localSize[1] * m_localSize[2]; |
| const int workGroupCount = m_workSize[0] * m_workSize[1] * m_workSize[2]; |
| const int numValues = workGroupSize * workGroupCount; |
| |
| const GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| std::ostringstream src; |
| |
| src << getGLSLVersionDeclaration(glslVersion) << "\n" |
| << "layout (local_size_x = " << m_localSize[0] << ", local_size_y = " << m_localSize[1] |
| << ", local_size_z = " << m_localSize[2] << ") in;\n" |
| << "layout(binding = 0) buffer Output {\n" |
| << " uint values[" << numValues << "];\n" |
| << "} sb_out;\n\n" |
| << "layout(binding = 0, offset = 0) uniform atomic_uint u_count;\n\n" |
| << "void main (void) {\n" |
| << " uint localSize = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z;\n" |
| << " uint globalNdx = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z + " |
| "gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n" |
| << " uint globalOffs = localSize*globalNdx;\n" |
| << " uint localOffs = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_LocalInvocationID.z + " |
| "gl_WorkGroupSize.x*gl_LocalInvocationID.y + gl_LocalInvocationID.x;\n" |
| << "\n" |
| << " uint oldVal = atomicCounterIncrement(u_count);\n" |
| << " sb_out.values[globalOffs+localOffs] = oldVal;\n" |
| << "}\n"; |
| |
| const ShaderProgram program(m_context.getRenderContext(), ProgramSources() << ComputeSource(src.str())); |
| |
| m_testCtx.getLog() << program; |
| if (!program.isOk()) |
| TCU_FAIL("Compile failed"); |
| |
| m_testCtx.getLog() << TestLog::Message << "Work groups: " << m_workSize << TestLog::EndMessage; |
| |
| gl.useProgram(program.getProgram()); |
| |
| // Atomic counter buffer setup |
| { |
| const uint32_t uniformIndex = gl.getProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_count"); |
| const uint32_t bufferIndex = getProgramResourceUint(gl, program.getProgram(), GL_UNIFORM, uniformIndex, |
| GL_ATOMIC_COUNTER_BUFFER_INDEX); |
| const uint32_t bufferSize = getProgramResourceUint(gl, program.getProgram(), GL_ATOMIC_COUNTER_BUFFER, |
| bufferIndex, GL_BUFFER_DATA_SIZE); |
| |
| gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, *counterBuffer); |
| gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, bufferSize, DE_NULL, GL_STREAM_READ); |
| |
| { |
| const BufferMemMap memMap(gl, GL_ATOMIC_COUNTER_BUFFER, 0, bufferSize, GL_MAP_WRITE_BIT); |
| deMemset(memMap.getPtr(), 0, (int)bufferSize); |
| } |
| |
| gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, *counterBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Atomic counter buffer setup failed"); |
| } |
| |
| // Output buffer setup |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| |
| gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *outputBuffer); |
| gl.bufferData(GL_SHADER_STORAGE_BUFFER, blockSize, DE_NULL, GL_STREAM_READ); |
| gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, *outputBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Output buffer setup failed"); |
| } |
| |
| // Dispatch compute workload |
| gl.dispatchCompute(m_workSize[0], m_workSize[1], m_workSize[2]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()"); |
| |
| // Read back and compare atomic counter |
| { |
| const uint32_t uniformIndex = gl.getProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_count"); |
| const uint32_t uniformOffset = |
| getProgramResourceUint(gl, program.getProgram(), GL_UNIFORM, uniformIndex, GL_OFFSET); |
| const uint32_t bufferIndex = getProgramResourceUint(gl, program.getProgram(), GL_UNIFORM, uniformIndex, |
| GL_ATOMIC_COUNTER_BUFFER_INDEX); |
| const uint32_t bufferSize = getProgramResourceUint(gl, program.getProgram(), GL_ATOMIC_COUNTER_BUFFER, |
| bufferIndex, GL_BUFFER_DATA_SIZE); |
| const BufferMemMap bufMap(gl, GL_ATOMIC_COUNTER_BUFFER, 0, bufferSize, GL_MAP_READ_BIT); |
| |
| const uint32_t resVal = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + uniformOffset)); |
| |
| if (resVal != (uint32_t)numValues) |
| throw tcu::TestError("Invalid atomic counter value"); |
| } |
| |
| // Read back and compare SSBO |
| { |
| const uint32_t blockIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_SHADER_STORAGE_BLOCK, "Output"); |
| const int blockSize = getProgramResourceInt(gl, program.getProgram(), GL_SHADER_STORAGE_BLOCK, blockIndex, |
| GL_BUFFER_DATA_SIZE); |
| const uint32_t valueIndex = |
| gl.getProgramResourceIndex(program.getProgram(), GL_BUFFER_VARIABLE, "Output.values"); |
| const InterfaceVariableInfo valueInfo = |
| getProgramInterfaceVariableInfo(gl, program.getProgram(), GL_BUFFER_VARIABLE, valueIndex); |
| const BufferMemMap bufMap(gl, GL_SHADER_STORAGE_BUFFER, 0, blockSize, GL_MAP_READ_BIT); |
| uint32_t valSum = 0; |
| uint32_t refSum = 0; |
| |
| for (int valNdx = 0; valNdx < numValues; valNdx++) |
| { |
| const uint32_t res = *((const uint32_t *)((const uint8_t *)bufMap.getPtr() + valueInfo.offset + |
| valueInfo.arrayStride * valNdx)); |
| |
| valSum += res; |
| refSum += (uint32_t)valNdx; |
| |
| if (!de::inBounds<uint32_t>(res, 0, (uint32_t)numValues)) |
| throw tcu::TestError(string("Comparison failed for Output.values[") + de::toString(valNdx) + "]"); |
| } |
| |
| if (valSum != refSum) |
| throw tcu::TestError("Total sum of values in Output.values doesn't match"); |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| private: |
| const tcu::IVec3 m_localSize; |
| const tcu::IVec3 m_workSize; |
| }; |
| |
| } // namespace |
| |
| BasicComputeShaderTests::BasicComputeShaderTests(Context &context) |
| : TestCaseGroup(context, "basic", "Basic Compute Shader Tests") |
| { |
| } |
| |
| BasicComputeShaderTests::~BasicComputeShaderTests(void) |
| { |
| } |
| |
| void BasicComputeShaderTests::init(void) |
| { |
| addChild(new EmptyComputeShaderCase(m_context)); |
| |
| addChild(new UBOToSSBOInvertCase(m_context, "ubo_to_ssbo_single_invocation", |
| "Copy from UBO to SSBO, inverting bits", 256, tcu::IVec3(1, 1, 1), |
| tcu::IVec3(1, 1, 1))); |
| addChild(new UBOToSSBOInvertCase(m_context, "ubo_to_ssbo_single_group", "Copy from UBO to SSBO, inverting bits", |
| 1024, tcu::IVec3(2, 1, 4), tcu::IVec3(1, 1, 1))); |
| addChild(new UBOToSSBOInvertCase(m_context, "ubo_to_ssbo_multiple_invocations", |
| "Copy from UBO to SSBO, inverting bits", 1024, tcu::IVec3(1, 1, 1), |
| tcu::IVec3(2, 4, 1))); |
| addChild(new UBOToSSBOInvertCase(m_context, "ubo_to_ssbo_multiple_groups", "Copy from UBO to SSBO, inverting bits", |
| 1024, tcu::IVec3(1, 4, 2), tcu::IVec3(2, 2, 4))); |
| |
| addChild(new CopyInvertSSBOCase(m_context, "copy_ssbo_single_invocation", "Copy between SSBOs, inverting bits", 256, |
| tcu::IVec3(1, 1, 1), tcu::IVec3(1, 1, 1))); |
| addChild(new CopyInvertSSBOCase(m_context, "copy_ssbo_multiple_invocations", "Copy between SSBOs, inverting bits", |
| 1024, tcu::IVec3(1, 1, 1), tcu::IVec3(2, 4, 1))); |
| addChild(new CopyInvertSSBOCase(m_context, "copy_ssbo_multiple_groups", "Copy between SSBOs, inverting bits", 1024, |
| tcu::IVec3(1, 4, 2), tcu::IVec3(2, 2, 4))); |
| |
| addChild(new InvertSSBOInPlaceCase(m_context, "ssbo_rw_single_invocation", "Read and write same SSBO", 256, true, |
| tcu::IVec3(1, 1, 1), tcu::IVec3(1, 1, 1))); |
| addChild(new InvertSSBOInPlaceCase(m_context, "ssbo_rw_multiple_groups", "Read and write same SSBO", 1024, true, |
| tcu::IVec3(1, 4, 2), tcu::IVec3(2, 2, 4))); |
| |
| addChild(new InvertSSBOInPlaceCase(m_context, "ssbo_unsized_arr_single_invocation", "Read and write same SSBO", 256, |
| false, tcu::IVec3(1, 1, 1), tcu::IVec3(1, 1, 1))); |
| addChild(new InvertSSBOInPlaceCase(m_context, "ssbo_unsized_arr_multiple_groups", "Read and write same SSBO", 1024, |
| false, tcu::IVec3(1, 4, 2), tcu::IVec3(2, 2, 4))); |
| |
| addChild(new WriteToMultipleSSBOCase(m_context, "write_multiple_arr_single_invocation", "Write to multiple SSBOs", |
| 256, true, tcu::IVec3(1, 1, 1), tcu::IVec3(1, 1, 1))); |
| addChild(new WriteToMultipleSSBOCase(m_context, "write_multiple_arr_multiple_groups", "Write to multiple SSBOs", |
| 1024, true, tcu::IVec3(1, 4, 2), tcu::IVec3(2, 2, 4))); |
| |
| addChild(new WriteToMultipleSSBOCase(m_context, "write_multiple_unsized_arr_single_invocation", |
| "Write to multiple SSBOs", 256, false, tcu::IVec3(1, 1, 1), |
| tcu::IVec3(1, 1, 1))); |
| addChild(new WriteToMultipleSSBOCase(m_context, "write_multiple_unsized_arr_multiple_groups", |
| "Write to multiple SSBOs", 1024, false, tcu::IVec3(1, 4, 2), |
| tcu::IVec3(2, 2, 4))); |
| |
| addChild(new SSBOLocalBarrierCase(m_context, "ssbo_local_barrier_single_invocation", "SSBO local barrier usage", |
| tcu::IVec3(1, 1, 1), tcu::IVec3(1, 1, 1))); |
| addChild(new SSBOLocalBarrierCase(m_context, "ssbo_local_barrier_single_group", "SSBO local barrier usage", |
| tcu::IVec3(3, 2, 5), tcu::IVec3(1, 1, 1))); |
| addChild(new SSBOLocalBarrierCase(m_context, "ssbo_local_barrier_multiple_groups", "SSBO local barrier usage", |
| tcu::IVec3(3, 4, 1), tcu::IVec3(2, 7, 3))); |
| |
| addChild( |
| new SSBOBarrierCase(m_context, "ssbo_cmd_barrier_single", "SSBO memory barrier usage", tcu::IVec3(1, 1, 1))); |
| addChild( |
| new SSBOBarrierCase(m_context, "ssbo_cmd_barrier_multiple", "SSBO memory barrier usage", tcu::IVec3(11, 5, 7))); |
| |
| addChild(new BasicSharedVarCase(m_context, "shared_var_single_invocation", "Basic shared variable usage", |
| tcu::IVec3(1, 1, 1), tcu::IVec3(1, 1, 1))); |
| addChild(new BasicSharedVarCase(m_context, "shared_var_single_group", "Basic shared variable usage", |
| tcu::IVec3(3, 2, 5), tcu::IVec3(1, 1, 1))); |
| addChild(new BasicSharedVarCase(m_context, "shared_var_multiple_invocations", "Basic shared variable usage", |
| tcu::IVec3(1, 1, 1), tcu::IVec3(2, 5, 4))); |
| addChild(new BasicSharedVarCase(m_context, "shared_var_multiple_groups", "Basic shared variable usage", |
| tcu::IVec3(3, 4, 1), tcu::IVec3(2, 7, 3))); |
| |
| addChild(new SharedVarAtomicOpCase(m_context, "shared_atomic_op_single_invocation", |
| "Atomic operation with shared var", tcu::IVec3(1, 1, 1), tcu::IVec3(1, 1, 1))); |
| addChild(new SharedVarAtomicOpCase(m_context, "shared_atomic_op_single_group", "Atomic operation with shared var", |
| tcu::IVec3(3, 2, 5), tcu::IVec3(1, 1, 1))); |
| addChild(new SharedVarAtomicOpCase(m_context, "shared_atomic_op_multiple_invocations", |
| "Atomic operation with shared var", tcu::IVec3(1, 1, 1), tcu::IVec3(2, 5, 4))); |
| addChild(new SharedVarAtomicOpCase(m_context, "shared_atomic_op_multiple_groups", |
| "Atomic operation with shared var", tcu::IVec3(3, 4, 1), tcu::IVec3(2, 7, 3))); |
| |
| addChild(new CopyImageToSSBOCase(m_context, "copy_image_to_ssbo_small", "Image to SSBO copy", tcu::IVec2(1, 1), |
| tcu::IVec2(64, 64))); |
| addChild(new CopyImageToSSBOCase(m_context, "copy_image_to_ssbo_large", "Image to SSBO copy", tcu::IVec2(2, 4), |
| tcu::IVec2(512, 512))); |
| |
| addChild(new CopySSBOToImageCase(m_context, "copy_ssbo_to_image_small", "SSBO to image copy", tcu::IVec2(1, 1), |
| tcu::IVec2(64, 64))); |
| addChild(new CopySSBOToImageCase(m_context, "copy_ssbo_to_image_large", "SSBO to image copy", tcu::IVec2(2, 4), |
| tcu::IVec2(512, 512))); |
| |
| addChild(new ImageAtomicOpCase(m_context, "image_atomic_op_local_size_1", "Atomic operation with image", 1, |
| tcu::IVec2(64, 64))); |
| addChild(new ImageAtomicOpCase(m_context, "image_atomic_op_local_size_8", "Atomic operation with image", 8, |
| tcu::IVec2(64, 64))); |
| |
| addChild(new ImageBarrierCase(m_context, "image_barrier_single", "Image barrier", tcu::IVec2(1, 1))); |
| addChild(new ImageBarrierCase(m_context, "image_barrier_multiple", "Image barrier", tcu::IVec2(64, 64))); |
| |
| addChild(new AtomicCounterCase(m_context, "atomic_counter_single_invocation", "Basic atomic counter test", |
| tcu::IVec3(1, 1, 1), tcu::IVec3(1, 1, 1))); |
| addChild(new AtomicCounterCase(m_context, "atomic_counter_single_group", "Basic atomic counter test", |
| tcu::IVec3(3, 2, 5), tcu::IVec3(1, 1, 1))); |
| addChild(new AtomicCounterCase(m_context, "atomic_counter_multiple_invocations", "Basic atomic counter test", |
| tcu::IVec3(1, 1, 1), tcu::IVec3(2, 5, 4))); |
| addChild(new AtomicCounterCase(m_context, "atomic_counter_multiple_groups", "Basic atomic counter test", |
| tcu::IVec3(3, 4, 1), tcu::IVec3(2, 7, 3))); |
| } |
| |
| } // namespace Functional |
| } // namespace gles31 |
| } // namespace deqp |