| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2014-2016 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 |
| * \brief |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "gl4cShaderAtomicCountersTests.hpp" |
| #include "gluContextInfo.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "tcuSurface.hpp" |
| #include "tcuVector.hpp" |
| #include <assert.h> |
| #include <cstdarg> |
| #include <map> |
| |
| namespace gl4cts |
| { |
| |
| using namespace glw; |
| using tcu::Vec4; |
| using tcu::UVec4; |
| |
| namespace |
| { |
| |
| class SACSubcaseBase : public deqp::SubcaseBase |
| { |
| public: |
| virtual std::string Title() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| virtual ~SACSubcaseBase() |
| { |
| } |
| |
| int getWindowWidth() |
| { |
| const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); |
| return renderTarget.getWidth(); |
| } |
| |
| int getWindowHeight() |
| { |
| const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); |
| return renderTarget.getHeight(); |
| } |
| |
| long ValidateReadBuffer(const Vec4& expected) |
| { |
| const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); |
| int viewportW = renderTarget.getWidth(); |
| int viewportH = renderTarget.getHeight(); |
| tcu::Surface renderedFrame(viewportW, viewportH); |
| tcu::Surface referenceFrame(viewportW, viewportH); |
| |
| glu::readPixels(m_context.getRenderContext(), 0, 0, renderedFrame.getAccess()); |
| |
| for (int y = 0; y < viewportH; ++y) |
| { |
| for (int x = 0; x < viewportW; ++x) |
| { |
| referenceFrame.setPixel( |
| x, y, tcu::RGBA(static_cast<int>(expected[0] * 255), static_cast<int>(expected[1] * 255), |
| static_cast<int>(expected[2] * 255), static_cast<int>(expected[3] * 255))); |
| } |
| } |
| tcu::TestLog& log = m_context.getTestContext().getLog(); |
| bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, |
| tcu::COMPARE_LOG_RESULT); |
| return (isOk ? NO_ERROR : ERROR); |
| } |
| |
| void LinkProgram(GLuint program) |
| { |
| glLinkProgram(program); |
| GLsizei length; |
| GLchar log[1024]; |
| glGetProgramInfoLog(program, sizeof(log), &length, log); |
| if (length > 1) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program Info Log:\n" |
| << log << tcu::TestLog::EndMessage; |
| } |
| } |
| |
| GLuint CreateProgram(const char* src_vs, const char* src_tcs, const char* src_tes, const char* src_gs, |
| const char* src_fs, bool link) |
| { |
| const GLuint p = glCreateProgram(); |
| |
| if (src_vs) |
| { |
| GLuint sh = glCreateShader(GL_VERTEX_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| glShaderSource(sh, 1, &src_vs, NULL); |
| glCompileShader(sh); |
| } |
| if (src_tcs) |
| { |
| GLuint sh = glCreateShader(GL_TESS_CONTROL_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| glShaderSource(sh, 1, &src_tcs, NULL); |
| glCompileShader(sh); |
| } |
| if (src_tes) |
| { |
| GLuint sh = glCreateShader(GL_TESS_EVALUATION_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| glShaderSource(sh, 1, &src_tes, NULL); |
| glCompileShader(sh); |
| } |
| if (src_gs) |
| { |
| GLuint sh = glCreateShader(GL_GEOMETRY_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| glShaderSource(sh, 1, &src_gs, NULL); |
| glCompileShader(sh); |
| } |
| if (src_fs) |
| { |
| GLuint sh = glCreateShader(GL_FRAGMENT_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| glShaderSource(sh, 1, &src_fs, NULL); |
| glCompileShader(sh); |
| } |
| if (link) |
| { |
| LinkProgram(p); |
| } |
| return p; |
| } |
| |
| bool CheckProgram(GLuint program) |
| { |
| GLint status; |
| glGetProgramiv(program, GL_LINK_STATUS, &status); |
| GLint length; |
| glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); |
| if (length > 1) |
| { |
| std::vector<GLchar> log(length); |
| glGetProgramInfoLog(program, length, NULL, &log[0]); |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage; |
| } |
| return status == GL_TRUE; |
| } |
| |
| GLuint CreateShaderProgram(GLenum type, GLsizei count, const GLchar** strings) |
| { |
| GLuint program = glCreateShaderProgramv(type, count, strings); |
| GLint status = GL_TRUE; |
| glGetProgramiv(program, GL_LINK_STATUS, &status); |
| if (status == GL_FALSE) |
| { |
| GLsizei length; |
| GLchar log[1024]; |
| glGetProgramInfoLog(program, sizeof(log), &length, log); |
| if (length > 1) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program Info Log:\n" |
| << log << tcu::TestLog::EndMessage; |
| } |
| } |
| return program; |
| } |
| |
| void CreateQuad(GLuint* vao, GLuint* vbo, GLuint* ebo) |
| { |
| assert(vao && vbo); |
| |
| // interleaved data (vertex, color0 (green), color1 (blue), color2 (red)) |
| const float v[] = { |
| -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, |
| 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, |
| 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, |
| }; |
| glGenBuffers(1, vbo); |
| glBindBuffer(GL_ARRAY_BUFFER, *vbo); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| if (ebo) |
| { |
| std::vector<GLushort> index_data(4); |
| for (int i = 0; i < 4; ++i) |
| { |
| index_data[i] = static_cast<GLushort>(i); |
| } |
| glGenBuffers(1, ebo); |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo); |
| glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * 4, &index_data[0], GL_STATIC_DRAW); |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
| } |
| |
| glGenVertexArrays(1, vao); |
| glBindVertexArray(*vao); |
| glBindBuffer(GL_ARRAY_BUFFER, *vbo); |
| glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, 0); |
| |
| glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 2)); |
| |
| glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 5)); |
| |
| glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 8)); |
| |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| glEnableVertexAttribArray(0); |
| glEnableVertexAttribArray(1); |
| glEnableVertexAttribArray(2); |
| glEnableVertexAttribArray(3); |
| if (ebo) |
| { |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo); |
| } |
| glBindVertexArray(0); |
| } |
| |
| void CreateTriangle(GLuint* vao, GLuint* vbo, GLuint* ebo) |
| { |
| assert(vao && vbo); |
| |
| // interleaved data (vertex, color0 (green), color1 (blue), color2 (red)) |
| const float v[] = { |
| -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 3.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, |
| 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 3.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, |
| }; |
| glGenBuffers(1, vbo); |
| glBindBuffer(GL_ARRAY_BUFFER, *vbo); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| if (ebo) |
| { |
| std::vector<GLushort> index_data(3); |
| for (int i = 0; i < 3; ++i) |
| { |
| index_data[i] = static_cast<GLushort>(i); |
| } |
| glGenBuffers(1, ebo); |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo); |
| glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * 4, &index_data[0], GL_STATIC_DRAW); |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
| } |
| |
| glGenVertexArrays(1, vao); |
| glBindVertexArray(*vao); |
| glBindBuffer(GL_ARRAY_BUFFER, *vbo); |
| glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, 0); |
| glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 2)); |
| glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 5)); |
| glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 8)); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| glEnableVertexAttribArray(0); |
| glEnableVertexAttribArray(1); |
| glEnableVertexAttribArray(2); |
| glEnableVertexAttribArray(3); |
| if (ebo) |
| { |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo); |
| } |
| glBindVertexArray(0); |
| } |
| |
| const char* GLenumToString(GLenum e) |
| { |
| switch (e) |
| { |
| case GL_ATOMIC_COUNTER_BUFFER_BINDING: |
| return "GL_ATOMIC_COUNTER_BUFFER_BINDING"; |
| case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS: |
| return "GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS"; |
| case GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS: |
| return "GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS"; |
| case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS: |
| return "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS"; |
| case GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS: |
| return "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS"; |
| case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS: |
| return "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS"; |
| case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS: |
| return "GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS"; |
| |
| case GL_MAX_VERTEX_ATOMIC_COUNTERS: |
| return "GL_MAX_VERTEX_ATOMIC_COUNTERS"; |
| case GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS: |
| return "GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS"; |
| case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS: |
| return "GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS"; |
| case GL_MAX_GEOMETRY_ATOMIC_COUNTERS: |
| return "GL_MAX_GEOMETRY_ATOMIC_COUNTERS"; |
| case GL_MAX_FRAGMENT_ATOMIC_COUNTERS: |
| return "GL_MAX_FRAGMENT_ATOMIC_COUNTERS"; |
| case GL_MAX_COMBINED_ATOMIC_COUNTERS: |
| return "GL_MAX_COMBINED_ATOMIC_COUNTERS"; |
| |
| case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE: |
| return "GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE"; |
| case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: |
| return "GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS"; |
| |
| default: |
| assert(0); |
| break; |
| } |
| return NULL; |
| } |
| |
| bool CheckMaxValue(GLenum e, GLint expected) |
| { |
| bool ok = true; |
| |
| GLint i; |
| glGetIntegerv(e, &i); |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << GLenumToString(e) << " = " << i << tcu::TestLog::EndMessage; |
| if (i < expected) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetIntegerv, is: " << i |
| << ", expected: " << expected << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLint64 i64; |
| glGetInteger64v(e, &i64); |
| if (i64 < static_cast<GLint64>(expected)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << GLenumToString(e) |
| << " state is incorrect (GetInteger64v, is: " << static_cast<GLint>(i64) |
| << ", expected: " << expected << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLfloat f; |
| glGetFloatv(e, &f); |
| if (f < static_cast<GLfloat>(expected)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetFloatv, is: " << f |
| << ", expected: " << expected << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLdouble d; |
| glGetDoublev(e, &d); |
| if (d < static_cast<GLdouble>(expected)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetDoublev, is: " << d |
| << ", expected: " << expected << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLboolean b; |
| glGetBooleanv(e, &b); |
| |
| return ok; |
| } |
| |
| bool CheckGetCommands(GLenum e, GLint expected) |
| { |
| bool ok = true; |
| |
| GLint i; |
| glGetIntegerv(e, &i); |
| if (i != expected) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetIntegerv, is: " << i |
| << ", expected: " << expected << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLint64 i64; |
| glGetInteger64v(e, &i64); |
| if (i64 != static_cast<GLint64>(expected)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << GLenumToString(e) |
| << " state is incorrect (GetInteger64v, is: " << static_cast<GLint>(i64) |
| << ", expected: " << expected << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLfloat f; |
| glGetFloatv(e, &f); |
| if (f != static_cast<GLfloat>(expected)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetFloatv, is: " << f |
| << ", expected: " << expected << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLdouble d; |
| glGetDoublev(e, &d); |
| if (d != static_cast<GLdouble>(expected)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetDoublev, is: " << d |
| << ", expected: " << expected << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLboolean b; |
| glGetBooleanv(e, &b); |
| if (b != (expected ? GL_TRUE : GL_FALSE)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetBooleanv, is: " << b |
| << ", expected: " << (expected ? GL_TRUE : GL_FALSE) << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| return ok; |
| } |
| |
| bool CheckBufferBindingState(GLuint index, GLint binding, GLint64 start, GLint64 size) |
| { |
| bool ok = true; |
| |
| GLint i; |
| glGetIntegeri_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, index, &i); |
| if (i != binding) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "GL_ATOMIC_COUNTER_BUFFER_BINDING state is incorrect (GetIntegeri_v, is: " << i |
| << ", expected: " << binding << ", index: " << index << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLint64 i64; |
| glGetInteger64i_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, index, &i64); |
| if (i64 != static_cast<GLint64>(binding)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "GL_ATOMIC_COUNTER_BUFFER_BINDING state is incorrect (GetInteger64i_v, is: " |
| << static_cast<GLint>(i64) << ", expected: " << binding << ", index: " << index << ")" |
| << tcu::TestLog::EndMessage; |
| } |
| |
| GLfloat f; |
| glGetFloati_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, index, &f); |
| if (f != static_cast<GLfloat>(binding)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "GL_ATOMIC_COUNTER_BUFFER_BINDING state is incorrect (GetFloati_v, is: " << f |
| << ", expected: " << binding << ", index: " << index << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLdouble d; |
| glGetDoublei_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, index, &d); |
| if (d != static_cast<GLdouble>(binding)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "GL_ATOMIC_COUNTER_BUFFER_BINDING state is incorrect (GetDoublei_v, is: " << d |
| << ", expected: " << binding << ", index: " << index << ")" << tcu::TestLog::EndMessage; |
| } |
| |
| GLboolean b; |
| glGetBooleani_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, index, &b); |
| if (b != (binding ? GL_TRUE : GL_FALSE)) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "GL_ATOMIC_COUNTER_BUFFER_BINDING state is incorrect (GetBooleani_v, is: " << d |
| << ", expected: " << (binding ? GL_TRUE : GL_FALSE) << ", index: " << index << ")" |
| << tcu::TestLog::EndMessage; |
| } |
| |
| glGetInteger64i_v(GL_ATOMIC_COUNTER_BUFFER_START, index, &i64); |
| if (i64 != start) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "GL_ATOMIC_COUNTER_BUFFER_START state is incorrect (GetInteger64i_v, is: " << static_cast<GLint>(i64) |
| << ", expected: " << static_cast<GLint>(start) << ", index: " << index << ")" |
| << tcu::TestLog::EndMessage; |
| } |
| glGetInteger64i_v(GL_ATOMIC_COUNTER_BUFFER_SIZE, index, &i64); |
| if (i64 != size && i64 != 0) |
| { |
| ok = false; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "GL_ATOMIC_COUNTER_BUFFER_SIZE state is incorrect (GetInteger64i_v, is: " << static_cast<GLint>(i64) |
| << ", expected: " << static_cast<GLint>(size) << ", index: " << index << ")" |
| << tcu::TestLog::EndMessage; |
| } |
| |
| return ok; |
| } |
| |
| bool CheckUniform(GLuint prog, const GLchar* uniform_name, GLuint uniform_index, GLint uniform_type, |
| GLint uniform_size, GLint uniform_offset, GLint uniform_array_stride, GLuint buffer_index) |
| { |
| bool ok = true; |
| |
| GLuint index; |
| glGetUniformIndices(prog, 1, &uniform_name, &index); |
| if (index != uniform_index) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name |
| << ": Bad index returned by glGetUniformIndices." << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| |
| const GLsizei uniform_length = static_cast<GLsizei>(strlen(uniform_name)); |
| |
| GLsizei length; |
| GLint size; |
| GLenum type; |
| GLchar name[32]; |
| |
| glGetActiveUniformName(prog, uniform_index, sizeof(name), &length, name); |
| if (strcmp(name, uniform_name)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name |
| << ": Bad name returned by glGetActiveUniformName." << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| if (length != uniform_length) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Length is " << length << " should be " |
| << uniform_length << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| |
| glGetActiveUniform(prog, uniform_index, sizeof(name), &length, &size, &type, name); |
| if (strcmp(name, uniform_name)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Bad name returned by glGetActiveUniform." |
| << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| if (length != uniform_length) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Length is " << length << " should be " |
| << uniform_length << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| if (size != uniform_size) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Size is " |
| << size << " should be " << uniform_size << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| if (type != static_cast<GLenum>(uniform_type)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Type is " |
| << type << " should be " << uniform_type << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| |
| GLint param; |
| glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_TYPE, ¶m); |
| if (param != uniform_type) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Type is " |
| << param << " should be " << uniform_type << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_SIZE, ¶m); |
| if (param != uniform_size) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_SIZE is " << param |
| << " should be " << uniform_size << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_NAME_LENGTH, ¶m); |
| if (param != (uniform_length + 1)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_NAME_LENGTH is " << param |
| << " should be " << (uniform_length + 1) << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_BLOCK_INDEX, ¶m); |
| if (param != -1) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name |
| << ": GL_UNIFORM_BLOCK_INDEX should be -1." << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_OFFSET, ¶m); |
| if (param != uniform_offset) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_OFFSET is " << param |
| << " should be " << uniform_offset << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_ARRAY_STRIDE, ¶m); |
| if (param != uniform_array_stride) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_ARRAY_STRIDE is " << param |
| << " should be " << uniform_array_stride << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_MATRIX_STRIDE, ¶m); |
| if (param != 0) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_MATRIX_STRIDE should be 0 is " |
| << param << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_IS_ROW_MAJOR, ¶m); |
| if (param != 0) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_IS_ROW_MAJOR should be 0 is " |
| << param << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX, ¶m); |
| if (param != static_cast<GLint>(buffer_index)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name |
| << ": GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX is " << param |
| << " should be " << buffer_index << tcu::TestLog::EndMessage; |
| ok = false; |
| } |
| |
| return ok; |
| } |
| |
| bool CheckCounterValues(GLuint size, GLuint* values, GLuint min_value) |
| { |
| std::sort(values, values + size); |
| for (GLuint i = 0; i < size; ++i) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << values[i] << tcu::TestLog::EndMessage; |
| if (values[i] != i + min_value) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Counter value is " << values[i] |
| << " should be " << (i + min_value) << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool CheckFinalCounterValue(GLuint buffer, GLintptr offset, GLuint expected_value) |
| { |
| GLuint value; |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer); |
| glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, offset, 4, &value); |
| if (value != expected_value) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Counter value is " << value |
| << " should be " << expected_value << tcu::TestLog::EndMessage; |
| return false; |
| } |
| return true; |
| } |
| }; |
| |
| class Buffer : public deqp::GLWrapper |
| { |
| public: |
| Buffer() |
| : size_(0) |
| , usage_(GL_STATIC_DRAW) |
| , access_(GL_READ_WRITE) |
| , access_flags_(0) |
| , mapped_(GL_FALSE) |
| , map_pointer_(NULL) |
| , map_offset_(0) |
| , map_length_(0) |
| { |
| glGenBuffers(1, &name_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, name_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| } |
| ~Buffer() |
| { |
| glDeleteBuffers(1, &name_); |
| } |
| |
| GLuint name() const |
| { |
| return name_; |
| } |
| |
| long Verify() |
| { |
| GLint i; |
| GLint64 i64; |
| |
| glGetBufferParameteri64v(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_SIZE, &i64); |
| if (i64 != size_) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "BUFFER_SIZE is " << static_cast<GLint>(i64) << " should be " |
| << static_cast<GLint>(size_) << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_USAGE, &i); |
| if (i != static_cast<GLint>(usage_)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "BUFFER_USAGE is " << i << " should be " |
| << usage_ << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_ACCESS, &i); |
| if (i != static_cast<GLint>(access_)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "BUFFER_ACCESS is " << i << " should be " |
| << access_ << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_ACCESS_FLAGS, &i); |
| if (i != access_flags_) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "BUFFER_ACCESS_FLAGS is " << i |
| << " should be " << access_flags_ << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAPPED, &i); |
| if (i != mapped_) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "BUFFER_MAPPED is " << i << " should be " |
| << mapped_ << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetBufferParameteri64v(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAP_OFFSET, &i64); |
| if (i64 != map_offset_) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "BUFFER_MAP_OFFSET is " << static_cast<GLint>(i64) << " should be " |
| << map_offset_ << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetBufferParameteri64v(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAP_LENGTH, &i64); |
| if (i64 != map_length_) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "BUFFER_MAP_LENGTH is " << static_cast<GLint>(i64) << " should be " |
| << static_cast<GLint>(map_length_) << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| |
| void* ptr; |
| glGetBufferPointerv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAP_POINTER, &ptr); |
| if (ptr != map_pointer_) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "BUFFER_MAP_POINTER is " << ptr |
| << " should be " << map_pointer_ << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| return NO_ERROR; |
| } |
| |
| void Data(GLsizeiptr size, const void* data, GLenum usage) |
| { |
| size_ = size; |
| usage_ = usage; |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, size, data, usage); |
| } |
| |
| void* MapRange(GLintptr offset, GLsizeiptr length, GLbitfield access) |
| { |
| assert(mapped_ == GL_FALSE); |
| |
| map_pointer_ = glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, offset, length, access); |
| if (map_pointer_) |
| { |
| map_offset_ = offset; |
| map_length_ = length; |
| access_flags_ = access; |
| if ((access & GL_MAP_WRITE_BIT) && (access & GL_MAP_READ_BIT)) |
| access_ = GL_READ_WRITE; |
| else if (access & GL_MAP_READ_BIT) |
| access_ = GL_READ_ONLY; |
| else if (access & GL_MAP_WRITE_BIT) |
| access_ = GL_WRITE_ONLY; |
| mapped_ = GL_TRUE; |
| } |
| return map_pointer_; |
| } |
| |
| void* Map(GLenum access) |
| { |
| assert(mapped_ == GL_FALSE); |
| |
| map_pointer_ = glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, access); |
| if (map_pointer_) |
| { |
| mapped_ = GL_TRUE; |
| access_ = access; |
| if (access == GL_READ_WRITE) |
| access_flags_ = GL_MAP_WRITE_BIT | GL_MAP_READ_BIT; |
| else if (access == GL_READ_ONLY) |
| access_flags_ = GL_MAP_READ_BIT; |
| else if (access == GL_WRITE_ONLY) |
| access_flags_ = GL_MAP_WRITE_BIT; |
| map_offset_ = 0; |
| map_length_ = size_; |
| } |
| return map_pointer_; |
| } |
| GLboolean Unmap() |
| { |
| assert(mapped_ == GL_TRUE); |
| |
| if (glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER)) |
| { |
| map_offset_ = 0; |
| map_length_ = 0; |
| map_pointer_ = 0; |
| mapped_ = GL_FALSE; |
| access_flags_ = 0; |
| access_ = GL_READ_WRITE; |
| return GL_TRUE; |
| } |
| return GL_FALSE; |
| } |
| |
| private: |
| GLuint name_; |
| GLint64 size_; |
| GLenum usage_; |
| GLenum access_; |
| GLint access_flags_; |
| GLboolean mapped_; |
| void* map_pointer_; |
| GLint64 map_offset_; |
| GLint64 map_length_; |
| }; |
| } |
| |
| class BasicBufferOperations : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Atomic Counter Buffer - basic operations"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL |
| "Verify that basic buffer operations work as expected with new buffer target." NL |
| "Tested commands: BindBuffer, BufferData, BufferSubData, MapBuffer, MapBufferRange, UnmapBuffer and" NL |
| "GetBufferSubData."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint buffer_; |
| |
| virtual long Setup() |
| { |
| buffer_ = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| glGenBuffers(1, &buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8 * 4, NULL, GL_STATIC_DRAW); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_); |
| GLuint* ptr = static_cast<GLuint*>(glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY)); |
| for (GLuint i = 0; i < 8; ++i) |
| ptr[i] = i; |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| long res = NO_ERROR; |
| GLuint data[8]; |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_); |
| glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(data), data); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| for (GLuint i = 0; i < 8; ++i) |
| { |
| if (data[i] != i) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "data[" << i << "] is: " << data[i] |
| << "should be: " << i << tcu::TestLog::EndMessage; |
| res = ERROR; |
| } |
| } |
| if (res != NO_ERROR) |
| return res; |
| |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_); |
| ptr = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_WRITE_BIT)); |
| for (GLuint i = 0; i < 8; ++i) |
| ptr[i] = i * 2; |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_); |
| ptr = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_READ_BIT)); |
| for (GLuint i = 0; i < 8; ++i) |
| { |
| if (ptr[i] != i * 2) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "data[" << i << "] is: " << data[i] |
| << "should be: " << (i * 2) << tcu::TestLog::EndMessage; |
| res = ERROR; |
| } |
| } |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_); |
| for (GLuint i = 0; i < 8; ++i) |
| data[i] = i * 3; |
| glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, 32, data); |
| for (GLuint i = 0; i < 8; ++i) |
| data[i] = 0; |
| glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(data), data); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| for (GLuint i = 0; i < 8; ++i) |
| { |
| if (data[i] != i * 3) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "data[" << i << "] is: " << data[i] |
| << "should be: " << (i * 3) << tcu::TestLog::EndMessage; |
| res = ERROR; |
| } |
| } |
| |
| return res; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteBuffers(1, &buffer_); |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicBufferState : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Atomic Counter Buffer - state"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Verify that setting and getting buffer state works as expected for new buffer target."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| virtual long Run() |
| { |
| Buffer buffer; |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer.name()); |
| |
| if (buffer.Verify() != NO_ERROR) |
| return ERROR; |
| |
| buffer.Data(100, NULL, GL_DYNAMIC_COPY); |
| if (buffer.Verify() != NO_ERROR) |
| return ERROR; |
| |
| buffer.MapRange(10, 50, GL_MAP_WRITE_BIT); |
| if (buffer.Verify() != NO_ERROR) |
| return ERROR; |
| buffer.Unmap(); |
| if (buffer.Verify() != NO_ERROR) |
| return ERROR; |
| |
| buffer.Map(GL_READ_ONLY); |
| if (buffer.Verify() != NO_ERROR) |
| return ERROR; |
| buffer.Unmap(); |
| if (buffer.Verify() != NO_ERROR) |
| return ERROR; |
| |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicBufferBind : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Atomic Counter Buffer - binding"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Verify that binding buffer objects to ATOMIC_COUNTER_BUFFER (indexed) target" NL |
| "works as expected. In particualr make sure that binding with BindBufferBase and BindBufferRange" NL |
| "also bind to generic binding point and deleting buffer that is currently bound unbinds it. Tested" NL |
| "commands: BindBuffer, BindBufferBase and BindBufferRange."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint buffer_; |
| |
| virtual long Setup() |
| { |
| buffer_ = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| GLint bindings; |
| glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &bindings); |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: " << bindings << tcu::TestLog::EndMessage; |
| |
| if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, 0)) |
| return ERROR; |
| for (GLint index = 0; index < bindings; ++index) |
| { |
| if (!CheckBufferBindingState(static_cast<GLuint>(index), 0, 0, 0)) |
| return ERROR; |
| } |
| |
| glGenBuffers(1, &buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_); |
| |
| if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLint>(buffer_))) |
| return ERROR; |
| for (GLint index = 0; index < bindings; ++index) |
| { |
| if (!CheckBufferBindingState(static_cast<GLuint>(index), 0, 0, 0)) |
| return ERROR; |
| } |
| |
| long res = NO_ERROR; |
| |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, 1000, NULL, GL_DYNAMIC_COPY); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, buffer_); |
| if (!CheckBufferBindingState(1, static_cast<GLint>(buffer_), 0, 1000)) |
| res = ERROR; |
| if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLint>(buffer_))) |
| res = ERROR; |
| |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings / 2), buffer_); |
| if (!CheckBufferBindingState(static_cast<GLuint>(bindings / 2), static_cast<GLint>(buffer_), 0, 1000)) |
| res = ERROR; |
| |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings - 1), buffer_); |
| if (!CheckBufferBindingState(static_cast<GLuint>(bindings - 1), static_cast<GLint>(buffer_), 0, 1000)) |
| res = ERROR; |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 1, buffer_, 8, 32); |
| if (!CheckBufferBindingState(1, static_cast<GLint>(buffer_), 8, 32)) |
| res = ERROR; |
| if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLint>(buffer_))) |
| res = ERROR; |
| |
| glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings / 2), buffer_, 512, 100); |
| if (!CheckBufferBindingState(static_cast<GLuint>(bindings / 2), static_cast<GLint>(buffer_), 512, 100)) |
| res = ERROR; |
| |
| glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings - 1), buffer_, 12, 128); |
| if (!CheckBufferBindingState(static_cast<GLuint>(bindings - 1), static_cast<GLint>(buffer_), 12, 128)) |
| res = ERROR; |
| |
| glDeleteBuffers(1, &buffer_); |
| buffer_ = 0; |
| |
| GLint i; |
| glGetIntegerv(GL_ATOMIC_COUNTER_BUFFER_BINDING, &i); |
| if (i != 0) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Generic binding point should be 0 after deleting bound buffer object." |
| << tcu::TestLog::EndMessage; |
| res = ERROR; |
| } |
| for (GLint index = 0; index < bindings; ++index) |
| { |
| glGetIntegeri_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLuint>(index), &i); |
| if (i != 0) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Binding point %u should be 0 after deleting bound buffer object." |
| << tcu::TestLog::EndMessage; |
| res = ERROR; |
| } |
| } |
| |
| return res; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteBuffers(1, &buffer_); |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicProgramMax : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Program - max values"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Verify all max values which deal with atomic counter buffers."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| virtual long Run() |
| { |
| if (!CheckMaxValue(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, 1)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, 32)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, 1)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_COMBINED_ATOMIC_COUNTERS, 8)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, 0)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_VERTEX_ATOMIC_COUNTERS, 0)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, 0)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, 0)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, 0)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, 0)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS, 0)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_GEOMETRY_ATOMIC_COUNTERS, 0)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, 1)) |
| return ERROR; |
| if (!CheckMaxValue(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, 8)) |
| return ERROR; |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicProgramQuery : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Program - atomic counters queries"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Get all the information from the program object about atomic counters." NL |
| "Verify that all informations are correct. Tested commands: glGetActiveAtomicCounterBufferiv," NL |
| "GetProgramiv and GetUniform* with new enums."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint counter_buffer_; |
| GLuint vao_, vbo_; |
| GLuint prog_; |
| |
| virtual long Setup() |
| { |
| counter_buffer_ = 0; |
| vao_ = vbo_ = 0; |
| prog_ = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| // create program |
| const char* glsl_vs = "#version 420 core" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL |
| " gl_Position = i_vertex;" NL "}"; |
| const char* glsl_fs = |
| "#version 420 core" NL "layout(location = 0, index = 0) out vec4 o_color;" NL |
| "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter0;" NL |
| "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter1;" NL |
| "layout(binding = 0) uniform atomic_uint ac_counter2;" NL |
| "layout(binding = 0) uniform atomic_uint ac_counter67[2];" NL |
| "layout(binding = 0) uniform atomic_uint ac_counter3;" NL |
| "layout(binding = 0) uniform atomic_uint ac_counter4;" NL |
| "layout(binding = 0) uniform atomic_uint ac_counter5;" NL "void main() {" NL " uint c = 0;" NL |
| " c += atomicCounterIncrement(ac_counter0);" NL " c += atomicCounterIncrement(ac_counter1);" NL |
| " c += atomicCounterIncrement(ac_counter2);" NL " c += atomicCounterIncrement(ac_counter3);" NL |
| " c += atomicCounterIncrement(ac_counter4);" NL " c += atomicCounterIncrement(ac_counter5);" NL |
| " c += atomicCounterIncrement(ac_counter67[0]);" NL " c += atomicCounterIncrement(ac_counter67[1]);" NL |
| " if (c > 10u) o_color = vec4(0.0, 1.0, 0.0, 1.0);" NL " else o_color = vec4(1.0, 0.0, 0.0, 1.0);" NL "}"; |
| |
| prog_ = CreateProgram(glsl_vs, NULL, NULL, NULL, glsl_fs, true); |
| |
| // get active buffers |
| GLuint active_buffers; |
| glGetProgramiv(prog_, GL_ACTIVE_ATOMIC_COUNTER_BUFFERS, reinterpret_cast<GLint*>(&active_buffers)); |
| if (active_buffers != 1) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_ACTIVE_ATOMIC_COUNTER_BUFFERS is " |
| << active_buffers << " should be 1." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| GLint buffers_binding_index; |
| glGetActiveAtomicCounterBufferiv(prog_, 0, GL_ATOMIC_COUNTER_BUFFER_BINDING, &buffers_binding_index); |
| |
| GLint i; |
| glGetActiveAtomicCounterBufferiv(prog_, buffers_binding_index, GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE, &i); |
| if (i < 32) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE is " |
| << i << " should be 32." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetActiveAtomicCounterBufferiv(prog_, buffers_binding_index, GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS, |
| &i); |
| if (i != 7) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS is " << i |
| << " should be 8." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| GLint indices[7] = { -1, -1, -1, -1, -1, -1, -1 }; |
| glGetActiveAtomicCounterBufferiv(prog_, buffers_binding_index, |
| GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES, indices); |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES:" << tcu::TestLog::EndMessage; |
| for (i = 0; i < 7; ++i) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << indices[i] << tcu::TestLog::EndMessage; |
| if (indices[i] == -1) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Index -1 found!" << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| } |
| |
| glGetActiveAtomicCounterBufferiv(prog_, buffers_binding_index, |
| GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER, &i); |
| if (i != GL_FALSE) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER is " << i |
| << " should be 0." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetActiveAtomicCounterBufferiv(prog_, buffers_binding_index, |
| GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER, &i); |
| if (i != GL_FALSE) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER is " << i |
| << " should be 0." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetActiveAtomicCounterBufferiv(prog_, buffers_binding_index, |
| GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER, &i); |
| if (i != GL_FALSE) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER is " << i |
| << " should be 0." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetActiveAtomicCounterBufferiv(prog_, buffers_binding_index, |
| GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER, &i); |
| if (i != GL_FALSE) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER is " << i |
| << " should be 0." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| glGetActiveAtomicCounterBufferiv(prog_, buffers_binding_index, |
| GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER, &i); |
| if (i != GL_TRUE) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER is " << i |
| << " should be 1." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| |
| // get active uniforms |
| std::map<std::string, GLuint> uniforms_name_index; |
| GLuint active_uniforms; |
| glGetProgramiv(prog_, GL_ACTIVE_UNIFORMS, reinterpret_cast<GLint*>(&active_uniforms)); |
| if (active_uniforms != 7) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_ACTIVE_UNIFORMS is " << active_uniforms |
| << " should be 8." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| for (GLuint index = 0; index < active_uniforms; ++index) |
| { |
| GLchar name[32]; |
| glGetActiveUniformName(prog_, index, sizeof(name), NULL, name); |
| uniforms_name_index.insert(std::make_pair(name, index)); |
| } |
| |
| if (!CheckUniform(prog_, "ac_counter0", uniforms_name_index["ac_counter0"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1, |
| 0, 0, buffers_binding_index)) |
| return ERROR; |
| if (!CheckUniform(prog_, "ac_counter1", uniforms_name_index["ac_counter1"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1, |
| 4, 0, buffers_binding_index)) |
| return ERROR; |
| if (!CheckUniform(prog_, "ac_counter2", uniforms_name_index["ac_counter2"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1, |
| 8, 0, buffers_binding_index)) |
| return ERROR; |
| if (!CheckUniform(prog_, "ac_counter3", uniforms_name_index["ac_counter3"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1, |
| 20, 0, buffers_binding_index)) |
| return ERROR; |
| if (!CheckUniform(prog_, "ac_counter4", uniforms_name_index["ac_counter4"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1, |
| 24, 0, buffers_binding_index)) |
| return ERROR; |
| if (!CheckUniform(prog_, "ac_counter5", uniforms_name_index["ac_counter5"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1, |
| 28, 0, buffers_binding_index)) |
| return ERROR; |
| if (!CheckUniform(prog_, "ac_counter67[0]", uniforms_name_index["ac_counter67[0]"], |
| GL_UNSIGNED_INT_ATOMIC_COUNTER, 2, 12, 4, buffers_binding_index)) |
| return ERROR; |
| |
| // create atomic counter buffer |
| glGenBuffers(1, &counter_buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| const unsigned int data[7] = { 20, 20, 20, 20, 20, 20, 20 }; |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| // create geometry |
| CreateQuad(&vao_, &vbo_, NULL); |
| |
| // draw |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_); |
| glUseProgram(prog_); |
| glBindVertexArray(vao_); |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| |
| if (ValidateReadBuffer(Vec4(0, 1, 0, 1)) != NO_ERROR) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Render target color should be (0.0, 1.0, 0.0, 1.0)." |
| << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteBuffers(1, &counter_buffer_); |
| glDeleteVertexArrays(1, &vao_); |
| glDeleteBuffers(1, &vbo_); |
| glDeleteProgram(prog_); |
| glUseProgram(0); |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicUsageSimple : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Simple Use Case"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Verify that simple usage of atomic counters work as expected." NL |
| "In FS value returned from atomicCounterIncrement is converted to color."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint counter_buffer_; |
| GLuint vao_, vbo_; |
| GLuint prog_; |
| |
| virtual long Setup() |
| { |
| counter_buffer_ = 0; |
| vao_ = vbo_ = 0; |
| prog_ = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| // create program |
| const char* src_vs = "#version 420 core" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL |
| " gl_Position = i_vertex;" NL "}"; |
| const char* src_fs = "#version 420 core" NL "layout(location = 0) out vec4 o_color;" NL |
| "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter;" NL "void main() {" NL |
| " uint c = atomicCounterIncrement(ac_counter);" NL |
| " float r = float(c / 40u) / 255.0;" NL " o_color = vec4(r, 0.0, 0.0, 1.0);" NL "}"; |
| prog_ = CreateProgram(src_vs, NULL, NULL, NULL, src_fs, true); |
| |
| // create atomic counter buffer |
| glGenBuffers(1, &counter_buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, NULL, GL_DYNAMIC_COPY); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| // create geometry |
| CreateQuad(&vao_, &vbo_, NULL); |
| |
| // clear counter buffer (set to 0) |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| unsigned int* ptr = static_cast<unsigned int*>( |
| glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)); |
| *ptr = 0; |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| |
| // draw |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_); |
| glUseProgram(prog_); |
| glBindVertexArray(vao_); |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| |
| ValidateReadBuffer(Vec4(1, 0, 0, 1)); |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteBuffers(1, &counter_buffer_); |
| glDeleteVertexArrays(1, &vao_); |
| glDeleteBuffers(1, &vbo_); |
| glDeleteProgram(prog_); |
| glUseProgram(0); |
| |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicUsageFS : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Atomic Counters usage in the Fragment Shader stage"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Verify that atomic counters work as expected in the Fragment Shader stage." NL |
| "In particular make sure that values returned by GLSL built-in functions" NL |
| "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL |
| "Also make sure that the final values in atomic counter buffer objects are as expected."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint counter_buffer_; |
| GLuint vao_, vbo_; |
| GLuint prog_; |
| GLuint fbo_, rt_[2]; |
| |
| virtual long Setup() |
| { |
| counter_buffer_ = 0; |
| vao_ = vbo_ = 0; |
| prog_ = 0; |
| fbo_ = rt_[0] = rt_[1] = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| // create program |
| const char* src_vs = "#version 420 core" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL |
| " gl_Position = i_vertex;" NL "}"; |
| |
| const char* src_fs = "#version 420 core" NL "layout(location = 0) out uvec4 o_color[2];" NL |
| "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL |
| "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL |
| " o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL |
| " o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}"; |
| prog_ = CreateProgram(src_vs, NULL, NULL, NULL, src_fs, true); |
| |
| // create atomic counter buffer |
| glGenBuffers(1, &counter_buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| // create render targets |
| const int s = 8; |
| glGenTextures(2, rt_); |
| |
| for (int i = 0; i < 2; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, rt_[i]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| } |
| |
| // create fbo |
| glGenFramebuffers(1, &fbo_); |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt_[0], 0); |
| glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, rt_[1], 0); |
| const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; |
| glDrawBuffers(2, draw_buffers); |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| // create geometry |
| CreateQuad(&vao_, &vbo_, NULL); |
| |
| // init counter buffer |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| unsigned int* ptr = static_cast<unsigned int*>( |
| glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)); |
| *ptr++ = 0; |
| *ptr++ = 80; |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| |
| // draw |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| glViewport(0, 0, s, s); |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_); |
| glUseProgram(prog_); |
| glBindVertexArray(vao_); |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| |
| // validate |
| GLuint data[s * s]; |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| if (!CheckCounterValues(s * s, data, 0)) |
| return ERROR; |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| if (!CheckCounterValues(s * s, data, 16)) |
| return ERROR; |
| |
| if (!CheckFinalCounterValue(counter_buffer_, 0, 64)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 4, 16)) |
| return ERROR; |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteFramebuffers(1, &fbo_); |
| glDeleteTextures(2, rt_); |
| glViewport(0, 0, getWindowWidth(), getWindowHeight()); |
| glDeleteBuffers(1, &counter_buffer_); |
| glDeleteVertexArrays(1, &vao_); |
| glDeleteBuffers(1, &vbo_); |
| glDeleteProgram(prog_); |
| glUseProgram(0); |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicUsageVS : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Atomic Counters usage in the Vertex Shader stage"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Verify that atomic counters work as expected in the Vertex Shader stage." NL |
| "In particular make sure that values returned by GLSL built-in functions" NL |
| "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL |
| "Also make sure that the final values in atomic counter buffer objects are as expected."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint counter_buffer_[2]; |
| GLuint xfb_buffer_[2]; |
| GLuint array_buffer_; |
| GLuint vao_; |
| GLuint prog_; |
| |
| virtual long Setup() |
| { |
| counter_buffer_[0] = counter_buffer_[1] = 0; |
| xfb_buffer_[0] = xfb_buffer_[1] = 0; |
| array_buffer_ = 0; |
| vao_ = 0; |
| prog_ = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| |
| GLint p1, p2; |
| glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1); |
| glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2); |
| if (p1 < 2 || p2 < 2) |
| { |
| return NO_ERROR; |
| } |
| |
| // create program |
| const char* src_vs = |
| "#version 420 core" NL "layout(location = 0) in uint i_zero;" NL "out uint o_atomic_inc;" NL |
| "out uint o_atomic_dec;" NL "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL |
| "layout(binding = 1, offset = 0) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL |
| " o_atomic_inc = i_zero + atomicCounterIncrement(ac_counter_inc);" NL |
| " o_atomic_dec = i_zero + atomicCounterDecrement(ac_counter_dec);" NL "}"; |
| prog_ = CreateProgram(src_vs, NULL, NULL, NULL, NULL, false); |
| const char* xfb_var[2] = { "o_atomic_inc", "o_atomic_dec" }; |
| glTransformFeedbackVaryings(prog_, 2, xfb_var, GL_SEPARATE_ATTRIBS); |
| LinkProgram(prog_); |
| |
| // create array buffer |
| const unsigned int array_buffer_data[32] = { 0 }; |
| glGenBuffers(1, &array_buffer_); |
| glBindBuffer(GL_ARRAY_BUFFER, array_buffer_); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(array_buffer_data), array_buffer_data, GL_STATIC_DRAW); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| // create atomic counter buffers |
| glGenBuffers(2, counter_buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[0]); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, NULL, GL_DYNAMIC_COPY); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[1]); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, NULL, GL_DYNAMIC_COPY); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| // create transform feedback buffers |
| glGenBuffers(2, xfb_buffer_); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]); |
| glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]); |
| glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); |
| |
| // init counter buffers |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[0]); |
| unsigned int* ptr = static_cast<unsigned int*>( |
| glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)); |
| *ptr = 7; |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[1]); |
| ptr = static_cast<unsigned int*>( |
| glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)); |
| *ptr = 77; |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| |
| // create vertex array object |
| glGenVertexArrays(1, &vao_); |
| glBindVertexArray(vao_); |
| glBindBuffer(GL_ARRAY_BUFFER, array_buffer_); |
| glVertexAttribIPointer(0, 1, GL_UNSIGNED_INT, 0, 0); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| glEnableVertexAttribArray(0); |
| glBindVertexArray(0); |
| |
| // draw |
| glEnable(GL_RASTERIZER_DISCARD); |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_[0]); |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, counter_buffer_[1]); |
| glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_[0]); |
| glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, xfb_buffer_[1]); |
| glUseProgram(prog_); |
| glBindVertexArray(vao_); |
| glBeginTransformFeedback(GL_POINTS); |
| glDrawArrays(GL_POINTS, 0, 32); |
| glEndTransformFeedback(); |
| glDisable(GL_RASTERIZER_DISCARD); |
| |
| // validate |
| GLuint data[32]; |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]); |
| glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), data); |
| if (!CheckCounterValues(32, data, 7)) |
| return ERROR; |
| |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]); |
| glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), data); |
| if (!CheckCounterValues(32, data, 45)) |
| return ERROR; |
| |
| if (!CheckFinalCounterValue(counter_buffer_[0], 0, 39)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_[1], 0, 45)) |
| return ERROR; |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteBuffers(2, counter_buffer_); |
| glDeleteBuffers(2, xfb_buffer_); |
| glDeleteBuffers(1, &array_buffer_); |
| glDeleteVertexArrays(1, &vao_); |
| glDeleteProgram(prog_); |
| glUseProgram(0); |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicUsageGS : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Atomic Counters usage in the Geometry Shader stage"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Verify that atomic counters work as expected in the Geometry Shader stage." NL |
| "In particular make sure that values returned by GLSL built-in functions" NL |
| "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL |
| "Also make sure that the final values in atomic counter buffer objects are as expected."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint counter_buffer_; |
| GLuint xfb_buffer_[2]; |
| GLuint array_buffer_; |
| GLuint vao_; |
| GLuint prog_; |
| |
| virtual long Setup() |
| { |
| counter_buffer_ = 0; |
| xfb_buffer_[0] = xfb_buffer_[1] = 0; |
| array_buffer_ = 0; |
| vao_ = 0; |
| prog_ = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| |
| GLint p1, p2; |
| glGetIntegerv(GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS, &p1); |
| glGetIntegerv(GL_MAX_GEOMETRY_ATOMIC_COUNTERS, &p2); |
| if (p1 < 1 || p2 < 2) |
| { |
| return NO_ERROR; |
| } |
| |
| // create program |
| const char* glsl_vs = "#version 420 core" NL "layout(location = 0) in uint i_zero;" NL "out uint vs_zero;" NL |
| "void main() {" NL " vs_zero = i_zero;" NL "}"; |
| const char* glsl_gs = |
| "#version 420 core" NL "layout(points) in;" NL "in uint vs_zero[];" NL |
| "layout(points, max_vertices = 1) out;" NL "out uint o_atomic_inc;" NL "out uint o_atomic_dec;" NL |
| "layout(binding = 0, offset = 8) uniform atomic_uint ac_counter_inc;" NL |
| "layout(binding = 0, offset = 16) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL |
| " o_atomic_inc = vs_zero[0] + atomicCounterIncrement(ac_counter_inc);" NL |
| " o_atomic_dec = vs_zero[0] + atomicCounterDecrement(ac_counter_dec);" NL " EmitVertex();" NL "}"; |
| prog_ = CreateProgram(glsl_vs, NULL, NULL, glsl_gs, NULL, false); |
| const char* xfb_var[2] = { "o_atomic_inc", "o_atomic_dec" }; |
| glTransformFeedbackVaryings(prog_, 2, xfb_var, GL_SEPARATE_ATTRIBS); |
| LinkProgram(prog_); |
| |
| // create array buffer |
| const unsigned int array_buffer_data[32] = { 0 }; |
| glGenBuffers(1, &array_buffer_); |
| glBindBuffer(GL_ARRAY_BUFFER, array_buffer_); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(array_buffer_data), array_buffer_data, GL_STATIC_DRAW); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| // create atomic counter buffer |
| glGenBuffers(1, &counter_buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, 32, NULL, GL_DYNAMIC_COPY); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| // create transform feedback buffers |
| glGenBuffers(2, xfb_buffer_); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]); |
| glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]); |
| glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); |
| |
| // create vertex array object |
| glGenVertexArrays(1, &vao_); |
| glBindVertexArray(vao_); |
| glBindBuffer(GL_ARRAY_BUFFER, array_buffer_); |
| glVertexAttribIPointer(0, 1, GL_UNSIGNED_INT, 0, 0); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| glEnableVertexAttribArray(0); |
| glBindVertexArray(0); |
| |
| // init counter buffer |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| unsigned int* ptr = static_cast<unsigned int*>( |
| glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)); |
| *(ptr + 2) = 17; |
| *(ptr + 4) = 100; |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| |
| // draw |
| glEnable(GL_RASTERIZER_DISCARD); |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_); |
| glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_[0]); |
| glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, xfb_buffer_[1]); |
| glUseProgram(prog_); |
| glBindVertexArray(vao_); |
| glBeginTransformFeedback(GL_POINTS); |
| glDrawArrays(GL_POINTS, 0, 32); |
| glEndTransformFeedback(); |
| glDisable(GL_RASTERIZER_DISCARD); |
| |
| // validate |
| GLuint data[32]; |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]); |
| glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), data); |
| if (!CheckCounterValues(32, data, 17)) |
| return ERROR; |
| |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]); |
| glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), data); |
| if (!CheckCounterValues(32, data, 68)) |
| return ERROR; |
| |
| if (!CheckFinalCounterValue(counter_buffer_, 8, 49)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 16, 68)) |
| return ERROR; |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteBuffers(1, &counter_buffer_); |
| glDeleteBuffers(2, xfb_buffer_); |
| glDeleteBuffers(1, &array_buffer_); |
| glDeleteVertexArrays(1, &vao_); |
| glDeleteProgram(prog_); |
| glUseProgram(0); |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicUsageTES : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Atomic Counters usage in the Tessellation Evaluation Shader stage"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Verify that atomic counters work as expected in the Tessellation Evaluation Shader stage." NL |
| "In particular make sure that values returned by GLSL built-in functions" NL |
| "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL |
| "Also make sure that the final values in atomic counter buffer objects are as expected."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint counter_buffer_; |
| GLuint xfb_buffer_[2]; |
| GLuint array_buffer_; |
| GLuint vao_; |
| GLuint prog_; |
| |
| virtual long Setup() |
| { |
| counter_buffer_ = 0; |
| xfb_buffer_[0] = xfb_buffer_[1] = 0; |
| array_buffer_ = 0; |
| vao_ = 0; |
| prog_ = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| |
| GLint p1, p2; |
| glGetIntegerv(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, &p1); |
| glGetIntegerv(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, &p2); |
| if (p1 < 1 || p2 < 1) |
| { |
| return NO_ERROR; |
| } |
| |
| const char* glsl_vs = "#version 420 core" NL "layout(location = 0) in uint i_zero;" NL "out uint vs_zero;" NL |
| "void main() {" NL " vs_zero = i_zero;" NL "}"; |
| const char* glsl_tes = |
| "#version 420 core" NL "layout(triangles, equal_spacing, ccw) in;" NL "in uint vs_zero[];" NL |
| "out uint o_atomic_inc;" NL "out uint o_atomic_dec;" NL |
| "layout(binding = 0, offset = 128) uniform atomic_uint ac_counter[2];" NL "void main() {" NL |
| " o_atomic_inc = vs_zero[0] + vs_zero[31] + atomicCounterIncrement(ac_counter[0]);" NL |
| " o_atomic_dec = vs_zero[0] + vs_zero[31] + atomicCounterDecrement(ac_counter[1]);" NL "}"; |
| // programs |
| prog_ = CreateProgram(glsl_vs, NULL, glsl_tes, NULL, NULL, false); |
| const char* xfb_var[2] = { "o_atomic_inc", "o_atomic_dec" }; |
| glTransformFeedbackVaryings(prog_, 2, xfb_var, GL_SEPARATE_ATTRIBS); |
| LinkProgram(prog_); |
| |
| // create array buffer |
| const unsigned int array_buffer_data[32] = { 0 }; |
| glGenBuffers(1, &array_buffer_); |
| glBindBuffer(GL_ARRAY_BUFFER, array_buffer_); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(array_buffer_data), array_buffer_data, GL_STATIC_DRAW); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| |
| // create atomic counter buffer |
| glGenBuffers(1, &counter_buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, 200, NULL, GL_DYNAMIC_READ); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| // create transform feedback buffers |
| glGenBuffers(2, xfb_buffer_); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]); |
| glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]); |
| glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); |
| |
| // create vertex array object |
| glGenVertexArrays(1, &vao_); |
| glBindVertexArray(vao_); |
| glBindBuffer(GL_ARRAY_BUFFER, array_buffer_); |
| glVertexAttribIPointer(0, 1, GL_UNSIGNED_INT, 0, 0); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| glEnableVertexAttribArray(0); |
| glBindVertexArray(0); |
| |
| // init counter buffer |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| unsigned int* ptr = static_cast<unsigned int*>( |
| glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 180, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)); |
| *(ptr + 32) = 100000; |
| *(ptr + 33) = 111; |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| |
| // draw |
| glEnable(GL_RASTERIZER_DISCARD); |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_); |
| glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_[0]); |
| glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, xfb_buffer_[1]); |
| glUseProgram(prog_); |
| glBindVertexArray(vao_); |
| glPatchParameteri(GL_PATCH_VERTICES, 32); |
| glBeginTransformFeedback(GL_TRIANGLES); |
| glDrawArrays(GL_PATCHES, 0, 32); |
| glEndTransformFeedback(); |
| glPatchParameteri(GL_PATCH_VERTICES, 3); |
| glDisable(GL_RASTERIZER_DISCARD); |
| |
| // validate |
| GLuint data[3]; |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]); |
| glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), data); |
| if (!CheckCounterValues(3, data, 100000)) |
| return ERROR; |
| |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]); |
| glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), data); |
| if (!CheckCounterValues(3, data, 108)) |
| return ERROR; |
| |
| if (!CheckFinalCounterValue(counter_buffer_, 128, 100003)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 132, 108)) |
| return ERROR; |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteBuffers(1, &counter_buffer_); |
| glDeleteBuffers(2, xfb_buffer_); |
| glDeleteBuffers(1, &array_buffer_); |
| glDeleteVertexArrays(1, &vao_); |
| glDeleteProgram(prog_); |
| glUseProgram(0); |
| return NO_ERROR; |
| } |
| }; |
| |
| class AdvancedUsageMultiStage : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Same atomic counter accessed from multiple shader stages"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Same atomic counter is incremented (decremented) from two shader stages (VS and FS)." NL |
| "Verify that this scenario works as expected. In particular ensure that all generated values are " |
| "unique and" NL "final value in atomic counter buffer objects are as expected."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint counter_buffer_; |
| GLuint xfb_buffer_[2]; |
| GLuint vao_, vbo_; |
| GLuint prog_; |
| GLuint fbo_, rt_[2]; |
| |
| virtual long Setup() |
| { |
| counter_buffer_ = 0; |
| xfb_buffer_[0] = xfb_buffer_[1] = 0; |
| vao_ = vbo_ = 0; |
| prog_ = 0; |
| fbo_ = rt_[0] = rt_[1] = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| |
| GLint p1, p2, p3; |
| glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1); |
| glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2); |
| glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p3); |
| if (p1 < 8 || p2 < 2 || p3 < 8) |
| { |
| return NO_ERROR; |
| } |
| |
| // create program |
| const char* src_vs = |
| "#version 420 core" NL "layout(location = 0) in vec4 i_vertex;" NL "out uint o_atomic_inc;" NL |
| "out uint o_atomic_dec;" NL "layout(binding = 1, offset = 16) uniform atomic_uint ac_counter_inc;" NL |
| "layout(binding = 7, offset = 128) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL |
| " gl_Position = i_vertex;" NL " o_atomic_inc = atomicCounterIncrement(ac_counter_inc);" NL |
| " o_atomic_dec = atomicCounterDecrement(ac_counter_dec);" NL "}"; |
| const char* src_fs = "#version 420 core" NL "layout(location = 0) out uvec4 o_color[2];" NL |
| "layout(binding = 1, offset = 16) uniform atomic_uint ac_counter_inc;" NL |
| "layout(binding = 7, offset = 128) uniform atomic_uint ac_counter_dec;" NL |
| "void main() {" NL " o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL |
| " o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}"; |
| prog_ = CreateProgram(src_vs, NULL, NULL, NULL, src_fs, false); |
| const char* xfb_var[2] = { "o_atomic_inc", "o_atomic_dec" }; |
| glTransformFeedbackVaryings(prog_, 2, xfb_var, GL_SEPARATE_ATTRIBS); |
| LinkProgram(prog_); |
| |
| // create atomic counter buffer |
| std::vector<GLuint> init_data(256, 100); |
| glGenBuffers(1, &counter_buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, (GLsizeiptr)(init_data.size() * sizeof(GLuint)), &init_data[0], |
| GL_DYNAMIC_COPY); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| // create transform feedback buffers |
| glGenBuffers(2, xfb_buffer_); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]); |
| glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]); |
| glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); |
| |
| // create render targets |
| const int s = 8; |
| glGenTextures(2, rt_); |
| for (int i = 0; i < 2; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, rt_[i]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| } |
| |
| // create fbo |
| glGenFramebuffers(1, &fbo_); |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt_[0], 0); |
| glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, rt_[1], 0); |
| const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; |
| glDrawBuffers(2, draw_buffers); |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| // create geometry |
| CreateTriangle(&vao_, &vbo_, NULL); |
| |
| // draw |
| glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 1, counter_buffer_, 16, 32); |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 7, counter_buffer_); |
| glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_[0]); |
| glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, xfb_buffer_[1]); |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| glViewport(0, 0, s, s); |
| glUseProgram(prog_); |
| glBindVertexArray(vao_); |
| glBeginTransformFeedback(GL_TRIANGLES); |
| glDrawArrays(GL_TRIANGLES, 0, 3); |
| glEndTransformFeedback(); |
| |
| // validate |
| GLuint data[s * s + 3]; |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]); |
| glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 3 * sizeof(GLuint), &data[s * s]); |
| if (!CheckCounterValues(s * s + 3, data, 100)) |
| return ERROR; |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]); |
| glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 3 * sizeof(GLuint), &data[s * s]); |
| if (!CheckCounterValues(s * s + 3, data, 33)) |
| return ERROR; |
| |
| if (!CheckFinalCounterValue(counter_buffer_, 32, 167)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 128, 33)) |
| return ERROR; |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteFramebuffers(1, &fbo_); |
| glDeleteTextures(2, rt_); |
| glViewport(0, 0, getWindowWidth(), getWindowHeight()); |
| glDeleteBuffers(1, &counter_buffer_); |
| glDeleteBuffers(2, xfb_buffer_); |
| glDeleteVertexArrays(1, &vao_); |
| glDeleteBuffers(1, &vbo_); |
| glDeleteProgram(prog_); |
| glUseProgram(0); |
| return NO_ERROR; |
| } |
| }; |
| |
| class AdvancedUsageDrawUpdateDraw : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Update via Draw Call and update via MapBufferRange"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "1. Create atomic counter buffers and init them with start values." NL |
| "2. Increment (decrement) buffer values in the shader." NL |
| "3. Map buffers with MapBufferRange command. Increment (decrement) buffer values manually." NL |
| "4. Unmap buffers with UnmapBuffer command." NL |
| "5. Again increment (decrement) buffer values in the shader." NL |
| "Verify that this scenario works as expected and final values in the buffer objects are correct."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint counter_buffer_; |
| GLuint vao_, vbo_; |
| GLuint prog_, prog2_; |
| GLuint fbo_, rt_[2]; |
| |
| virtual long Setup() |
| { |
| counter_buffer_ = 0; |
| vao_ = vbo_ = 0; |
| prog_ = 0; |
| fbo_ = rt_[0] = rt_[1] = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| // create program |
| const char* src_vs = "#version 420 core" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL |
| " gl_Position = i_vertex;" NL "}"; |
| const char* src_fs = "#version 420 core" NL "layout(location = 0) out uvec4 o_color[2];" NL |
| "layout(binding = 0) uniform atomic_uint ac_counter[2];" NL "void main() {" NL |
| " o_color[0] = uvec4(atomicCounterIncrement(ac_counter[0]));" NL |
| " o_color[1] = uvec4(atomicCounterDecrement(ac_counter[1]));" NL "}"; |
| const char* src_fs2 = "#version 420 core" NL "layout(location = 0) out uvec4 o_color[2];" NL |
| "layout(binding = 0) uniform atomic_uint ac_counter[2];" NL "void main() {" NL |
| " o_color[0] = uvec4(atomicCounter(ac_counter[0]));" NL |
| " o_color[1] = uvec4(atomicCounter(ac_counter[1]));" NL "}"; |
| prog_ = CreateProgram(src_vs, NULL, NULL, NULL, src_fs, true); |
| prog2_ = CreateProgram(src_vs, NULL, NULL, NULL, src_fs2, true); |
| |
| // create atomic counter buffer |
| glGenBuffers(1, &counter_buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| // create render targets |
| const int s = 8; |
| glGenTextures(2, rt_); |
| |
| for (int i = 0; i < 2; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, rt_[i]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| } |
| |
| // create fbo |
| glGenFramebuffers(1, &fbo_); |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt_[0], 0); |
| glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, rt_[1], 0); |
| const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; |
| glDrawBuffers(2, draw_buffers); |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| // create geometry |
| CreateQuad(&vao_, &vbo_, NULL); |
| |
| // init counter buffer |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| unsigned int* ptr = static_cast<unsigned int*>( |
| glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)); |
| *ptr++ = 256; |
| *ptr++ = 256; |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| |
| // draw |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| glViewport(0, 0, s, s); |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_); |
| glUseProgram(prog_); |
| glBindVertexArray(vao_); |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| |
| // update counter buffer |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| ptr = static_cast<unsigned int*>( |
| glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_READ_BIT)); |
| *ptr++ += 512; |
| *ptr++ += 1024; |
| glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); |
| |
| // draw |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT); |
| |
| // draw |
| glUseProgram(prog2_); |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| |
| // validate |
| GLuint data[s * s]; |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| for (int i = 0; i < s * s; ++i) |
| { |
| if (data[i] != 896) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Counter value is " << data[i] |
| << " should be 896." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| } |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| for (int i = 0; i < s * s; ++i) |
| { |
| if (data[i] != 1152) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Counter value is " << data[i] |
| << " should be 896." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| } |
| |
| if (!CheckFinalCounterValue(counter_buffer_, 0, 896)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 4, 1152)) |
| return ERROR; |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteFramebuffers(1, &fbo_); |
| glDeleteTextures(2, rt_); |
| glViewport(0, 0, getWindowWidth(), getWindowHeight()); |
| glDeleteBuffers(1, &counter_buffer_); |
| glDeleteVertexArrays(1, &vao_); |
| glDeleteBuffers(1, &vbo_); |
| glDeleteProgram(prog_); |
| glDeleteProgram(prog2_); |
| glUseProgram(0); |
| return NO_ERROR; |
| } |
| }; |
| |
| class AdvancedUsageManyCounters : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Large atomic counters array indexed with uniforms"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Verify that large atomic counters array works as expected when indexed with dynamically uniform " |
| "expressions." NL |
| "Built-ins tested: atomicCounterIncrement, atomicCounterDecrement and atomicCounter."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint counter_buffer_; |
| GLuint vao_, vbo_; |
| GLuint prog_; |
| GLuint fbo_, rt_[8]; |
| |
| virtual long Setup() |
| { |
| counter_buffer_ = 0; |
| vao_ = vbo_ = 0; |
| prog_ = 0; |
| fbo_ = 0; |
| memset(rt_, 0, sizeof(rt_)); |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| // create program |
| const char* src_vs = "#version 420 core" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL |
| " gl_Position = i_vertex;" NL "}"; |
| const char* src_fs = |
| "#version 420 core" NL "layout(location = 0) out uvec4 o_color[8];" NL |
| "uniform int u_active_counters[8];" NL "layout(binding = 0) uniform atomic_uint ac_counter[8];" NL |
| "void main() {" NL " o_color[0] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[0]]));" NL |
| " o_color[1] = uvec4(atomicCounterDecrement(ac_counter[u_active_counters[1]]));" NL |
| " o_color[2] = uvec4(atomicCounter(ac_counter[u_active_counters[2]]));" NL |
| " o_color[3] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[3]]));" NL |
| " o_color[4] = uvec4(atomicCounterDecrement(ac_counter[u_active_counters[4]]));" NL |
| " o_color[5] = uvec4(atomicCounter(ac_counter[u_active_counters[5]]));" NL |
| " o_color[6] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[6]]));" NL |
| " o_color[7] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[7]]));" NL "}"; |
| prog_ = CreateProgram(src_vs, NULL, NULL, NULL, src_fs, true); |
| |
| // create atomic counter buffer |
| std::vector<GLuint> init_data(8, 1000); |
| glGenBuffers(1, &counter_buffer_); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, 32, &init_data[0], GL_DYNAMIC_COPY); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| // create render targets |
| const int s = 8; |
| glGenTextures(8, rt_); |
| |
| for (int i = 0; i < 8; ++i) |
| { |
| glBindTexture(GL_TEXTURE_2D, rt_[i]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| } |
| |
| // create fbo |
| glGenFramebuffers(1, &fbo_); |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| GLenum draw_buffers[8]; |
| for (int i = 0; i < 8; ++i) |
| { |
| glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, rt_[i], 0); |
| draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i; |
| }; |
| glDrawBuffers(8, draw_buffers); |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| // create geometry |
| CreateTriangle(&vao_, &vbo_, NULL); |
| |
| // set uniforms |
| glUseProgram(prog_); |
| glUniform1i(glGetUniformLocation(prog_, "u_active_counters[0]"), 5); |
| glUniform1i(glGetUniformLocation(prog_, "u_active_counters[1]"), 2); |
| glUniform1i(glGetUniformLocation(prog_, "u_active_counters[2]"), 7); |
| glUniform1i(glGetUniformLocation(prog_, "u_active_counters[3]"), 3); |
| glUniform1i(glGetUniformLocation(prog_, "u_active_counters[4]"), 0); |
| glUniform1i(glGetUniformLocation(prog_, "u_active_counters[5]"), 4); |
| glUniform1i(glGetUniformLocation(prog_, "u_active_counters[6]"), 6); |
| glUniform1i(glGetUniformLocation(prog_, "u_active_counters[7]"), 1); |
| |
| // draw |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| glViewport(0, 0, s, s); |
| glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_); |
| glBindVertexArray(vao_); |
| glDrawArrays(GL_TRIANGLES, 0, 3); |
| |
| // validate |
| GLuint data[s * s]; |
| glReadBuffer(GL_COLOR_ATTACHMENT0); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| if (!CheckCounterValues(s * s, data, 1000)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 20, 1064)) |
| return ERROR; |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT1); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| if (!CheckCounterValues(s * s, data, 1000 - 64)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 8, 1000 - 64)) |
| return ERROR; |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT2); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| for (int i = 0; i < s * s; ++i) |
| if (data[i] != 1000) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 28, 1000)) |
| return ERROR; |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT3); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| if (!CheckCounterValues(s * s, data, 1000)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 12, 1064)) |
| return ERROR; |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT4); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| if (!CheckCounterValues(s * s, data, 1000 - 64)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 0, 1000 - 64)) |
| return ERROR; |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT5); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| for (int i = 0; i < s * s; ++i) |
| if (data[i] != 1000) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 16, 1000)) |
| return ERROR; |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT6); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| if (!CheckCounterValues(s * s, data, 1000)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 24, 1064)) |
| return ERROR; |
| |
| glReadBuffer(GL_COLOR_ATTACHMENT7); |
| glReadPixels(0, 0, s, s, GL_RED_INTEGER, GL_UNSIGNED_INT, data); |
| if (!CheckCounterValues(s * s, data, 1000)) |
| return ERROR; |
| if (!CheckFinalCounterValue(counter_buffer_, 4, 1064)) |
| return ERROR; |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteFramebuffers(1, &fbo_); |
| glDeleteTextures(8, rt_); |
| glViewport(0, 0, getWindowWidth(), getWindowHeight()); |
| glDeleteBuffers(1, &counter_buffer_); |
| glDeleteVertexArrays(1, &vao_); |
| glDeleteBuffers(1, &vbo_); |
| glDeleteProgram(prog_); |
| glUseProgram(0); |
| return NO_ERROR; |
| } |
| }; |
| |
| class AdvancedUsageSwitchPrograms : public SACSubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return NL "Switching several program objects with different atomic counters with different bindings"; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return NL "Verify that each program upadate atomic counter buffer object in appropriate binding point."; |
| } |
| |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| |
| GLuint counter_buffer_[8]; |
| GLuint xfb_buffer_; |
| GLuint vao_, vbo_; |
| GLuint prog_[8]; |
| GLuint fbo_, rt_; |
| |
| std::string GenVSSrc(int binding, int offset) |
| { |
| std::ostringstream os; |
| os << "#version 420 core" NL "layout(location = 0) in vec4 i_vertex;" NL "out uvec4 o_atomic_value;" NL |
| "layout(binding = " |
| << binding << ", offset = " << offset |
| << ") uniform atomic_uint ac_counter_vs;" NL "void main() {" NL " gl_Position = i_vertex;" NL |
| " o_atomic_value = uvec4(atomicCounterIncrement(ac_counter_vs));" NL "}"; |
| return os.str(); |
| } |
| std::string GenFSSrc(int binding, int offset) |
| { |
| std::ostringstream os; |
| os << "#version 420 core" NL "layout(location = 0) out uvec4 o_color;" NL "layout(binding = " << binding |
| << ", offset = " << offset << ") uniform atomic_uint ac_counter_fs;" NL "void main() {" NL |
| " o_color = uvec4(atomicCounterIncrement(ac_counter_fs));" NL "}"; |
| return os.str(); |
| } |
| |
| virtual long Setup() |
| { |
| memset(counter_buffer_, 0, sizeof(counter_buffer_)); |
| xfb_buffer_ = 0; |
| vao_ = vbo_ = 0; |
| memset(prog_, 0, sizeof(prog_)); |
| fbo_ = rt_ = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| |
| GLint p1, p2, p3; |
| glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1); |
| glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2); |
| glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p3); |
| if (p1 < 8 || p2 < 1 || p3 < 8) |
| { |
| return NO_ERROR; |
| } |
| |
| // create programs |
| for (int i = 0; i < 8; ++i) |
| { |
| std::string vs_str = GenVSSrc(i, i * 8); |
| std::string fs_str = GenFSSrc(7 - i, 128 + i * 16); |
| const char* src_vs = vs_str.c_str(); |
| const char* src_fs = fs_str.c_str(); |
| prog_[i] = CreateProgram(src_vs, NULL, NULL, NULL, src_fs, false); |
| const char* xfb_var = "o_atomic_value"; |
| glTransformFeedbackVaryings(prog_[i], 1, &xfb_var, GL_SEPARATE_ATTRIBS); |
| LinkProgram(prog_[i]); |
| } |
| |
| // create atomic counter buffers |
| glGenBuffers(8, counter_buffer_); |
| for (int i = 0; i < 8; ++i) |
| { |
| std::vector<GLuint> init_data(256); |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[i]); |
| glBufferData(GL_ATOMIC_COUNTER_BUFFER, (GLsizeiptr)(init_data.size() * sizeof(GLuint)), &init_data[0], |
| GL_DYNAMIC_COPY); |
| } |
| glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0); |
| |
| // create transform feedback buffer |
| glGenBuffers(1, &xfb_buffer_); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_); |
| glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); |
| |
| // create render target |
| const int s = 8; |
| glGenTextures(1, &rt_); |
| glBindTexture(GL_TEXTURE_2D, rt_); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, |