blob: 73ffa7171c00780488325bd18272d2c405de330b [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 gl4cDirectStateAccessVertexArraysTests.cpp
* \brief Conformance tests for the Direct State Access feature functionality (Vertex Array Objects access part).
*/ /*-----------------------------------------------------------------------------------------------------------*/
/* Includes. */
#include "gl4cDirectStateAccessTests.hpp"
#include "deSharedPtr.hpp"
#include "gluContextInfo.hpp"
#include "gluDefs.hpp"
#include "gluPixelTransfer.hpp"
#include "gluStrUtil.hpp"
#include "tcuFuzzyImageCompare.hpp"
#include "tcuImageCompare.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuSurface.hpp"
#include "tcuTestLog.hpp"
#include "glw.h"
#include "glwFunctions.hpp"
#include <algorithm>
#include <climits>
#include <cmath>
#include <set>
#include <sstream>
#include <stack>
namespace gl4cts
{
namespace DirectStateAccess
{
namespace VertexArrays
{
/******************************** Creation Test Implementation ********************************/
/** @brief Creation Test constructor.
*
* @param [in] context OpenGL context.
*/
CreationTest::CreationTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_creation", "Vertex Array Objects Creation Test")
{
/* Intentionally left blank. */
}
/** @brief Iterate Creation Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult CreationTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* VertexArrays' objects */
static const glw::GLuint vertex_arrays_count = 2;
glw::GLuint vertex_arrays_legacy[vertex_arrays_count] = {};
glw::GLuint vertex_arrays_dsa[vertex_arrays_count] = {};
try
{
/* Check legacy state creation. */
gl.genVertexArrays(vertex_arrays_count, vertex_arrays_legacy);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays have failed");
for (glw::GLuint i = 0; i < vertex_arrays_count; ++i)
{
if (gl.isVertexArray(vertex_arrays_legacy[i]))
{
is_ok = false;
/* Log. */
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "GenVertexArrays has created default objects, but it should create only a names."
<< tcu::TestLog::EndMessage;
}
}
/* Check direct state creation. */
gl.createVertexArrays(vertex_arrays_count, vertex_arrays_dsa);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays have failed");
for (glw::GLuint i = 0; i < vertex_arrays_count; ++i)
{
if (!gl.isVertexArray(vertex_arrays_dsa[i]))
{
is_ok = false;
/* Log. */
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "CreateVertexArrays has not created default objects."
<< tcu::TestLog::EndMessage;
}
}
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
for (glw::GLuint i = 0; i < vertex_arrays_count; ++i)
{
if (vertex_arrays_legacy[i])
{
gl.deleteVertexArrays(1, &vertex_arrays_legacy[i]);
vertex_arrays_legacy[i] = 0;
}
if (vertex_arrays_dsa[i])
{
gl.deleteVertexArrays(1, &vertex_arrays_dsa[i]);
vertex_arrays_dsa[i] = 0;
}
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/******************************** Vertex Array Object Enable Disable Attributes Test Implementation ********************************/
/** @brief Vertex Array Object Enable Disable Attributes Test constructor.
*
* @param [in] context OpenGL context.
*/
EnableDisableAttributesTest::EnableDisableAttributesTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_enable_disable_attributes",
"Vertex Array Objects Enable Disable Attributes Test")
, m_po_even(0)
, m_po_odd(0)
, m_vao(0)
, m_bo(0)
, m_bo_xfb(0)
, m_max_attributes(16) /* Required Minimum: OpenGL 4.5 Table 23.57: Implementation Dependent Vertex Shader Limits */
{
/* Intentionally left blank. */
}
/** @brief Iterate Vertex Array Object Enable Disable Attributes Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult EnableDisableAttributesTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
try
{
gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS, &m_max_attributes);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, ...) have failed");
m_po_even = PrepareProgram(false);
m_po_odd = PrepareProgram(true);
PrepareVAO();
PrepareXFB();
is_ok &= TurnOnAttributes(true, false);
is_ok &= DrawAndCheck(false);
is_ok &= TurnOnAttributes(false, true);
is_ok &= DrawAndCheck(true);
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
Clean();
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
glw::GLuint EnableDisableAttributesTest::PrepareProgram(const bool bind_even_or_odd)
{
/* Preprocess vertex shader sources. */
std::string declarations = "";
std::string copies = " sum = 0;\n";
for (glw::GLint i = (glw::GLint)(bind_even_or_odd); i < m_max_attributes; i += 2)
{
declarations.append((std::string("in int a_").append(Utilities::itoa(i))).append(";\n"));
copies.append((std::string(" sum += a_").append(Utilities::itoa(i))).append(";\n"));
}
std::string vs_template(s_vertex_shader_template);
std::string vs_source = Utilities::replace(vs_template, "DECLARATION_TEMPLATE", declarations);
vs_source = Utilities::replace(vs_source, "COPY_TEMPLATE", copies);
/* Build and compile. */
return BuildProgram(vs_source.c_str(), bind_even_or_odd);
}
/** @brief Build test's GLSL program.
*
* @note The function may throw if unexpected error has occured.
*/
glw::GLuint EnableDisableAttributesTest::BuildProgram(const char* vertex_shader, const bool bind_even_or_odd)
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
struct Shader
{
glw::GLchar const* const source;
glw::GLenum const type;
glw::GLuint id;
} shader[] = { { vertex_shader, GL_VERTEX_SHADER, 0 }, { s_fragment_shader, GL_FRAGMENT_SHADER, 0 } };
glw::GLuint const shader_count = DE_LENGTH_OF_ARRAY(shader);
glw::GLuint po = 0;
try
{
/* Create program. */
po = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed.");
/* Shader compilation. */
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (DE_NULL != shader[i].source)
{
shader[i].id = gl.createShader(shader[i].type);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed.");
gl.attachShader(po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed.");
gl.shaderSource(shader[i].id, 1, &(shader[i].source), NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed.");
gl.compileShader(shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed.");
glw::GLint status = GL_FALSE;
gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
if (GL_FALSE == status)
{
glw::GLint log_size = 0;
gl.getShaderiv(shader[i].id, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getShaderInfoLog(shader[i].id, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n"
<< "Shader type: " << glu::getShaderTypeStr(shader[i].type)
<< "\n"
<< "Shader compilation error log:\n"
<< log_text << "\n"
<< "Shader source code:\n"
<< shader[i].source << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog call failed.");
throw 0;
}
}
}
/* Transform Feedback setup. */
static const glw::GLchar* xfb_varying = "sum";
gl.transformFeedbackVaryings(po, 1, &xfb_varying, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
for (glw::GLint i = (glw::GLint)(bind_even_or_odd); i < m_max_attributes; i += 2)
{
std::string attribute = std::string("a_").append(Utilities::itoa(i));
gl.bindAttribLocation(po, i, attribute.c_str());
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindAttribLocation call failed.");
}
/* Link. */
gl.linkProgram(po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
glw::GLint status = GL_FALSE;
gl.getProgramiv(po, GL_LINK_STATUS, &status);
if (GL_TRUE == status)
{
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (shader[i].id)
{
gl.detachShader(po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed.");
}
}
}
else
{
glw::GLint log_size = 0;
gl.getProgramiv(po, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getProgramInfoLog(po, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program linkage has failed due to:\n"
<< log_text << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
throw 0;
}
}
catch (...)
{
if (po)
{
gl.deleteProgram(po);
po = 0;
}
}
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (0 != shader[i].id)
{
gl.deleteShader(shader[i].id);
shader[i].id = 0;
}
}
if (0 == po)
{
throw 0;
}
return po;
}
/** @brief Prepare vertex array object for the test.
*/
void EnableDisableAttributesTest::PrepareVAO()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* VAO creation. */
gl.genVertexArrays(1, &m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
/* Buffer creation. */
gl.genBuffers(1, &m_bo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
glw::GLint* reference_data = new glw::GLint[m_max_attributes];
if (DE_NULL == reference_data)
{
throw 0;
}
for (glw::GLint i = 0; i < m_max_attributes; ++i)
{
reference_data[i] = i;
}
gl.bufferData(GL_ARRAY_BUFFER, sizeof(glw::GLint) * m_max_attributes, reference_data, GL_STATIC_DRAW);
delete[] reference_data;
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
/* VAO setup. */
for (glw::GLint i = 0; i < m_max_attributes; ++i)
{
gl.vertexAttribIPointer(i, 1, GL_INT, static_cast<glw::GLsizei>(sizeof(glw::GLint) * m_max_attributes),
glu::BufferOffsetAsPointer(i * sizeof(glw::GLint)));
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribIPointer call failed.");
}
}
/** @brief Prepare buffer object for test GLSL program transform feedback results.
*/
void EnableDisableAttributesTest::PrepareXFB()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Buffer creation. */
gl.genBuffers(1, &m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
/* Preparing storage. */
gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(glw::GLint), NULL, GL_MAP_READ_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
}
/** @brief Draw test program, fetch transform feedback results and compare them with expected values.
*
* @param [in] bind_even_or_odd Even or odd attribute are enabled.
*
* @return True if expected results are equal to returned by XFB, false otherwise.
*/
bool EnableDisableAttributesTest::DrawAndCheck(bool bind_even_or_odd)
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Setup state. */
gl.useProgram(bind_even_or_odd ? m_po_odd : m_po_even);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
/* Draw. */
gl.drawArrays(GL_POINTS, 0, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
/* State reset. */
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* Result query. */
glw::GLint* result_ptr = (glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed.");
glw::GLint result = *result_ptr;
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
/* Check result and return. */
if (bind_even_or_odd)
{
glw::GLint reference_sum = 0;
for (glw::GLint i = 1; i < m_max_attributes; i += 2)
{
reference_sum += i;
}
if (reference_sum == result)
{
return true;
}
}
else
{
glw::GLint reference_sum = 0;
for (glw::GLint i = 0; i < m_max_attributes; i += 2)
{
reference_sum += i;
}
if (reference_sum == result)
{
return true;
}
}
return false;
}
/** @brief Turn on even or odd attributes (up to m_max_attributes) using EnableVertexArrayAttrib function.
*
* @param [in] enable_even Turn on even attribute indexes.
* @param [in] enable_odd Turn on odd attribute indexes.
*
* @return True if EnableVertexArrayAttrib does not generate any error, false otherwise.
*/
bool EnableDisableAttributesTest::TurnOnAttributes(bool enable_even, bool enable_odd)
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindVertexArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
for (glw::GLint i = 0; i < m_max_attributes; ++i)
{
bool disable = true;
if (i % 2) /* if odd */
{
if (enable_odd)
{
gl.enableVertexArrayAttrib(m_vao, i);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "glEnableVertexArrayAttrib generated error "
<< glu::getErrorStr(error) << " when called with VAO " << m_vao << " and index " << i << "."
<< tcu::TestLog::EndMessage;
return false;
}
disable = false;
}
}
else
{
if (enable_even)
{
gl.enableVertexArrayAttrib(m_vao, i);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "glEnableVertexArrayAttrib generated error "
<< glu::getErrorStr(error) << " when called with VAO " << m_vao << " and index " << i << "."
<< tcu::TestLog::EndMessage;
return false;
}
disable = false;
}
}
if (disable)
{
gl.disableVertexArrayAttrib(m_vao, i);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "glDisableVertexArrayAttrib generated error " << glu::getErrorStr(error)
<< " when called with VAO " << m_vao << " and index " << i << "." << tcu::TestLog::EndMessage;
return false;
}
}
}
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
return true;
}
/** @brief Clean GL objects. */
void EnableDisableAttributesTest::Clean()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(0);
if (m_po_even)
{
gl.deleteProgram(m_po_even);
m_po_even = 0;
}
if (m_po_odd)
{
gl.deleteProgram(m_po_odd);
m_po_odd = 0;
}
if (m_vao)
{
gl.deleteVertexArrays(1, &m_vao);
m_vao = 0;
}
if (m_bo)
{
gl.deleteBuffers(1, &m_bo);
m_bo = 0;
}
if (m_bo_xfb)
{
gl.deleteBuffers(1, &m_bo_xfb);
m_bo_xfb = 0;
}
if (m_max_attributes)
{
m_max_attributes =
16; /* OpenGL 4.5 Required Minimum Table 23.57: Implementation Dependent Vertex Shader Limits */
}
while (gl.getError())
;
}
std::string Utilities::itoa(glw::GLuint i)
{
std::string s = "";
std::stringstream ss;
ss << i;
s = ss.str();
return s;
}
std::string Utilities::replace(const std::string& src, const std::string& key, const std::string& value)
{
size_t pos = 0;
std::string dst = src;
while (std::string::npos != (pos = dst.find(key, pos)))
{
dst.replace(pos, key.length(), value);
pos += key.length();
}
return dst;
}
const glw::GLchar EnableDisableAttributesTest::s_vertex_shader_template[] = "#version 450\n"
"\n"
"DECLARATION_TEMPLATE"
"out int sum;\n"
"\n"
"void main()\n"
"{\n"
"COPY_TEMPLATE"
"}\n";
const glw::GLchar EnableDisableAttributesTest::s_fragment_shader[] = "#version 450\n"
"\n"
"out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0);"
"}\n";
/******************************** Vertex Array Object Element Buffer Test Implementation ********************************/
/** @brief Vertex Array Object Element Buffer Test constructor.
*
* @param [in] context OpenGL context.
*/
ElementBufferTest::ElementBufferTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_element_buffer", "Vertex Array Objects Element Buffer Test")
, m_po(0)
, m_vao(0)
, m_bo_array(0)
, m_bo_elements(0)
, m_bo_xfb(0)
{
/* Intentionally left blank. */
}
/** @brief Iterate Vertex Array Object Enable Disable Attributes Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult ElementBufferTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
try
{
PrepareProgram();
is_ok &= PrepareVAO();
PrepareXFB();
is_ok &= DrawAndCheck();
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
Clean();
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Build test's GLSL program.
*
* @note The function may throw if unexpected error has occured.
*/
void ElementBufferTest::PrepareProgram()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
struct Shader
{
glw::GLchar const* const source;
glw::GLenum const type;
glw::GLuint id;
} shader[] = { { s_vertex_shader, GL_VERTEX_SHADER, 0 }, { s_fragment_shader, GL_FRAGMENT_SHADER, 0 } };
glw::GLuint const shader_count = DE_LENGTH_OF_ARRAY(shader);
try
{
/* Create program. */
m_po = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed.");
/* Shader compilation. */
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (DE_NULL != shader[i].source)
{
shader[i].id = gl.createShader(shader[i].type);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed.");
gl.attachShader(m_po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed.");
gl.shaderSource(shader[i].id, 1, &(shader[i].source), NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed.");
gl.compileShader(shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed.");
glw::GLint status = GL_FALSE;
gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
if (GL_FALSE == status)
{
glw::GLint log_size = 0;
gl.getShaderiv(shader[i].id, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getShaderInfoLog(shader[i].id, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n"
<< "Shader type: " << glu::getShaderTypeStr(shader[i].type)
<< "\n"
<< "Shader compilation error log:\n"
<< log_text << "\n"
<< "Shader source code:\n"
<< shader[i].source << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog call failed.");
throw 0;
}
}
}
/* Transform Feedback setup. */
static const glw::GLchar* xfb_varying = "result";
gl.transformFeedbackVaryings(m_po, 1, &xfb_varying, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
/* Link. */
gl.linkProgram(m_po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
glw::GLint status = GL_FALSE;
gl.getProgramiv(m_po, GL_LINK_STATUS, &status);
if (GL_TRUE == status)
{
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (shader[i].id)
{
gl.detachShader(m_po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed.");
}
}
}
else
{
glw::GLint log_size = 0;
gl.getProgramiv(m_po, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getProgramInfoLog(m_po, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program linkage has failed due to:\n"
<< log_text << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
throw 0;
}
}
catch (...)
{
if (m_po)
{
gl.deleteProgram(m_po);
m_po = 0;
}
}
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (0 != shader[i].id)
{
gl.deleteShader(shader[i].id);
shader[i].id = 0;
}
}
if (0 == m_po)
{
throw 0;
}
}
/** @brief Prepare vertex array object for the test of VertexArrayElementBuffer function.
*
* @return True if function VertexArrayElementBuffer* does not generate any error.
*/
bool ElementBufferTest::PrepareVAO()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* VAO creation. */
gl.genVertexArrays(1, &m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
/* Array buffer creation. */
glw::GLint array_data[3] = { 2, 1, 0 };
gl.genBuffers(1, &m_bo_array);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_array);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.bufferData(GL_ARRAY_BUFFER, sizeof(array_data), array_data, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
gl.vertexAttribIPointer(gl.getAttribLocation(m_po, "a"), 1, GL_INT, 0, NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribIPointer call failed.");
gl.enableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.bindVertexArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
/* Element buffer creation. */
glw::GLuint elements_data[3] = { 2, 1, 0 };
gl.genBuffers(1, &m_bo_elements);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_bo_elements);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements_data), elements_data, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
gl.vertexArrayElementBuffer(m_vao, m_bo_elements);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "VertexArrayElementBuffer has unexpectedly generated "
<< glu::getErrorStr(error) << "error. Test fails.\n"
<< tcu::TestLog::EndMessage;
return false;
}
return true;
}
/** @brief Prepare buffer object for test GLSL program transform feedback results.
*/
void ElementBufferTest::PrepareXFB()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Buffer creation. */
gl.genBuffers(1, &m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
/* Preparing storage. */
gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, 3 * sizeof(glw::GLint), NULL, GL_MAP_READ_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
}
/** @brief Draw test program, fetch transform feedback results and compare them with expected values.
*
* @return True if expected results are equal to returned by XFB, false otherwise.
*/
bool ElementBufferTest::DrawAndCheck()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Setup state. */
gl.useProgram(m_po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
/* Draw. */
gl.drawElements(GL_POINTS, 3, GL_UNSIGNED_INT, NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
/* State reset. */
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* Result query. */
glw::GLint* result_ptr = (glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed.");
glw::GLint result[3] = { result_ptr[0], result_ptr[1], result_ptr[2] };
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
/* Check result and return. */
for (glw::GLint i = 0; i < 3; ++i)
{
if (i != result[i])
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Result vector is equal to [" << result[0]
<< ", " << result[1] << ", " << result[2]
<< "], but [0, 1, 2] was expected." << tcu::TestLog::EndMessage;
return false;
}
}
return true;
}
/** @brief Clean GL objects. */
void ElementBufferTest::Clean()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(0);
if (m_po)
{
gl.deleteProgram(m_po);
m_po = 0;
}
if (m_vao)
{
gl.deleteVertexArrays(1, &m_vao);
m_vao = 0;
}
if (m_bo_array)
{
gl.deleteBuffers(1, &m_bo_array);
m_bo_array = 0;
}
if (m_bo_elements)
{
gl.deleteBuffers(1, &m_bo_elements);
m_bo_elements = 0;
}
if (m_bo_xfb)
{
gl.deleteBuffers(1, &m_bo_xfb);
m_bo_xfb = 0;
}
while (gl.getError())
;
}
const glw::GLchar ElementBufferTest::s_vertex_shader[] = "#version 450\n"
"\n"
"in int a;"
"out int result;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(1.0);\n"
" result = a;"
"}\n";
const glw::GLchar ElementBufferTest::s_fragment_shader[] = "#version 450\n"
"\n"
"out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0);"
"}\n";
/******************************** Vertex Array Object Vertex Buffer and Buffers Test Implementation ********************************/
/** @brief Vertex Array Object Element Buffer Test constructor.
*
* @param [in] context OpenGL context.
*/
VertexBuffersTest::VertexBuffersTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_vertex_buffers", "Vertex Array Object Vertex Buffer and Buffers Test")
, m_po(0)
, m_vao(0)
, m_bo_array_0(0)
, m_bo_array_1(0)
, m_bo_xfb(0)
{
/* Intentionally left blank. */
}
/** @brief Iterate Vertex Array Object Enable Disable Attributes Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult VertexBuffersTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
try
{
PrepareProgram();
is_ok &= PrepareVAO(false);
PrepareXFB();
is_ok &= DrawAndCheck();
Clean();
PrepareProgram();
is_ok &= PrepareVAO(true);
PrepareXFB();
is_ok &= DrawAndCheck();
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
Clean();
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Build test's GLSL program.
*
* @note The function may throw if unexpected error has occured.
*/
void VertexBuffersTest::PrepareProgram()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
struct Shader
{
glw::GLchar const* const source;
glw::GLenum const type;
glw::GLuint id;
} shader[] = { { s_vertex_shader, GL_VERTEX_SHADER, 0 }, { s_fragment_shader, GL_FRAGMENT_SHADER, 0 } };
glw::GLuint const shader_count = DE_LENGTH_OF_ARRAY(shader);
try
{
/* Create program. */
m_po = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed.");
/* Shader compilation. */
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (DE_NULL != shader[i].source)
{
shader[i].id = gl.createShader(shader[i].type);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed.");
gl.attachShader(m_po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed.");
gl.shaderSource(shader[i].id, 1, &(shader[i].source), NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed.");
gl.compileShader(shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed.");
glw::GLint status = GL_FALSE;
gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
if (GL_FALSE == status)
{
glw::GLint log_size = 0;
gl.getShaderiv(shader[i].id, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getShaderInfoLog(shader[i].id, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n"
<< "Shader type: " << glu::getShaderTypeStr(shader[i].type)
<< "\n"
<< "Shader compilation error log:\n"
<< log_text << "\n"
<< "Shader source code:\n"
<< shader[i].source << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog call failed.");
throw 0;
}
}
}
/* Transform Feedback setup. */
static const glw::GLchar* xfb_varying = "result";
gl.transformFeedbackVaryings(m_po, 1, &xfb_varying, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
/* Link. */
gl.linkProgram(m_po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
glw::GLint status = GL_FALSE;
gl.getProgramiv(m_po, GL_LINK_STATUS, &status);
if (GL_TRUE == status)
{
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (shader[i].id)
{
gl.detachShader(m_po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed.");
}
}
}
else
{
glw::GLint log_size = 0;
gl.getProgramiv(m_po, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getProgramInfoLog(m_po, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program linkage has failed due to:\n"
<< log_text << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
throw 0;
}
}
catch (...)
{
if (m_po)
{
gl.deleteProgram(m_po);
m_po = 0;
}
}
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (0 != shader[i].id)
{
gl.deleteShader(shader[i].id);
shader[i].id = 0;
}
}
if (0 == m_po)
{
throw 0;
}
}
/** @brief Prepare vertex array object for the test of gl.vertexArrayVertexBuffer* functions.
*
* @param [in] use_multiple_buffers_function Use gl.vertexArrayVertexBuffers instead of gl.vertexArrayVertexBuffer.
*
* @return True if functions gl.vertexArrayVertexBuffer* do not generate any error.
*/
bool VertexBuffersTest::PrepareVAO(bool use_multiple_buffers_function)
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* VAO creation. */
gl.genVertexArrays(1, &m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
/* Array buffer 0 creation. */
glw::GLint array_data_0[4] = { 0, 2, 1, 3 };
gl.genBuffers(1, &m_bo_array_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_array_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.bufferData(GL_ARRAY_BUFFER, sizeof(array_data_0), array_data_0, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
gl.vertexAttribBinding(gl.getAttribLocation(m_po, "a_0"), 0);
gl.vertexAttribBinding(gl.getAttribLocation(m_po, "a_1"), 1);
gl.vertexAttribIFormat(gl.getAttribLocation(m_po, "a_0"), 1, GL_INT, 0);
gl.vertexAttribIFormat(gl.getAttribLocation(m_po, "a_1"), 1, GL_INT, 0);
if (use_multiple_buffers_function)
{
const glw::GLuint buffers[2] = { m_bo_array_0, m_bo_array_0 };
static const glw::GLintptr offsets[2] = { 0, sizeof(glw::GLint) };
static const glw::GLsizei strides[2] = { sizeof(glw::GLint) * 2, sizeof(glw::GLint) * 2 };
gl.vertexArrayVertexBuffers(m_vao, 0, 2, buffers, offsets, strides);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "VertexArrayVertexBuffers has unexpectedly generated "
<< glu::getErrorStr(error) << "error. Test fails.\n"
<< tcu::TestLog::EndMessage;
return false;
}
}
else
{
gl.vertexArrayVertexBuffer(m_vao, 0, m_bo_array_0, (glw::GLintptr)NULL, sizeof(glw::GLint) * 2);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "VertexArrayVertexBuffer has unexpectedly generated "
<< glu::getErrorStr(error) << "error. Test fails.\n"
<< tcu::TestLog::EndMessage;
return false;
}
gl.vertexArrayVertexBuffer(m_vao, 1, m_bo_array_0, sizeof(glw::GLint),
sizeof(glw::GLint) * 2);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "VertexArrayVertexBuffer has unexpectedly generated "
<< glu::getErrorStr(error) << "error. Test fails.\n"
<< tcu::TestLog::EndMessage;
return false;
}
}
gl.enableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.enableVertexAttribArray(1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
/* Array buffer 1 creation. */
glw::GLint array_data_1[2] = { 4, 5 };
gl.genBuffers(1, &m_bo_array_1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_array_1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.bufferData(GL_ARRAY_BUFFER, sizeof(array_data_1), array_data_1, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
gl.vertexAttribBinding(gl.getAttribLocation(m_po, "a_2"), 2);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribBinding call failed.");
gl.vertexAttribIFormat(gl.getAttribLocation(m_po, "a_2"), 1, GL_INT, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribIFormat call failed.");
if (use_multiple_buffers_function)
{
glw::GLintptr offset = (glw::GLintptr)NULL;
glw::GLsizei stride = sizeof(glw::GLint);
gl.vertexArrayVertexBuffers(m_vao, 2, 1, &m_bo_array_1, &offset, &stride);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "VertexArrayVertexBuffers has unexpectedly generated "
<< glu::getErrorStr(error) << "error. Test fails.\n"
<< tcu::TestLog::EndMessage;
return false;
}
}
else
{
gl.vertexArrayVertexBuffer(m_vao, 2, m_bo_array_1, (glw::GLintptr)NULL, sizeof(glw::GLint));
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "VertexArrayVertexBuffer has unexpectedly generated "
<< glu::getErrorStr(error) << "error. Test fails.\n"
<< tcu::TestLog::EndMessage;
return false;
}
}
gl.enableVertexAttribArray(2);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.bindVertexArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
return true;
}
/** @brief Prepare buffer object for test GLSL program transform feedback results.
*/
void VertexBuffersTest::PrepareXFB()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Buffer creation. */
gl.genBuffers(1, &m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
/* Preparing storage. */
gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, 2 * sizeof(glw::GLint), NULL, GL_MAP_READ_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
}
/** @brief Draw test program, fetch transform feedback results and compare them with expected values.
*
* @return True if expected results are equal to returned by XFB, false otherwise.
*/
bool VertexBuffersTest::DrawAndCheck()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Setup state. */
gl.useProgram(m_po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
/* Draw. */
gl.drawArrays(GL_POINTS, 0, 2);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
/* State reset. */
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* Result query. */
glw::GLint* result_ptr = (glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed.");
glw::GLint result[2] = { result_ptr[0], result_ptr[1] };
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
static const glw::GLint reference[2] = { 0 + 2 + 4, 1 + 3 + 5 };
/* Check result and return. */
for (glw::GLint i = 0; i < 2; ++i)
{
if (reference[i] != result[i])
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Result vector is equal to [" << result[0]
<< ", " << result[1] << "], but [" << reference[0] << ", "
<< reference[1] << "] was expected." << tcu::TestLog::EndMessage;
return false;
}
}
return true;
}
/** @brief Clean GL objects. */
void VertexBuffersTest::Clean()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(0);
if (m_po)
{
gl.deleteProgram(m_po);
m_po = 0;
}
if (m_vao)
{
gl.deleteVertexArrays(1, &m_vao);
m_vao = 0;
}
if (m_bo_array_0)
{
gl.deleteBuffers(1, &m_bo_array_0);
m_bo_array_0 = 0;
}
if (m_bo_array_1)
{
gl.deleteBuffers(1, &m_bo_array_1);
m_bo_array_1 = 0;
}
if (m_bo_xfb)
{
gl.deleteBuffers(1, &m_bo_xfb);
m_bo_xfb = 0;
}
while (gl.getError())
;
}
const glw::GLchar VertexBuffersTest::s_vertex_shader[] = "#version 450\n"
"\n"
"in int a_0;"
"in int a_1;"
"in int a_2;"
"\n"
"out int result;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(1.0);\n"
" result = a_0 + a_1 + a_2;"
"}\n";
const glw::GLchar VertexBuffersTest::s_fragment_shader[] = "#version 450\n"
"\n"
"out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0);"
"}\n";
/******************************** Vertex Array Object Attribute Format Test Implementation ********************************/
/** @brief Vertex Array Object Element Buffer Test constructor.
*
* @param [in] context OpenGL context.
*/
AttributeFormatTest::AttributeFormatTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_attribute_format", "Vertex Array Object Attribute Format Test")
, m_po(0)
, m_vao(0)
, m_bo_array(0)
, m_bo_xfb(0)
{
/* Intentionally left blank. */
}
/** @brief Iterate Vertex Array Object Enable Disable Attributes Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult AttributeFormatTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
try
{
PrepareXFB();
/* Test floating function. */
for (glw::GLuint i = 1; i <= 4 /* max size */; ++i)
{
PrepareProgram(i, ATTRIBUTE_FORMAT_FUNCTION_FLOAT);
is_ok &= PrepareVAO<glw::GLfloat>(i, GL_FLOAT, false, ATTRIBUTE_FORMAT_FUNCTION_FLOAT);
is_ok &= DrawAndCheck<glw::GLfloat>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLbyte>(i, GL_BYTE, false, ATTRIBUTE_FORMAT_FUNCTION_FLOAT);
is_ok &= DrawAndCheck<glw::GLfloat>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLbyte>(i, GL_BYTE, true, ATTRIBUTE_FORMAT_FUNCTION_FLOAT);
is_ok &= DrawAndCheck<glw::GLfloat>(i, true);
CleanVAO();
is_ok &= PrepareVAO<glw::GLubyte>(i, GL_UNSIGNED_BYTE, false, ATTRIBUTE_FORMAT_FUNCTION_FLOAT);
is_ok &= DrawAndCheck<glw::GLfloat>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLshort>(i, GL_SHORT, false, ATTRIBUTE_FORMAT_FUNCTION_FLOAT);
is_ok &= DrawAndCheck<glw::GLfloat>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLushort>(i, GL_UNSIGNED_SHORT, false, ATTRIBUTE_FORMAT_FUNCTION_FLOAT);
is_ok &= DrawAndCheck<glw::GLfloat>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLint>(i, GL_INT, false, ATTRIBUTE_FORMAT_FUNCTION_FLOAT);
is_ok &= DrawAndCheck<glw::GLfloat>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLuint>(i, GL_UNSIGNED_INT, false, ATTRIBUTE_FORMAT_FUNCTION_FLOAT);
is_ok &= DrawAndCheck<glw::GLfloat>(i, false);
CleanVAO();
CleanProgram();
}
for (glw::GLuint i = 1; i <= 2 /* max size */; ++i)
{
PrepareProgram(i, ATTRIBUTE_FORMAT_FUNCTION_DOUBLE);
is_ok &= PrepareVAO<glw::GLdouble>(i, GL_DOUBLE, false, ATTRIBUTE_FORMAT_FUNCTION_DOUBLE);
is_ok &= DrawAndCheck<glw::GLdouble>(i, false);
CleanProgram();
CleanVAO();
}
for (glw::GLuint i = 1; i <= 4 /* max size */; ++i)
{
PrepareProgram(i, ATTRIBUTE_FORMAT_FUNCTION_INTEGER);
is_ok &= PrepareVAO<glw::GLbyte>(i, GL_BYTE, false, ATTRIBUTE_FORMAT_FUNCTION_INTEGER);
is_ok &= DrawAndCheck<glw::GLint>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLubyte>(i, GL_UNSIGNED_BYTE, false, ATTRIBUTE_FORMAT_FUNCTION_INTEGER);
is_ok &= DrawAndCheck<glw::GLint>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLshort>(i, GL_SHORT, false, ATTRIBUTE_FORMAT_FUNCTION_INTEGER);
is_ok &= DrawAndCheck<glw::GLint>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLushort>(i, GL_UNSIGNED_SHORT, false, ATTRIBUTE_FORMAT_FUNCTION_INTEGER);
is_ok &= DrawAndCheck<glw::GLint>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLint>(i, GL_INT, false, ATTRIBUTE_FORMAT_FUNCTION_INTEGER);
is_ok &= DrawAndCheck<glw::GLint>(i, false);
CleanVAO();
is_ok &= PrepareVAO<glw::GLuint>(i, GL_UNSIGNED_INT, false, ATTRIBUTE_FORMAT_FUNCTION_INTEGER);
is_ok &= DrawAndCheck<glw::GLint>(i, false);
CleanVAO();
CleanProgram();
}
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
CleanProgram();
CleanVAO();
CleanXFB();
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Build test's GLSL program.
*
* @note The function may throw if unexpected error has occured.
*/
void AttributeFormatTest::PrepareProgram(glw::GLint size, AtributeFormatFunctionType function_selector)
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
struct Shader
{
glw::GLchar const* source[3];
glw::GLuint const count;
glw::GLenum const type;
glw::GLuint id;
} shader[] = { { { s_vertex_shader_head, s_vertex_shader_declaration[function_selector][size - 1],
s_vertex_shader_body },
3,
GL_VERTEX_SHADER,
0 },
{ { s_fragment_shader, DE_NULL, DE_NULL }, 1, GL_FRAGMENT_SHADER, 0 } };
glw::GLuint const shader_count = DE_LENGTH_OF_ARRAY(shader);
try
{
/* Create program. */
m_po = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed.");
/* Shader compilation. */
for (glw::GLuint i = 0; i < shader_count; ++i)
{
{
shader[i].id = gl.createShader(shader[i].type);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed.");
gl.attachShader(m_po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed.");
gl.shaderSource(shader[i].id, shader[i].count, shader[i].source, NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed.");
gl.compileShader(shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed.");
glw::GLint status = GL_FALSE;
gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
if (GL_FALSE == status)
{
glw::GLint log_size = 0;
gl.getShaderiv(shader[i].id, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getShaderInfoLog(shader[i].id, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n"
<< "Shader type: " << glu::getShaderTypeStr(shader[i].type)
<< "\n"
<< "Shader compilation error log:\n"
<< log_text << "\n"
<< "Shader source code:\n"
<< shader[i].source << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog call failed.");
throw 0;
}
}
}
/* Transform Feedback setup. */
static const glw::GLchar* xfb_varying = "result";
gl.transformFeedbackVaryings(m_po, 1, &xfb_varying, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
/* Link. */
gl.linkProgram(m_po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
glw::GLint status = GL_FALSE;
gl.getProgramiv(m_po, GL_LINK_STATUS, &status);
if (GL_TRUE == status)
{
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (shader[i].id)
{
gl.detachShader(m_po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed.");
}
}
}
else
{
glw::GLint log_size = 0;
gl.getProgramiv(m_po, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getProgramInfoLog(m_po, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program linkage has failed due to:\n"
<< log_text << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
throw 0;
}
}
catch (...)
{
if (m_po)
{
gl.deleteProgram(m_po);
m_po = 0;
}
}
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (0 != shader[i].id)
{
gl.deleteShader(shader[i].id);
shader[i].id = 0;
}
}
if (0 == m_po)
{
throw 0;
}
}
template <>
glw::GLdouble AttributeFormatTest::NormalizationScaleFactor<glw::GLuint>()
{
return std::pow(2.0, (glw::GLdouble)(CHAR_BIT * sizeof(glw::GLuint) - 4 /* 1.0 / 16.0 */));
}
template <>
glw::GLdouble AttributeFormatTest::NormalizationScaleFactor<glw::GLushort>()
{
return std::pow(2.0, (glw::GLdouble)(CHAR_BIT * sizeof(glw::GLushort) - 4 /* 1.0 / 16.0 */));
}
template <>
glw::GLdouble AttributeFormatTest::NormalizationScaleFactor<glw::GLubyte>()
{
return std::pow(2.0, (glw::GLdouble)(CHAR_BIT * sizeof(glw::GLubyte) - 4 /* 1.0 / 16.0 */));
}
template <>
glw::GLdouble AttributeFormatTest::NormalizationScaleFactor<glw::GLint>()
{
return std::pow(2.0, (glw::GLdouble)(CHAR_BIT * sizeof(glw::GLint) - 4 /* 1.0 / 16.0 */ - 1 /* sign bit */));
}
template <>
glw::GLdouble AttributeFormatTest::NormalizationScaleFactor<glw::GLshort>()
{
return std::pow(2.0, (glw::GLdouble)(CHAR_BIT * sizeof(glw::GLshort) - 4 /* 1.0 / 16.0 */ - 1 /* sign bit */));
}
template <>
glw::GLdouble AttributeFormatTest::NormalizationScaleFactor<glw::GLbyte>()
{
return std::pow(2.0, (glw::GLdouble)(CHAR_BIT * sizeof(glw::GLbyte) - 4 /* 1.0 / 16.0 */ - 1 /* sign bit */));
}
template <typename T>
glw::GLdouble AttributeFormatTest::NormalizationScaleFactor()
{
return 1.0; /* Rest of the types cannot be normalized. */
}
/** @brief Prepare vertex array object for the test of VertexArrayAttrib*Format function.
*
* @param [in] size Size passed to VertexArrayAttrib*Format.
* @param [in] type_gl_name Type passed to VertexArrayAttrib*Format.
* @param [in] function_selector Selects one of VertexArrayAttrib*Format functions.
*
* @return True if function VertexArrayAttrib*Format does not generate any error.
*/
template <typename T>
bool AttributeFormatTest::PrepareVAO(glw::GLint size, glw::GLenum type_gl_name, bool normalized,
AtributeFormatFunctionType function_selector)
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* VAO creation. */
gl.genVertexArrays(1, &m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
/* Array buffer 0 creation. */
const glw::GLdouble scale = normalized ? NormalizationScaleFactor<T>() : 1.0;
const T array_data[16] = { (T)(0.0 * scale), (T)(1.0 * scale), (T)(2.0 * scale), (T)(3.0 * scale),
(T)(4.0 * scale), (T)(5.0 * scale), (T)(6.0 * scale), (T)(7.0 * scale),
(T)(8.0 * scale), (T)(9.0 * scale), (T)(10.0 * scale), (T)(11.0 * scale),
(T)(12.0 * scale), (T)(13.0 * scale), (T)(14.0 * scale), (T)(15.0 * scale) };
gl.genBuffers(1, &m_bo_array);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_array);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.bufferData(GL_ARRAY_BUFFER, sizeof(array_data), array_data, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
/* Attribute setup. */
gl.vertexAttribBinding(gl.getAttribLocation(m_po, "a_0"), 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribBinding call failed.");
gl.vertexAttribBinding(gl.getAttribLocation(m_po, "a_1"), 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribBinding call failed.");
/* Tested attribute format setup. */
switch (function_selector)
{
case ATTRIBUTE_FORMAT_FUNCTION_FLOAT:
gl.vertexArrayAttribFormat(m_vao, gl.getAttribLocation(m_po, "a_0"), size, type_gl_name, normalized, 0);
gl.vertexArrayAttribFormat(m_vao, gl.getAttribLocation(m_po, "a_1"), size, type_gl_name, normalized, 0);
break;
case ATTRIBUTE_FORMAT_FUNCTION_DOUBLE:
gl.vertexArrayAttribLFormat(m_vao, gl.getAttribLocation(m_po, "a_0"), size, type_gl_name, 0);
gl.vertexArrayAttribLFormat(m_vao, gl.getAttribLocation(m_po, "a_1"), size, type_gl_name, 0);
break;
case ATTRIBUTE_FORMAT_FUNCTION_INTEGER:
gl.vertexArrayAttribIFormat(m_vao, gl.getAttribLocation(m_po, "a_0"), size, type_gl_name, 0);
gl.vertexArrayAttribIFormat(m_vao, gl.getAttribLocation(m_po, "a_1"), size, type_gl_name, 0);
break;
default:
throw 0;
}
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< ((ATTRIBUTE_FORMAT_FUNCTION_FLOAT == function_selector) ?
"VertexArrayAttribFormat" :
((ATTRIBUTE_FORMAT_FUNCTION_DOUBLE == function_selector) ?
"VertexArrayAttribLFormat" :
((ATTRIBUTE_FORMAT_FUNCTION_INTEGER == function_selector) ? "VertexArrayAttribIFormat" :
"VertexArrayAttrib?Format")))
<< " has unexpectedly generated " << glu::getErrorStr(error) << "error for test with size = " << size
<< ", type = " << glu::getTypeStr(type_gl_name)
<< ((ATTRIBUTE_FORMAT_FUNCTION_FLOAT == function_selector) ?
(normalized ? ", which was normalized." : ", which was not normalized.") :
".")
<< " Test fails.\n"
<< tcu::TestLog::EndMessage;
return false;
}
gl.bindVertexBuffer(0, m_bo_array, 0, static_cast<glw::GLsizei>(sizeof(T) * size * 2));
gl.bindVertexBuffer(1, m_bo_array, size * sizeof(T),
static_cast<glw::GLsizei>(sizeof(T) * size * 2));
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
gl.enableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.enableVertexAttribArray(1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.bindVertexArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
return true;
}
/** @brief Prepare buffer object for test GLSL program transform feedback results.
*/
void AttributeFormatTest::PrepareXFB()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Buffer creation. */
gl.genBuffers(1, &m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
/* Calculating maximum size. */
glw::GLsizei size = static_cast<glw::GLsizei>(
de::max(sizeof(glw::GLubyte),
de::max(sizeof(glw::GLbyte),
de::max(sizeof(glw::GLushort),
de::max(sizeof(glw::GLshort),
de::max(sizeof(glw::GLhalf),
de::max(sizeof(glw::GLint),
de::max(sizeof(glw::GLuint),
de::max(sizeof(glw::GLfixed),
de::max(sizeof(glw::GLfloat),
sizeof(glw::GLdouble)))))))))) *
4 /* maximum number of components */);
/* Preparing storage. */
gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, size, NULL, GL_MAP_READ_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
}
template <>
bool AttributeFormatTest::compare<glw::GLfloat>(glw::GLfloat a, glw::GLfloat b)
{
if (de::abs(a - b) < 0.03125)
{
return true;
}
return false;
}
template <>
bool AttributeFormatTest::compare<glw::GLdouble>(glw::GLdouble a, glw::GLdouble b)
{
if (de::abs(a - b) < 0.03125)
{
return true;
}
return false;
}
template <typename T>
bool AttributeFormatTest::compare(T a, T b)
{
return (a == b);
}
/** @brief Draw test program, fetch transform feedback results and compare them with expected values.
*
* @param [in] size Count of elements of the XFB vector is expected.
* @param [in] normalized Normalized values are expected.
*
* @return True if expected results are equal to returned by XFB, false otherwise.
*/
template <typename T>
bool AttributeFormatTest::DrawAndCheck(glw::GLint size, bool normalized)
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Setup state. */
gl.useProgram(m_po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
/* Draw. */
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
gl.drawArrays(GL_POINTS, 0, 2);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* Result query. */
T* result_ptr = (T*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed.");
T result[8] = { 0 };
for (glw::GLint i = 0; i < size * 2 /* two points */; ++i)
{
result[i] = result_ptr[i];
}
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
const glw::GLdouble scale = normalized ? (1.0 / 16.0) /* Floating point scalling factor. */ : 1.0;
const T array_data[16] = { (T)(0.0 * scale), (T)(1.0 * scale), (T)(2.0 * scale), (T)(3.0 * scale),
(T)(4.0 * scale), (T)(5.0 * scale), (T)(6.0 * scale), (T)(7.0 * scale),
(T)(8.0 * scale), (T)(9.0 * scale), (T)(10.0 * scale), (T)(11.0 * scale),
(T)(12.0 * scale), (T)(13.0 * scale), (T)(14.0 * scale), (T)(15.0 * scale) };
T reference[8] = { 0 };
for (glw::GLint i = 0; i < 2 /* two points */; ++i)
{
for (glw::GLint j = 0; j < size /* size components */; ++j)
{
reference[i * size + j] = array_data[i * size * 2 + j] + array_data[i * size * 2 + j + size];
}
}
/* Check result and return. */
for (glw::GLint i = 0; i < size * 2 /* two points */; ++i)
{
if (!AttributeFormatTest::compare<T>(reference[i], result[i]))
{
std::string reference_str = "[ ";
for (glw::GLint j = 0; j < size * 2 /* two points */; ++j)
{
std::stringstream ss;
ss << reference[j];
reference_str.append(ss.str());
if (j < size * 2 - 1 /* if it is not the last value */)
{
reference_str.append(", ");
}
else
{
reference_str.append(" ]");
}
}
std::string result_str = "[ ";
for (glw::GLint j = 0; j < size * 2 /* two points */; ++j)
{
std::stringstream ss;
ss << result[j];
result_str.append(ss.str());
if (j < size * 2 - 1 /* if it is not the last value */)
{
result_str.append(", ");
}
else
{
result_str.append(" ]");
}
}
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Result vector is equal to "
<< result_str.c_str() << ", but " << reference_str.c_str()
<< " was expected." << tcu::TestLog::EndMessage;
return false;
}
}
return true;
}
/** @brief Clean GLSL program object. */
void AttributeFormatTest::CleanProgram()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(0);
if (m_po)
{
gl.deleteProgram(m_po);
m_po = 0;
}
}
/** @brief Clean Vertex Array Object and related buffer. */
void AttributeFormatTest::CleanVAO()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_vao)
{
gl.deleteVertexArrays(1, &m_vao);
m_vao = 0;
}
if (m_bo_array)
{
gl.deleteBuffers(1, &m_bo_array);
m_bo_array = 0;
}
}
/** @brief Clean GL objects related to transform feedback. */
void AttributeFormatTest::CleanXFB()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_bo_xfb)
{
gl.deleteBuffers(1, &m_bo_xfb);
m_bo_xfb = 0;
}
while (gl.getError())
;
}
const glw::GLchar* AttributeFormatTest::s_vertex_shader_head = "#version 450\n"
"\n";
const glw::GLchar* AttributeFormatTest::s_vertex_shader_body = "\n"
"void main()\n"
"{\n"
" gl_Position = vec4(1.0);\n"
" result = a_0 + a_1;"
"}\n";
const glw::GLchar* AttributeFormatTest::s_vertex_shader_declaration[ATTRIBUTE_FORMAT_FUNCTION_COUNT]
[4 /* sizes count */] = { {
"in float a_0;"
"in float a_1;"
"out float result;\n",
"in vec2 a_0;"
"in vec2 a_1;"
"out vec2 result;\n",
"in vec3 a_0;"
"in vec3 a_1;"
"out vec3 result;\n",
"in vec4 a_0;"
"in vec4 a_1;"
"out vec4 result;\n",
},
{
"in double a_0;"
"in double a_1;"
"out double result;\n",
"in dvec2 a_0;"
"in dvec2 a_1;"
"out dvec2 result;\n",
"in dvec3 a_0;"
"in dvec3 a_1;"
"out dvec3 result;\n",
"in dvec4 a_0;"
"in dvec4 a_1;"
"out dvec4 result;\n",
},
{
"in int a_0;"
"in int a_1;"
"out int result;\n",
"in ivec2 a_0;"
"in ivec2 a_1;"
"out ivec2 result;\n",
"in ivec3 a_0;"
"in ivec3 a_1;"
"out ivec3 result;\n",
"in ivec4 a_0;"
"in ivec4 a_1;"
"out ivec4 result;\n",
} };
const glw::GLchar* AttributeFormatTest::s_fragment_shader = "#version 450\n"
"\n"
"out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0);"
"}\n";
/******************************** Vertex Array Object Attribute Binding Test Implementation ********************************/
/** @brief Attribute Binding Test constructor.
*
* @param [in] context OpenGL context.
*/
AttributeBindingTest::AttributeBindingTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_attribute_binding", "Vertex Array Objects Attribute Binding Test")
, m_po(0)
, m_vao(0)
, m_bo_array(0)
, m_bo_xfb(0)
{
/* Intentionally left blank. */
}
/** @brief Iterate Attribute Binding Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult AttributeBindingTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
try
{
PrepareProgram();
is_ok &= PrepareVAO();
PrepareXFB();
is_ok &= DrawAndCheck();
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
Clean();
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Build test's GLSL program.
*
* @note The function may throw if unexpected error has occured.
*/
void AttributeBindingTest::PrepareProgram()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
struct Shader
{
glw::GLchar const* const source;
glw::GLenum const type;
glw::GLuint id;
} shader[] = { { s_vertex_shader, GL_VERTEX_SHADER, 0 }, { s_fragment_shader, GL_FRAGMENT_SHADER, 0 } };
glw::GLuint const shader_count = DE_LENGTH_OF_ARRAY(shader);
try
{
/* Create program. */
m_po = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed.");
/* Shader compilation. */
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (DE_NULL != shader[i].source)
{
shader[i].id = gl.createShader(shader[i].type);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed.");
gl.attachShader(m_po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed.");
gl.shaderSource(shader[i].id, 1, &(shader[i].source), NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed.");
gl.compileShader(shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed.");
glw::GLint status = GL_FALSE;
gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
if (GL_FALSE == status)
{
glw::GLint log_size = 0;
gl.getShaderiv(shader[i].id, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getShaderInfoLog(shader[i].id, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n"
<< "Shader type: " << glu::getShaderTypeStr(shader[i].type)
<< "\n"
<< "Shader compilation error log:\n"
<< log_text << "\n"
<< "Shader source code:\n"
<< shader[i].source << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog call failed.");
throw 0;
}
}
}
/* Binding attributes. */
gl.bindAttribLocation(m_po, 0, "a_0");
gl.bindAttribLocation(m_po, 1, "a_1");
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindAttribLocation call failed.");
/* Transform Feedback setup. */
static const glw::GLchar* xfb_varying = "result";
gl.transformFeedbackVaryings(m_po, 1, &xfb_varying, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
/* Link. */
gl.linkProgram(m_po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
glw::GLint status = GL_FALSE;
gl.getProgramiv(m_po, GL_LINK_STATUS, &status);
if (GL_TRUE == status)
{
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (shader[i].id)
{
gl.detachShader(m_po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed.");
}
}
}
else
{
glw::GLint log_size = 0;
gl.getProgramiv(m_po, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getProgramInfoLog(m_po, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program linkage has failed due to:\n"
<< log_text << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
throw 0;
}
}
catch (...)
{
if (m_po)
{
gl.deleteProgram(m_po);
m_po = 0;
}
}
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (0 != shader[i].id)
{
gl.deleteShader(shader[i].id);
shader[i].id = 0;
}
}
if (0 == m_po)
{
throw 0;
}
}
/** @brief Prepare vertex array object for the test.
*
* @return True if function VertexArrayAttribBinding does not generate any error.
*/
bool AttributeBindingTest::PrepareVAO()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* VAO creation. */
gl.genVertexArrays(1, &m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
/* Array buffer creation. */
glw::GLint array_data[2] = { 1, 0 };
gl.genBuffers(1, &m_bo_array);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_array);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.bufferData(GL_ARRAY_BUFFER, sizeof(array_data), array_data, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
gl.vertexAttribIPointer(0, 1, GL_INT, sizeof(glw::GLint) * 2, NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribIPointer call failed.");
gl.vertexAttribIPointer(1, 1, GL_INT, sizeof(glw::GLint) * 2, glu::BufferOffsetAsPointer(1 * sizeof(glw::GLint)));
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribIPointer call failed.");
gl.enableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.enableVertexAttribArray(1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.vertexArrayAttribBinding(m_vao, 0, 1);
gl.vertexArrayAttribBinding(m_vao, 1, 0);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "VertexArrayAttribBinding has unexpectedly generated "
<< glu::getErrorStr(error) << "error. Test fails.\n"
<< tcu::TestLog::EndMessage;
return false;
}
return true;
}
/** @brief Prepare buffer object for test GLSL program transform feedback results.
*/
void AttributeBindingTest::PrepareXFB()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Buffer creation. */
gl.genBuffers(1, &m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
/* Preparing storage. */
gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, 2 * sizeof(glw::GLint), NULL, GL_MAP_READ_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
}
/** @brief Draw test program, fetch transform feedback results and compare them with expected values.
*
* @return True if expected results are equal to returned by XFB, false otherwise.
*/
bool AttributeBindingTest::DrawAndCheck()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Setup state. */
gl.useProgram(m_po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
/* Draw. */
gl.drawArrays(GL_POINTS, 0, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
/* State reset. */
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* Result query. */
glw::GLint* result_ptr = (glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed.");
glw::GLint result[2] = { result_ptr[0], result_ptr[1] };
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
/* Check result and return. */
if ((0 == result[0]) || (1 == result[1]))
{
return true;
}
return false;
}
/** @brief Clean GL objects. */
void AttributeBindingTest::Clean()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(0);
if (m_po)
{
gl.deleteProgram(m_po);
m_po = 0;
}
if (m_vao)
{
gl.deleteVertexArrays(1, &m_vao);
m_vao = 0;
}
if (m_bo_array)
{
gl.deleteBuffers(1, &m_bo_array);
m_bo_array = 0;
}
if (m_bo_xfb)
{
gl.deleteBuffers(1, &m_bo_xfb);
m_bo_xfb = 0;
}
while (gl.getError())
;
}
const glw::GLchar AttributeBindingTest::s_vertex_shader[] = "#version 450\n"
"\n"
"in int a_0;\n"
"in int a_1;\n"
"out ivec2 result;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(1.0);\n"
" result[0] = a_0;\n"
" result[1] = a_1;\n"
"}\n";
const glw::GLchar AttributeBindingTest::s_fragment_shader[] = "#version 450\n"
"\n"
"out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0);"
"}\n";
/******************************** Vertex Array Attribute Binding Divisor Test Implementation ********************************/
/** @brief Vertex Array Attribute Binding Divisor Test constructor.
*
* @param [in] context OpenGL context.
*/
AttributeBindingDivisorTest::AttributeBindingDivisorTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_attribute_binding_divisor", "Vertex Array Attribute Binding Divisor Test")
, m_po(0)
, m_vao(0)
, m_bo_array(0)
, m_bo_xfb(0)
{
/* Intentionally left blank. */
}
/** @brief Iterate Vertex Array Attribute Binding Divisor Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult AttributeBindingDivisorTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
try
{
PrepareProgram();
PrepareVAO();
PrepareXFB();
{
glw::GLint reference[] = { 0, 2 };
is_ok = SetDivisor(2);
Draw(1, 2);
is_ok = CheckXFB((sizeof(reference) / sizeof(reference[0])), reference,
"Draw of 1 point with 2 instances with 2 divisor has failed.");
}
{
glw::GLint reference[] = { 0, 0, 1, 1 };
is_ok = SetDivisor(1);
Draw(2, 2);
is_ok = CheckXFB((sizeof(reference) / sizeof(reference[0])), reference,
"Draw of 2 points with 2 instances with 1 divisor has failed.");
}
{
glw::GLint reference[] = { 0, 1, 2, 3 };
is_ok = SetDivisor(1);
Draw(1, 4);
is_ok = CheckXFB((sizeof(reference) / sizeof(reference[0])), reference,
"Draw of 1 point with 4 instances with 1 divisor has failed.");
}
{
glw::GLint reference[] = { 0, 1, 0, 1 };
is_ok = SetDivisor(0);
Draw(2, 2);
is_ok = CheckXFB((sizeof(reference) / sizeof(reference[0])), reference,
"Draw of 2 points with 2 instances with 0 divisor has failed.");
}
{
glw::GLint reference[] = { 0, 1, 2, 3 };
is_ok = SetDivisor(0);
Draw(4, 1);
is_ok = CheckXFB((sizeof(reference) / sizeof(reference[0])), reference,
"Draw of 4 points with 1 instance with 0 divisor has failed.");
}
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
Clean();
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Build test's GLSL program.
*
* @note The function may throw if unexpected error has occured.
*/
void AttributeBindingDivisorTest::PrepareProgram()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
struct Shader
{
glw::GLchar const* const source;
glw::GLenum const type;
glw::GLuint id;
} shader[] = { { s_vertex_shader, GL_VERTEX_SHADER, 0 }, { s_fragment_shader, GL_FRAGMENT_SHADER, 0 } };
glw::GLuint const shader_count = sizeof(shader) / sizeof(shader[0]);
try
{
/* Create program. */
m_po = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed.");
/* Shader compilation. */
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (DE_NULL != shader[i].source)
{
shader[i].id = gl.createShader(shader[i].type);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed.");
gl.attachShader(m_po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed.");
gl.shaderSource(shader[i].id, 1, &(shader[i].source), NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed.");
gl.compileShader(shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed.");
glw::GLint status = GL_FALSE;
gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
if (GL_FALSE == status)
{
glw::GLint log_size = 0;
gl.getShaderiv(shader[i].id, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getShaderInfoLog(shader[i].id, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n"
<< "Shader type: " << glu::getShaderTypeStr(shader[i].type)
<< "\n"
<< "Shader compilation error log:\n"
<< log_text << "\n"
<< "Shader source code:\n"
<< shader[i].source << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog call failed.");
throw 0;
}
}
}
/* Transform Feedback setup. */
static const glw::GLchar* xfb_varying = "result";
gl.transformFeedbackVaryings(m_po, 1, &xfb_varying, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
/* Link. */
gl.linkProgram(m_po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
glw::GLint status = GL_FALSE;
gl.getProgramiv(m_po, GL_LINK_STATUS, &status);
if (GL_TRUE == status)
{
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (shader[i].id)
{
gl.detachShader(m_po, shader[i].id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed.");
}
}
}
else
{
glw::GLint log_size = 0;
gl.getProgramiv(m_po, GL_INFO_LOG_LENGTH, &log_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
glw::GLchar* log_text = new glw::GLchar[log_size];
gl.getProgramInfoLog(m_po, log_size, NULL, &log_text[0]);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program linkage has failed due to:\n"
<< log_text << "\n"
<< tcu::TestLog::EndMessage;
delete[] log_text;
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
throw 0;
}
}
catch (...)
{
if (m_po)
{
gl.deleteProgram(m_po);
m_po = 0;
}
}
for (glw::GLuint i = 0; i < shader_count; ++i)
{
if (0 != shader[i].id)
{
gl.deleteShader(shader[i].id);
shader[i].id = 0;
}
}
if (m_po)
{
gl.useProgram(m_po);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
}
if (0 == m_po)
{
throw 0;
}
}
/** @brief Prepare vertex array object for the test.
*/
void AttributeBindingDivisorTest::PrepareVAO()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* VAO creation. */
gl.genVertexArrays(1, &m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
/* Array buffer 0 creation. */
glw::GLint array_data[4] = { 0, 1, 2, 3 };
gl.genBuffers(1, &m_bo_array);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_array);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.bufferData(GL_ARRAY_BUFFER, sizeof(array_data), array_data, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
gl.vertexAttribBinding(gl.getAttribLocation(m_po, "a"), 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribBinding call failed.");
gl.vertexAttribIFormat(gl.getAttribLocation(m_po, "a"), 1, GL_INT, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribIFormat call failed.");
gl.bindVertexBuffer(0, m_bo_array, 0, sizeof(glw::GLint));
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexBuffer call failed.");
gl.enableVertexAttribArray(gl.getAttribLocation(m_po, "a"));
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
}
/** @brief Prepare buffer object for test GLSL program transform feedback results.
*/
void AttributeBindingDivisorTest::PrepareXFB()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Buffer creation. */
gl.genBuffers(1, &m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
/* Preparing storage. */
gl.bufferStorage(GL_TRANSFORM_FEEDBACK_BUFFER, 4 * sizeof(glw::GLint), NULL, GL_MAP_READ_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferStorage call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
}
/** @brief Draw number of points and number of instances with XFB environment.
*
* @param [in] number_of_points Number of points to be drawn.
* @param [in] number_of_instances Number of instances to be drawn.
*/
void AttributeBindingDivisorTest::Draw(glw::GLuint number_of_points, glw::GLuint number_of_instances)
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Setup state. */
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
/* Draw. */
gl.drawArraysInstanced(GL_POINTS, 0, number_of_points, number_of_instances);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArraysInstanced call failed.");
/* State reset. */
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
}
/** @brief Call VertexArrayBindingDivisor on m_vao object and check errors.
*
* @param [in] divisor Divisor to be passed.
*
* @return True if VertexArrayBindingDivisor doe not generate any error, false otherwise.
*/
bool AttributeBindingDivisorTest::SetDivisor(glw::GLuint divisor)
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Setup. */
gl.vertexArrayBindingDivisor(m_vao, 0, divisor);
/* Checking for errors (this is tested function so it fail the test if there is error). */
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "VertexArrayBindingDivisor unexpectedl generated " << glu::getErrorStr(error)
<< " error when called with divisor" << divisor << ". " << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/** @brief Check transform feedback results and log.
*
* @param [in] count Number of results to be checked.
* @param [in] expected Expected results.
* @param [in] log_message Message to be logged if expected values are not equal to queried.
*
* @return True if expected values are equal to queried, false otherwise.
*/
bool AttributeBindingDivisorTest::CheckXFB(const glw::GLuint count, const glw::GLint expected[],
const glw::GLchar* log_message)
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Result setup */
bool is_ok = true;
/* Result query. */
glw::GLint* result = (glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed.");
/* Check result and return. */
for (glw::GLuint i = 0; i < count; ++i)
{
if (expected[i] != result[i])
{
std::string expected_str = "[";
std::string result_str = "[";
for (glw::GLuint j = 0; j < count; ++j)
{
expected_str.append(Utilities::itoa((glw::GLuint)expected[j]));
result_str.append(Utilities::itoa((glw::GLuint)result[j]));
if (j < count - 1)
{
expected_str.append(", ");
result_str.append(", ");
}
else
{
expected_str.append("]");
result_str.append("]");
}
}
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Result is " << result_str << ", but "
<< expected_str << " was expected. " << log_message
<< tcu::TestLog::EndMessage;
is_ok = false;
break;
}
}
/* Unmaping GL buffer. */
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
return is_ok;
}
/** @brief Clean GL objects. */
void AttributeBindingDivisorTest::Clean()
{
/* Shortcut for GL functionality */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(0);
if (m_po)
{
gl.deleteProgram(m_po);
m_po = 0;
}
if (m_vao)
{
gl.deleteVertexArrays(1, &m_vao);
m_vao = 0;
}
if (m_bo_array)
{
gl.deleteBuffers(1, &m_bo_array);
m_bo_array = 0;
}
if (m_bo_xfb)
{
gl.deleteBuffers(1, &m_bo_xfb);
m_bo_xfb = 0;
}
while (gl.getError())
;
}
const glw::GLchar AttributeBindingDivisorTest::s_vertex_shader[] = "#version 450\n"
"\n"
"in int a;\n"
"out int result;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(1.0);\n"
" result = a;"
"}\n";
const glw::GLchar AttributeBindingDivisorTest::s_fragment_shader[] = "#version 450\n"
"\n"
"out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0);"
"}\n";
/******************************** Get Vertex Array Test Implementation ********************************/
/** @brief Get Vertex Array Test constructor.
*
* @param [in] context OpenGL context.
*/
GetVertexArrayTest::GetVertexArrayTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_get_vertex_array", "Get Vertex Array Test")
{
/* Intentionally left blank. */
}
/** @brief Iterate Vertex Array Attribute Binding Divisor Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult GetVertexArrayTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* Test objects. */
glw::GLuint vao = 0;
glw::GLuint bo = 0;
try
{
gl.genVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
gl.bindVertexArray(vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
gl.genBuffers(1, &bo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateBuffers call failed.");
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
glw::GLint result = 0;
gl.getVertexArrayiv(vao, GL_ELEMENT_ARRAY_BUFFER_BINDING, &result);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GetVertexArrayiv unexpectedly generated "
<< glu::getErrorStr(error) << "error. Test fails."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
if ((glw::GLuint)result != bo)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GetVertexArrayiv was expected to return "
<< bo << ", but " << result << " was observed. Test fails."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
if (vao)
{
gl.deleteVertexArrays(1, &vao);
}
if (bo)
{
gl.deleteBuffers(1, &bo);
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/******************************** Get Vertex Array Test Indexed Implementation ********************************/
/** @brief Get Vertex Array Indexed Test constructor.
*
* @param [in] context OpenGL context.
*/
GetVertexArrayIndexedTest::GetVertexArrayIndexedTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_get_vertex_array_indexed", "Get Vertex Array Indexed Test"), m_vao(0)
{
m_bo[0] = 0;
m_bo[1] = 0;
m_bo[2] = 0;
m_bo[3] = 0;
}
/** @brief Iterate Vertex Array Attribute Binding Divisor Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult GetVertexArrayIndexedTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
try
{
PrepareVAO();
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_ENABLED, 0, GL_TRUE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_ENABLED, 1, GL_TRUE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_ENABLED, 2, GL_TRUE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_ENABLED, 3, GL_TRUE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_ENABLED, 5, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_STRIDE, 0, 0);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_STRIDE, 1, 2);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_STRIDE, 2, 0);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_STRIDE, 3, 8);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_TYPE, 0, GL_BYTE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_TYPE, 1, GL_SHORT);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_TYPE, 2, GL_FLOAT);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_TYPE, 3, GL_UNSIGNED_INT_2_10_10_10_REV);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, 0, GL_TRUE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, 1, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, 2, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, 3, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_INTEGER, 0, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_INTEGER, 1, GL_TRUE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_INTEGER, 2, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_INTEGER, 3, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_DIVISOR, 0, 3);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_DIVISOR, 1, 2);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_DIVISOR, 2, 1);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_DIVISOR, 3, 0);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_LONG, 0, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_LONG, 1, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_LONG, 2, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_ARRAY_LONG, 3, GL_FALSE);
is_ok &= Check(GL_VERTEX_ATTRIB_RELATIVE_OFFSET, 0, 0);
is_ok &= Check(GL_VERTEX_ATTRIB_RELATIVE_OFFSET, 1, 0);
is_ok &= Check(GL_VERTEX_ATTRIB_RELATIVE_OFFSET, 2, 4);
is_ok &= Check(GL_VERTEX_ATTRIB_RELATIVE_OFFSET, 3, 0);
is_ok &= Check64(GL_VERTEX_BINDING_OFFSET, 0, 0);
is_ok &= Check64(GL_VERTEX_BINDING_OFFSET, 1, 2);
is_ok &= Check64(GL_VERTEX_BINDING_OFFSET, 2, 8);
is_ok &= Check64(GL_VERTEX_BINDING_OFFSET, 3, 4);
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
if (m_vao)
{
gl.deleteVertexArrays(1, &m_vao);
m_vao = 0;
}
if (m_bo[0] || m_bo[1] || m_bo[2] || m_bo[3])
{
gl.deleteBuffers(4, m_bo);
m_bo[0] = 0;
m_bo[1] = 0;
m_bo[2] = 0;
m_bo[3] = 0;
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Prepare vertex array object for the test.
*/
void GetVertexArrayIndexedTest::PrepareVAO()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.genVertexArrays(1, &m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
gl.genBuffers(4, m_bo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateBuffers call failed.");
/* Attribute 0. */
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.vertexAttribPointer(0, 1, GL_BYTE, GL_TRUE, 0, NULL);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer call failed.");
gl.enableVertexAttribArray(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.vertexAttribDivisor(0, 3);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribDivisor call failed.");
/* Attribute 1. */
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo[1]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.vertexAttribIPointer(1, 2, GL_SHORT, 2, glu::BufferOffsetAsPointer(2 * sizeof(glw::GLchar)));
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer call failed.");
gl.enableVertexAttribArray(1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.vertexAttribDivisor(1, 2);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribDivisor call failed.");
/* Attribute 2. */
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo[2]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.vertexAttribBinding(2, 2);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribBinding call failed.");
gl.vertexAttribFormat(2, 3, GL_FLOAT, GL_FALSE, 4);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribIFormat call failed.");
gl.bindVertexBuffer(2, m_bo[2], 8, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexBuffer call failed.");
gl.enableVertexAttribArray(2);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.vertexAttribDivisor(2, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribDivisor call failed.");
/* Attribute 3. */
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo[3]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.vertexAttribPointer(3, 4, GL_UNSIGNED_INT_2_10_10_10_REV, GL_FALSE, 8, glu::BufferOffsetAsPointer(4 * sizeof(glw::GLchar)));
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer call failed.");
gl.enableVertexAttribArray(3);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
gl.vertexAttribDivisor(3, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribDivisor call failed.");
}
/** @brief Compare value queried using GetVertexArrayIndexediv with expected value and log.
*
* @param [in] pname Parameter to be queried.
* @param [in] index Index to be queried.
* @param [in] expected Expected error.
*
* @return True if value is equal to expected, false otherwise.
*/
bool GetVertexArrayIndexedTest::Check(const glw::GLenum pname, const glw::GLuint index, const glw::GLint expected)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLint result = 0;
gl.getVertexArrayIndexediv(m_vao, index, pname, &result);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GetVertexArrayIndexediv called with index "
<< index << ", with pname" << glu::getVertexAttribParameterNameStr(pname)
<< " unexpectedly generated " << glu::getErrorStr(error)
<< "error. Test fails." << tcu::TestLog::EndMessage;
return false;
}
if (result != expected)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GetVertexArrayIndexediv called with index "
<< index << " and with pname" << glu::getVertexAttribParameterNameStr(pname)
<< " returned " << result << ", but " << expected
<< " was expected. Test fails." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/** @brief Compare value queried using GetVertexArrayIndexed64iv with expected value and log.
*
* @param [in] pname Parameter to be queried.
* @param [in] index Index to be queried.
* @param [in] expected Expected error.
*
* @return True if value is equal to expected, false otherwise.
*/
bool GetVertexArrayIndexedTest::Check64(const glw::GLenum pname, const glw::GLuint index, const glw::GLint64 expected)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLint64 result = 0;
gl.getVertexArrayIndexed64iv(m_vao, index, pname, &result);
if (glw::GLenum error = gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GetVertexArrayIndexed64iv called with index "
<< index << ", with pname" << glu::getVertexAttribParameterNameStr(pname)
<< " unexpectedly generated " << glu::getErrorStr(error)
<< "error. Test fails." << tcu::TestLog::EndMessage;
return false;
}
if (result != expected)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GetVertexArrayIndexed64iv called with index "
<< index << " and with pname" << glu::getVertexAttribParameterNameStr(pname)
<< " returned " << result << ", but " << expected
<< " was expected. Test fails." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/******************************** Defaults Test Implementation ********************************/
/** @brief Defaults Test constructor.
*
* @param [in] context OpenGL context.
*/
DefaultsTest::DefaultsTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_defaults", "Defaults Test"), m_vao(0)
{
}
/** @brief Iterate Defaults Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult DefaultsTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* Test objects. */
glw::GLint max_attributes = 8;
try
{
/* Query limits. */
gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_attributes);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
/* Prepare default Vertex Array Object. */
PrepareVAO();
/* Check default values per attribute index. */
for (glw::GLint i = 0; i < max_attributes; ++i)
{
is_ok &= CheckIndexed(GL_VERTEX_ATTRIB_ARRAY_ENABLED, i, GL_FALSE);
is_ok &= CheckIndexed(GL_VERTEX_ATTRIB_ARRAY_SIZE, i, 4);
is_ok &= CheckIndexed(GL_VERTEX_ATTRIB_ARRAY_STRIDE, i, 0);
is_ok &= CheckIndexed(GL_VERTEX_ATTRIB_ARRAY_TYPE, i, GL_FLOAT);
is_ok &= CheckIndexed(GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, i, GL_FALSE);
is_ok &= CheckIndexed(GL_VERTEX_ATTRIB_ARRAY_INTEGER, i, GL_FALSE);
is_ok &= CheckIndexed(GL_VERTEX_ATTRIB_ARRAY_DIVISOR, i, 0);
is_ok &= CheckIndexed(GL_VERTEX_ATTRIB_ARRAY_LONG, i, GL_FALSE);
is_ok &= CheckIndexed(GL_VERTEX_ATTRIB_RELATIVE_OFFSET, i, 0);
is_ok &= CheckIndexed64(GL_VERTEX_BINDING_OFFSET, i, 0);
}
/* Check default values per vertex array object. */
is_ok &= Check(GL_ELEMENT_ARRAY_BUFFER_BINDING, 0);
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
if (m_vao)
{
gl.deleteVertexArrays(1, &m_vao);
m_vao = 0;
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Prepare vertex array object for the test.
*/
void DefaultsTest::PrepareVAO()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.createVertexArrays(1, &m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
}
/** @brief Compare value queried using GetVertexArrayiv with expected value and log.
*
* @param [in] pname Parameter to be queried.
* @param [in] expected Expected error.
*
* @return True if value is equal to expected, false otherwise.
*/
bool DefaultsTest::Check(const glw::GLenum pname, const glw::GLint expected)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLint result = 0;
gl.getVertexArrayiv(m_vao, pname, &result);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetVertexArrayiv call failed.");
if (result != expected)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Default Vertex Array Object has parameter "
<< glu::getVertexAttribParameterNameStr(pname) << " equal to " << result
<< ", but " << expected << " was expected. Test fails."
<< tcu::TestLog::EndMessage;
return false;
}
return true;
}
/** @brief Compare value queried using GetVertexArrayIndexediv with expected value and log.
*
* @param [in] pname Parameter to be queried.
* @param [in] index Index to be queried.
* @param [in] expected Expected error.
*
* @return True if value is equal to expected, false otherwise.
*/
bool DefaultsTest::CheckIndexed(const glw::GLenum pname, const glw::GLuint index, const glw::GLint expected)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLint result = 0;
gl.getVertexArrayIndexediv(m_vao, index, pname, &result);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetVertexArrayIndexediv call failed.");
if (result != expected)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Default Vertex Array Object at index " << index
<< " has parameter " << glu::getVertexAttribParameterNameStr(pname)
<< " equal to " << result << ", but " << expected
<< " was expected. Test fails." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/** @brief Compare value queried using GetVertexArrayIndexed64iv with expected value and log.
*
* @param [in] pname Parameter to be queried.
* @param [in] index Index to be queried.
* @param [in] expected Expected error.
*
* @return True if value is equal to expected, false otherwise.
*/
bool DefaultsTest::CheckIndexed64(const glw::GLenum pname, const glw::GLuint index, const glw::GLint64 expected)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLint64 result = 0;
gl.getVertexArrayIndexed64iv(m_vao, index, pname, &result);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetVertexArrayIndexed64iv call failed.");
if (result != expected)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Default Vertex Array Object at index " << index
<< " has parameter " << glu::getVertexAttribParameterNameStr(pname)
<< " equal to " << result << ", but " << expected
<< " was expected. Test fails." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/******************************** Creation Error Test Implementation ********************************/
/** @brief Creation Error Test constructor.
*
* @param [in] context OpenGL context.
*/
CreationErrorTest::CreationErrorTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_creation_error", "Creation Error Test")
{
}
/** @brief Iterate Creation Error Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult CreationErrorTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
try
{
glw::GLuint negative_vao = 0;
gl.createVertexArrays(-1, &negative_vao);
is_ok = CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated if n is negative.");
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Compare error returned by GL with expected value and log.
*
* @param [in] expected Expected error.
* @param [in] log_message Message to be logged if expected error is not the equal to the reported one.
*
* @return True if GL error is equal to expected, false otherwise.
*/
bool CreationErrorTest::CheckError(const glw::GLenum expected, const glw::GLchar* log_message)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLenum error = 0;
if (expected != (error = gl.getError()))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << log_message << " " << glu::getErrorStr(error)
<< "was observed instead." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/******************************** Enable Disable Attribute Errors Test Implementation ********************************/
/** @brief Enable Disable Attribute Errors Test constructor.
*
* @param [in] context OpenGL context.
*/
EnableDisableAttributeErrorsTest::EnableDisableAttributeErrorsTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_enable_disable_attribute_errors", "Enable Disable Attribute Errors Test")
{
}
/** @brief Enable Disable Attribute Errors Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult EnableDisableAttributeErrorsTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* Test objects. */
glw::GLint max_attributes = 8;
/* Tested VAOs. */
glw::GLuint vao = 0;
glw::GLuint not_a_vao = 0;
try
{
/* Query limits. */
gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_attributes);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
/* Prepare valid VAO. */
gl.createVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
/* Prepare invalid VAO. */
while (gl.isVertexArray(++not_a_vao))
;
/* Test not a VAO. */
gl.enableVertexArrayAttrib(0, not_a_vao);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by EnableVertexArrayAttrib if "
"vaobj is not the name of an existing vertex array object.");
gl.disableVertexArrayAttrib(0, not_a_vao);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by DisableVertexArrayAttrib if "
"vaobj is not the name of an existing vertex array object.");
/* Test to big attribute index. */
gl.enableVertexArrayAttrib(max_attributes, vao);
is_ok &= CheckError(
GL_INVALID_OPERATION,
"INVALID_VALUE was not generated by EnableVertexArrayAttrib if index is equal to MAX_VERTEX_ATTRIBS.");
gl.disableVertexArrayAttrib(max_attributes, vao);
is_ok &= CheckError(
GL_INVALID_OPERATION,
"INVALID_VALUE was not generated by DisableVertexArrayAttrib if index is equal to MAX_VERTEX_ATTRIBS.");
gl.enableVertexArrayAttrib(max_attributes + 1, vao);
is_ok &= CheckError(
GL_INVALID_OPERATION,
"INVALID_VALUE was not generated by EnableVertexArrayAttrib if index is greater than MAX_VERTEX_ATTRIBS.");
gl.disableVertexArrayAttrib(max_attributes + 1, vao);
is_ok &= CheckError(
GL_INVALID_OPERATION,
"INVALID_VALUE was not generated by DisableVertexArrayAttrib if index is greater than MAX_VERTEX_ATTRIBS.");
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Clean up. */
if (vao)
{
gl.deleteVertexArrays(1, &vao);
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Compare error returned by GL with expected value and log.
*
* @param [in] expected Expected error.
* @param [in] log_message Message to be logged if expected error is not the equal to the reported one.
*
* @return True if GL error is equal to expected, false otherwise.
*/
bool EnableDisableAttributeErrorsTest::CheckError(const glw::GLenum expected, const glw::GLchar* log_message)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLenum error = 0;
if (expected != (error = gl.getError()))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << log_message << " " << glu::getErrorStr(error)
<< "was observed instead." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/******************************** Element Buffer Errors Test Implementation ********************************/
/** @brief Element Buffer Errors Test constructor.
*
* @param [in] context OpenGL context.
*/
ElementBufferErrorsTest::ElementBufferErrorsTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_element_buffer_errors", "Element Buffer Errors Test")
{
}
/** @brief Element Buffer Errors Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult ElementBufferErrorsTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* Tested Objects. */
glw::GLuint vao = 0;
glw::GLuint not_a_vao = 0;
glw::GLuint bo = 0;
glw::GLuint not_a_bo = 0;
try
{
/* Prepare valid Objects. */
gl.createVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
gl.createBuffers(1, &bo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateBuffers call failed.");
/* Prepare invalid VAO. */
while (gl.isVertexArray(++not_a_vao))
;
while (gl.isBuffer(++not_a_bo))
;
/* Test not a VAO. */
gl.vertexArrayElementBuffer(not_a_vao, bo);
is_ok &=
CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION error was not generated by VertexArrayElementBuffer if "
"vaobj is not the name of an existing vertex array object.");
/* Test not a BO. */
gl.vertexArrayElementBuffer(vao, not_a_bo);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION error is generated by VertexArrayElementBuffer if "
"buffer is not zero or the name of an existing buffer object.");
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Clean up. */
if (vao)
{
gl.deleteVertexArrays(1, &vao);
}
if (bo)
{
gl.deleteBuffers(1, &bo);
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Compare error returned by GL with expected value and log.
*
* @param [in] expected Expected error.
* @param [in] log_message Message to be logged if expected error is not the equal to the reported one.
*
* @return True if GL error is equal to expected, false otherwise.
*/
bool ElementBufferErrorsTest::CheckError(const glw::GLenum expected, const glw::GLchar* log_message)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLenum error = 0;
if (expected != (error = gl.getError()))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << log_message << " " << glu::getErrorStr(error)
<< " was observed instead." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/******************************** Vertex Buffers Errors Test Implementation ********************************/
/** @brief Vertex Buffers Errors Test constructor.
*
* @param [in] context OpenGL context.
*/
VertexBuffersErrorsTest::VertexBuffersErrorsTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_vertex_buffers_errors", "Vertex Buffers Errors Test")
{
}
/** @brief Vertex Buffers Errors Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult VertexBuffersErrorsTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* Tested Objects. */
glw::GLuint vao = 0;
glw::GLuint not_a_vao = 0;
glw::GLuint bo = 0;
glw::GLuint not_a_bo = 0;
/* Valid setup. */
glw::GLintptr valid_offset = 0;
glw::GLsizei valid_stride = 1;
/* Limits. (Minimum values - OpenGL 4.5 Core Specification, Table 23.55) */
glw::GLint max_vertex_attrib_bindings = 16;
glw::GLint max_vertex_attrib_stride = 2048;
try
{
/* Prepare valid Objects. */
gl.createVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
gl.createBuffers(1, &bo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateBuffers call failed.");
/* Prepare invalid VAO. */
while (gl.isVertexArray(++not_a_vao))
;
while (gl.isBuffer(++not_a_bo))
;
/* Prepare limits. */
gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &max_vertex_attrib_bindings);
gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &max_vertex_attrib_stride);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
/* Invalid setup. */
glw::GLintptr invalid_offset = -1;
glw::GLsizei invalid_stride_0 = -1;
glw::GLsizei invalid_stride_1 = max_vertex_attrib_stride + 1;
/* Test not a VAO. */
gl.vertexArrayVertexBuffer(not_a_vao, 0, bo, valid_offset, valid_stride);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayVertexBuffer if "
"vaobj is not the name of an existing vertex array object.");
gl.vertexArrayVertexBuffers(not_a_vao, 0, 1, &bo, &valid_offset, &valid_stride);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayVertexBuffers if "
"vaobj is not the name of an existing vertex array object.");
/* Test not a BO. */
gl.vertexArrayVertexBuffer(vao, 0, not_a_bo, valid_offset, valid_stride);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayVertexBuffer if "
"vaobj is not the name of an existing vertex array object.");
gl.vertexArrayVertexBuffers(vao, 0, 1, &not_a_bo, &valid_offset, &valid_stride);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayVertexBuffers if "
"vaobj is not the name of an existing vertex array object.");
/* Test too big binding index. */
gl.vertexArrayVertexBuffer(vao, max_vertex_attrib_bindings, bo, valid_offset, valid_stride);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayVertexBuffer if "
"bindingindex is equal to the value of MAX_VERTEX_ATTRIB_BINDINGS.");
gl.vertexArrayVertexBuffer(vao, max_vertex_attrib_bindings + 1, bo, valid_offset, valid_stride);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayVertexBuffer if "
"bindingindex is greater than the value of MAX_VERTEX_ATTRIB_BINDINGS.");
gl.vertexArrayVertexBuffers(vao, max_vertex_attrib_bindings, 1, &bo, &valid_offset, &valid_stride);
is_ok &=
CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayVertexBuffers if "
"first+count is greater than the value of MAX_VERTEX_ATTRIB_BINDINGS.");
/* Test too big stride. */
gl.vertexArrayVertexBuffer(vao, 0, bo, -1, valid_stride);
is_ok &= CheckError(GL_INVALID_VALUE,
"INVALID_VALUE is generated by VertexArrayVertexBuffer if offset less than zero.");
gl.vertexArrayVertexBuffer(vao, 0, bo, valid_offset, -1);
is_ok &= CheckError(GL_INVALID_VALUE,
"INVALID_VALUE is generated by VertexArrayVertexBuffer if stride is less than zero.");
gl.vertexArrayVertexBuffer(vao, 0, bo, valid_offset, max_vertex_attrib_stride + 1);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE is generated by VertexArrayVertexBuffer if stride is "
"greater than the value of MAX_VERTEX_ATTRIB_STRIDE.");
gl.vertexArrayVertexBuffers(vao, 0, 1, &bo, &invalid_offset, &valid_stride);
is_ok &=
CheckError(GL_INVALID_VALUE,
"INVALID_VALUE is generated by VertexArrayVertexBuffers if any value in offsets is negative.");
gl.vertexArrayVertexBuffers(vao, 0, 1, &bo, &valid_offset, &invalid_stride_0);
is_ok &=
CheckError(GL_INVALID_VALUE,
"INVALID_VALUE is generated by VertexArrayVertexBuffers if any value in strides is negative.");
gl.vertexArrayVertexBuffers(vao, 0, 1, &bo, &valid_offset, &invalid_stride_1);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE is generated by VertexArrayVertexBuffers if a value in "
"strides is greater than the value of MAX_VERTEX_ATTRIB_STRIDE.");
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Clean up. */
if (vao)
{
gl.deleteVertexArrays(1, &vao);
}
if (bo)
{
gl.deleteBuffers(1, &bo);
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Compare error returned by GL with expected value and log.
*
* @param [in] expected Expected error.
* @param [in] log_message Message to be logged if expected error is not the equal to the reported one.
*
* @return True if GL error is equal to expected, false otherwise.
*/
bool VertexBuffersErrorsTest::CheckError(const glw::GLenum expected, const glw::GLchar* log_message)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLenum error = 0;
if (expected != (error = gl.getError()))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << log_message << " " << glu::getErrorStr(error)
<< " was observed instead." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/******************************** Attribute Format Errors Test Implementation ********************************/
/** @brief Attribute Format Errors Test constructor.
*
* @param [in] context OpenGL context.
*/
AttributeFormatErrorsTest::AttributeFormatErrorsTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_attribute_format_errors", "Attribute Format Errors Test")
{
}
/** @brief Attribute Format Errors Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult AttributeFormatErrorsTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* Tested Objects. */
glw::GLuint vao = 0;
glw::GLuint not_a_vao = 0;
/* Limits. (Minimum values - OpenGL 4.5 Core Specification, Table 23.55) */
glw::GLint max_vertex_attribs = 16;
glw::GLint max_vertex_attrib_relative_offset = 2047;
/* Invalid values. */
glw::GLenum bad_type = 0;
static const glw::GLenum accepted_types[] = { GL_BYTE,
GL_SHORT,
GL_INT,
GL_FIXED,
GL_FLOAT,
GL_HALF_FLOAT,
GL_DOUBLE,
GL_UNSIGNED_BYTE,
GL_UNSIGNED_SHORT,
GL_UNSIGNED_INT,
GL_INT_2_10_10_10_REV,
GL_UNSIGNED_INT_2_10_10_10_REV,
GL_UNSIGNED_INT_10F_11F_11F_REV };
{
bool is_accepted_type = true;
while (is_accepted_type)
{
bad_type++;
is_accepted_type = false;
for (glw::GLuint i = 0; i < DE_LENGTH_OF_ARRAY(accepted_types); ++i)
{
if (accepted_types[i] == bad_type)
{
is_accepted_type = true;
break;
}
}
}
}
try
{
/* Prepare valid Objects. */
gl.createVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
/* Prepare invalid VAO. */
while (gl.isVertexArray(++not_a_vao))
;
/* Prepare limits. */
gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);
gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &max_vertex_attrib_relative_offset);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
/* TESTS OF VERTEXARRAYATTRIBFORMAT */
/* MAX_VERTEX_ATTRIBS < */
gl.vertexArrayAttribFormat(vao, max_vertex_attribs, 1, GL_BYTE, GL_FALSE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribFormat if "
"attribindex is equal to the value of MAX_VERTEX_ATTRIBS.");
gl.vertexArrayAttribFormat(vao, max_vertex_attribs + 1, 1, GL_BYTE, GL_FALSE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribFormat if "
"attribindex is greater than the value of MAX_VERTEX_ATTRIBS.");
gl.vertexArrayAttribIFormat(vao, max_vertex_attribs, 1, GL_BYTE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribIFormat if "
"attribindex is equal to the value of MAX_VERTEX_ATTRIBS.");
gl.vertexArrayAttribIFormat(vao, max_vertex_attribs + 1, 1, GL_BYTE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribIFormat if "
"attribindex is greater than the value of MAX_VERTEX_ATTRIBS.");
gl.vertexArrayAttribLFormat(vao, max_vertex_attribs, 1, GL_DOUBLE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribLFormat if "
"attribindex is equal to the value of MAX_VERTEX_ATTRIBS.");
gl.vertexArrayAttribLFormat(vao, max_vertex_attribs + 1, 1, GL_DOUBLE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribLFormat if "
"attribindex is greater than the value of MAX_VERTEX_ATTRIBS.");
/* size */
gl.vertexArrayAttribFormat(vao, 0, 0, GL_BYTE, GL_FALSE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttrib*Format if size is "
"not one of the accepted values (0).");
gl.vertexArrayAttribFormat(vao, 0, 5, GL_BYTE, GL_FALSE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttrib*Format if size is "
"not one of the accepted values (5).");
gl.vertexArrayAttribIFormat(vao, 0, 0, GL_BYTE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribIFormat if size is "
"not one of the accepted values (0).");
gl.vertexArrayAttribIFormat(vao, 0, 5, GL_BYTE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribIFormat if size is "
"not one of the accepted values (5).");
gl.vertexArrayAttribLFormat(vao, 0, 0, GL_DOUBLE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribLFormat if size is "
"not one of the accepted values (0).");
gl.vertexArrayAttribLFormat(vao, 0, 5, GL_DOUBLE, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribLFormat if size is "
"not one of the accepted values (5).");
/* relative offset */
gl.vertexArrayAttribFormat(vao, 0, 1, GL_BYTE, GL_FALSE, max_vertex_attrib_relative_offset + 1);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttrib*Format if "
"relativeoffset is greater than the value of "
"MAX_VERTEX_ATTRIB_RELATIVE_OFFSET.");
gl.vertexArrayAttribIFormat(vao, 0, 1, GL_BYTE, max_vertex_attrib_relative_offset + 1);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribIFormat if "
"relativeoffset is greater than the value of "
"MAX_VERTEX_ATTRIB_RELATIVE_OFFSET.");
gl.vertexArrayAttribLFormat(vao, 0, 1, GL_DOUBLE, max_vertex_attrib_relative_offset + 1);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribLFormat if "
"relativeoffset is greater than the value of "
"MAX_VERTEX_ATTRIB_RELATIVE_OFFSET.");
/* type */
gl.vertexArrayAttribFormat(vao, 0, 1, bad_type, GL_FALSE, 0);
is_ok &= CheckError(
GL_INVALID_ENUM,
"INVALID_ENUM was not generated by VertexArrayAttribFormat if type is not one of the accepted tokens.");
gl.vertexArrayAttribIFormat(vao, 0, 1, bad_type, 0);
is_ok &= CheckError(
GL_INVALID_ENUM,
"INVALID_ENUM was not generated by VertexArrayAttribIFormat if type is not one of the accepted tokens.");
gl.vertexArrayAttribLFormat(vao, 0, 1, bad_type, 0);
is_ok &= CheckError(
GL_INVALID_ENUM,
"INVALID_ENUM was not generated by VertexArrayAttribLFormat if type is not one of the accepted tokens.");
/* type UNSIGNED_INT_10F_11F_11F_REV case */
gl.vertexArrayAttribIFormat(vao, 0, 1, GL_UNSIGNED_INT_10F_11F_11F_REV, 0);
is_ok &= CheckError(
GL_INVALID_ENUM,
"INVALID_ENUM was not generated by VertexArrayAttribIFormat if type is UNSIGNED_INT_10F_11F_11F_REV.");
gl.vertexArrayAttribLFormat(vao, 0, 1, GL_UNSIGNED_INT_10F_11F_11F_REV, 0);
is_ok &= CheckError(
GL_INVALID_ENUM,
"INVALID_ENUM was not generated by VertexArrayAttribLFormat if type is UNSIGNED_INT_10F_11F_11F_REV.");
/* Test not a VAO. */
gl.vertexArrayAttribFormat(not_a_vao, 0, 1, GL_BYTE, GL_FALSE, 0);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayAttribFormat if "
"vaobj is not the name of an existing vertex array object.");
gl.vertexArrayAttribIFormat(not_a_vao, 0, 1, GL_BYTE, 0);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayAttribIFormat if "
"vaobj is not the name of an existing vertex array object.");
gl.vertexArrayAttribLFormat(not_a_vao, 0, 1, GL_DOUBLE, 0);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayAttribLFormat if "
"vaobj is not the name of an existing vertex array object.");
/* BGRA */
gl.vertexArrayAttribFormat(vao, 0, GL_BGRA, GL_BYTE, GL_TRUE, 0);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayAttribFormat if "
"size is BGRA and type is not UNSIGNED_BYTE, INT_2_10_10_10_REV or "
"UNSIGNED_INT_2_10_10_10_REV.");
gl.vertexArrayAttribFormat(vao, 0, 1, GL_INT_2_10_10_10_REV, GL_TRUE, 0);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayAttribFormat if "
"type is INT_2_10_10_10_REV and size is neither 4 nor BGRA.");
gl.vertexArrayAttribFormat(vao, 0, 1, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 0);
is_ok &=
CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayAttribFormat if type "
"is UNSIGNED_INT_2_10_10_10_REV and size is neither 4 nor BGRA.");
gl.vertexArrayAttribFormat(vao, 0, 1, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_TRUE, 0);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayAttribFormat if "
"type is UNSIGNED_INT_10F_11F_11F_REV and size is not 3.");
gl.vertexArrayAttribFormat(vao, 0, GL_BGRA, GL_UNSIGNED_BYTE, GL_FALSE, 0);
is_ok &= CheckError(
GL_INVALID_OPERATION,
"INVALID_OPERATION was not generated by VertexArrayAttribFormat if size is BGRA and normalized is FALSE.");
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Clean up. */
if (vao)
{
gl.deleteVertexArrays(1, &vao);
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Compare error returned by GL with expected value and log.
*
* @param [in] expected Expected error.
* @param [in] log_message Message to be logged if expected error is not the equal to the reported one.
*
* @return True if GL error is equal to expected, false otherwise.
*/
bool AttributeFormatErrorsTest::CheckError(const glw::GLenum expected, const glw::GLchar* log_message)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLenum error = 0;
if (expected != (error = gl.getError()))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << log_message << " " << glu::getErrorStr(error)
<< " was observed instead." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/******************************** Attribute Binding Errors Test Implementation ********************************/
/** @brief Attribute Binding Errors Test constructor.
*
* @param [in] context OpenGL context.
*/
AttributeBindingErrorsTest::AttributeBindingErrorsTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_attribute_binding_errors", "Attribute Binding Errors Test")
{
}
/** @brief Attribute Binding Errors Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult AttributeBindingErrorsTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* Tested Objects. */
glw::GLuint vao = 0;
glw::GLuint not_a_vao = 0;
/* Limits. (Minimum values - OpenGL 4.5 Core Specification, Table 23.55) */
glw::GLint max_vertex_attribs = 16;
glw::GLint max_vertex_attrib_bindings = 16;
try
{
/* Prepare valid Objects. */
gl.createVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
/* Prepare invalid VAO. */
while (gl.isVertexArray(++not_a_vao))
;
/* Prepare limits. */
gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);
gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &max_vertex_attrib_bindings);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
/* Not a VAO. */
gl.vertexArrayAttribBinding(not_a_vao, 0, 0);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayAttribBinding if "
"vaobj is not the name of an existing vertex array object.");
/* Too big attribute index. */
gl.vertexArrayAttribBinding(vao, max_vertex_attribs, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribBinding if "
"attribindex is equal to the value of MAX_VERTEX_ATTRIBS.");
gl.vertexArrayAttribBinding(vao, max_vertex_attribs + 1, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribBinding if "
"attribindex is greater than the value of MAX_VERTEX_ATTRIBS.");
/* Too big binding index. */
gl.vertexArrayAttribBinding(vao, 0, max_vertex_attrib_bindings);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribBinding if "
"bindingindex is equal to the value of MAX_VERTEX_ATTRIB_BINDINGS.");
gl.vertexArrayAttribBinding(vao, 0, max_vertex_attrib_bindings + 1);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayAttribBinding if "
"bindingindex is greater than the value of MAX_VERTEX_ATTRIB_BINDINGS.");
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Clean up. */
if (vao)
{
gl.deleteVertexArrays(1, &vao);
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Compare error returned by GL with expected value and log.
*
* @param [in] expected Expected error.
* @param [in] log_message Message to be logged if expected error is not the equal to the reported one.
*
* @return True if GL error is equal to expected, false otherwise.
*/
bool AttributeBindingErrorsTest::CheckError(const glw::GLenum expected, const glw::GLchar* log_message)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLenum error = 0;
if (expected != (error = gl.getError()))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << log_message << " " << glu::getErrorStr(error)
<< " was observed instead." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/******************************** Attribute Binding Divisor Errors Test Implementation ********************************/
/** @brief Attribute Binding Divisor Errors Test constructor.
*
* @param [in] context OpenGL context.
*/
AttributeBindingDivisorErrorsTest::AttributeBindingDivisorErrorsTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_attribute_binding_divisor_errors", "Attribute Binding Divisor Errors Test")
{
}
/** @brief Attribute Binding Divisor Errors Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult AttributeBindingDivisorErrorsTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* Tested Objects. */
glw::GLuint vao = 0;
glw::GLuint not_a_vao = 0;
/* Limits. (Minimum values - OpenGL 4.5 Core Specification, Table 23.55) */
glw::GLint max_vertex_attrib_bindings = 16;
try
{
/* Prepare valid Objects. */
gl.createVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
/* Prepare invalid VAO. */
while (gl.isVertexArray(++not_a_vao))
;
/* Prepare limits. */
gl.getIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &max_vertex_attrib_bindings);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
/* Not a VAO. */
gl.vertexArrayBindingDivisor(not_a_vao, 0, 0);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION was not generated by VertexArrayBindingDivisor if "
"vaobj is not the name of an existing vertex array object.");
/* Too big binding index. */
gl.vertexArrayBindingDivisor(vao, max_vertex_attrib_bindings, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayBindingDivisor if "
"bindingindex is equal to the value of MAX_VERTEX_ATTRIB_BINDINGS.");
gl.vertexArrayBindingDivisor(vao, max_vertex_attrib_bindings + 1, 0);
is_ok &= CheckError(GL_INVALID_VALUE, "INVALID_VALUE was not generated by VertexArrayBindingDivisor if "
"bindingindex is greater than the value of MAX_VERTEX_ATTRIB_BINDINGS.");
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Clean up. */
if (vao)
{
gl.deleteVertexArrays(1, &vao);
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Compare error returned by GL with expected value and log.
*
* @param [in] expected Expected error.
* @param [in] log_message Message to be logged if expected error is not the equal to the reported one.
*
* @return True if GL error is equal to expected, false otherwise.
*/
bool AttributeBindingDivisorErrorsTest::CheckError(const glw::GLenum expected, const glw::GLchar* log_message)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLenum error = 0;
if (expected != (error = gl.getError()))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << log_message << " " << glu::getErrorStr(error)
<< " was observed instead." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/******************************** Get Vertex Array Errors Test Implementation ********************************/
/** @brief Get Vertex Array Errors Test constructor.
*
* @param [in] context OpenGL context.
*/
GetVertexArrayErrorsTest::GetVertexArrayErrorsTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_get_vertex_array_errors", "Get Vertex Array Errors Test")
{
}
/** @brief Iterate over Get Vertex Array Errors Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult GetVertexArrayErrorsTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* Tested Objects. */
glw::GLuint vao = 0;
glw::GLuint not_a_vao = 0;
glw::GLint storage = 0;
try
{
/* Prepare valid Objects. */
gl.createVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
/* Prepare invalid VAO. */
while (gl.isVertexArray(++not_a_vao))
;
/* Not a VAO. */
gl.getVertexArrayiv(not_a_vao, GL_ELEMENT_ARRAY_BUFFER_BINDING, &storage);
is_ok &= CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION error was not generated by GetVertexArrayiv if "
"vaobj is not the name of an existing vertex array object.");
/* Bad parameter. */
gl.getVertexArrayiv(vao, GL_ELEMENT_ARRAY_BUFFER_BINDING + 1, &storage);
is_ok &= CheckError(
GL_INVALID_ENUM,
"INVALID_ENUM error was not generated by GetVertexArrayiv if pname is not ELEMENT_ARRAY_BUFFER_BINDING.");
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Clean up. */
if (vao)
{
gl.deleteVertexArrays(1, &vao);
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Compare error returned by GL with expected value and log.
*
* @param [in] expected Expected error.
* @param [in] log_message Message to be logged if expected error is not the equal to the reported one.
*
* @return True if GL error is equal to expected, false otherwise.
*/
bool GetVertexArrayErrorsTest::CheckError(const glw::GLenum expected, const glw::GLchar* log_message)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLenum error = 0;
if (expected != (error = gl.getError()))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << log_message << " " << glu::getErrorStr(error)
<< " was observed instead." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/******************************** Get Vertex Array Indexed Errors Test Implementation ********************************/
/** @brief Get Vertex Array Indexed Errors Test constructor.
*
* @param [in] context OpenGL context.
*/
GetVertexArrayIndexedErrorsTest::GetVertexArrayIndexedErrorsTest(deqp::Context& context)
: deqp::TestCase(context, "vertex_arrays_get_vertex_array_indexed_errors", "Get Vertex Array Indexed Errors Test")
{
}
/** @brief Iterate over Get Vertex Array Indexed Errors Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult GetVertexArrayIndexedErrorsTest::iterate()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get context setup. */
bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access");
if ((!is_at_least_gl_45) && (!is_arb_direct_state_access))
{
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
return STOP;
}
/* Running tests. */
bool is_ok = true;
bool is_error = false;
/* Tested Objects. */
glw::GLuint vao = 0;
glw::GLuint not_a_vao = 0;
/* Unused storage. */
glw::GLint storage = 0;
glw::GLint64 storage64 = 0;
/* Bad parameter setup. */
glw::GLenum bad_pname = 0;
static const glw::GLenum accepted_pnames[] = { GL_VERTEX_ATTRIB_ARRAY_ENABLED, GL_VERTEX_ATTRIB_ARRAY_SIZE,
GL_VERTEX_ATTRIB_ARRAY_STRIDE, GL_VERTEX_ATTRIB_ARRAY_TYPE,
GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, GL_VERTEX_ATTRIB_ARRAY_INTEGER,
GL_VERTEX_ATTRIB_ARRAY_LONG, GL_VERTEX_ATTRIB_ARRAY_DIVISOR,
GL_VERTEX_ATTRIB_RELATIVE_OFFSET };
{
bool is_accepted_pname = true;
while (is_accepted_pname)
{
bad_pname++;
is_accepted_pname = false;
for (glw::GLuint i = 0; i < DE_LENGTH_OF_ARRAY(accepted_pnames); ++i)
{
if (accepted_pnames[i] == bad_pname)
{
is_accepted_pname = true;
break;
}
}
}
}
try
{
/* Prepare valid Objects. */
gl.createVertexArrays(1, &vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateVertexArrays call failed.");
/* Prepare invalid VAO. */
while (gl.isVertexArray(++not_a_vao))
;
/* Not a VAO. */
gl.getVertexArrayIndexediv(not_a_vao, 0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &storage);
is_ok &=
CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION error was not generated by GetVertexArrayIndexediv if "
"vaobj is not the name of an existing vertex array object.");
gl.getVertexArrayIndexed64iv(not_a_vao, 0, GL_VERTEX_BINDING_OFFSET, &storage64);
is_ok &=
CheckError(GL_INVALID_OPERATION, "INVALID_OPERATION error was not generated by GetVertexArrayIndexed64iv "
"if vaobj is not the name of an existing vertex array object.");
/* Bad parameter. */
gl.getVertexArrayIndexediv(vao, 0, bad_pname, &storage);
is_ok &= CheckError(
GL_INVALID_ENUM,
"INVALID_ENUM error was not generated by GetVertexArrayIndexediv if pname is not one of the valid values.");
/* Bad parameter 64. */
gl.getVertexArrayIndexed64iv(vao, 0, GL_VERTEX_BINDING_OFFSET + 1, &storage64);
is_ok &= CheckError(
GL_INVALID_ENUM,
"INVALID_ENUM error was not generated by GetVertexArrayIndexed64iv if pname is not VERTEX_BINDING_OFFSET.");
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Clean up. */
if (vao)
{
gl.deleteVertexArrays(1, &vao);
}
/* Errors clean up. */
while (gl.getError())
;
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (is_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
/** @brief Compare error returned by GL with expected value and log.
*
* @param [in] expected Expected error.
* @param [in] log_message Message to be logged if expected error is not the equal to the reported one.
*
* @return True if GL error is equal to expected, false otherwise.
*/
bool GetVertexArrayIndexedErrorsTest::CheckError(const glw::GLenum expected, const glw::GLchar* log_message)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLenum error = 0;
if (expected != (error = gl.getError()))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << log_message << " " << glu::getErrorStr(error)
<< " was observed instead." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
} /* VertexArrays namespace. */
} /* DirectStateAccess namespace. */
} /* gl4cts namespace. */