blob: a72d778187e2beec3ef42182b363223a1095fae4 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2015-2016 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/ /*!
* \file
* \brief
*/ /*-------------------------------------------------------------------*/
/**
*/ /*!
* \file gl3cTransformFeedback.cpp
* \brief Transform Feedback Test Suite Implementation
*/ /*-------------------------------------------------------------------*/
/* Includes. */
#include "gl3cTransformFeedbackTests.hpp"
#include "gluContextInfo.hpp"
#include "gluDefs.hpp"
#include "gluRenderContext.hpp"
#include "gluStrUtil.hpp"
#include "tcuTestLog.hpp"
#include <algorithm>
#include <climits>
#include <cmath>
#include <cstdlib>
#include <sstream>
/* Stringify macro. */
#define _STR(s) STR(s)
#define STR(s) #s
/* Unused attribute / variable MACRO.
Some methods of clesses' heirs do not need all function parameters.
This triggers warnings on GCC platform. This macro will silence them.
*/
#ifdef __GNUC__
#define UNUSED __attribute__((__unused__))
#else
#define UNUSED
#endif
gl3cts::TransformFeedback::Tests::Tests(deqp::Context& context)
: TestCaseGroup(context, "transform_feedback", "Transform Feedback Test Suite")
{
addChild(new TransformFeedback::APIErrors(m_context));
addChild(new TransformFeedback::LinkingErrors(m_context));
addChild(new TransformFeedback::Limits(m_context));
addChild(new TransformFeedback::CaptureVertexInterleaved(m_context, "capture_vertex_interleaved_test",
"Transform Feedback Capture Vertex Interleaved Test"));
addChild(new TransformFeedback::CaptureGeometryInterleaved(m_context, "capture_geometry_interleaved_test",
"Transform Feedback Capture Geometry Interleaved Test"));
addChild(new TransformFeedback::CaptureVertexSeparate(m_context, "capture_vertex_separate_test",
"Transform Feedback Capture Vertex Separate Test"));
addChild(new TransformFeedback::CaptureGeometrySeparate(m_context, "capture_geometry_separate_test",
"Transform Feedback Capture Geometry Separate Test"));
addChild(new TransformFeedback::CheckGetXFBVarying(m_context, "get_xfb_varying",
"Transform Feedback Varying Getters Test"));
addChild(new TransformFeedback::QueryVertexInterleaved(m_context, "query_vertex_interleaved_test",
"Transform Feedback Query Vertex Interleaved Test"));
addChild(new TransformFeedback::QueryGeometryInterleaved(m_context, "query_geometry_interleaved_test",
"Transform Feedback Query Geometry Interleaved Test"));
addChild(new TransformFeedback::QueryVertexSeparate(m_context, "query_vertex_separate_test",
"Transform Feedback Query Vertex Separate Test"));
addChild(new TransformFeedback::QueryGeometrySeparate(m_context, "query_geometry_separate_test",
"Transform Feedback Query Geometry Separate Test"));
addChild(new TransformFeedback::DiscardVertex(m_context, "discard_vertex_test",
"Transform Feedback Discard Vertex Test"));
addChild(new TransformFeedback::DiscardGeometry(m_context, "discard_geometry_test",
"Transform Feedback Discard Geometry Test"));
addChild(new TransformFeedback::DrawXFB(m_context, "draw_xfb_test", "Transform Feedback Draw Test"));
addChild(new TransformFeedback::DrawXFBFeedback(m_context, "draw_xfb_feedbackk_test",
"Transform Feedback Draw Feedback Test"));
addChild(
new TransformFeedback::DrawXFBStream(m_context, "draw_xfb_stream_test", "Transform Feedback Draw Stream Test"));
addChild(new TransformFeedback::CaptureSpecialInterleaved(m_context, "capture_special_interleaved_test",
"Transform Feedback Capture Special Test"));
addChild(new TransformFeedback::DrawXFBInstanced(m_context, "draw_xfb_instanced_test",
"Transform Feedback Draw Instanced Test"));
addChild(new TransformFeedback::DrawXFBStreamInstanced(m_context, "draw_xfb_stream_instanced_test",
"Transform Feedback Draw Stream Instanced Test"));
}
gl3cts::TransformFeedback::Tests::~Tests(void)
{
}
void gl3cts::TransformFeedback::Tests::init(void)
{
}
gl3cts::TransformFeedback::APIErrors::APIErrors(deqp::Context& context)
: deqp::TestCase(context, "api_errors_test", "Transform Feedback API Errors Test")
, m_context(context)
, m_buffer_0(0)
, m_buffer_1(0)
, m_vertex_array_object(0)
, m_transform_feedback_object_0(0)
, m_transform_feedback_object_1(0)
, m_query_object(0)
, m_program_id_with_input_output(0)
, m_program_id_with_output(0)
, m_program_id_without_output(0)
, m_program_id_with_geometry_shader(0)
, m_program_id_with_tessellation_shaders(0)
, m_glBindBufferOffsetEXT(DE_NULL)
, m_glGetIntegerIndexedvEXT(DE_NULL)
, m_glGetBooleanIndexedvEXT(DE_NULL)
{
}
gl3cts::TransformFeedback::APIErrors::~APIErrors(void)
{
}
tcu::TestNode::IterateResult gl3cts::TransformFeedback::APIErrors::iterate(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Initializations. */
bool is_at_least_gl_30 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 0)));
bool is_at_least_gl_40 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)));
bool is_at_least_gl_42 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 2)));
bool is_ext_tf_1 = m_context.getContextInfo().isExtensionSupported("GL_EXT_transform_feedback");
bool is_arb_tf_2 = m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback2");
bool is_arb_tf_3 = m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback3");
bool is_arb_tf_instanced = m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback_instanced");
if (is_ext_tf_1)
{
/* Extension query. */
m_glBindBufferOffsetEXT =
(BindBufferOffsetEXT_ProcAddress)m_context.getRenderContext().getProcAddress("glBindBufferOffsetEXT");
m_glGetIntegerIndexedvEXT =
(GetIntegerIndexedvEXT_ProcAddress)m_context.getRenderContext().getProcAddress("glGetIntegerIndexedvEXT");
m_glGetBooleanIndexedvEXT =
(GetBooleanIndexedvEXT_ProcAddress)m_context.getRenderContext().getProcAddress("glGetBooleanIndexedvEXT");
}
if (is_at_least_gl_40 || is_arb_tf_2)
{
/* Create transform feedback objects. */
gl.genTransformFeedbacks(1, &m_transform_feedback_object_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks call failed.");
}
if (is_at_least_gl_40 || is_arb_tf_3)
{
/* Create query object. */
gl.genQueries(1, &m_query_object);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries call failed.");
}
if (is_at_least_gl_42 || is_arb_tf_instanced)
{
/* Create transform feedback objects. */
gl.genTransformFeedbacks(1, &m_transform_feedback_object_1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks call failed.");
}
/* Default result. */
bool is_ok = true;
bool test_error = false;
/* Entities setup. */
try
{
/* VAO setup. */
gl.genVertexArrays(1, &m_vertex_array_object);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
gl.bindVertexArray(m_vertex_array_object);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
/* Buffer setup. */
gl.genBuffers(1, &m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
gl.genBuffers(1, &m_buffer_1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer_1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.bufferData(GL_ARRAY_BUFFER, m_buffer_1_size, m_buffer_1_data, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
/* Programs setup. */
m_program_id_with_input_output = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, s_vertex_shader_with_input_output,
s_fragment_shader, &m_varying_name, 1, GL_INTERLEAVED_ATTRIBS);
m_program_id_with_output = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, s_vertex_shader_with_output, s_fragment_shader,
&m_varying_name, 1, GL_INTERLEAVED_ATTRIBS, true);
m_program_id_without_output = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, s_vertex_shader_without_output,
s_fragment_shader, NULL, 0, GL_SEPARATE_ATTRIBS);
m_program_id_with_geometry_shader = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), m_geometry_shader, NULL, NULL, s_vertex_shader_without_output,
s_fragment_shader, &m_varying_name, 1, GL_INTERLEAVED_ATTRIBS);
m_program_id_with_tessellation_shaders = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), NULL, m_tessellation_control_shader,
m_tessellation_evaluation_shader, s_vertex_shader_without_output, s_fragment_shader, &m_varying_name, 1,
GL_INTERLEAVED_ATTRIBS);
is_ok = is_ok && m_program_id_with_input_output && m_program_id_with_output && m_program_id_without_output &&
m_program_id_with_geometry_shader && m_program_id_with_tessellation_shaders;
}
catch (...)
{
is_ok = false;
test_error = true;
}
/* Iterating tests. */
try
{
if (is_at_least_gl_30 || is_ext_tf_1)
{
is_ok = is_ok && testExtension1();
}
if (is_at_least_gl_40 || is_arb_tf_2)
{
is_ok = is_ok && testExtension2();
}
if (is_at_least_gl_40 || is_arb_tf_3)
{
is_ok = is_ok && testExtension3();
}
if (is_at_least_gl_42 || is_arb_tf_instanced)
{
is_ok = is_ok && testInstanced();
}
}
catch (...)
{
is_ok = false;
test_error = true;
}
/* Deinitialization. */
if (m_vertex_array_object)
{
gl.deleteVertexArrays(1, &m_vertex_array_object);
m_vertex_array_object = 0;
}
if (m_buffer_0)
{
gl.deleteBuffers(1, &m_buffer_0); // silently unbinds
m_buffer_0 = 0;
}
if (m_buffer_1)
{
gl.deleteBuffers(1, &m_buffer_1); // silently unbinds
m_buffer_1 = 0;
}
if (m_transform_feedback_object_0)
{
gl.deleteTransformFeedbacks(1, &m_transform_feedback_object_0);
m_transform_feedback_object_0 = 0;
}
if (m_transform_feedback_object_1)
{
gl.deleteTransformFeedbacks(1, &m_transform_feedback_object_1);
m_transform_feedback_object_1 = 0;
}
if (m_query_object)
{
gl.deleteQueries(1, &m_query_object);
m_query_object = 0;
}
if (m_program_id_with_input_output)
{
gl.deleteProgram(m_program_id_with_input_output);
m_program_id_with_input_output = 0;
}
if (m_program_id_with_output)
{
gl.deleteProgram(m_program_id_with_output);
m_program_id_with_output = 0;
}
if (m_program_id_without_output)
{
gl.deleteProgram(m_program_id_without_output);
m_program_id_without_output = 0;
}
if (m_program_id_with_geometry_shader)
{
gl.deleteProgram(m_program_id_with_geometry_shader);
m_program_id_with_geometry_shader = 0;
}
if (m_program_id_with_tessellation_shaders)
{
gl.deleteProgram(m_program_id_with_tessellation_shaders);
m_program_id_with_tessellation_shaders = 0;
}
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (test_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
bool gl3cts::TransformFeedback::APIErrors::testExtension1(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* INVALID_VALUE is generated by BindBufferRange, BindBufferOffset and
BindBufferBase when <index> is greater or equal to
MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS; */
glw::GLint index_count = 0;
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &index_count);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (index_count == 0)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetIntegerv did not returned any value."
<< tcu::TestLog::EndMessage;
throw 0;
}
gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, index_count, m_buffer_0, 0, 16);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_VALUE was not generated by BindBufferRange "
"when <index> was greater or equal to "
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS."
<< tcu::TestLog::EndMessage;
return false;
}
if (DE_NULL != m_glBindBufferOffsetEXT)
{
m_glBindBufferOffsetEXT(GL_TRANSFORM_FEEDBACK_BUFFER, index_count, m_buffer_0, 0);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_VALUE was not generated by BindBufferOffset "
"when <index> was greater or equal to "
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS."
<< tcu::TestLog::EndMessage;
return false;
}
}
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, index_count, m_buffer_0);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_VALUE was not generated by "
"BindBufferBase when <index> was greater or equal to "
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_VALUE is generated by BindBufferRange when <size> is less or equal to zero; */
gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, index_count, m_buffer_0, 0, 0);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_VALUE was not generated by BindBufferRange when <size> was less or equal to zero."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_VALUE is generated by BindBufferRange and BindBufferOffset
when <offset> is not word-aligned; */
gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, index_count, m_buffer_0, 3, 4);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_VALUE was not generated by BindBufferRange when <offset> was not word-aligned."
<< tcu::TestLog::EndMessage;
return false;
}
if (DE_NULL != m_glBindBufferOffsetEXT)
{
m_glBindBufferOffsetEXT(GL_TRANSFORM_FEEDBACK_BUFFER, index_count, m_buffer_0, 3);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_VALUE was not generated by BindBufferOffset when <offset> was not word-aligned."
<< tcu::TestLog::EndMessage;
return false;
}
}
/* INVALID_VALUE is generated by BindBufferRange when <size> is not word-aligned; */
gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, index_count, m_buffer_0, 0, 3);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_VALUE was not generated by BindBufferRange when <size> was not word-aligned."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_OPERATION is generated by BindBufferRange, BindBufferOffset and
BindBufferBase when <target> is TRANSFORM_FEEDBACK_BUFFER and transform
feedback is active; */
gl.useProgram(m_program_id_with_output);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0, 0, 16);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by BindBufferRange "
"when <target> was TRANSFORM_FEEDBACK_BUFFER and transform "
"feedback was active."
<< tcu::TestLog::EndMessage;
gl.endTransformFeedback();
return false;
}
if (DE_NULL != m_glBindBufferOffsetEXT)
{
m_glBindBufferOffsetEXT(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0, 0);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by BindBufferOffset "
"when <target> was TRANSFORM_FEEDBACK_BUFFER and transform "
"feedback was active."
<< tcu::TestLog::EndMessage;
gl.endTransformFeedback();
return false;
}
}
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_OPERATION was not generated by "
"BindBufferBase when <target> was TRANSFORM_FEEDBACK_BUFFER and transform "
"feedback was active."
<< tcu::TestLog::EndMessage;
gl.endTransformFeedback();
return false;
}
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* INVALID_OPERATION is generated by UseProgram when transform feedback is
active; */
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
gl.useProgram(0);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by UseProgram when transform feedback was active."
<< tcu::TestLog::EndMessage;
gl.endTransformFeedback();
return false;
}
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* INVALID_OPERATION is generated by LinkProgram when <program> is currently
active and transform feedback is active; */
gl.useProgram(m_program_id_with_output);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
gl.linkProgram(m_program_id_with_output);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by LinkProgram when <program> was "
"currently active and transform feedback was active."
<< tcu::TestLog::EndMessage;
gl.endTransformFeedback();
return false;
}
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* INVALID_OPERATION is generated by BeginTransformFeedback when transform
feedback is active; */
gl.useProgram(m_program_id_with_output);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
gl.beginTransformFeedback(GL_POINTS);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by BeginTransformFeedback when transform feedback was active."
<< tcu::TestLog::EndMessage;
gl.endTransformFeedback();
return false;
}
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* INVALID_OPERATION is generated by EndTransformFeedback when transform
feedback is inactive; */
gl.endTransformFeedback();
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by EndTransformFeedback when transform feedback was inactive."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_OPERATION is generated by draw command when generated primitives
type does not match <primitiveMode>; */
gl.useProgram(m_program_id_with_output);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
gl.drawArrays(GL_LINES, 0, 2);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by draw command when generated "
"primitives type does not match <primitiveMode>."
<< tcu::TestLog::EndMessage;
gl.endTransformFeedback();
return false;
}
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* INVALID_OPERATION is generated by BeginTransformFeedback when any binding
point used by XFB does not have buffer bound; */
gl.useProgram(m_program_id_with_output);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
gl.beginTransformFeedback(GL_POINTS);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by BeginTransformFeedback when any "
"binding point used by XFB does not have buffer bound."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_OPERATION is generated by BeginTransformFeedback when no program
is active; */
gl.useProgram(0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
gl.beginTransformFeedback(GL_POINTS);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by BeginTransformFeedback when no program was active."
<< tcu::TestLog::EndMessage;
gl.endTransformFeedback();
return false;
}
/* INVALID_OPERATION is generated by BeginTransformFeedback when no variable
are specified to be captured in the active program; */
gl.useProgram(m_program_id_without_output);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
gl.beginTransformFeedback(GL_POINTS);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by BeginTransformFeedback when no variable "
"are specified to be captured in the active program."
<< tcu::TestLog::EndMessage;
gl.endTransformFeedback();
return false;
}
/* INVALID_VALUE is generated by TransformFeedbackVaryings when <program> is
not id of the program object; */
unsigned short int invalid_name = 1;
while (gl.isProgram(invalid_name) || gl.isShader(invalid_name))
{
++invalid_name;
/* Make sure that this loop ends someday, bad day. */
if (invalid_name == USHRT_MAX)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Cannot find unused trnasform feedback object." << tcu::TestLog::EndMessage;
throw 0;
}
}
gl.transformFeedbackVaryings((glw::GLuint)invalid_name, 1, &m_varying_name, GL_INTERLEAVED_ATTRIBS);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_VALUE was not generated by TransformFeedbackVaryings when "
"<program> was not id of the program object."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_VALUE is generated by TransformFeedbackVaryings when <bufferMode>
is SEPARATE_ATTRIBS and <count> is exceeds limits; */
glw::GLint max_separate_attribs = 0;
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &max_separate_attribs);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_separate_attribs == 0)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_VALUE was not generated by TransformFeedbackVaryings when <bufferMode>"
" was SEPARATE_ATTRIBS and <count> was exceeds limits."
<< tcu::TestLog::EndMessage;
throw 0;
}
glw::GLint more_than_max_separate_attribs = max_separate_attribs + 1;
glw::GLchar** attrib = new glw::GLchar*[more_than_max_separate_attribs];
for (glw::GLint i = 0; i < more_than_max_separate_attribs; ++i)
{
std::string new_attrib = "a" + gl3cts::TransformFeedback::Utilities::itoa(i);
size_t new_attrib_size = new_attrib.size();
attrib[i] = new glw::GLchar[new_attrib_size + 1];
memset(attrib[i], 0, new_attrib_size + 1);
memcpy(attrib[i], new_attrib.c_str(), new_attrib_size);
}
gl.transformFeedbackVaryings(m_program_id_with_output, more_than_max_separate_attribs, attrib, GL_SEPARATE_ATTRIBS);
for (glw::GLint i = 0; i < more_than_max_separate_attribs; ++i)
{
delete[] attrib[i];
}
delete[] attrib;
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_VALUE was not generated by TransformFeedbackVaryings when "
"<bufferMode> was SEPARATE_ATTRIBS and <count> exceeded limits."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_VALUE is generated by GetTransformFeedbackVarying when <index> is
greater than or equal to TRANSFORM_FEEDBACK_VARYINGS; */
glw::GLint transform_feedback_varyings = 0;
gl.getProgramiv(m_program_id_with_output, GL_TRANSFORM_FEEDBACK_VARYINGS, &transform_feedback_varyings);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
if (transform_feedback_varyings == 0)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "glGetProgramiv failed to return GL_TRANSFORM_FEEDBACK_VARYINGS."
<< tcu::TestLog::EndMessage;
throw 0;
}
glw::GLchar tmp_buffer[256];
glw::GLsizei tmp_size = 0;
glw::GLenum tmp_type = GL_NONE;
gl.getTransformFeedbackVarying(m_program_id_with_output, transform_feedback_varyings, sizeof(tmp_buffer), NULL,
&tmp_size, &tmp_type, tmp_buffer);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_VALUE was not generated by GetTransformFeedbackVarying when "
"<index> was greater than or equal to TRANSFORM_FEEDBACK_VARYINGS."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_VALUE is generated by GetIntegerIndexdv when <index> exceeds the
limits of MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS and <param> is one of the
following:
* TRANSFORM_FEEDBACK_BUFFER_BINDING,
* TRANSFORM_FEEDBACK_BUFFER_START,
* TRANSFORM_FEEDBACK_BUFFER_SIZE; */
if (DE_NULL != m_glGetIntegerIndexedvEXT)
{
glw::GLint tmp_int_value;
m_glGetIntegerIndexedvEXT(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, more_than_max_separate_attribs, &tmp_int_value);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_VALUE was not generated by GetIntegerIndexdv when <index> exceeds the "
"limits of MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS and <param> was "
"TRANSFORM_FEEDBACK_BUFFER_BINDING."
<< tcu::TestLog::EndMessage;
return false;
}
m_glGetIntegerIndexedvEXT(GL_TRANSFORM_FEEDBACK_BUFFER_START, more_than_max_separate_attribs, &tmp_int_value);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_VALUE was not generated by GetIntegerIndexdv when <index> exceeds the "
"limits of MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS and <param> was "
"GL_TRANSFORM_FEEDBACK_BUFFER_START."
<< tcu::TestLog::EndMessage;
return false;
}
m_glGetIntegerIndexedvEXT(GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, more_than_max_separate_attribs, &tmp_int_value);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_VALUE was not generated by GetIntegerIndexdv when <index> exceeds the "
"limits of MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS and <param> was "
"GL_TRANSFORM_FEEDBACK_BUFFER_SIZE."
<< tcu::TestLog::EndMessage;
return false;
}
}
/* INVALID_VALUE is generated by GetBooleanIndexedv when <index> exceeds the
limits of MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS and <param> is
TRANSFORM_FEEDBACK_BUFFER_BINDING. */
if (DE_NULL != m_glGetBooleanIndexedvEXT)
{
glw::GLboolean tmp_bool_value;
m_glGetBooleanIndexedvEXT(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, more_than_max_separate_attribs,
&tmp_bool_value);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_VALUE was not generated by GetBooleanIndexedv when <index> exceeds the "
"limits of MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS and <param> was "
"TRANSFORM_FEEDBACK_BUFFER_BINDING."
<< tcu::TestLog::EndMessage;
return false;
}
}
return true;
}
bool gl3cts::TransformFeedback::APIErrors::testExtension2(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Bind Transform Feedback Object */
gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_transform_feedback_object_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback call failed.");
/* INVALID_OPERATION is generated by PauseTransformFeedback if current
transform feedback is not active or paused; */
gl.pauseTransformFeedback();
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION is not generated by PauseTransformFeedback if "
"current transform feedback is not active or paused."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_OPERATION is generated by ResumeTransformFeedback if current
transform feedback is not active; */
gl.resumeTransformFeedback();
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION is not generated by ResumeTransformFeedback if "
"current transform feedback is not active."
<< tcu::TestLog::EndMessage;
return false;
}
/* Prepare program and buffer. */
gl.useProgram(m_program_id_with_output);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
/* INVALID_OPERATION is generated by DrawTransformFeedback when
EndTransformFeedback was never called for the object named <id>. */
gl.drawTransformFeedback(GL_POINTS, m_transform_feedback_object_0);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION is not generated by DrawTransformFeedback when "
"EndTransformFeedback was never called for the object named <id>."
<< tcu::TestLog::EndMessage;
return false;
}
/* Make Transform Feedback Active */
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
/* INVALID_OPERATION is generated by BindTransformFeedback if current
transform feedback is active and not paused; */
gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_transform_feedback_object_0);
if (GL_INVALID_OPERATION != gl.getError())
{
gl.endTransformFeedback();
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION is not generated by BindTransformFeedback if current "
"transform feedback is active and not paused."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_OPERATION is generated by DeleteTransformFeedbacks if any of <ids>
is active; */
gl.deleteTransformFeedbacks(1, &m_transform_feedback_object_0);
if (GL_INVALID_OPERATION != gl.getError())
{
gl.endTransformFeedback();
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "INVALID_OPERATION is not generated by DeleteTransformFeedbacks if any of <ids> is active."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_OPERATION is generated by ResumeTransformFeedback if current
transform feedback is not not paused; */
gl.resumeTransformFeedback();
if (GL_INVALID_OPERATION != gl.getError())
{
gl.endTransformFeedback();
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION is not generated by ResumeTransformFeedback if "
"current transform feedback is not not paused."
<< tcu::TestLog::EndMessage;
return false;
}
/* pause transform feedback */
gl.pauseTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glPauseTransformFeedback call failed.");
/* No error is generated by draw command when transform feedback is paused
and primitive modes do not match; */
gl.drawArrays(GL_LINES, 0, 2);
if (GL_NO_ERROR != gl.getError())
{
gl.endTransformFeedback();
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "No error is not generated by draw command when transform feedback is "
"paused and primitive modes do not match."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_OPERATION is generated by LinkProgram when <program> is used by
some transform feedback object that is currently not active; */
gl.linkProgram(m_program_id_with_output);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_OPERATION was not generated by LinkProgram when <program> was "
"used by some transform feedback object that is currently not active."
<< tcu::TestLog::EndMessage;
gl.endTransformFeedback();
return false;
}
/* No error is generated by UseProgram when transform feedback is paused; */
gl.useProgram(0);
if (GL_NO_ERROR != gl.getError())
{
gl.endTransformFeedback();
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "glUseProgram unexpectedly failed when transform feedback is paused."
<< tcu::TestLog::EndMessage;
return false;
}
gl.useProgram(m_program_id_with_output);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
/* End Transform Feedback and make draw. */
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
/* INVALID_VALUE is generated by DrawTransformFeedback if <id> is not name of
transform feedback object; */
unsigned short int invalid_name = 1;
while (gl.isTransformFeedback(invalid_name))
{
++invalid_name;
/* Make sure that this loop ends someday, bad day. */
if (invalid_name == USHRT_MAX)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Cannot find unused trnasform feedback object." << tcu::TestLog::EndMessage;
throw 0;
}
}
gl.drawTransformFeedback(GL_POINTS, (glw::GLuint)invalid_name);
if (GL_INVALID_VALUE != gl.getError())
{
gl.endTransformFeedback();
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "glUseProgram unexpectedly failed when transform feedback is paused."
<< tcu::TestLog::EndMessage;
return false;
}
return true;
}
bool gl3cts::TransformFeedback::APIErrors::testExtension3(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* INVALID_VALUE is generated by BeginQueryIndexed, EndQueryIndexed and
GetQueryIndexediv when <target> is TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN and
<index> exceeds limits of MAX_VERTEX_STREAMS
INVALID_VALUE is generated by BeginQueryIndexed, EndQueryIndexed and
GetQueryIndexediv when <target> is PRIMITIVES_GENERATED and <index> exceeds
limits of MAX_VERTEX_STREAMS */
glw::GLint max_vertex_streams = 0;
gl.getIntegerv(GL_MAX_VERTEX_STREAMS, &max_vertex_streams);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_vertex_streams == 0)
{
/* Nothing returned. */
throw 0;
}
++max_vertex_streams;
static const glw::GLenum target[] = { GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_PRIMITIVES_GENERATED };
static const glw::GLchar* target_str[] = { STR(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN),
STR(GL_PRIMITIVES_GENERATED) };
static const glw::GLuint target_count = sizeof(target) / sizeof(target[0]);
for (glw::GLuint i = 0; i < target_count; ++i)
{
gl.beginQueryIndexed(target[i], max_vertex_streams, m_query_object);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_VALUE was not generated by BeginQueryIndexed, EndQueryIndexed and"
"GetQueryIndexediv when <target> was "
<< target_str[i] << " and "
"<index> exceeded limits of MAX_VERTEX_STREAMS."
<< tcu::TestLog::EndMessage;
return false;
}
gl.endQueryIndexed(target[i], max_vertex_streams);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_VALUE was not generated by EndQueryIndexed "
"when <target> was "
<< target_str[i] << " and "
"<index> exceeded limits of MAX_VERTEX_STREAMS."
<< tcu::TestLog::EndMessage;
return false;
}
glw::GLint param = 0;
gl.getQueryIndexediv(target[i], max_vertex_streams, GL_QUERY_COUNTER_BITS, &param);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "INVALID_VALUE was not generated by "
"GetQueryIndexediv when <target> was "
<< target_str[i] << " and "
"<index> exceeded limits of MAX_VERTEX_STREAMS."
<< tcu::TestLog::EndMessage;
return false;
}
}
/* INVALID_OPERATION is generated by EndQueryIndexed when name of active
query at <index> of <target> is zero */
gl.endQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, 0);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_OPERATION was not generated by EndQueryIndexed when name of active "
"query at <index> of <target> is zero"
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_VALUE is generated by DrawTransformFeedbackStream when <stream>
exceeds limits of MAX_VERTEX_STREAMS */
gl.drawTransformFeedbackStream(GL_POINTS, m_transform_feedback_object_0, max_vertex_streams);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_VALUE was not generated by DrawTransformFeedbackStream when <stream> "
"exceeded limits of MAX_VERTEX_STREAMS"
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_OPERATION is generated by TransformFeedbackVaryings when
<varyings> contains any of the special names while <bufferMode> is not
INTERLEAVED_ATTRIBS */
static const glw::GLchar* tf_varying_names[] = { "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2",
"gl_SkipComponents3", "gl_SkipComponents4" };
static const glw::GLuint tf_varying_names_count = sizeof(tf_varying_names) / sizeof(tf_varying_names[0]);
for (glw::GLuint i = 0; i < tf_varying_names_count; ++i)
{
gl.transformFeedbackVaryings(m_program_id_with_output, 1, &tf_varying_names[i], GL_SEPARATE_ATTRIBS);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_OPERATION was not generated by TransformFeedbackVaryings when "
"<varyings> contained any of the special names while <bufferMode> was "
"GL_SEPARATE_ATTRIBS."
<< tcu::TestLog::EndMessage;
return false;
}
}
/* INVALID_OPERATION is generated by TransformFeedbackVaryings when
<varyings> contains more "gl_NextBuffer" entries than allowed limit of
MAX_TRANSFORM_FEEDBACK_BUFFERS */
glw::GLint max_transform_feedback_buffers = 0;
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max_transform_feedback_buffers);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_transform_feedback_buffers == 0)
{
/* Nothing returned. */
throw 0;
}
glw::GLint more_than_max_transform_feedback_buffers = max_transform_feedback_buffers + 1;
const glw::GLchar** tf_next_buffer_varying_names = new const glw::GLchar*[more_than_max_transform_feedback_buffers];
if (DE_NULL == tf_next_buffer_varying_names)
{
/* Allocation error. */
throw 0;
}
for (glw::GLint i = 0; i < more_than_max_transform_feedback_buffers; ++i)
{
tf_next_buffer_varying_names[i] = tf_varying_names[0];
}
gl.transformFeedbackVaryings(m_program_id_with_output, more_than_max_transform_feedback_buffers,
tf_next_buffer_varying_names, GL_INTERLEAVED_ATTRIBS);
delete[] tf_next_buffer_varying_names;
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_OPERATION was not generated by TransformFeedbackVaryings when "
"<varyings> contained more \"gl_NextBuffer\" entries than allowed limit of "
"MAX_TRANSFORM_FEEDBACK_BUFFER."
<< tcu::TestLog::EndMessage;
return false;
}
return true;
}
bool gl3cts::TransformFeedback::APIErrors::testInstanced(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* INVALID_ENUM is generated by DrawTransformFeedbackInstanced and
DrawTransformFeedbackStreamInstanced if <mode> is invalid */
glw::GLenum _supported_mode[] = { GL_POINTS,
GL_LINE_STRIP,
GL_LINE_LOOP,
GL_LINES,
GL_LINE_STRIP_ADJACENCY,
GL_LINES_ADJACENCY,
GL_TRIANGLE_STRIP,
GL_TRIANGLE_FAN,
GL_TRIANGLES,
GL_TRIANGLE_STRIP_ADJACENCY,
GL_TRIANGLES_ADJACENCY,
GL_PATCHES };
std::set<glw::GLenum> supported_mode(_supported_mode,
_supported_mode + sizeof(_supported_mode) / sizeof(_supported_mode[0]));
int mode = 0;
while (supported_mode.find(mode) != supported_mode.end())
{
mode++;
}
gl.drawTransformFeedbackInstanced(mode, m_transform_feedback_object_0, 1);
if (GL_INVALID_ENUM != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_ENUM was not generated by DrawTransformFeedbackInstanced and "
"DrawTransformFeedbackStreamInstanced when <mode> was invalid."
<< tcu::TestLog::EndMessage;
return false;
}
gl.drawTransformFeedbackStreamInstanced(mode, m_transform_feedback_object_0, 0, 1);
if (GL_INVALID_ENUM != gl.getError())
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "INVALID_ENUM was not generated by DrawTransformFeedbackInstanced and "
"DrawTransformFeedbackStreamInstanced when <mode> was invalid."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_OPERATION is generated by DrawTransformFeedbackInstanced and
DrawTransformFeedbackStreamInstanced if <mode> does not match geometry
shader */
gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_transform_feedback_object_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback call failed.");
gl.useProgram(m_program_id_with_geometry_shader);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindVertexArray(m_vertex_array_object);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
gl.drawArrays(GL_POINTS, 0, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
gl.drawTransformFeedbackInstanced(GL_LINES, m_transform_feedback_object_0, 1);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_OPERATION was not generated by DrawTransformFeedbackInstanced and "
"DrawTransformFeedbackStreamInstanced if <mode> did not match geometry shader."
<< tcu::TestLog::EndMessage;
return false;
}
gl.drawTransformFeedbackStreamInstanced(GL_LINES, m_transform_feedback_object_0, 0, 1);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_OPERATION was not generated by DrawTransformFeedbackInstanced and "
"DrawTransformFeedbackStreamInstanced if <mode> did not match geometry shader."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_OPERATION is generated by DrawTransformFeedbackInstanced and
DrawTransformFeedbackStreamInstanced if <mode> does not match tessellation */
gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_transform_feedback_object_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback call failed.");
gl.useProgram(m_program_id_with_tessellation_shaders);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
gl.bindVertexArray(m_vertex_array_object);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer_0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
gl.beginTransformFeedback(GL_LINES);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
gl.drawArrays(GL_PATCHES, 0, 2);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
gl.drawTransformFeedbackInstanced(GL_POINTS, m_transform_feedback_object_0, 1);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_OPERATION was not generated by DrawTransformFeedbackInstanced and "
"DrawTransformFeedbackStreamInstanced if <mode> did not match geometry shader."
<< tcu::TestLog::EndMessage;
return false;
}
gl.drawTransformFeedbackStreamInstanced(GL_POINTS, m_transform_feedback_object_0, 0, 1);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_OPERATION was not generated by DrawTransformFeedbackInstanced and "
"DrawTransformFeedbackStreamInstanced if <mode> did not match geometry shader."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_VALUE is generated by DrawTransformFeedbackStreamInstanced if
<stream> is greater than or equal to MAX_VERTEX_STREAMS */
glw::GLint max_vertex_streams = 0;
gl.getIntegerv(GL_MAX_VERTEX_STREAMS, &max_vertex_streams);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_vertex_streams == 0)
{
/* Failed to query GL_MAX_VERTEX_STREAMS. */
throw 0;
}
glw::GLint more_than_max_vertex_streams = max_vertex_streams + 1;
gl.drawTransformFeedbackStreamInstanced(GL_PATCHES, m_transform_feedback_object_0, more_than_max_vertex_streams, 1);
if (GL_INVALID_VALUE != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_OPERATION was not generated by DrawTransformFeedbackInstanced and "
"DrawTransformFeedbackStreamInstanced if <mode> did not match geometry shader."
<< tcu::TestLog::EndMessage;
return false;
}
/* INVALID_VALUE is generated by DrawTransformFeedbackInstanced and
DrawTransformFeedbackStreamInstanced if <id> is not name of transform
feedback object */
unsigned short int invalid_name = 1;
while (gl.isTransformFeedback(invalid_name))
{
++invalid_name;
/* Make sure that this loop ends someday, bad day. */
if (invalid_name == USHRT_MAX)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Cannot find unused trnasform feedback object." << tcu::TestLog::EndMessage;
throw 0;
}
}
gl.drawTransformFeedbackInstanced(GL_PATCHES, (glw::GLuint)invalid_name, 1);
if (GL_INVALID_VALUE != gl.getError())
{
gl.endTransformFeedback();
return false;
}
gl.drawTransformFeedbackStreamInstanced(GL_PATCHES, (glw::GLuint)invalid_name, 0, 1);
if (GL_INVALID_VALUE != gl.getError())
{
gl.endTransformFeedback();
return false;
}
/* INVALID_OPERATION is generated if by DrawTransformFeedbackStreamInstanced
if EndTransformFeedback was never called for the object named <id>.
return true */
gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_transform_feedback_object_1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback call failed.");
gl.drawTransformFeedbackStreamInstanced(GL_PATCHES, m_transform_feedback_object_1, 0, 1);
if (GL_INVALID_OPERATION != gl.getError())
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "INVALID_OPERATION was not generated by DrawTransformFeedbackInstanced and "
"DrawTransformFeedbackStreamInstanced if <mode> did not match geometry shader."
<< tcu::TestLog::EndMessage;
return false;
}
return true;
}
const glw::GLchar* gl3cts::TransformFeedback::APIErrors::m_tessellation_control_shader =
"#version 400\n"
"\n"
"layout (vertices = 2 ) out;\n"
"\n"
"void main()\n"
"{\n"
" gl_TessLevelOuter[1] = 3.0;\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::APIErrors::m_tessellation_evaluation_shader =
"#version 400\n"
"\n"
"layout(isolines, equal_spacing, ccw) in;\n"
"\n"
"out float result;\n"
"\n"
"void main()\n"
"{\n"
" result = 0.5;\n"
" gl_Position = gl_in[0].gl_Position + gl_in[1].gl_Position + gl_in[2].gl_Position;\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::APIErrors::m_geometry_shader =
"#version 150\n"
"\n"
"layout(points) in;\n"
"layout(points, max_vertices = 2) out;\n"
"\n"
"out float result;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.0, 0.0, 0.0);\n"
" result = 0.0;\n"
" EmitVertex();\n"
"\n"
" gl_Position = gl_in[0].gl_Position + vec4(1.0, 0.0, 0.0, 0.0);\n"
" result = 1.0;\n"
" EmitVertex();\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::APIErrors::s_vertex_shader_with_output =
"#version 130\n"
"\n"
"out float result;\n"
"\n"
"void main()\n"
"{\n"
" result = float(gl_VertexID);\n"
" gl_Position = vec4(1.0);\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::APIErrors::s_vertex_shader_with_input_output =
"#version 130\n"
"\n"
"in float v_input;\n"
"\n"
"out float result;\n"
"\n"
"void main()\n"
"{\n"
" result = float(gl_VertexID);\n"
" gl_Position = vec4(v_input);\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::APIErrors::s_vertex_shader_without_output =
"#version 130\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(1.0);\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::APIErrors::s_fragment_shader = "#version 130\n"
"\n"
"out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0);\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::APIErrors::m_varying_name = "result";
const glw::GLfloat gl3cts::TransformFeedback::APIErrors::m_buffer_1_data[] = { 3.14159265359f, 2.7182818f };
const glw::GLsizei gl3cts::TransformFeedback::APIErrors::m_buffer_1_size =
sizeof(gl3cts::TransformFeedback::APIErrors::m_buffer_1_data);
/*-----------------------------------------------------------------------------------------------*/
gl3cts::TransformFeedback::LinkingErrors::LinkingErrors(deqp::Context& context)
: deqp::TestCase(context, "linking_errors_test", "Transform Feedback Linking Errors Test"), m_context(context)
{
/* Left intentionally blank. */
}
gl3cts::TransformFeedback::LinkingErrors::~LinkingErrors(void)
{
}
tcu::TestNode::IterateResult gl3cts::TransformFeedback::LinkingErrors::iterate(void)
{
bool is_ok = true;
bool test_error = false;
try
{
is_ok = is_ok && testNoVertexNoGeometry();
is_ok = is_ok && testInvalidVarying();
is_ok = is_ok && testRepeatedVarying();
is_ok = is_ok && testTooManyVaryings();
}
catch (...)
{
is_ok = false;
test_error = true;
}
/* Result's setup. */
if (is_ok)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (test_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
bool gl3cts::TransformFeedback::LinkingErrors::testNoVertexNoGeometry(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check if link process fails under the following conditions:
<count> specified by TransformFeedbackVaryings is non-zero and program has
neither vertex nor geometry shader; */
glw::GLint linking_status = 1;
glw::GLuint program = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, NULL, s_fragment_shader,
&s_valid_transform_feedback_varying, 1, GL_INTERLEAVED_ATTRIBS, false, &linking_status);
if ((GL_FALSE != linking_status) || program)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Linking unexpectedly succeded when Transform Feedback varying was "
"specified but program had neither vertex nor geometry shader stages."
<< tcu::TestLog::EndMessage;
if (program)
{
gl.deleteProgram(program);
}
return false;
}
/* Log success. */
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Linking failed as expected when Transform Feedback varying was specified "
"but program had neither vertex nor geometry shader stages."
<< tcu::TestLog::EndMessage;
return true;
}
bool gl3cts::TransformFeedback::LinkingErrors::testInvalidVarying(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check if link process fails under the following conditions:
<varyings> specified by TransformFeedbackVaryings contains name of
variable that is not available for capture; */
std::string vertex_shader(s_vertex_shader_template);
vertex_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(
vertex_shader, "TEMPLATE_INPUT_OUTPUT_DECLARATIONS", "in float data;\n");
vertex_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(vertex_shader, "TEMPLATE_OUTPUT_SETTERS", "");
glw::GLint linking_status = 1;
glw::GLuint program = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, vertex_shader.c_str(), s_fragment_shader,
&s_invalid_transform_feedback_varying, 1, GL_INTERLEAVED_ATTRIBS, false, &linking_status);
if ((GL_FALSE != linking_status) || program)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Linking unexpectedly succeded when Transform Feedback varying was specified with name of variable ("
<< s_invalid_transform_feedback_varying << ") that is not available for capture."
<< tcu::TestLog::EndMessage;
if (program)
{
gl.deleteProgram(program);
}
return false;
}
/* Log success. */
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Linking failed as expected when Transform Feedback varying was specified with name of variable ("
<< s_invalid_transform_feedback_varying << ") that is not available for capture." << tcu::TestLog::EndMessage;
return true;
}
bool gl3cts::TransformFeedback::LinkingErrors::testRepeatedVarying(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check if link process fails under the following conditions:
<varyings> specified by TransformFeedbackVaryings contains name of
variable more than once; */
std::string vertex_shader(s_vertex_shader_template);
vertex_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(
vertex_shader, "TEMPLATE_INPUT_OUTPUT_DECLARATIONS", "out float result;\n");
vertex_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(vertex_shader, "TEMPLATE_OUTPUT_SETTERS",
" result = 0.577215664901532;\n");
glw::GLint linking_status = 1;
glw::GLuint program = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, vertex_shader.c_str(), s_fragment_shader,
s_repeated_transform_feedback_varying, s_repeated_transform_feedback_varying_count, GL_INTERLEAVED_ATTRIBS,
false, &linking_status);
if ((GL_FALSE != linking_status) || program)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Linking unexpectedly succeded when Transform Feedback varying was specified twice."
<< tcu::TestLog::EndMessage;
if (program)
{
gl.deleteProgram(program);
}
return false;
}
/* Log success. */
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Linking failed as expected when Transform Feedback varying was specified twice."
<< tcu::TestLog::EndMessage;
return true;
}
bool gl3cts::TransformFeedback::LinkingErrors::testTooManyVaryings(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check if link process fails under the following conditions:
number of components specified to capture exceeds limits
MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS or
MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS. */
/* Fetching limits. */
glw::GLint max_transform_feedback_separate_components = 0;
glw::GLint max_transform_feedback_interleaved_components = 0;
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &max_transform_feedback_separate_components);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_transform_feedback_separate_components == 0)
{
throw 0;
}
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &max_transform_feedback_interleaved_components);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_transform_feedback_interleaved_components == 0)
{
throw 0;
}
glw::GLint more_than_max_transform_feedback_components =
deMax32(max_transform_feedback_separate_components, max_transform_feedback_interleaved_components) + 1;
/* Preparing source code. */
std::string vertex_shader(s_vertex_shader_template);
std::string transform_feedback_variable_declarations("");
std::string transform_feedback_variable_setters("");
std::vector<std::string> transform_feedback_varyings(more_than_max_transform_feedback_components);
std::vector<const glw::GLchar*> transform_feedback_varyings_c(more_than_max_transform_feedback_components);
for (glw::GLint i = 0; i < more_than_max_transform_feedback_components; ++i)
{
std::string varying = "result_";
varying.append(gl3cts::TransformFeedback::Utilities::itoa(i));
transform_feedback_varyings[i] = varying;
transform_feedback_varyings_c[i] = transform_feedback_varyings[i].c_str();
transform_feedback_variable_declarations.append("out float ");
transform_feedback_variable_declarations.append(varying);
transform_feedback_variable_declarations.append(";\n");
transform_feedback_variable_setters.append(" ");
transform_feedback_variable_setters.append(varying);
transform_feedback_variable_setters.append(" = ");
transform_feedback_variable_setters.append(gl3cts::TransformFeedback::Utilities::itoa(i * i));
transform_feedback_variable_setters.append(".0;\n");
}
vertex_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(
vertex_shader, "TEMPLATE_INPUT_OUTPUT_DECLARATIONS", transform_feedback_variable_declarations);
vertex_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(vertex_shader, "TEMPLATE_OUTPUT_SETTERS",
transform_feedback_variable_setters);
glw::GLuint program = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, vertex_shader.c_str(), s_fragment_shader,
&transform_feedback_varyings_c[0], more_than_max_transform_feedback_components, GL_INTERLEAVED_ATTRIBS);
/* Note: we check for program as not only linking shall fail, but also glTransformFeedbackVaryings shall return an error. */
if (program)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Linking unexpectedly succeded when too many Transform Feedback varying "
"were specified in INTERLEAVED mode."
<< tcu::TestLog::EndMessage;
if (program)
{
gl.deleteProgram(program);
}
return false;
}
program = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, vertex_shader.c_str(), s_fragment_shader,
&transform_feedback_varyings_c[0], more_than_max_transform_feedback_components, GL_SEPARATE_ATTRIBS);
if (program)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Linking unexpectedly succeded when too many Transform Feedback "
"varyings were specified in SEPARATE mode."
<< tcu::TestLog::EndMessage;
if (program)
{
gl.deleteProgram(program);
}
return false;
}
/* Log success. */
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Linking failed as expected when too many Transform Feedback varyings were specified."
<< tcu::TestLog::EndMessage;
return true;
}
const glw::GLchar* gl3cts::TransformFeedback::LinkingErrors::s_fragment_shader = "#version 130\n"
"\n"
"out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0);\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::LinkingErrors::s_vertex_shader_template =
"#version 130\n"
"\n"
"TEMPLATE_INPUT_OUTPUT_DECLARATIONS"
"\n"
"void main()\n"
"{\n"
"TEMPLATE_OUTPUT_SETTERS"
"\n"
" gl_Position = vec4(1.618033988749);\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::LinkingErrors::s_valid_transform_feedback_varying = "result";
const glw::GLchar* gl3cts::TransformFeedback::LinkingErrors::s_invalid_transform_feedback_varying = "data";
const glw::GLchar* gl3cts::TransformFeedback::LinkingErrors::s_repeated_transform_feedback_varying[] = { "result",
"result" };
const glw::GLsizei gl3cts::TransformFeedback::LinkingErrors::s_repeated_transform_feedback_varying_count =
sizeof(s_repeated_transform_feedback_varying) / sizeof(s_repeated_transform_feedback_varying[0]);
/*-----------------------------------------------------------------------------------------------*/
const glw::GLint gl3cts::TransformFeedback::Limits::s_min_value_of_max_transform_feedback_interleaved_components = 64;
const glw::GLint gl3cts::TransformFeedback::Limits::s_min_value_of_max_transform_feedback_separate_attribs = 4;
const glw::GLint gl3cts::TransformFeedback::Limits::s_min_value_of_max_transform_feedback_separate_components = 4;
const glw::GLint gl3cts::TransformFeedback::Limits::s_min_value_of_max_transform_feedback_buffers = 4;
const glw::GLint gl3cts::TransformFeedback::Limits::s_min_value_of_max_vertex_streams = 1;
gl3cts::TransformFeedback::Limits::Limits(deqp::Context& context)
: deqp::TestCase(context, "limits_test", "Transform Feedback Limits Test"), m_context(context)
{
}
gl3cts::TransformFeedback::Limits::~Limits(void)
{
}
tcu::TestNode::IterateResult gl3cts::TransformFeedback::Limits::iterate(void)
{
/* Initializations. */
bool is_at_least_gl_30 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 0)));
bool is_at_least_gl_40 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)));
bool is_ext_tf_1 = m_context.getContextInfo().isExtensionSupported("GL_EXT_transform_feedback");
bool is_arb_tf_3 = m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback3");
bool is_ok = true;
bool test_error = false;
/* Tests. */
try
{
if (is_at_least_gl_30 || is_ext_tf_1)
{
is_ok = is_ok && test_max_transform_feedback_interleaved_components();
is_ok = is_ok && test_max_transform_feedback_separate_attribs();
is_ok = is_ok && test_max_transform_feedback_separate_components();
}
if (is_at_least_gl_40 || is_arb_tf_3)
{
is_ok = is_ok && test_max_transform_feedback_buffers();
is_ok = is_ok && test_max_vertex_streams();
}
}
catch (...)
{
is_ok = false;
test_error = true;
}
/* Result's setup. */
if (is_ok)
{
/* Log success. */
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Limits are in range of specification."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (test_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
bool gl3cts::TransformFeedback::Limits::test_max_transform_feedback_interleaved_components(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check that MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS is at least 64. */
glw::GLint max_transform_feedback_interleaved_components = 0;
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &max_transform_feedback_interleaved_components);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_transform_feedback_interleaved_components < s_min_value_of_max_transform_feedback_interleaved_components)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS is equal to "
<< max_transform_feedback_interleaved_components << " which is less than expected "
<< s_min_value_of_max_transform_feedback_interleaved_components << "." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
bool gl3cts::TransformFeedback::Limits::test_max_transform_feedback_separate_attribs(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check that MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS is at least 4. */
glw::GLint max_transform_feedback_separate_attribs = 0;
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &max_transform_feedback_separate_attribs);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_transform_feedback_separate_attribs < s_min_value_of_max_transform_feedback_separate_attribs)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS is equal to "
<< max_transform_feedback_separate_attribs << " which is less than expected "
<< s_min_value_of_max_transform_feedback_separate_attribs << "." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
bool gl3cts::TransformFeedback::Limits::test_max_transform_feedback_separate_components(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check that MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS is at least 4. */
glw::GLint max_transform_feedback_separate_components = 0;
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &max_transform_feedback_separate_components);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_transform_feedback_separate_components < s_min_value_of_max_transform_feedback_separate_components)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS is equal to "
<< max_transform_feedback_separate_components << " which is less than expected "
<< s_min_value_of_max_transform_feedback_separate_components << "." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
bool gl3cts::TransformFeedback::Limits::test_max_transform_feedback_buffers(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check that MAX_TRANSFORM_FEEDBACK_BUFFERS is at least 4. */
glw::GLint max_transform_feedback_buffers = 0;
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max_transform_feedback_buffers);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_transform_feedback_buffers < s_min_value_of_max_transform_feedback_buffers)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "MAX_TRANSFORM_FEEDBACK_BUFFERS is equal to "
<< max_transform_feedback_buffers << " which is less than expected "
<< s_min_value_of_max_transform_feedback_buffers << "."
<< tcu::TestLog::EndMessage;
return false;
}
return true;
}
bool gl3cts::TransformFeedback::Limits::test_max_vertex_streams(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check that MAX_VERTEX_STREAMS is at least 1. */
glw::GLint max_vertex_streams = 0;
gl.getIntegerv(GL_MAX_VERTEX_STREAMS, &max_vertex_streams);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_vertex_streams < s_min_value_of_max_vertex_streams)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "MAX_VERTEX_STREAMS is equal to "
<< max_vertex_streams << " which is less than expected "
<< s_min_value_of_max_vertex_streams << "." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/*-----------------------------------------------------------------------------------------------*/
gl3cts::TransformFeedback::CaptureVertexInterleaved::CaptureVertexInterleaved(deqp::Context& context,
const char* test_name,
const char* test_description)
: deqp::TestCase(context, test_name, test_description)
, m_context(context)
, m_program(0)
, m_framebuffer(0)
, m_renderbuffer(0)
, m_buffer(0)
, m_buffer_size(0)
, m_vertex_array_object(0)
, m_max_transform_feedback_components(0)
, m_attrib_type(GL_INTERLEAVED_ATTRIBS)
, m_max_vertices_drawn(8)
, m_glBindBufferOffsetEXT(DE_NULL)
{
}
gl3cts::TransformFeedback::CaptureVertexInterleaved::~CaptureVertexInterleaved(void)
{
}
tcu::TestNode::IterateResult gl3cts::TransformFeedback::CaptureVertexInterleaved::iterate(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Initializations. */
bool is_at_least_gl_30 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 0)));
bool is_ext_tf_1 = m_context.getContextInfo().isExtensionSupported("GL_EXT_transform_feedback");
bool is_ok = true;
bool test_error = false;
try
{
if (is_ext_tf_1)
{
/* Extension query. */
m_glBindBufferOffsetEXT =
(BindBufferOffsetEXT_ProcAddress)m_context.getRenderContext().getProcAddress("glBindBufferOffsetEXT");
if (DE_NULL == m_glBindBufferOffsetEXT)
{
throw 0;
}
}
if (is_at_least_gl_30 || is_ext_tf_1)
{
fetchLimits();
buildProgram();
createFramebuffer();
createTransformFeedbackBuffer();
createVertexArrayObject();
gl.useProgram(m_program);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
for (glw::GLint i_bind_case = 0; (i_bind_case < BIND_BUFFER_CASES_COUNT) && is_ok; ++i_bind_case)
{
if ((i_bind_case == BIND_BUFFER_OFFSET_CASE) && (DE_NULL == m_glBindBufferOffsetEXT))
{
continue;
}
bindBuffer((BindBufferCase)i_bind_case);
for (glw::GLuint i_primitive_case = 0; (i_primitive_case < s_primitive_cases_count) && is_ok;
++i_primitive_case)
{
draw(i_primitive_case);
is_ok = is_ok && checkFramebuffer(s_primitive_cases[i_primitive_case]);
is_ok = is_ok && checkTransformFeedbackBuffer((BindBufferCase)i_bind_case,
s_primitive_cases[i_primitive_case]);
}
}
}
}
catch (...)
{
is_ok = false;
test_error = true;
}
/* Clean objects. */
clean();
/* Result's setup. */
if (is_ok)
{
/* Log success. */
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Capture Vertex have passed."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (test_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
void gl3cts::TransformFeedback::CaptureVertexInterleaved::fetchLimits(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Fetching limits. */
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &m_max_transform_feedback_components);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (m_max_transform_feedback_components == 0)
{
throw 0;
}
glw::GLint max_varyings_components = 0;
gl.getIntegerv(GL_MAX_VARYING_COMPONENTS, &max_varyings_components);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_varyings_components == 0)
{
throw 0;
}
if (m_max_transform_feedback_components > max_varyings_components)
{
m_max_transform_feedback_components = max_varyings_components;
}
}
void gl3cts::TransformFeedback::CaptureVertexInterleaved::buildProgram(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Preparing source code. */
std::string vertex_shader(s_vertex_shader_source_code_template); /* Storage for vertex shader source code. */
std::string transform_feedback_variable_declarations(
""); /* String to contain all custom outputs from vertex shader. */
std::string transform_feedback_variable_setters(
""); /* String containing all initializations of custom outputs from vertex shader. */
std::vector<std::string> transform_feedback_varyings(m_max_transform_feedback_components); /* Varyings array. */
std::vector<const glw::GLchar*> transform_feedback_varyings_c(
m_max_transform_feedback_components); /* Varyings array in C form to pass to the GL. */
glw::GLint user_defined_transform_feedback_interleaved_varyings_count =
m_max_transform_feedback_components /* total max to be written by the shader */
/ 4 /* components per vec4 */
- 1 /* gl_Position */;
glw::GLint all_transform_feedback_interleaved_varyings_count =
user_defined_transform_feedback_interleaved_varyings_count + 1 /* gl_Position */;
/* Most of varyings is declarated output variables. */
for (glw::GLint i = 0; i < user_defined_transform_feedback_interleaved_varyings_count; ++i)
{
std::string varying = "result_";
varying.append(gl3cts::TransformFeedback::Utilities::itoa(i));
transform_feedback_varyings[i] = varying;
transform_feedback_varyings_c[i] = transform_feedback_varyings[i].c_str();
transform_feedback_variable_declarations.append("out vec4 ");
transform_feedback_variable_declarations.append(varying);
transform_feedback_variable_declarations.append(";\n");
transform_feedback_variable_setters.append(" ");
transform_feedback_variable_setters.append(varying);
transform_feedback_variable_setters.append(" = vec4(");
transform_feedback_variable_setters.append(gl3cts::TransformFeedback::Utilities::itoa(i * 4));
transform_feedback_variable_setters.append(".0, ");
transform_feedback_variable_setters.append(gl3cts::TransformFeedback::Utilities::itoa(i * 4 + 1));
transform_feedback_variable_setters.append(".0, ");
transform_feedback_variable_setters.append(gl3cts::TransformFeedback::Utilities::itoa(i * 4 + 2));
transform_feedback_variable_setters.append(".0, ");
transform_feedback_variable_setters.append(gl3cts::TransformFeedback::Utilities::itoa(i * 4 + 3));
transform_feedback_variable_setters.append(".0);\n");
}
/* Last four varying components are gl_Position components. */
transform_feedback_varyings[user_defined_transform_feedback_interleaved_varyings_count] = "gl_Position";
transform_feedback_varyings_c[user_defined_transform_feedback_interleaved_varyings_count] =
transform_feedback_varyings[user_defined_transform_feedback_interleaved_varyings_count].c_str();
/* Preprocess vertex shader source code template. */
vertex_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(
vertex_shader, "TEMPLATE_INPUT_OUTPUT_DECLARATIONS", transform_feedback_variable_declarations);
vertex_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(vertex_shader, "TEMPLATE_OUTPUT_SETTERS",
transform_feedback_variable_setters);
vertex_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(
vertex_shader, "TEMPLATE_RASTERIZATION_EPSILON",
gl3cts::TransformFeedback::Utilities::ftoa(s_rasterization_epsilon));
/* Compile, link and check. */
m_program = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, vertex_shader.c_str(), s_fragment_shader_source_code,
&transform_feedback_varyings_c[0], all_transform_feedback_interleaved_varyings_count, m_attrib_type);
if (0 == m_program)
{
throw 0;
}
}
void gl3cts::TransformFeedback::CaptureVertexInterleaved::createFramebuffer(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Setting clear color */
gl.clearColor(0.f, 0.f, 0.f, 1.f);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
/* Creating framebuffer */
gl.genFramebuffers(1, &m_framebuffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed.");
gl.genRenderbuffers(1, &m_renderbuffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed.");
gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed.");
gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed.");
gl.renderbufferStorage(GL_RENDERBUFFER, GL_R32F, s_framebuffer_size, s_framebuffer_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed.");
gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed.");
if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
throw 0;
}
gl.viewport(0, 0, s_framebuffer_size, s_framebuffer_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport call failed.");
}
void gl3cts::TransformFeedback::CaptureVertexInterleaved::createTransformFeedbackBuffer(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Creating xfb buffer */
gl.genBuffers(1, &m_buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
m_buffer_size =
static_cast<glw::GLuint>(m_max_transform_feedback_components * m_max_vertices_drawn * sizeof(glw::GLfloat));
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, m_buffer_size, NULL, GL_DYNAMIC_READ);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
}
void gl3cts::TransformFeedback::CaptureVertexInterleaved::createVertexArrayObject(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* VAO Creations */
gl.genVertexArrays(1, &m_vertex_array_object);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
gl.bindVertexArray(m_vertex_array_object);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
}
void gl3cts::TransformFeedback::CaptureVertexInterleaved::draw(glw::GLuint primitive_case)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Draw */
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
gl.beginTransformFeedback(s_primitive_cases_xfb[primitive_case]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedbac call failed.");
gl.drawElements(s_primitive_cases[primitive_case], s_element_indices_counts[primitive_case], GL_UNSIGNED_INT,
s_element_indices[primitive_case]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElements call failed.");
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedbac call failed.");
}
bool gl3cts::TransformFeedback::CaptureVertexInterleaved::checkFramebuffer(glw::GLenum primitive_type UNUSED)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Fetch framebuffer. */
std::vector<glw::GLfloat> pixels(s_framebuffer_size * s_framebuffer_size);
if ((s_framebuffer_size > 0) && (s_framebuffer_size > 0))
{
gl.readPixels(0, 0, s_framebuffer_size, s_framebuffer_size, GL_RED, GL_FLOAT, pixels.data());
GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels call failed.");
}
/* Check results.
Note: assuming that s_buffer_size == 2 -> then all points shall be drawn. */
for (std::vector<glw::GLfloat>::iterator i = pixels.begin(); i != pixels.end(); ++i)
{
if (fabs(*i - 0.5f) > 0.0625f /* precision */)
{
return false;
}
}
return true;
}
bool gl3cts::TransformFeedback::CaptureVertexInterleaved::checkTransformFeedbackBuffer(BindBufferCase bind_case UNUSED,
glw::GLenum primitive_type)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check */
glw::GLuint number_of_vertices = 0;
switch (primitive_type)
{
case GL_POINTS:
number_of_vertices = 4;
break;
case GL_LINES:
number_of_vertices = 4;
break;
case GL_LINE_LOOP:
number_of_vertices = 8;
break;
case GL_LINE_STRIP:
number_of_vertices = 6;
break;
case GL_TRIANGLES:
number_of_vertices = 6;
break;
case GL_TRIANGLE_STRIP:
number_of_vertices = 6;
break;
case GL_TRIANGLE_FAN:
number_of_vertices = 6;
break;
default:
throw 0;
}
glw::GLfloat* results = (glw::GLfloat*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed.");
bool is_ok = true;
for (glw::GLuint j = 0; (j < number_of_vertices) && is_ok; ++j)
{
for (glw::GLint i = 0; i < m_max_transform_feedback_components - 4; ++i)
{
glw::GLfloat result = results[i + j * m_max_transform_feedback_components];
glw::GLfloat reference = (glw::GLfloat)(i);
if (fabs(result - reference) > 0.125 /* precision */)
{
is_ok = false;
break;
}
}
/* gl_Position */
glw::GLfloat result[4] = { results[(j + 1) * m_max_transform_feedback_components - 4],
results[(j + 1) * m_max_transform_feedback_components - 3],
results[(j + 1) * m_max_transform_feedback_components - 2],
results[(j + 1) * m_max_transform_feedback_components - 1] };
if ((fabs(fabs(result[0]) - 1.0 + s_rasterization_epsilon) > 0.125 /* precision */) ||
(fabs(fabs(result[1]) - 1.0 + s_rasterization_epsilon) > 0.125 /* precision */) ||
(fabs(result[2]) > 0.125 /* precision */) || (fabs(result[3] - 1.0) > 0.125 /* precision */))
{
is_ok = false;
break;
}
}
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
return is_ok;
}
void gl3cts::TransformFeedback::CaptureVertexInterleaved::bindBuffer(BindBufferCase bind_case)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
switch (bind_case)
{
case BIND_BUFFER_BASE_CASE:
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer);
break;
case BIND_BUFFER_RANGE_CASE:
gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer, 0, m_buffer_size);
break;
case BIND_BUFFER_OFFSET_CASE:
if (DE_NULL == m_glBindBufferOffsetEXT)
{
throw 0;
}
m_glBindBufferOffsetEXT(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffer, 0);
break;
default:
throw 0;
}
}
void gl3cts::TransformFeedback::CaptureVertexInterleaved::clean(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_program)
{
gl.deleteProgram(m_program);
m_program = 0;
}
if (m_framebuffer)
{
gl.deleteFramebuffers(1, &m_framebuffer);
m_framebuffer = 0;
}
if (m_renderbuffer)
{
gl.deleteRenderbuffers(1, &m_renderbuffer);
m_renderbuffer = 0;
}
cleanBuffer();
if (m_vertex_array_object)
{
gl.deleteVertexArrays(1, &m_vertex_array_object);
m_vertex_array_object = 0;
}
}
void gl3cts::TransformFeedback::CaptureVertexInterleaved::cleanBuffer(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_buffer)
{
gl.deleteBuffers(1, &m_buffer);
m_buffer = 0;
}
}
const glw::GLchar* gl3cts::TransformFeedback::CaptureVertexInterleaved::s_vertex_shader_source_code_template =
"#version 130\n"
"\n"
"TEMPLATE_INPUT_OUTPUT_DECLARATIONS"
"\n"
"void main()\n"
"{\n"
"TEMPLATE_OUTPUT_SETTERS"
"\n"
" vec4 position = vec4(0.0);\n"
"\n"
" /* Note: The points are moved 0.0625 from the borders to\n"
" reduce non-XFB related rasterization problems. */\n"
" switch(gl_VertexID)\n"
" {\n"
" case 0:\n"
" position = vec4(-1.0 + TEMPLATE_RASTERIZATION_EPSILON, 1.0 - TEMPLATE_RASTERIZATION_EPSILON, 0.0, "
"1.0);\n"
" break;\n"
" case 1:\n"
" position = vec4( 1.0 - TEMPLATE_RASTERIZATION_EPSILON, 1.0 - TEMPLATE_RASTERIZATION_EPSILON, 0.0, "
"1.0);\n"
" break;\n"
" case 2:\n"
" position = vec4(-1.0 + TEMPLATE_RASTERIZATION_EPSILON, -1.0 + TEMPLATE_RASTERIZATION_EPSILON, 0.0, "
"1.0);\n"
" break;\n"
" case 3:\n"
" position = vec4( 1.0 - TEMPLATE_RASTERIZATION_EPSILON, -1.0 + TEMPLATE_RASTERIZATION_EPSILON, 0.0, "
"1.0);\n"
" break;\n"
" }\n"
"\n"
" gl_Position = position;\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::CaptureVertexInterleaved::s_fragment_shader_source_code =
"#version 130\n"
"\n"
"out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(0.5);\n"
"}\n";
const glw::GLuint
gl3cts::TransformFeedback::CaptureVertexInterleaved::s_element_indices[][s_max_element_indices_count] = {
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 }, { 0, 1, 3, 2 }, { 0, 1, 3, 2 },
{ 2, 0, 1, 2, 1, 3 }, { 0, 1, 2, 3 }, { 2, 0, 1, 3 }
};
const glw::GLuint gl3cts::TransformFeedback::CaptureVertexInterleaved::s_primitive_cases_count =
sizeof(s_element_indices) / sizeof(s_element_indices[0]);
const glw::GLenum gl3cts::TransformFeedback::CaptureVertexInterleaved::s_primitive_cases[] = {
GL_POINTS, GL_LINES, GL_LINE_LOOP, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN
};
const glw::GLenum gl3cts::TransformFeedback::CaptureVertexInterleaved::s_primitive_cases_xfb[] = {
GL_POINTS, GL_LINES, GL_LINES, GL_LINES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES
};
const glw::GLuint gl3cts::TransformFeedback::CaptureVertexInterleaved::s_element_indices_counts[] = { 4, 4, 4, 4,
6, 4, 4 };
const glw::GLuint gl3cts::TransformFeedback::CaptureVertexInterleaved::s_framebuffer_size =
2; /* If you change this, update checkFramebuffer function according. */
const glw::GLfloat gl3cts::TransformFeedback::CaptureVertexInterleaved::s_rasterization_epsilon = 0.0625;
/*-----------------------------------------------------------------------------------------------*/
gl3cts::TransformFeedback::CaptureGeometryInterleaved::CaptureGeometryInterleaved(deqp::Context& context,
const char* test_name,
const char* test_description)
: CaptureVertexInterleaved(context, test_name, test_description)
{
}
gl3cts::TransformFeedback::CaptureGeometryInterleaved::~CaptureGeometryInterleaved(void)
{
}
tcu::TestNode::IterateResult gl3cts::TransformFeedback::CaptureGeometryInterleaved::iterate(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Initializations. */
bool is_at_least_gl_30 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 0)));
bool is_at_least_gl_32 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 2)));
bool is_ext_tf_1 = m_context.getContextInfo().isExtensionSupported("GL_EXT_transform_feedback");
bool is_arb_gs_4 = m_context.getContextInfo().isExtensionSupported("GL_ARB_geometry_shader4");
bool is_ok = true;
bool test_error = false;
/* Tests. */
try
{
if ((is_at_least_gl_30 || is_ext_tf_1) && (is_at_least_gl_32 || is_arb_gs_4))
{
fetchLimits();
createFramebuffer();
createTransformFeedbackBuffer();
createVertexArrayObject();
for (glw::GLuint i_primitive_case = 0;
(i_primitive_case < s_geometry_interleaved_primitive_cases_count) && is_ok; ++i_primitive_case)
{
buildProgram(i_primitive_case);
gl.useProgram(m_program);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
for (glw::GLint i_bind_case = 0; (i_bind_case < BIND_BUFFER_CASES_COUNT) && is_ok; ++i_bind_case)
{
if ((i_bind_case == BIND_BUFFER_OFFSET_CASE) && (DE_NULL == m_glBindBufferOffsetEXT))
{
continue;
}
bindBuffer((BindBufferCase)i_bind_case);
draw(i_primitive_case);
is_ok = is_ok && checkFramebuffer(s_primitive_cases[i_primitive_case]);
is_ok = is_ok &&
checkTransformFeedbackBuffer((BindBufferCase)i_bind_case,
s_geometry_interleaved_primitive_cases_xfb[i_primitive_case]);
}
gl.deleteProgram(m_program);
m_program = 0;
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram call failed.");
}
}
}
catch (...)
{
is_ok = false;
test_error = true;
}
/* Clean objects. */
clean();
/* Result's setup. */
if (is_ok)
{
/* Log success. */
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Capture Geometry have passed."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
if (test_error)
{
m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
}
return STOP;
}
void gl3cts::TransformFeedback::CaptureGeometryInterleaved::fetchLimits(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Fetching limits. */
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &m_max_transform_feedback_components);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (m_max_transform_feedback_components == 0)
{
throw 0;
}
glw::GLint max_geometry_total_components = 0;
gl.getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &max_geometry_total_components);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
if (max_geometry_total_components == 0)
{
throw 0;
}
if (m_max_transform_feedback_components * 4 > max_geometry_total_components)
{
m_max_transform_feedback_components = max_geometry_total_components / 4;
}
}
void gl3cts::TransformFeedback::CaptureGeometryInterleaved::buildProgram(glw::GLuint primitive_case)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Preparing source code. */
std::string geometry_shader(s_geometry_shader_source_code_template); /* Storage for vertex shader source code. */
std::string transform_feedback_variable_declarations(
""); /* String to contain all custom outputs from vertex shader. */
std::string transform_feedback_variable_setters(
""); /* String containing all initializations of custom outputs from vertex shader. */
std::vector<std::string> transform_feedback_varyings(m_max_transform_feedback_components); /* Varyings array. */
std::vector<const glw::GLchar*> transform_feedback_varyings_c(
m_max_transform_feedback_components); /* Varyings array in C form to pass to the GL. */
glw::GLint user_defined_transform_feedback_interleaved_varyings_count =
m_max_transform_feedback_components /* total max to be written by the shader */
/ 4 /* components per vec4 */
// / 4 /* number of vertices */
- 1 /* gl_Position */;
glw::GLint all_transform_feedback_interleaved_varyings_count =
user_defined_transform_feedback_interleaved_varyings_count + 1 /* gl_Position */;
/* Most of varyings is declarated output variables. */
for (glw::GLint i = 0; i < user_defined_transform_feedback_interleaved_varyings_count; ++i)
{
/* Preparing variable name. */
std::string varying = "result_";
varying.append(gl3cts::TransformFeedback::Utilities::itoa(i));
transform_feedback_varyings[i] = varying;
transform_feedback_varyings_c[i] = transform_feedback_varyings[i].c_str();
/* Preparing variable declaration. */
transform_feedback_variable_declarations.append("out vec4 ");
transform_feedback_variable_declarations.append(varying);
transform_feedback_variable_declarations.append(";\n");
/* Preparing variable setters. */
transform_feedback_variable_setters.append(" ");
transform_feedback_variable_setters.append(varying);
transform_feedback_variable_setters.append(" = vec4(");
transform_feedback_variable_setters.append(gl3cts::TransformFeedback::Utilities::itoa(i * 4));
transform_feedback_variable_setters.append(".0, ");
transform_feedback_variable_setters.append(gl3cts::TransformFeedback::Utilities::itoa(i * 4 + 1));
transform_feedback_variable_setters.append(".0, ");
transform_feedback_variable_setters.append(gl3cts::TransformFeedback::Utilities::itoa(i * 4 + 2));
transform_feedback_variable_setters.append(".0, ");
transform_feedback_variable_setters.append(gl3cts::TransformFeedback::Utilities::itoa(i * 4 + 3));
transform_feedback_variable_setters.append(".0);\n");
}
/* Last four varying components are gl_Position components. */
transform_feedback_varyings[user_defined_transform_feedback_interleaved_varyings_count /* gl_Position */] =
"gl_Position";
transform_feedback_varyings_c[user_defined_transform_feedback_interleaved_varyings_count /* gl_Position */] =
transform_feedback_varyings[user_defined_transform_feedback_interleaved_varyings_count /* gl_Position */]
.c_str();
/* Preprocess vertex shader source code template. */
geometry_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(
geometry_shader, "TEMPLATE_PRIMITIVE_TYPE", s_geometry_interleaved_primitive_cases[primitive_case]);
geometry_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(
geometry_shader, "TEMPLATE_INPUT_OUTPUT_DECLARATIONS", transform_feedback_variable_declarations);
geometry_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(geometry_shader, "TEMPLATE_OUTPUT_SETTERS",
transform_feedback_variable_setters);
geometry_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(
geometry_shader, "TEMPLATE_RASTERIZATION_EPSILON",
gl3cts::TransformFeedback::Utilities::ftoa(s_rasterization_epsilon));
/* Compile, link and check. */
m_program = gl3cts::TransformFeedback::Utilities::buildProgram(
gl, m_context.getTestContext().getLog(), geometry_shader.c_str(), NULL, NULL, s_blank_vertex_shader_source_code,
s_fragment_shader_source_code, &transform_feedback_varyings_c[0],
all_transform_feedback_interleaved_varyings_count, m_attrib_type);
if (0 == m_program)
{
throw 0;
}
}
void gl3cts::TransformFeedback::CaptureGeometryInterleaved::draw(glw::GLuint primitive_case)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
gl.beginTransformFeedback(s_geometry_interleaved_primitive_cases_xfb[primitive_case]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
gl.drawArrays(GL_POINTS, 0, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedbac call failed.");
}
const glw::GLchar* gl3cts::TransformFeedback::CaptureGeometryInterleaved::s_geometry_shader_source_code_template =
"#version 150\n"
"\n"
"layout(points) in;\n"
"layout(TEMPLATE_PRIMITIVE_TYPE, max_vertices = 4) out;\n"
"\n"
"TEMPLATE_INPUT_OUTPUT_DECLARATIONS"
"\n"
"void main()\n"
"{\n"
" /* Note: The points are moved 0.0625 from the borders to\n"
" reduce non-XFB related rasterization problems. */\n"
"\n"
" gl_Position = vec4(-1.0 + TEMPLATE_RASTERIZATION_EPSILON, 1.0 - TEMPLATE_RASTERIZATION_EPSILON, 0.0, "
"1.0);\n"
"TEMPLATE_OUTPUT_SETTERS"
" EmitVertex();\n"
"\n"
" gl_Position = vec4( 1.0 - TEMPLATE_RASTERIZATION_EPSILON, 1.0 - TEMPLATE_RASTERIZATION_EPSILON, 0.0, "
"1.0);\n"
"TEMPLATE_OUTPUT_SETTERS"
" EmitVertex();\n"
"\n"
" gl_Position = vec4(-1.0 + TEMPLATE_RASTERIZATION_EPSILON, -1.0 + TEMPLATE_RASTERIZATION_EPSILON, 0.0, "
"1.0);\n"
"TEMPLATE_OUTPUT_SETTERS"
" EmitVertex();\n"
"\n"
" gl_Position = vec4( 1.0 - TEMPLATE_RASTERIZATION_EPSILON, -1.0 + TEMPLATE_RASTERIZATION_EPSILON, 0.0, "
"1.0);\n"
"TEMPLATE_OUTPUT_SETTERS"
" EmitVertex();\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::CaptureGeometryInterleaved::s_blank_vertex_shader_source_code =
"#version 130\n"
"\n"
"void main()\n"
"{\n"
"}\n";
const glw::GLchar* gl3cts::TransformFeedback::CaptureGeometryInterleaved::s_geometry_interleaved_primitive_cases[] = {
"points", "line_strip", "triangle_strip"
};
const glw::GLenum gl3cts::TransformFeedback::CaptureGeometryInterleaved::s_geometry_interleaved_primitive_cases_xfb[] =
{ GL_POINTS, GL_LINES, GL_TRIANGLES };
const glw::GLuint gl3cts::TransformFeedback::CaptureGeometryInterleaved::s_geometry_interleaved_primitive_cases_count =
sizeof(s_geometry_interleaved_primitive_cases) / sizeof(s_geometry_interleaved_primitive_cases[0]);
/*-----------------------------------------------------------------------------------------------*/
gl3cts::TransformFeedback::CaptureVertexSeparate::CaptureVertexSeparate(deqp::Context& context, const char* test_name,
const char* test_description)
: CaptureVertexInterleaved(context, test_name, test_description)
, m_buffers(DE_NULL)
, m_max_transform_feedback_separate_attribs(0)
{
m_attrib_type = GL_SEPARATE_ATTRIBS;
}
void gl3cts::TransformFeedback::CaptureVertexSeparate::fetchLimits(void)
{
/* Functions handler */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Fetching limits. */
glw::GLint max_transform_feedback_separate_components;
gl.getIntegerv(