blob: 88d950cad97c8f842679bd540beb935be4790be1 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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 <algorithm>
#include <vector>
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:
* - <buffer> values;
* - <access> combinations.
*
* <offset> 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<GLubyte> 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<GLint>(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<glw::GLint>(buffer_size * sizeof(GLfloat));
break;
case GL_MAX_ELEMENTS_INDICES:
buffer_size = static_cast<glw::GLint>(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 */