| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2017 The Khronos Group Inc. |
| * |
| * 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 gl4cShaderAtomicCounterOpsTests.cpp |
| * \brief Conformance tests for the ARB_shader_atomic_counter_ops functionality. |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "gl4cShaderAtomicCounterOpsTests.hpp" |
| #include "gluContextInfo.hpp" |
| #include "gluDefs.hpp" |
| #include "gluDrawUtil.hpp" |
| #include "gluObjectWrapper.hpp" |
| #include "gluShaderProgram.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuRenderTarget.hpp" |
| |
| #include <algorithm> |
| #include <sstream> |
| #include <string> |
| |
| using namespace glw; |
| |
| namespace gl4cts |
| { |
| |
| ShaderAtomicCounterOpsTestBase::ShaderPipeline::ShaderPipeline(glu::ShaderType testedShader, AtomicOperation* newOp, |
| bool contextGL46) |
| : m_program(NULL), m_programCompute(NULL), m_testedShader(testedShader), m_atomicOp(newOp) |
| { |
| m_shaders[glu::SHADERTYPE_VERTEX] = "<version>\n" |
| "<head>" |
| "in highp vec2 inPosition;\n" |
| "out highp vec3 vsPosition;\n" |
| "out highp vec4 vsColor;\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(inPosition, 0.0, 1.0);\n" |
| " vsPosition = vec3(inPosition, 0.0);\n" |
| " vec4 outColor = vec4(1.0);\n" |
| "<atomic_operation>" |
| " vsColor = outColor;\n" |
| "}\n"; |
| |
| m_shaders[glu::SHADERTYPE_FRAGMENT] = "<version>\n" |
| "<head>" |
| "in highp vec4 gsColor;\n" |
| "out highp vec4 fsColor;\n" |
| "void main()\n" |
| "{\n" |
| " vec4 outColor = gsColor; \n" |
| "<atomic_operation>" |
| " fsColor = outColor;\n" |
| "}\n"; |
| |
| m_shaders[glu::SHADERTYPE_TESSELLATION_CONTROL] = "<version>\n" |
| "<head>" |
| "layout(vertices = 3) out;\n" |
| "in highp vec4 vsColor[];\n" |
| "in highp vec3 vsPosition[];\n" |
| "out highp vec3 tcsPosition[];\n" |
| "out highp vec4 tcsColor[];\n" |
| "void main()\n" |
| "{\n" |
| " tcsPosition[gl_InvocationID] = vsPosition[gl_InvocationID];\n" |
| " vec4 outColor = vsColor[gl_InvocationID];\n" |
| "<atomic_operation>" |
| " tcsColor[gl_InvocationID] = outColor;\n" |
| " gl_TessLevelInner[0] = 3;\n" |
| " gl_TessLevelOuter[0] = 3;\n" |
| " gl_TessLevelOuter[1] = 3;\n" |
| " gl_TessLevelOuter[2] = 3;\n" |
| "}\n"; |
| |
| m_shaders[glu::SHADERTYPE_TESSELLATION_EVALUATION] = "<version>\n" |
| "<head>" |
| "layout(triangles, equal_spacing, cw) in;\n" |
| "in highp vec3 tcsPosition[];\n" |
| "in highp vec4 tcsColor[];\n" |
| "out highp vec4 tesColor;\n" |
| "void main()\n" |
| "{\n" |
| " vec3 p0 = gl_TessCoord.x * tcsPosition[0];\n" |
| " vec3 p1 = gl_TessCoord.y * tcsPosition[1];\n" |
| " vec3 p2 = gl_TessCoord.z * tcsPosition[2];\n" |
| " vec4 outColor = tcsColor[0];\n" |
| "<atomic_operation>" |
| " tesColor = outColor;\n" |
| " gl_Position = vec4(normalize(p0 + p1 + p2), 1.0);\n" |
| "}\n"; |
| |
| m_shaders[glu::SHADERTYPE_GEOMETRY] = "<version>\n" |
| "<head>" |
| "layout(triangles) in;\n" |
| "layout(triangle_strip, max_vertices = 3) out;\n" |
| "in highp vec4 tesColor[];\n" |
| "out highp vec4 gsColor;\n" |
| "void main()\n" |
| "{\n" |
| " for (int i = 0; i<3; i++)\n" |
| " {\n" |
| " gl_Position = gl_in[i].gl_Position;\n" |
| " vec4 outColor = tesColor[i];\n" |
| "<atomic_operation>" |
| " gsColor = outColor;\n" |
| " EmitVertex();\n" |
| " }\n" |
| " EndPrimitive();\n" |
| "}\n"; |
| |
| m_shaders[glu::SHADERTYPE_COMPUTE] = "<version>\n" |
| "<head>" |
| "layout(rgba32f, binding = 2) writeonly uniform highp image2D destImage;\n" |
| "layout (local_size_x = 16, local_size_y = 16) in;\n" |
| "void main (void)\n" |
| "{\n" |
| " vec4 outColor = vec4(1.0);\n" |
| "<atomic_operation>" |
| " imageStore(destImage, ivec2(gl_GlobalInvocationID.xy), outColor);\n" |
| "}\n"; |
| |
| // prepare shaders |
| |
| std::string postfix(contextGL46 ? "" : "ARB"); |
| std::stringstream atomicOperationStream; |
| atomicOperationStream << "uint returned = " << m_atomicOp->getFunction() + postfix + "(counter, "; |
| if (m_atomicOp->getCompareValue() != 0) |
| { |
| atomicOperationStream << m_atomicOp->getCompareValue(); |
| atomicOperationStream << "u, "; |
| } |
| atomicOperationStream << m_atomicOp->getParamValue(); |
| atomicOperationStream << "u);\n"; |
| atomicOperationStream << "uint after = atomicCounter(counter);\n"; |
| |
| if (m_atomicOp->shouldTestReturnValue()) |
| { |
| atomicOperationStream << "if(after == returned) outColor = vec4(0.0f);\n"; |
| } |
| |
| atomicOperationStream << "atomicCounterIncrement(calls);\n"; |
| |
| std::string versionString; |
| std::string headString; |
| if (contextGL46) |
| { |
| versionString = "#version 460 core"; |
| headString = "layout (binding=0) uniform atomic_uint counter;\n" |
| "layout (binding=1) uniform atomic_uint calls;\n"; |
| } |
| else |
| { |
| versionString = "#version 450 core"; |
| headString = "#extension GL_ARB_shader_atomic_counters: enable\n" |
| "#extension GL_ARB_shader_atomic_counter_ops: enable\n" |
| "layout (binding=0) uniform atomic_uint counter;\n" |
| "layout (binding=1) uniform atomic_uint calls;\n"; |
| } |
| |
| for (unsigned int i = 0; i <= glu::SHADERTYPE_COMPUTE; ++i) |
| { |
| prepareShader(m_shaders[i], "<version>", versionString); |
| prepareShader(m_shaders[i], "<head>", i == testedShader ? headString : ""); |
| prepareShader(m_shaders[i], "<atomic_operation>", i == testedShader ? atomicOperationStream.str() : ""); |
| } |
| } |
| |
| ShaderAtomicCounterOpsTestBase::ShaderPipeline::~ShaderPipeline() |
| { |
| if (m_program) |
| { |
| delete m_program; |
| } |
| |
| if (m_programCompute) |
| { |
| delete m_programCompute; |
| } |
| } |
| |
| void ShaderAtomicCounterOpsTestBase::ShaderPipeline::prepareShader(std::string& shader, const std::string& tag, |
| const std::string& value) |
| { |
| size_t tagPos = shader.find(tag); |
| |
| if (tagPos != std::string::npos) |
| shader.replace(tagPos, tag.length(), value); |
| } |
| |
| void ShaderAtomicCounterOpsTestBase::ShaderPipeline::create(deqp::Context& context) |
| { |
| glu::ProgramSources sources; |
| for (unsigned int i = 0; i < glu::SHADERTYPE_COMPUTE; ++i) |
| { |
| if (!m_shaders[i].empty()) |
| { |
| sources.sources[i].push_back(m_shaders[i]); |
| } |
| } |
| m_program = new glu::ShaderProgram(context.getRenderContext(), sources); |
| |
| if (!m_program->isOk()) |
| { |
| TCU_FAIL("Shader compilation failed"); |
| } |
| |
| glu::ProgramSources sourcesCompute; |
| sourcesCompute.sources[glu::SHADERTYPE_COMPUTE].push_back(m_shaders[glu::SHADERTYPE_COMPUTE]); |
| m_programCompute = new glu::ShaderProgram(context.getRenderContext(), sourcesCompute); |
| |
| if (!m_programCompute->isOk()) |
| { |
| TCU_FAIL("Shader compilation failed"); |
| } |
| } |
| |
| void ShaderAtomicCounterOpsTestBase::ShaderPipeline::use(deqp::Context& context) |
| { |
| const glw::Functions& gl = context.getRenderContext().getFunctions(); |
| gl.useProgram(m_program->getProgram()); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram failed"); |
| } |
| |
| void ShaderAtomicCounterOpsTestBase::ShaderPipeline::test(deqp::Context& context) |
| { |
| const glw::Functions& gl = context.getRenderContext().getFunctions(); |
| |
| gl.clearColor(0.5f, 0.5f, 0.5f, 1.0f); |
| gl.clear(GL_COLOR_BUFFER_BIT); |
| |
| if (m_testedShader == glu::SHADERTYPE_COMPUTE) |
| { |
| executeComputeShader(context); |
| } |
| else |
| { |
| renderQuad(context); |
| } |
| |
| gl.flush(); |
| } |
| |
| void ShaderAtomicCounterOpsTestBase::ShaderPipeline::renderQuad(deqp::Context& context) |
| { |
| const glw::Functions& gl = context.getRenderContext().getFunctions(); |
| |
| deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 }; |
| |
| float const position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }; |
| |
| glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("inPosition", 2, 4, 0, position) }; |
| |
| this->use(context); |
| |
| glu::PrimitiveList primitiveList = glu::pr::Patches(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices); |
| |
| glu::draw(context.getRenderContext(), this->getShaderProgram()->getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), |
| vertexArrays, primitiveList); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error"); |
| |
| gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() error"); |
| } |
| |
| void ShaderAtomicCounterOpsTestBase::ShaderPipeline::executeComputeShader(deqp::Context& context) |
| { |
| const glw::Functions& gl = context.getRenderContext().getFunctions(); |
| |
| const glu::Texture outputTexture(context.getRenderContext()); |
| |
| gl.useProgram(m_programCompute->getProgram()); |
| |
| // output image |
| gl.bindTexture(GL_TEXTURE_2D, *outputTexture); |
| gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, 16, 16); |
| 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 image |
| gl.bindImageTexture(2, *outputTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Image setup failed"); |
| |
| // dispatch compute |
| gl.dispatchCompute(1, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() error"); |
| gl.memoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() error"); |
| |
| // render output texture |
| |
| std::string vs = "#version 450 core\n" |
| "in highp vec2 position;\n" |
| "in vec2 inTexcoord;\n" |
| "out vec2 texcoord;\n" |
| "void main()\n" |
| "{\n" |
| " texcoord = inTexcoord;\n" |
| " gl_Position = vec4(position, 0.0, 1.0);\n" |
| "}\n"; |
| |
| std::string fs = "#version 450 core\n" |
| "uniform sampler2D sampler;\n" |
| "in vec2 texcoord;\n" |
| "out vec4 color;\n" |
| "void main()\n" |
| "{\n" |
| " color = texture(sampler, texcoord);\n" |
| "}\n"; |
| |
| glu::ProgramSources sources; |
| sources.sources[glu::SHADERTYPE_VERTEX].push_back(vs); |
| sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(fs); |
| glu::ShaderProgram renderShader(context.getRenderContext(), sources); |
| |
| if (!m_program->isOk()) |
| { |
| TCU_FAIL("Shader compilation failed"); |
| } |
| |
| gl.bindTexture(GL_TEXTURE_2D, *outputTexture); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed."); |
| |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri failed"); |
| |
| gl.useProgram(renderShader.getProgram()); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "useProgram failed"); |
| |
| gl.uniform1i(gl.getUniformLocation(renderShader.getProgram(), "sampler"), 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i failed"); |
| |
| deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 }; |
| |
| float const position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }; |
| |
| float const texCoord[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f }; |
| |
| glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("position", 2, 4, 0, position), |
| glu::va::Float("inTexcoord", 2, 4, 0, texCoord) }; |
| |
| glu::draw(context.getRenderContext(), renderShader.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays, |
| glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices)); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error"); |
| } |
| |
| void ShaderAtomicCounterOpsTestBase::fillAtomicCounterBuffer(AtomicOperation* atomicOp) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GLuint* dataPtr; |
| |
| // fill values buffer |
| |
| GLuint inputValue = atomicOp->getInputValue(); |
| |
| gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed."); |
| |
| dataPtr = (GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), |
| GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed."); |
| |
| *dataPtr = inputValue; |
| |
| gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed."); |
| |
| // fill calls buffer |
| |
| gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterCallsBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed."); |
| |
| dataPtr = (GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), |
| GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed."); |
| |
| *dataPtr = 0; |
| |
| gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed."); |
| } |
| |
| bool ShaderAtomicCounterOpsTestBase::checkAtomicCounterBuffer(AtomicOperation* atomicOp) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GLuint* dataPtr; |
| |
| // get value |
| |
| gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed."); |
| |
| dataPtr = (GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed."); |
| |
| GLuint finalValue = *dataPtr; |
| |
| gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed."); |
| |
| // get calls |
| |
| gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterCallsBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed."); |
| |
| dataPtr = (GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed."); |
| |
| GLuint numberOfCalls = *dataPtr; |
| |
| gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed."); |
| |
| // validate |
| |
| GLuint expectedValue = atomicOp->getResult(numberOfCalls); |
| |
| return finalValue == expectedValue; |
| } |
| |
| void ShaderAtomicCounterOpsTestBase::bindBuffers() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_atomicCounterBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferBase() call failed."); |
| |
| gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, m_atomicCounterCallsBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferBase() call failed."); |
| } |
| |
| bool ShaderAtomicCounterOpsTestBase::validateColor(tcu::Vec4 testedColor, tcu::Vec4 desiredColor) |
| { |
| const float epsilon = 1.1f / 31.0f; // Accommodate framebuffers with 5-bit channels. |
| return de::abs(testedColor.x() - desiredColor.x()) < epsilon && |
| de::abs(testedColor.y() - desiredColor.y()) < epsilon && |
| de::abs(testedColor.z() - desiredColor.z()) < epsilon; |
| } |
| |
| bool ShaderAtomicCounterOpsTestBase::validateScreenPixels(tcu::Vec4 desiredColor, tcu::Vec4 ignoredColor) |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| const tcu::RenderTarget renderTarget = m_context.getRenderContext().getRenderTarget(); |
| tcu::IVec2 size(renderTarget.getWidth(), renderTarget.getHeight()); |
| |
| glw::GLfloat* pixels = new glw::GLfloat[size.x() * size.y() * 4]; |
| |
| // clear buffer |
| for (int x = 0; x < size.x(); ++x) |
| { |
| for (int y = 0; y < size.y(); ++y) |
| { |
| int mappedPixelPosition = y * size.x() + x; |
| |
| pixels[mappedPixelPosition * 4 + 0] = -1.0f; |
| pixels[mappedPixelPosition * 4 + 1] = -1.0f; |
| pixels[mappedPixelPosition * 4 + 2] = -1.0f; |
| pixels[mappedPixelPosition * 4 + 3] = -1.0f; |
| } |
| } |
| |
| // read pixels |
| gl.readPixels(0, 0, size.x(), size.y(), GL_RGBA, GL_FLOAT, pixels); |
| |
| // validate pixels |
| bool rendered = false; |
| for (int x = 0; x < size.x(); ++x) |
| { |
| for (int y = 0; y < size.y(); ++y) |
| { |
| int mappedPixelPosition = y * size.x() + x; |
| |
| tcu::Vec4 color(pixels[mappedPixelPosition * 4 + 0], pixels[mappedPixelPosition * 4 + 1], |
| pixels[mappedPixelPosition * 4 + 2], pixels[mappedPixelPosition * 4 + 3]); |
| |
| if (!validateColor(color, ignoredColor)) |
| { |
| rendered = true; |
| if (!validateColor(color, desiredColor)) |
| { |
| delete[] pixels; |
| return false; |
| } |
| } |
| } |
| } |
| |
| delete[] pixels; |
| |
| return rendered; |
| } |
| |
| ShaderAtomicCounterOpsTestBase::ShaderAtomicCounterOpsTestBase(deqp::Context& context, const char* name, |
| const char* description) |
| : TestCase(context, name, description), m_atomicCounterBuffer(0), m_atomicCounterCallsBuffer(0) |
| { |
| glu::ContextType contextType = m_context.getRenderContext().getType(); |
| m_contextSupportsGL46 = glu::contextSupports(contextType, glu::ApiType::core(4, 6)); |
| } |
| |
| void ShaderAtomicCounterOpsTestBase::init() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| // generate atomic counter buffer |
| |
| gl.genBuffers(1, &m_atomicCounterBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "genBuffers() call failed."); |
| |
| gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed."); |
| |
| gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData() call failed."); |
| |
| // generate atomic counter calls buffer |
| |
| gl.genBuffers(1, &m_atomicCounterCallsBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "genBuffers() call failed."); |
| |
| gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterCallsBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed."); |
| |
| gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData() call failed."); |
| |
| // setup tested atomic operations |
| |
| setOperations(); |
| |
| // setup shaders |
| |
| for (ShaderPipelineIter iter = m_shaderPipelines.begin(); iter != m_shaderPipelines.end(); ++iter) |
| { |
| iter->create(m_context); |
| } |
| } |
| |
| void ShaderAtomicCounterOpsTestBase::deinit() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| // delete atomic counter buffer |
| |
| gl.deleteBuffers(1, &m_atomicCounterBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "deleteBuffers() call failed."); |
| |
| // delete atomic counter calls buffer |
| |
| gl.deleteBuffers(1, &m_atomicCounterCallsBuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "deleteBuffers() call failed."); |
| |
| // delete operations |
| |
| for (AtomicOperationIter iter = m_operations.begin(); iter != m_operations.end(); ++iter) |
| { |
| delete *iter; |
| } |
| } |
| |
| tcu::TestNode::IterateResult ShaderAtomicCounterOpsTestBase::iterate() |
| { |
| if (!m_contextSupportsGL46) |
| { |
| if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters") || |
| !m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counter_ops")) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported"); |
| return STOP; |
| } |
| } |
| |
| for (ShaderPipelineIter iter = m_shaderPipelines.begin(); iter != m_shaderPipelines.end(); ++iter) |
| { |
| fillAtomicCounterBuffer(iter->getAtomicOperation()); |
| bindBuffers(); |
| iter->test(m_context); |
| |
| bool operationValueValid = checkAtomicCounterBuffer(iter->getAtomicOperation()); |
| std::string operationFailMsg = "Result of atomic operation was different than expected (" + |
| iter->getAtomicOperation()->getFunction() + ")."; |
| TCU_CHECK_MSG(operationValueValid, operationFailMsg.c_str()); |
| |
| bool returnValueValid = validateScreenPixels(tcu::Vec4(1.0f), tcu::Vec4(0.5f)); |
| std::string returnFailMsg = "Result of atomic operation return value was different than expected (" + |
| iter->getAtomicOperation()->getFunction() + ")."; |
| TCU_CHECK_MSG(returnValueValid, returnFailMsg.c_str()); |
| } |
| |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| return STOP; |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context |
| */ |
| ShaderAtomicCounterOpsAdditionSubstractionTestCase::ShaderAtomicCounterOpsAdditionSubstractionTestCase( |
| deqp::Context& context) |
| : ShaderAtomicCounterOpsTestBase( |
| context, "ShaderAtomicCounterOpsAdditionSubstractionTestCase", |
| "Implements verification of new built-in addition and substraction atomic counter operations") |
| { |
| } |
| |
| void ShaderAtomicCounterOpsAdditionSubstractionTestCase::setOperations() |
| { |
| glw::GLuint input = 12; |
| glw::GLuint param = 4; |
| |
| addOperation(new AtomicOperationAdd(input, param)); |
| addOperation(new AtomicOperationSubtract(input, param)); |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context |
| */ |
| ShaderAtomicCounterOpsMinMaxTestCase::ShaderAtomicCounterOpsMinMaxTestCase(deqp::Context& context) |
| : ShaderAtomicCounterOpsTestBase( |
| context, "ShaderAtomicCounterOpsMinMaxTestCase", |
| "Implements verification of new built-in minimum and maximum atomic counter operations") |
| { |
| } |
| |
| void ShaderAtomicCounterOpsMinMaxTestCase::setOperations() |
| { |
| glw::GLuint input = 12; |
| glw::GLuint params[] = { 4, 16 }; |
| |
| addOperation(new AtomicOperationMin(input, params[0])); |
| addOperation(new AtomicOperationMin(input, params[1])); |
| addOperation(new AtomicOperationMax(input, params[0])); |
| addOperation(new AtomicOperationMax(input, params[1])); |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context |
| */ |
| ShaderAtomicCounterOpsBitwiseTestCase::ShaderAtomicCounterOpsBitwiseTestCase(deqp::Context& context) |
| : ShaderAtomicCounterOpsTestBase(context, "ShaderAtomicCounterOpsBitwiseTestCase", |
| "Implements verification of new built-in bitwise atomic counter operations") |
| { |
| } |
| |
| void ShaderAtomicCounterOpsBitwiseTestCase::setOperations() |
| { |
| glw::GLuint input = 0x2ED; // 0b1011101101; |
| glw::GLuint param = 0x3A9; // 0b1110101001; |
| |
| addOperation(new AtomicOperationAnd(input, param)); |
| addOperation(new AtomicOperationOr(input, param)); |
| addOperation(new AtomicOperationXor(input, param)); |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context |
| */ |
| ShaderAtomicCounterOpsExchangeTestCase::ShaderAtomicCounterOpsExchangeTestCase(deqp::Context& context) |
| : ShaderAtomicCounterOpsTestBase( |
| context, "ShaderAtomicCounterOpsExchangeTestCase", |
| "Implements verification of new built-in exchange and swap atomic counter operations") |
| { |
| } |
| |
| void ShaderAtomicCounterOpsExchangeTestCase::setOperations() |
| { |
| glw::GLuint input = 5; |
| glw::GLuint param = 10; |
| glw::GLuint compare[] = { 5, 20 }; |
| |
| addOperation(new AtomicOperationExchange(input, param)); |
| addOperation(new AtomicOperationCompSwap(input, param, compare[0])); |
| addOperation(new AtomicOperationCompSwap(input, param, compare[1])); |
| } |
| |
| /** Constructor. |
| * |
| * @param context Rendering context. |
| */ |
| ShaderAtomicCounterOps::ShaderAtomicCounterOps(deqp::Context& context) |
| : TestCaseGroup(context, "shader_atomic_counter_ops_tests", |
| "Verify conformance of CTS_ARB_shader_atomic_counter_ops implementation") |
| { |
| } |
| |
| /** Initializes the test group contents. */ |
| void ShaderAtomicCounterOps::init() |
| { |
| addChild(new ShaderAtomicCounterOpsAdditionSubstractionTestCase(m_context)); |
| addChild(new ShaderAtomicCounterOpsMinMaxTestCase(m_context)); |
| addChild(new ShaderAtomicCounterOpsBitwiseTestCase(m_context)); |
| addChild(new ShaderAtomicCounterOpsExchangeTestCase(m_context)); |
| } |
| } /* gl4cts namespace */ |