/*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2015-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 */ /*-------------------------------------------------------------------*/ /** * \file gl4cMapBufferAlignmentTests.cpp * \brief Implements conformance tests for "Map Buffer Alignment" functionality. */ /*-------------------------------------------------------------------*/ #include "gl4cMapBufferAlignmentTests.hpp" #include "gluDefs.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include #include using namespace glw; namespace gl4cts { namespace MapBufferAlignment { /** Implementation of Query test, description follows: * * Verify that GetInteger returns at least 64 when MIN_MAP_BUFFER_ALIGNEMENT is * requested. **/ class Query : public deqp::TestCase { public: /* Public methods */ Query(deqp::Context& context) : TestCase(context, "query", "Verifies value of MIN_MAP_BUFFER_ALIGNEMENT") { /* Nothing to be done */ } virtual ~Query() { /* Nothing to be done */ } /** Execute test * * @return tcu::TestNode::STOP **/ virtual tcu::TestNode::IterateResult iterate(void); static const GLint m_min_map_buffer_alignment = 64; }; /** Implementation of Functional test, description follows: * * Verifies that results of MapBuffer operations are as required. * * Steps: * - prepare buffer filled with specific content; * - map buffer with MapBuffer; * - verify that returned data match contents of the buffer; * - unmap buffer; * - map buffer with MapBufferRange; * - verify that returned data match contents of the buffer; * - unmap buffer; * - verify that pointers returned by map operations fulfil alignment * requirements. * * Repeat steps for all valid: * - values; * - combinations. * * should be set to MIN_MAP_BUFFER_ALIGNEMENT - 1. **/ class Functional : public deqp::TestCase { public: /* Public methods */ Functional(deqp::Context& context) : TestCase(context, "functional", "Verifies alignment of memory returned by MapBuffer operations") { /* Nothing to be done */ } virtual ~Functional() { /* Nothing to be done */ } /** Execute test * * @return tcu::TestNode::STOP **/ virtual tcu::TestNode::IterateResult iterate(void); }; /** Execute test * * @return tcu::TestNode::STOP **/ tcu::TestNode::IterateResult Query::iterate() { GLint min_map_buffer_alignment = 0; bool test_result = true; const Functions& gl = m_context.getRenderContext().getFunctions(); gl.getIntegerv(GL_MIN_MAP_BUFFER_ALIGNMENT, &min_map_buffer_alignment); GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); if (m_min_map_buffer_alignment > min_map_buffer_alignment) { test_result = false; } /* Set result */ if (true == test_result) { m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } /* Done */ return tcu::TestNode::STOP; } struct BufferEnums { GLenum m_target; GLenum m_max_size; }; /** Execute test * * @return tcu::TestNode::STOP **/ tcu::TestNode::IterateResult Functional::iterate() { static const GLenum storage_flags[] = { GL_MAP_READ_BIT, GL_MAP_WRITE_BIT, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT, GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT, GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT, GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT, GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT, GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT, GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT, GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT, GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT, GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT, GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT, GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT, GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT, GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT, GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT | GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, }; static const size_t n_storage_flags = sizeof(storage_flags) / sizeof(storage_flags[0]); static const BufferEnums buffers[] = { { GL_ARRAY_BUFFER, GL_MAX_VARYING_COMPONENTS }, { GL_ATOMIC_COUNTER_BUFFER, GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE }, { GL_COPY_READ_BUFFER, 0 }, { GL_COPY_WRITE_BUFFER, 0 }, { GL_DISPATCH_INDIRECT_BUFFER, 0 }, { GL_DRAW_INDIRECT_BUFFER, 0 }, { GL_ELEMENT_ARRAY_BUFFER, GL_MAX_ELEMENTS_INDICES }, { GL_PIXEL_PACK_BUFFER, 0 }, { GL_PIXEL_UNPACK_BUFFER, 0 }, { GL_QUERY_BUFFER, 0 }, { GL_SHADER_STORAGE_BUFFER, GL_MAX_SHADER_STORAGE_BLOCK_SIZE }, { GL_TEXTURE_BUFFER, GL_MAX_TEXTURE_BUFFER_SIZE }, { GL_TRANSFORM_FEEDBACK_BUFFER, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS }, { GL_UNIFORM_BUFFER, GL_MAX_UNIFORM_BLOCK_SIZE } }; static const size_t n_buffers = sizeof(buffers) / sizeof(buffers[0]); const Functions& gl = m_context.getRenderContext().getFunctions(); std::vector buffer_data; size_t buffer_data_size = 0; GLuint buffer_id = 0; GLint buffer_size = 0; GLint min_map_buffer_alignment = 0; GLuint offset = 0; bool test_result = true; /* Get min alignment */ gl.getIntegerv(GL_MIN_MAP_BUFFER_ALIGNMENT, &min_map_buffer_alignment); GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); /* Prepare storage */ buffer_data_size = 2 * min_map_buffer_alignment; buffer_data.resize(buffer_data_size); /* Prepare data */ for (size_t i = 0; i < buffer_data_size; ++i) { buffer_data[i] = (GLubyte)i; } /* Run test */ try { for (size_t buffer_idx = 0; buffer_idx < n_buffers; ++buffer_idx) { const BufferEnums& buffer = buffers[buffer_idx]; buffer_size = static_cast(buffer_data_size); /* Get max size */ if (0 != buffer.m_max_size) { gl.getIntegerv(buffer.m_max_size, &buffer_size); GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); } switch (buffer.m_max_size) { case GL_MAX_VARYING_COMPONENTS: case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: buffer_size = static_cast(buffer_size * sizeof(GLfloat)); break; case GL_MAX_ELEMENTS_INDICES: buffer_size = static_cast(buffer_size * sizeof(GLuint)); break; default: break; } buffer_size = std::min(buffer_size, (GLint)buffer_data_size); offset = std::min(buffer_size - 1, min_map_buffer_alignment - 1); for (size_t set_idx = 0; set_idx < n_storage_flags; ++set_idx) { const GLenum& storage_set = storage_flags[set_idx]; /* Prepare buffer */ gl.genBuffers(1, &buffer_id); GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers"); gl.bindBuffer(buffer.m_target, buffer_id); GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer"); gl.bufferStorage(buffer.m_target, buffer_size, &buffer_data[0], storage_set); GLU_EXPECT_NO_ERROR(gl.getError(), "BufferStorage"); /* Test MapBuffer */ GLenum map_buffer_access = GL_READ_WRITE; if (0 == (storage_set & GL_MAP_READ_BIT)) { map_buffer_access = GL_WRITE_ONLY; } else if (0 == (storage_set & GL_MAP_WRITE_BIT)) { map_buffer_access = GL_READ_ONLY; } GLubyte* map_buffer_ptr = (GLubyte*)gl.mapBuffer(buffer.m_target, map_buffer_access); GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer"); if (GL_WRITE_ONLY != map_buffer_access) { for (size_t i = 0; i < (size_t)buffer_size; ++i) { if (buffer_data[i] != map_buffer_ptr[i]) { test_result = false; break; } } } gl.unmapBuffer(buffer.m_target); GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer"); /* Test MapBufferRange */ static const GLenum map_buffer_range_access_mask = GL_DYNAMIC_STORAGE_BIT | GL_CLIENT_STORAGE_BIT; GLenum map_buffer_range_access = (storage_set & (~map_buffer_range_access_mask)); GLubyte* map_buffer_range_ptr = (GLubyte*)gl.mapBufferRange(buffer.m_target, offset, buffer_size - offset, map_buffer_range_access); GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange"); if (0 != (GL_MAP_READ_BIT & map_buffer_range_access)) { for (size_t i = 0; i < (size_t)buffer_size - (size_t)offset; ++i) { if (buffer_data[i + offset] != map_buffer_range_ptr[i]) { test_result = false; break; } } } gl.unmapBuffer(buffer.m_target); GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer"); gl.bindBuffer(buffer.m_target, 0 /* id */); GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer"); /* Remove buffer */ gl.deleteBuffers(1, &buffer_id); GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteBuffers"); buffer_id = 0; /* Verify that pointers are properly aligned */ if (0 != ((GLintptr)map_buffer_ptr % min_map_buffer_alignment)) { test_result = false; break; } if (0 != (((GLintptr)map_buffer_range_ptr - offset) % min_map_buffer_alignment)) { test_result = false; break; } } } } catch (const std::exception& exc) { if (0 != buffer_id) { gl.deleteBuffers(1, &buffer_id); GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteBuffers"); } TCU_FAIL(exc.what()); } /* Set result */ if (true == test_result) { m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } /* Done */ return tcu::TestNode::STOP; } } /* MapBufferAlignment namespace */ /** Constructor. * * @param context Rendering context. **/ MapBufferAlignmentTests::MapBufferAlignmentTests(deqp::Context& context) : TestCaseGroup(context, "map_buffer_alignment", "Verifies \"map buffer alignment\" functionality") { /* Left blank on purpose */ } /** Initializes a texture_storage_multisample test group. * **/ void MapBufferAlignmentTests::init(void) { addChild(new MapBufferAlignment::Query(m_context)); addChild(new MapBufferAlignment::Functional(m_context)); } } /* gl4cts namespace */