| /*------------------------------------------------------------------------- |
| * 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, ¬_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; |
| |
| /* Dummy 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; |
| } |
| } // namespace VertexArrays |
| } // namespace DirectStateAccess |
| } // namespace gl4cts |