text: /*-------------------------------------------------------------------------
   * 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(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 < 4)
  	{
  		throw 0;
  	}
  
  	gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &m_max_transform_feedback_separate_attribs);
  
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
  
  	if (m_max_transform_feedback_separate_attribs == 0)
  	{
  		throw 0;
  	}
  
  	m_max_transform_feedback_components = m_max_transform_feedback_separate_attribs * 4 /* vec4 is used */;
  
  	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::CaptureVertexSeparate::createTransformFeedbackBuffer(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	m_buffers = new glw::GLuint[m_max_transform_feedback_components];
  
  	if (DE_NULL == m_buffers)
  	{
  		throw 0;
  	}
  
  	gl.genBuffers(m_max_transform_feedback_separate_attribs, m_buffers);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
  
  	m_buffer_size = static_cast<glw::GLuint>(m_max_vertices_drawn * 4 /* vec4 */ * sizeof(glw::GLfloat));
  
  	for (glw::GLint i = 0; i < m_max_transform_feedback_separate_attribs; ++i)
  	{
  		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_buffers[i]);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  		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::CaptureVertexSeparate::bindBuffer(BindBufferCase bind_case)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	switch (bind_case)
  	{
  	case BIND_BUFFER_BASE_CASE:
  		for (glw::GLint i = 0; i < m_max_transform_feedback_separate_attribs; ++i)
  		{
  			gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, m_buffers[i]);
  		}
  		break;
  	case BIND_BUFFER_RANGE_CASE:
  		for (glw::GLint i = 0; i < m_max_transform_feedback_separate_attribs; ++i)
  		{
  			gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, i, m_buffers[i], 0, m_buffer_size);
  		}
  		break;
  	case BIND_BUFFER_OFFSET_CASE:
  		for (glw::GLint i = 0; i < m_max_transform_feedback_separate_attribs; ++i)
  		{
  			m_glBindBufferOffsetEXT(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_buffers[i], 0);
  		}
  		break;
  	default:
  		throw 0;
  	}
  }
  
  void gl3cts::TransformFeedback::CaptureVertexSeparate::cleanBuffer(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	if (DE_NULL != m_buffers)
  	{
  		gl.deleteBuffers(m_max_transform_feedback_separate_attribs, m_buffers);
  
  		delete[] m_buffers;
  
  		m_buffers = DE_NULL;
  	}
  }
  
  bool gl3cts::TransformFeedback::CaptureVertexSeparate::checkTransformFeedbackBuffer(BindBufferCase bind_case UNUSED,
  																					glw::GLenum primitive_type)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	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;
  	}
  
  	bool is_ok = true;
  
  	for (glw::GLint i = 0; i < m_max_transform_feedback_separate_attribs - 1; ++i)
  	{
  		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_buffers[i]);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  		glw::GLfloat* results = (glw::GLfloat*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed.");
  
  		for (glw::GLuint j = 0; (j < number_of_vertices) && is_ok; ++j)
  		{
  			for (glw::GLuint k = 0; k < 4 /* vec4 */; ++k)
  			{
  				glw::GLfloat result	= results[j * 4 + k];
  				glw::GLfloat reference = (glw::GLfloat)(i * 4 + k);
  
  				if (fabs(result - reference) > 0.125 /* precision */)
  				{
  					is_ok = false;
  
  					break;
  				}
  			}
  		}
  
  		gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
  	}
  
  	/* gl_Position */
  	if (is_ok)
  	{
  		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_buffers[m_max_transform_feedback_separate_attribs - 1]);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  		glw::GLfloat* results = (glw::GLfloat*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed.");
  
  		for (glw::GLuint j = 0; (j < number_of_vertices) && is_ok; ++j)
  		{
  			glw::GLfloat result[4] = { results[j * 4], results[j * 4 + 1], results[j * 4 + 2], results[j * 4 + 3] };
  
  			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;
  }
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::CaptureGeometrySeparate::CaptureGeometrySeparate(deqp::Context& context,
  																			const char*	test_name,
  																			const char*	test_description)
  	: CaptureVertexInterleaved(context, test_name, test_description)
  	, CaptureVertexSeparate(context, test_name, test_description)
  	, CaptureGeometryInterleaved(context, test_name, test_description)
  	, m_buffers(DE_NULL)
  	, m_max_transform_feedback_separate_attribs(0)
  {
  }
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::CheckGetXFBVarying::CheckGetXFBVarying(deqp::Context& context, const char* test_name,
  																  const char* test_description)
  	: deqp::TestCase(context, test_name, test_description)
  	, m_context(context)
  	, m_max_xfb_interleaved_components(0)
  	, m_max_xfb_separate_attributes(0)
  	, m_max_xfb_separate_components(0)
  	, m_max_varying_components(0)
  	, m_max_varying_vectors(0)
  	, m_max_geometry_total_output_components(0)
  {
  }
  
  gl3cts::TransformFeedback::CheckGetXFBVarying::~CheckGetXFBVarying(void)
  {
  }
  
  void gl3cts::TransformFeedback::CheckGetXFBVarying::fetchLimits(void)
  {
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Fetching limits. */
  	gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &m_max_xfb_interleaved_components);
  	gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &m_max_xfb_separate_attributes);
  	gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &m_max_xfb_separate_components);
  	gl.getIntegerv(GL_MAX_VARYING_COMPONENTS, &m_max_varying_components);
  	gl.getIntegerv(GL_MAX_VARYING_VECTORS, &m_max_varying_vectors);
  	gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &m_max_geometry_total_output_components);
  
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
  }
  
  glw::GLuint gl3cts::TransformFeedback::CheckGetXFBVarying::numberOfAttributes(glw::GLuint capture_way,
  																			  glw::GLuint shader_case,
  																			  glw::GLuint varying_type)
  {
  	/* Setup limits of the case. */
  	const glw::GLuint max_total_components =
  		((s_shader_cases[shader_case].geometry_shader == DE_NULL) ? m_max_varying_components :
  																	m_max_geometry_total_output_components) -
  		4 /* gl_Position is not captured */;
  
  	const glw::GLuint attribute_components = s_varying_types[varying_type].components_count;
  	const glw::GLuint max_xfb_components   = (s_capture_ways[capture_way] == GL_INTERLEAVED_ATTRIBS) ?
  											   m_max_xfb_interleaved_components :
  											   (attribute_components * m_max_xfb_separate_components);
  
  	if (s_capture_ways[capture_way] == GL_SEPARATE_ATTRIBS)
  	{
  		if (attribute_components > glw::GLuint(m_max_xfb_separate_components))
  		{
  			return 0;
  		}
  	}
  
  	/* Setup number of attributes. */
  	glw::GLuint number_of_attributes = max_xfb_components / attribute_components;
  
  	if (s_capture_ways[capture_way] == GL_SEPARATE_ATTRIBS &&
  		number_of_attributes > glw::GLuint(m_max_xfb_separate_attributes))
  	{
  		number_of_attributes = m_max_xfb_separate_attributes;
  	}
  
  	/* Clamp to limits. */
  	if (number_of_attributes * attribute_components > max_total_components)
  	{
  		number_of_attributes = max_total_components / attribute_components;
  	}
  
  	/* Vectors limit. */
  	if (attribute_components <= 4)
  	{
  		if (number_of_attributes > glw::GLuint(m_max_varying_vectors))
  		{
  			number_of_attributes = m_max_varying_vectors;
  		}
  	}
  	else
  	{
  		if (number_of_attributes > glw::GLuint(m_max_varying_vectors) / 4)
  		{
  			number_of_attributes = glw::GLuint(m_max_varying_vectors) / 4;
  		}
  	}
  
  	/* Return. */
  	return number_of_attributes;
  }
  
  tcu::TestNode::IterateResult gl3cts::TransformFeedback::CheckGetXFBVarying::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;
  
  	glw::GLuint program = 0;
  
  	/* Tests. */
  	try
  	{
  		if (is_at_least_gl_30 || is_ext_tf_1)
  		{
  			fetchLimits();
  
  			for (glw::GLuint i = 0; (i < s_capture_ways_count) && is_ok; ++i)
  			{
  				for (glw::GLuint j = 0; (j < s_shader_cases_count) && is_ok; ++j)
  				{
  					for (glw::GLuint k = 0; (k < s_varying_types_count) && is_ok; ++k)
  					{
  						glw::GLuint n = numberOfAttributes(i, j, k);
  
  						if (n)
  						{
  							program = buildProgram(i, j, k, n);
  
  							is_ok = is_ok && (program != 0);
  
  							is_ok = is_ok && check(program, i, j, k, n);
  
  							gl.deleteProgram(program);
  
  							GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram call failed.");
  
  							program = 0;
  						}
  					}
  				}
  			}
  		}
  	}
  	catch (...)
  	{
  		is_ok	  = false;
  		test_error = true;
  
  		if (program)
  		{
  			gl.deleteProgram(program);
  
  			program = 0;
  		}
  	}
  
  	/* Result's setup. */
  	if (is_ok)
  	{
  		/* Log success. */
  		m_context.getTestContext().getLog() << tcu::TestLog::Message
  											<< "Test checking Get Transform Feedback Varying 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;
  }
  
  glw::GLuint gl3cts::TransformFeedback::CheckGetXFBVarying::buildProgram(glw::GLuint capture_way,
  																		glw::GLuint shader_case,
  																		glw::GLuint varying_type,
  																		glw::GLuint number_of_attributes)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Preparing source code. */
  	std::string						xfb_variable_declarations("");
  	std::string						xfb_variable_setters("");
  	std::vector<std::string>		xfb_varyings(number_of_attributes);
  	std::vector<const glw::GLchar*> xfb_varyings_c(number_of_attributes);
  
  	/* Most of varyings is declarated output variables. */
  	for (glw::GLuint i = 0; i < number_of_attributes; ++i)
  	{
  		/* Varying name: result_# */
  		std::string varying = "result_";
  		varying.append(gl3cts::TransformFeedback::Utilities::itoa(i));
  
  		xfb_varyings[i]   = varying;
  		xfb_varyings_c[i] = xfb_varyings[i].c_str();
  
  		/* Varying declaration: out TYPE result_#;*/
  		xfb_variable_declarations.append("out ");
  		xfb_variable_declarations.append(s_varying_types[varying_type].name);
  		xfb_variable_declarations.append(" ");
  		xfb_variable_declarations.append(varying);
  		xfb_variable_declarations.append(";\n");
  
  		/* Varying setter: result_# = TYPE(#); */
  		xfb_variable_setters.append("    ");
  		xfb_variable_setters.append(varying);
  		xfb_variable_setters.append(" = ");
  		xfb_variable_setters.append(s_varying_types[varying_type].name);
  		xfb_variable_setters.append("(");
  		xfb_variable_setters.append("2"); //gl3cts::TransformFeedback::Utilities::itoa(i));
  		if (s_varying_types[varying_type].float_component)
  		{
  			/* if varying is float varying setter is: result_# = TYPE(#.0); */
  			xfb_variable_setters.append(".0");
  		}
  		xfb_variable_setters.append(");\n");
  	}
  
  	/* Preprocess vertex shader source code template. */
  	const glw::GLchar* vertex_shader   = s_shader_cases[shader_case].vertex_shader;
  	const glw::GLchar* geometry_shader = s_shader_cases[shader_case].geometry_shader;
  
  	std::string xfb_shader;
  
  	if (DE_NULL == s_shader_cases[shader_case].geometry_shader)
  	{
  		/* XFB tested in vertex shader. */
  		xfb_shader = vertex_shader;
  	}
  	else
  	{
  		/* XFB tested in geometry shader. */
  		xfb_shader = geometry_shader;
  	}
  
  	/* Preprocess shader. */
  	xfb_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(xfb_shader, "TEMPLATE_OUTPUT_DECLARATIONS",
  																	  xfb_variable_declarations);
  	xfb_shader = gl3cts::TransformFeedback::Utilities::preprocessCode(xfb_shader, "TEMPLATE_OUTPUT_SETTERS",
  																	  xfb_variable_setters);
  
  	if (DE_NULL == s_shader_cases[shader_case].geometry_shader)
  	{
  		/* XFB tested in vertex shader. */
  		vertex_shader = xfb_shader.c_str();
  	}
  	else
  	{
  		/* XFB tested in geometry shader. */
  		geometry_shader = xfb_shader.c_str();
  	}
  
  	/* Compile, link and check. */
  	glw::GLuint program = gl3cts::TransformFeedback::Utilities::buildProgram(
  		gl, m_context.getTestContext().getLog(), geometry_shader, NULL, NULL, vertex_shader, s_generic_fragment_shader,
  		&xfb_varyings_c[0], number_of_attributes, s_capture_ways[capture_way]);
  
  	/* Check compilation status. */
  	if (0 == program)
  	{
  		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Building program has failed.\nVertex shader:\n"
  											<< vertex_shader << "Geometry shader:\n"
  											<< ((DE_NULL == geometry_shader) ? "" : geometry_shader)
  											<< "Fragment shader:\n"
  											<< s_generic_fragment_shader << tcu::TestLog::EndMessage;
  
  		throw 0;
  	}
  
  	return program;
  }
  
  bool gl3cts::TransformFeedback::CheckGetXFBVarying::check(glw::GLuint program, glw::GLuint capture_way,
  														  glw::GLuint shader_case UNUSED, glw::GLuint varying_type,
  														  glw::GLuint number_of_attributes)
  {
  	/* Functions handler */
  	const glw::Functions& gl		 = m_context.getRenderContext().getFunctions();
  	glw::GLuint			  max_length = 0;
  
  	/* Inspect glGetTransformFeedbackVarying. */
  	for (glw::GLuint i = 0; i < number_of_attributes; ++i)
  	{
  		const glw::GLsizei bufSize  = 18;
  		glw::GLsizei	   length   = 0;
  		glw::GLsizei	   size		= 0;
  		glw::GLenum		   type		= GL_NONE;
  		glw::GLchar		   name[18] = { 0 }; /* Size of bufSize. */
  
  		gl.getTransformFeedbackVarying(program, i, bufSize, &length, &size, &type, name);
  
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbackVarying call failed.");
  
  		max_length = deMaxu32(max_length, glw::GLuint(length));
  
  		/* Check name. */
  		if (length)
  		{
  			std::string varying		= name;
  			std::string varying_ref = "result_";
  			varying_ref.append(gl3cts::TransformFeedback::Utilities::itoa(i));
  
  			if (0 != varying.compare(varying_ref))
  			{
  				return false;
  			}
  		}
  		else
  		{
  			return false;
  		}
  
  		/* Check size. */
  		const glw::GLuint size_ref = 1;
  
  		if (size != size_ref)
  		{
  			return false;
  		}
  
  		/* Check type. */
  		if (type != s_varying_types[varying_type].type)
  		{
  			return false;
  		}
  	}
  
  	/* Inspect glGetProgramiv. */
  	glw::GLint xfb_varyings			  = 0;
  	glw::GLint xfb_mode				  = 0;
  	glw::GLint xfb_varying_max_length = 0;
  
  	gl.getProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &xfb_varyings);
  	gl.getProgramiv(program, GL_TRANSFORM_FEEDBACK_BUFFER_MODE, &xfb_mode);
  	gl.getProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &xfb_varying_max_length);
  
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
  
  	if (glw::GLuint(xfb_varyings) != number_of_attributes)
  	{
  		return false;
  	}
  
  	if (glw::GLenum(xfb_mode) != s_capture_ways[capture_way])
  	{
  		return false;
  	}
  
  	if (glw::GLuint(xfb_varying_max_length) < max_length)
  	{
  		return false;
  	}
  
  	return true;
  }
  
  const glw::GLchar* gl3cts::TransformFeedback::CheckGetXFBVarying::s_generic_fragment_shader = "#version 130\n"
  																							  "\n"
  																							  "out vec4 color;\n"
  																							  "\n"
  																							  "void main()\n"
  																							  "{\n"
  																							  "    color = vec4(1.0);\n"
  																							  "}\n";
  
  const struct gl3cts::TransformFeedback::CheckGetXFBVarying::ShaderCase
  	gl3cts::TransformFeedback::CheckGetXFBVarying::s_shader_cases[] = { { /* Vertex Shader. */
  																		  "#version 130\n"
  																		  "\n"
  																		  "TEMPLATE_OUTPUT_DECLARATIONS"
  																		  "\n"
  																		  "void main()\n"
  																		  "{\n"
  																		  "    gl_Position = vec4(1.0);\n"
  																		  "TEMPLATE_OUTPUT_SETTERS"
  																		  "}\n",
  
  																		  /* Geometry Shader. */
  																		  NULL },
  																		{ /* Vertex Shader. */
  																		  "#version 130\n"
  																		  "\n"
  																		  "void main()\n"
  																		  "{\n"
  																		  "}\n",
  
  																		  /* Geometry Shader. */
  																		  "#version 150\n"
  																		  "\n"
  																		  "layout(points) in;\n"
  																		  "layout(points, max_vertices = 1) out;\n"
  																		  "\n"
  																		  "TEMPLATE_OUTPUT_DECLARATIONS"
  																		  "\n"
  																		  "void main()\n"
  																		  "{\n"
  																		  "    gl_Position = vec4(1.0);\n"
  																		  "TEMPLATE_OUTPUT_SETTERS"
  																		  "    EmitVertex();\n"
  																		  "}\n" } };
  
  const glw::GLuint gl3cts::TransformFeedback::CheckGetXFBVarying::s_shader_cases_count =
  	sizeof(s_shader_cases) / sizeof(s_shader_cases[0]);
  
  const struct gl3cts::TransformFeedback::CheckGetXFBVarying::VaryingType
  	gl3cts::TransformFeedback::CheckGetXFBVarying::s_varying_types[] = {
  		/* type,				name,		#components,	is component float */
  		{ GL_FLOAT, "float", 1, true },
  		{ GL_FLOAT_VEC2, "vec2", 2, true },
  		{ GL_FLOAT_VEC3, "vec3", 3, true },
  		{ GL_FLOAT_VEC4, "vec4", 4, true },
  		{ GL_INT, "int", 1, false },
  		{ GL_INT_VEC2, "ivec2", 2, false },
  		{ GL_INT_VEC3, "ivec3", 3, false },
  		{ GL_INT_VEC4, "ivec4", 4, false },
  		{ GL_UNSIGNED_INT, "uint", 1, false },
  		{ GL_UNSIGNED_INT_VEC2, "uvec2", 2, false },
  		{ GL_UNSIGNED_INT_VEC3, "uvec3", 3, false },
  		{ GL_UNSIGNED_INT_VEC4, "uvec4", 4, false },
  		{ GL_FLOAT_MAT2, "mat2", 4, true },
  		{ GL_FLOAT_MAT3, "mat3", 9, true },
  		{ GL_FLOAT_MAT4, "mat4", 16, true }
  	};
  
  const glw::GLuint gl3cts::TransformFeedback::CheckGetXFBVarying::s_varying_types_count =
  	sizeof(s_varying_types) / sizeof(s_varying_types[0]);
  
  const glw::GLenum gl3cts::TransformFeedback::CheckGetXFBVarying::s_capture_ways[] = { GL_INTERLEAVED_ATTRIBS,
  																					  GL_SEPARATE_ATTRIBS };
  
  const glw::GLuint gl3cts::TransformFeedback::CheckGetXFBVarying::s_capture_ways_count =
  	sizeof(s_capture_ways) / sizeof(s_capture_ways[0]);
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::QueryVertexInterleaved::QueryVertexInterleaved(deqp::Context& context, const char* test_name,
  																		  const char* test_description)
  	: CaptureVertexInterleaved(context, test_name, test_description), m_query_object(0)
  {
  	m_max_vertices_drawn = 3; /* Make buffer smaller up to 3 vertices. */
  }
  
  void gl3cts::TransformFeedback::QueryVertexInterleaved::createTransformFeedbackBuffer(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Create buffer object. */
  	gl3cts::TransformFeedback::CaptureVertexInterleaved::createTransformFeedbackBuffer();
  
  	/* Create query object. */
  	gl.genQueries(1, &m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries call failed.");
  }
  
  void gl3cts::TransformFeedback::QueryVertexInterleaved::draw(glw::GLuint primitive_case)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQuery call failed.");
  
  	gl3cts::TransformFeedback::CaptureVertexInterleaved::draw(primitive_case);
  
  	gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery call failed.");
  }
  
  bool gl3cts::TransformFeedback::QueryVertexInterleaved::checkTransformFeedbackBuffer(BindBufferCase bind_case UNUSED,
  																					 glw::GLenum primitive_type)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	glw::GLuint number_of_primitives;
  
  	gl.getQueryObjectuiv(m_query_object, GL_QUERY_RESULT, &number_of_primitives);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv call failed.");
  
  	/* expected result */
  	glw::GLuint number_of_primitives_reference = (primitive_type == GL_POINTS) ? 3 : 1; /* m_max_vertices_drawn == 3 */
  
  	if (number_of_primitives_reference != number_of_primitives)
  	{
  		return false;
  	}
  
  	return true;
  }
  
  void gl3cts::TransformFeedback::QueryVertexInterleaved::clean(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Delete query object. */
  	gl.deleteQueries(1, &m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteQueries call failed.");
  
  	/* Other */
  	gl3cts::TransformFeedback::CaptureVertexInterleaved::clean();
  }
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::QueryGeometryInterleaved::QueryGeometryInterleaved(deqp::Context& context,
  																			  const char*	test_name,
  																			  const char*	test_description)
  	: CaptureVertexInterleaved(context, test_name, test_description)
  	, CaptureGeometryInterleaved(context, test_name, test_description)
  {
  	m_query_object		 = 0;
  	m_max_vertices_drawn = 3; /* Make buffer smaller up to 3 vertices. */
  }
  
  void gl3cts::TransformFeedback::QueryGeometryInterleaved::createTransformFeedbackBuffer(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Create buffer object. */
  	gl3cts::TransformFeedback::CaptureGeometryInterleaved::createTransformFeedbackBuffer();
  
  	/* Create query object. */
  	gl.genQueries(1, &m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries call failed.");
  }
  
  void gl3cts::TransformFeedback::QueryGeometryInterleaved::draw(glw::GLuint primitive_case)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQuery call failed.");
  
  	gl3cts::TransformFeedback::CaptureGeometryInterleaved::draw(primitive_case);
  
  	gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery call failed.");
  }
  
  bool gl3cts::TransformFeedback::QueryGeometryInterleaved::checkTransformFeedbackBuffer(BindBufferCase bind_case UNUSED,
  																					   glw::GLenum primitive_type)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	glw::GLuint number_of_primitives;
  
  	gl.getQueryObjectuiv(m_query_object, GL_QUERY_RESULT, &number_of_primitives);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv call failed.");
  
  	/* expected result */
  	glw::GLuint number_of_primitives_reference = (primitive_type == GL_POINTS) ? 3 : 1; /* m_max_vertices_drawn == 3 */
  
  	if (number_of_primitives_reference != number_of_primitives)
  	{
  		return false;
  	}
  
  	return true;
  }
  
  void gl3cts::TransformFeedback::QueryGeometryInterleaved::clean(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Delete query object. */
  	gl.deleteQueries(1, &m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteQueries call failed.");
  
  	/* Other. */
  	gl3cts::TransformFeedback::CaptureGeometryInterleaved::clean();
  }
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::QueryVertexSeparate::QueryVertexSeparate(deqp::Context& context, const char* test_name,
  																	const char* test_description)
  	: CaptureVertexInterleaved(context, test_name, test_description)
  	, CaptureVertexSeparate(context, test_name, test_description)
  {
  	m_query_object		 = 0;
  	m_max_vertices_drawn = 3; /* Make buffer smaller up to 3 vertices. */
  }
  
  void gl3cts::TransformFeedback::QueryVertexSeparate::createTransformFeedbackBuffer(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Create buffer object. */
  	gl3cts::TransformFeedback::CaptureVertexSeparate::createTransformFeedbackBuffer();
  
  	/* Create query object. */
  	gl.genQueries(1, &m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries call failed.");
  }
  
  void gl3cts::TransformFeedback::QueryVertexSeparate::draw(glw::GLuint primitive_case)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQuery call failed.");
  
  	gl3cts::TransformFeedback::CaptureVertexSeparate::draw(primitive_case);
  
  	gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery call failed.");
  }
  
  bool gl3cts::TransformFeedback::QueryVertexSeparate::checkTransformFeedbackBuffer(BindBufferCase bind_case UNUSED,
  																				  glw::GLenum primitive_type)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	glw::GLuint number_of_primitives;
  
  	gl.getQueryObjectuiv(m_query_object, GL_QUERY_RESULT, &number_of_primitives);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv call failed.");
  
  	/* expected result */
  	glw::GLuint number_of_primitives_reference = (primitive_type == GL_POINTS) ? 3 : 1; /* m_max_vertices_drawn == 3 */
  
  	if (number_of_primitives_reference != number_of_primitives)
  	{
  		return false;
  	}
  
  	return true;
  }
  
  void gl3cts::TransformFeedback::QueryVertexSeparate::clean(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Delete query object. */
  	gl.deleteQueries(1, &m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteQueries call failed.");
  
  	/* Other */
  	gl3cts::TransformFeedback::CaptureVertexSeparate::clean();
  }
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::QueryGeometrySeparate::QueryGeometrySeparate(deqp::Context& context, const char* test_name,
  																		const char* test_description)
  	: CaptureVertexInterleaved(context, test_name, test_description)
  	, CaptureVertexSeparate(context, test_name, test_description)
  	, CaptureGeometrySeparate(context, test_name, test_description)
  {
  	m_query_object		 = 0;
  	m_max_vertices_drawn = 3; /* Make buffer smaller up to 3 vertices. */
  }
  
  void gl3cts::TransformFeedback::QueryGeometrySeparate::createTransformFeedbackBuffer(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Create buffer object. */
  	gl3cts::TransformFeedback::CaptureGeometrySeparate::createTransformFeedbackBuffer();
  
  	/* Create query object. */
  	gl.genQueries(1, &m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries call failed.");
  }
  
  void gl3cts::TransformFeedback::QueryGeometrySeparate::draw(glw::GLuint primitive_case)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQuery call failed.");
  
  	gl3cts::TransformFeedback::CaptureGeometrySeparate::draw(primitive_case);
  
  	gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery call failed.");
  }
  
  bool gl3cts::TransformFeedback::QueryGeometrySeparate::checkTransformFeedbackBuffer(BindBufferCase bind_case UNUSED,
  																					glw::GLenum primitive_type)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	glw::GLuint number_of_primitives;
  
  	gl.getQueryObjectuiv(m_query_object, GL_QUERY_RESULT, &number_of_primitives);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv call failed.");
  
  	/* expected result */
  	glw::GLuint number_of_primitives_reference = (primitive_type == GL_POINTS) ? 3 : 1; /* m_max_vertices_drawn == 3 */
  
  	if (number_of_primitives_reference != number_of_primitives)
  	{
  		return false;
  	}
  
  	return true;
  }
  
  void gl3cts::TransformFeedback::QueryGeometrySeparate::clean(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Delete query object. */
  	gl.deleteQueries(1, &m_query_object);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteQueries call failed.");
  
  	/* Other */
  	gl3cts::TransformFeedback::CaptureGeometrySeparate::clean();
  }
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::DiscardVertex::DiscardVertex(deqp::Context& context, const char* test_name,
  														const char* test_description)
  	: CaptureVertexInterleaved(context, test_name, test_description)
  {
  }
  
  void gl3cts::TransformFeedback::DiscardVertex::draw(glw::GLuint primitive_case)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Must clear before rasterizer discard */
  	gl.clear(GL_COLOR_BUFFER_BIT);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
  
  	gl.enable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable call failed.");
  
  	gl3cts::TransformFeedback::CaptureVertexInterleaved::draw(primitive_case);
  
  	gl.disable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable call failed.");
  }
  
  bool gl3cts::TransformFeedback::DiscardVertex::checkFramebuffer(glw::GLuint primitive_case 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.0625f /* precision */)
  		{
  			return false;
  		}
  	}
  
  	return true;
  }
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::DiscardGeometry::DiscardGeometry(deqp::Context& context, const char* test_name,
  															const char* test_description)
  	: CaptureVertexInterleaved(context, test_name, test_description)
  	, CaptureGeometryInterleaved(context, test_name, test_description)
  {
  }
  
  void gl3cts::TransformFeedback::DiscardGeometry::draw(glw::GLuint primitive_case)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Must clear before rasterizer discard */
  	gl.clear(GL_COLOR_BUFFER_BIT);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
  
  	gl.enable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable call failed.");
  
  	gl3cts::TransformFeedback::CaptureGeometryInterleaved::draw(primitive_case);
  
  	gl.disable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable call failed.");
  }
  
  bool gl3cts::TransformFeedback::DiscardGeometry::checkFramebuffer(glw::GLuint primitive_case 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.0625f /* precision */)
  		{
  			return false;
  		}
  	}
  
  	return true;
  }
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::DrawXFB::DrawXFB(deqp::Context& context, const char* test_name, const char* test_description)
  	: deqp::TestCase(context, test_name, test_description)
  	, m_context(context)
  	, m_program_id_xfb(0)
  	, m_program_id_draw(0)
  	, m_fbo_id(0)
  	, m_rbo_id(0)
  	, m_vao_id(0)
  {
  	memset(m_xfb_id, 0, sizeof(m_xfb_id));
  	memset(m_bo_id, 0, sizeof(m_bo_id));
  }
  
  gl3cts::TransformFeedback::DrawXFB::~DrawXFB(void)
  {
  }
  
  tcu::TestNode::IterateResult gl3cts::TransformFeedback::DrawXFB::iterate(void)
  {
  	/* Initializations. */
  	bool is_at_least_gl_40 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)));
  	bool is_arb_tf_2	   = m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback2");
  
  	bool is_ok		= true;
  	bool test_error = false;
  
  	/* Tests. */
  	try
  	{
  		if (is_at_least_gl_40 || is_arb_tf_2)
  		{
  			for (glw::GLuint i = 0; (i < s_capture_modes_count) && is_ok; ++i)
  			{
  				prepare(s_capture_modes[i]);
  
  				bindVAO(m_vao_id);
  				useProgram(m_program_id_xfb);
  
  				for (glw::GLuint j = 0; (j < s_xfb_count) && is_ok; ++j)
  				{
  					bindXFB(m_xfb_id[j]);
  					bindBOForXFB(s_capture_modes[i], m_bo_id[j]);
  					useColour(m_program_id_xfb, s_colours[j][0], s_colours[j][1], s_colours[j][2], s_colours[j][3]);
  					useGeometrySet(m_program_id_xfb, false);
  					drawForCapture(true, true, false, false);
  
  					is_ok = is_ok && inspectXFBState(true, true);
  				}
  
  				for (glw::GLuint j = 0; (j < s_xfb_count) && is_ok; ++j)
  				{
  					bindXFB(m_xfb_id[j]);
  					useColour(m_program_id_xfb, s_colours[j][0], s_colours[j][1], s_colours[j][2], s_colours[j][3]);
  					useGeometrySet(m_program_id_xfb, true);
  					drawForCapture(false, false, true, true);
  
  					is_ok = is_ok && inspectXFBState(false, false);
  				}
  
  				useProgram(m_program_id_draw);
  
  				for (glw::GLuint j = 0; (j < s_xfb_count) && is_ok; ++j)
  				{
  					bindXFB(m_xfb_id[j]);
  					bindBOForDraw(m_program_id_draw, s_capture_modes[i], m_bo_id[j]);
  					drawToFramebuffer(m_xfb_id[j]);
  
  					is_ok =
  						is_ok && checkFramebuffer(s_colours[j][0], s_colours[j][1], s_colours[j][2], s_colours[j][3]);
  				}
  
  				clean();
  			}
  		}
  	}
  	catch (...)
  	{
  		is_ok	  = false;
  		test_error = true;
  		clean();
  	}
  
  	/* Result's setup. */
  	if (is_ok)
  	{
  		/* Log success. */
  		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB have passed."
  											<< tcu::TestLog::EndMessage;
  
  		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
  	}
  	else
  	{
  		if (test_error)
  		{
  			/* Log error. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB have approached error."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
  		}
  		else
  		{
  			/* Log fail. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB have failed."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
  		}
  	}
  
  	return STOP;
  }
  
  void gl3cts::TransformFeedback::DrawXFB::prepare(glw::GLenum capture_mode)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Prepare programs. */
  	m_program_id_xfb = gl3cts::TransformFeedback::Utilities::buildProgram(
  		gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, s_vertex_shader_xfb, s_fragment_shader,
  		s_xfb_varyings, s_xfb_varyings_count, capture_mode);
  
  	if (0 == m_program_id_xfb)
  	{
  		throw 0;
  	}
  
  	m_program_id_draw = gl3cts::TransformFeedback::Utilities::buildProgram(gl, m_context.getTestContext().getLog(),
  																		   NULL, NULL, NULL, s_vertex_shader_draw,
  																		   s_fragment_shader, NULL, 0, capture_mode);
  
  	if (0 == m_program_id_draw)
  	{
  		throw 0;
  	}
  
  	/* Prepare transform feedbacks. */
  	gl.genTransformFeedbacks(s_xfb_count, m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks call failed.");
  
  	/* Prepare buffer objects. */
  	gl.genBuffers(s_xfb_count, m_bo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
  
  	for (glw::GLuint i = 0; i < s_xfb_count; ++i)
  	{
  		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id[i]);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  		gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, s_capture_size, NULL, GL_DYNAMIC_COPY);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
  	}
  
  	/* Prepare framebuffer. */
  	gl.clearColor(0.f, 0.f, 0.f, 1.f);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
  
  	gl.genFramebuffers(1, &m_fbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed.");
  
  	gl.genRenderbuffers(1, &m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed.");
  
  	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed.");
  
  	gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed.");
  
  	gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, s_view_size, s_view_size);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed.");
  
  	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed.");
  
  	if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  	{
  		throw 0;
  	}
  
  	gl.viewport(0, 0, s_view_size, s_view_size);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport call failed.");
  
  	/* Create empty Vertex Array Object */
  	gl.genVertexArrays(1, &m_vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFB::bindXFB(glw::GLuint xfb_id)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFB::bindVAO(glw::GLuint vao_id)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.bindVertexArray(vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFB::bindBOForXFB(glw::GLenum capture_mode, glw::GLuint bo_id)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	switch (capture_mode)
  	{
  	case GL_INTERLEAVED_ATTRIBS:
  		gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bo_id);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
  		break;
  	case GL_SEPARATE_ATTRIBS:
  		for (glw::GLuint i = 0; i < s_xfb_varyings_count; ++i)
  		{
  			gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, i, bo_id, i * s_capture_size / s_xfb_varyings_count,
  							   (i + 1) * s_capture_size / s_xfb_varyings_count);
  			GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase call failed.");
  		}
  		break;
  	default:
  		throw 0;
  	};
  }
  
  void gl3cts::TransformFeedback::DrawXFB::bindBOForDraw(glw::GLuint program_id, glw::GLenum capture_mode,
  													   glw::GLuint bo_id)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.bindBuffer(GL_ARRAY_BUFFER, bo_id);
  
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	glw::GLuint position_location = gl.getAttribLocation(program_id, "position");
  	glw::GLuint color_location	= gl.getAttribLocation(program_id, "color");
  
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation call failed.");
  
  	glw::GLvoid* color_offset = (capture_mode == GL_INTERLEAVED_ATTRIBS) ?
  									(glw::GLvoid*)(4 /* components */ * sizeof(glw::GLfloat)) :
  									(glw::GLvoid*)(4 /* components */ * 6 /* vertices */ * sizeof(glw::GLfloat));
  
  	glw::GLuint stride =
  		static_cast<glw::GLuint>((capture_mode == GL_INTERLEAVED_ATTRIBS) ?
  									 (4 /* components */ * 2 /* position and color */ * sizeof(glw::GLfloat)) :
  									 (4 /* components */ * sizeof(glw::GLfloat)));
  
  	gl.vertexAttribPointer(position_location, 4, GL_FLOAT, GL_FALSE, stride, NULL);
  	gl.vertexAttribPointer(color_location, 4, GL_FLOAT, GL_FALSE, stride, color_offset);
  
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer call failed.");
  
  	gl.enableVertexAttribArray(position_location);
  	gl.enableVertexAttribArray(color_location);
  
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFB::useProgram(glw::GLuint program_id)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.useProgram(program_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFB::useColour(glw::GLuint program_id, glw::GLfloat r, glw::GLfloat g,
  												   glw::GLfloat b, glw::GLfloat a)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	glw::GLint location = gl.getUniformLocation(program_id, "color");
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation call failed.");
  
  	gl.uniform4f(location, r, g, b, a);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4f call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFB::useGeometrySet(glw::GLuint program_id, bool invert_sign)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	glw::GLint location = gl.getUniformLocation(program_id, "invert_sign");
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation call failed.");
  
  	gl.uniform1f(location, invert_sign ? -1.f : 1.f);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4f call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFB::clean()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.useProgram(0);
  
  	if (m_program_id_xfb)
  	{
  		gl.deleteProgram(m_program_id_xfb);
  
  		m_program_id_xfb = 0;
  	}
  
  	if (m_program_id_draw)
  	{
  		gl.deleteProgram(m_program_id_draw);
  
  		m_program_id_draw = 1;
  	}
  
  	for (glw::GLuint i = 0; i < s_xfb_count; ++i)
  	{
  		if (m_xfb_id[i])
  		{
  			gl.deleteTransformFeedbacks(1, &m_xfb_id[i]);
  
  			m_xfb_id[i] = 0;
  		}
  	}
  
  	for (glw::GLuint i = 0; i < s_xfb_count; ++i)
  	{
  		if (m_bo_id[i])
  		{
  			gl.deleteBuffers(1, &m_bo_id[i]);
  
  			m_bo_id[i] = 0;
  		}
  	}
  
  	if (m_vao_id)
  	{
  		gl.deleteVertexArrays(1, &m_vao_id);
  
  		m_vao_id = 0;
  	}
  
  	if (m_fbo_id)
  	{
  		gl.deleteFramebuffers(1, &m_fbo_id);
  
  		m_fbo_id = 0;
  	}
  
  	if (m_rbo_id)
  	{
  		gl.deleteRenderbuffers(1, &m_rbo_id);
  
  		m_rbo_id = 0;
  	}
  }
  
  void gl3cts::TransformFeedback::DrawXFB::drawForCapture(bool begin_xfb, bool pause_xfb, bool resume_xfb, bool end_xfb)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.enable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable call failed.");
  
  	if (begin_xfb)
  	{
  		gl.beginTransformFeedback(GL_POINTS);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
  	}
  
  	if (resume_xfb)
  	{
  		gl.resumeTransformFeedback();
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glResumeTransformFeedback call failed.");
  	}
  
  	gl.drawArrays(GL_POINTS, 0, 3);
  
  	if (pause_xfb)
  	{
  		gl.pauseTransformFeedback();
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glPauseTransformFeedback call failed.");
  	}
  
  	if (end_xfb)
  	{
  		gl.endTransformFeedback();
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
  	}
  
  	gl.disable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFB::drawToFramebuffer(glw::GLuint xfb_id)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.clearColor(0.f, 0.f, 0.f, 0.f);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
  
  	gl.clear(GL_COLOR_BUFFER_BIT);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
  
  	gl.drawTransformFeedback(GL_TRIANGLES, xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawTransformFeedback call failed.");
  }
  
  bool gl3cts::TransformFeedback::DrawXFB::checkFramebuffer(glw::GLfloat r, glw::GLfloat g, glw::GLfloat b,
  														  glw::GLfloat a)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Number of pixels. */
  	const glw::GLuint number_of_pixels = s_view_size * s_view_size;
  
  	/* Fetch framebuffer. */
  	std::vector<glw::GLubyte> pixels(number_of_pixels * 4 /* components */);
  
  	if ((s_view_size > 0) && (s_view_size > 0))
  	{
  		gl.readPixels(0, 0, s_view_size, s_view_size, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels call failed.");
  	}
  
  	/* Convert color to integer. */
  	glw::GLubyte ir = (glw::GLubyte)(255.f * r);
  	glw::GLubyte ig = (glw::GLubyte)(255.f * g);
  	glw::GLubyte ib = (glw::GLubyte)(255.f * b);
  	glw::GLubyte ia = (glw::GLubyte)(255.f * a);
  
  	/* Check results. */
  	for (glw::GLuint i = 0; i < number_of_pixels; ++i)
  	{
  		if ((pixels[i * 4 /* components */] != ir) || (pixels[i * 4 /* components */ + 1] != ig) ||
  			(pixels[i * 4 /* components */ + 2] != ib) || (pixels[i * 4 /* components */ + 3] != ia))
  		{
  			return false;
  		}
  	}
  
  	return true;
  }
  
  bool gl3cts::TransformFeedback::DrawXFB::inspectXFBState(bool shall_be_paused, bool shall_be_active)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	glw::GLint is_paused = 0;
  	glw::GLint is_active = 0;
  
  	gl.getIntegerv(GL_TRANSFORM_FEEDBACK_PAUSED, &is_paused);
  	gl.getIntegerv(GL_TRANSFORM_FEEDBACK_ACTIVE, &is_active);
  
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
  
  	if ((is_paused == -1) || (is_active == -1))
  	{
  		throw 0;
  	}
  
  	if (shall_be_paused ^ (is_paused == GL_TRUE))
  	{
  		return false;
  	}
  
  	if (shall_be_active ^ (is_active == GL_TRUE))
  	{
  		return false;
  	}
  
  	return true;
  }
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFB::s_vertex_shader_xfb =
  	"#version 130\n"
  	"\n"
  	"uniform vec4 color;\n"
  	"uniform float invert_sign;\n"
  	"out     vec4 colour;\n"
  	"\n"
  	"void main()\n"
  	"{\n"
  	"    switch(gl_VertexID)\n"
  	"    {\n"
  	"        case 0:\n"
  	"            gl_Position = vec4(-1.0,               -1.0,              0.0,  1.0);\n"
  	"        break;\n"
  	"        case 1:\n"
  	"            gl_Position = vec4(-1.0 * invert_sign,  1.0,              0.0,  1.0);\n"
  	"        break;\n"
  	"        case 2:\n"
  	"            gl_Position = vec4( 1.0,                1.0 * invert_sign, 0.0,  1.0);\n"
  	"        break;\n"
  	"    }\n"
  	"\n"
  	"    colour = color;\n"
  	"}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFB::s_vertex_shader_draw = "#version 130\n"
  																			  "\n"
  																			  "in  vec4 color;\n"
  																			  "in  vec4 position;\n"
  																			  "out vec4 colour;\n"
  																			  "\n"
  																			  "void main()\n"
  																			  "{\n"
  																			  "    gl_Position = position;\n"
  																			  "    colour      = color;\n"
  																			  "}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFB::s_fragment_shader = "#version 130\n"
  																		   "\n"
  																		   "in  vec4 colour;\n"
  																		   "out vec4 pixel;\n"
  																		   "\n"
  																		   "void main()\n"
  																		   "{\n"
  																		   "    pixel = colour;\n"
  																		   "}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFB::s_xfb_varyings[s_xfb_varyings_count] = { "gl_Position",
  																								"colour" };
  
  const glw::GLenum gl3cts::TransformFeedback::DrawXFB::s_capture_modes[] = { GL_INTERLEAVED_ATTRIBS,
  																			GL_SEPARATE_ATTRIBS };
  const glw::GLuint gl3cts::TransformFeedback::DrawXFB::s_capture_modes_count =
  	sizeof(s_capture_modes) / sizeof(s_capture_modes[0]);
  
  const glw::GLfloat gl3cts::TransformFeedback::DrawXFB::s_colours[s_xfb_count][4] = { { 1.f, 0.f, 0.f, 1.f },
  																					 { 0.f, 1.f, 0.f, 1.f },
  																					 { 0.f, 0.f, 1.f, 1.f } };
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::DrawXFBFeedback::DrawXFBFeedback(deqp::Context& context, const char* test_name,
  															const char* test_description)
  	: deqp::TestCase(context, test_name, test_description)
  	, m_context(context)
  	, m_program_id(0)
  	, m_xfb_id(0)
  	, m_source_bo_index(0)
  {
  	memset(m_bo_id, 1, sizeof(m_bo_id));
  	memset(m_bo_id, 1, sizeof(m_vao_id));
  }
  
  gl3cts::TransformFeedback::DrawXFBFeedback::~DrawXFBFeedback(void)
  {
  }
  
  tcu::TestNode::IterateResult gl3cts::TransformFeedback::DrawXFBFeedback::iterate(void)
  {
  	/* Initializations. */
  	bool is_at_least_gl_40 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)));
  	bool is_arb_tf_2	   = m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback2");
  
  	bool is_ok		= true;
  	bool test_error = false;
  
  	/* Tests. */
  	try
  	{
  		if (is_at_least_gl_40 || is_arb_tf_2)
  		{
  			prepareAndBind();
  			draw(true);
  			swapBuffers();
  			draw(false);
  			swapBuffers();
  			draw(false);
  
  			is_ok = is_ok && check();
  		}
  	}
  	catch (...)
  	{
  		is_ok	  = false;
  		test_error = true;
  	}
  
  	/* Clean GL objects. */
  	clean();
  
  	/* Result's setup. */
  	if (is_ok)
  	{
  		/* Log success. */
  		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Feedback have passed."
  											<< tcu::TestLog::EndMessage;
  
  		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
  	}
  	else
  	{
  		if (test_error)
  		{
  			/* Log error. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Feedback have approached error."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
  		}
  		else
  		{
  			/* Log fail. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Feedback have failed."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
  		}
  	}
  
  	return STOP;
  }
  
  void gl3cts::TransformFeedback::DrawXFBFeedback::prepareAndBind()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Prepare programs. */
  	m_program_id = gl3cts::TransformFeedback::Utilities::buildProgram(gl, m_context.getTestContext().getLog(), NULL,
  																	  NULL, NULL, s_vertex_shader, s_fragment_shader,
  																	  &s_xfb_varying, 1, GL_INTERLEAVED_ATTRIBS);
  
  	if (0 == m_program_id)
  	{
  		throw 0;
  	}
  
  	gl.useProgram(m_program_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
  
  	/* Prepare transform feedbacks. */
  	gl.genTransformFeedbacks(1, &m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks call failed.");
  
  	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedbacks call failed.");
  
  	/* Prepare buffer objects. */
  	gl.genBuffers(s_bo_count, m_bo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
  
  	gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id[0]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	gl.bufferData(GL_ARRAY_BUFFER, s_bo_size, s_initial_data, GL_DYNAMIC_COPY);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
  
  	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_id[1]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, s_bo_size, NULL, GL_DYNAMIC_COPY);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
  
  	/* Setup vertex arrays. */
  	gl.genVertexArrays(s_bo_count, m_vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
  
  	glw::GLuint position_location = gl.getAttribLocation(m_program_id, "position");
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation call failed.");
  
  	for (glw::GLuint i = 0; i < 2; ++i)
  	{
  		gl.bindVertexArray(m_vao_id[i]);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
  
  		gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id[i]);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  		gl.vertexAttribPointer(position_location, 4, GL_FLOAT, GL_FALSE, 0, NULL);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer call failed.");
  
  		gl.enableVertexAttribArray(position_location);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
  	}
  
  	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	gl.bindVertexArray(m_vao_id[0]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFBFeedback::swapBuffers()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_id[m_source_bo_index]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	m_source_bo_index = (m_source_bo_index + 1) % 2;
  
  	gl.bindVertexArray(m_vao_id[(m_source_bo_index)]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFBFeedback::draw(bool is_first_draw)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.enable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable call failed.");
  
  	gl.beginTransformFeedback(GL_POINTS);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
  
  	if (is_first_draw)
  	{
  		gl.drawArrays(GL_POINTS, 0, 1);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
  	}
  	else
  	{
  		gl.drawTransformFeedback(GL_POINTS, m_xfb_id);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawTransformFeedback call failed.");
  	}
  
  	gl.endTransformFeedback();
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
  
  	gl.disable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable call failed.");
  }
  
  bool gl3cts::TransformFeedback::DrawXFBFeedback::check()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	glw::GLfloat* results =
  		(glw::GLfloat*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, s_bo_size, GL_MAP_READ_BIT);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange call failed.");
  
  	bool is_ok = false;
  
  	if (results)
  	{
  		if ((results[0] == 8.f) && (results[1] == 16.f) && (results[2] == 24.f) && (results[3] == 32.f))
  		{
  			is_ok = true;
  		}
  
  		gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
  	}
  
  	return is_ok;
  }
  
  void gl3cts::TransformFeedback::DrawXFBFeedback::clean()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.useProgram(0);
  
  	if (m_program_id)
  	{
  		gl.deleteProgram(m_program_id);
  
  		m_program_id = 0;
  	}
  
  	if (m_xfb_id)
  	{
  		gl.deleteTransformFeedbacks(1, &m_xfb_id);
  
  		m_xfb_id = 0;
  	}
  
  	for (glw::GLuint i = 0; i < s_bo_count; ++i)
  	{
  		if (m_bo_id[i])
  		{
  			gl.deleteBuffers(1, &m_bo_id[i]);
  
  			m_bo_id[i] = 0;
  		}
  	}
  
  	for (glw::GLuint i = 0; i < s_bo_count; ++i)
  	{
  		if (m_vao_id[i])
  		{
  			gl.deleteVertexArrays(1, &m_vao_id[i]);
  
  			m_vao_id[i] = 0;
  		}
  	}
  }
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBFeedback::s_vertex_shader = "#version 130\n"
  																				 "\n"
  																				 "in  vec4 position;\n"
  																				 "\n"
  																				 "void main()\n"
  																				 "{\n"
  																				 "    gl_Position = position * 2.0;\n"
  																				 "}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBFeedback::s_fragment_shader = "#version 130\n"
  																				   "\n"
  																				   "out vec4 pixel;\n"
  																				   "\n"
  																				   "void main()\n"
  																				   "{\n"
  																				   "    pixel = vec4(1.0);\n"
  																				   "}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBFeedback::s_xfb_varying = "gl_Position";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBFeedback::s_attrib = "position";
  
  const glw::GLfloat gl3cts::TransformFeedback::DrawXFBFeedback::s_initial_data[] = { 1.f, 2.f, 3.f, 4.f };
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBFeedback::s_draw_vertex_count =
  	sizeof(s_initial_data) / sizeof(s_initial_data[0]) / 4 /* components */;
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBFeedback::s_bo_size = sizeof(s_initial_data);
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::CaptureSpecialInterleaved::CaptureSpecialInterleaved(deqp::Context& context,
  																				const char*	test_name,
  																				const char*	test_description)
  	: deqp::TestCase(context, test_name, test_description)
  	, m_context(context)
  	, m_program_id(0)
  	, m_vao_id(0)
  	, m_xfb_id(0)
  {
  	memset(m_bo_id, 0, sizeof(m_bo_id));
  }
  
  gl3cts::TransformFeedback::CaptureSpecialInterleaved::~CaptureSpecialInterleaved(void)
  {
  }
  
  tcu::TestNode::IterateResult gl3cts::TransformFeedback::CaptureSpecialInterleaved::iterate(void)
  {
  	/* Initializations. */
  	bool is_at_least_gl_40 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)));
  	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_40 || is_arb_tf_3)
  		{
  			prepareAndBind();
  			draw();
  
  			is_ok = is_ok && check();
  		}
  	}
  	catch (...)
  	{
  		is_ok	  = false;
  		test_error = true;
  	}
  
  	/* Clean GL objects. */
  	clean();
  
  	/* Result's setup. */
  	if (is_ok)
  	{
  		/* Log success. */
  		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Capture Special Interleaved have passed."
  											<< tcu::TestLog::EndMessage;
  
  		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
  	}
  	else
  	{
  		if (test_error)
  		{
  			/* Log error. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message
  												<< "Capture Special Interleaved have approached error."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
  		}
  		else
  		{
  			/* Log fail. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Capture Special Interleaved have failed."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
  		}
  	}
  
  	return STOP;
  }
  
  void gl3cts::TransformFeedback::CaptureSpecialInterleaved::prepareAndBind()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Prepare programs. */
  	m_program_id = gl3cts::TransformFeedback::Utilities::buildProgram(
  		gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, s_vertex_shader, s_fragment_shader, s_xfb_varyings,
  		s_xfb_varyings_count, GL_INTERLEAVED_ATTRIBS);
  
  	if (0 == m_program_id)
  	{
  		throw 0;
  	}
  
  	gl.useProgram(m_program_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
  
  	/* Prepare transform feedbacks. */
  	gl.genTransformFeedbacks(1, &m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks call failed.");
  
  	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedbacks call failed.");
  
  	/* Create empty Vertex Array Object */
  	gl.genVertexArrays(1, &m_vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
  
  	gl.bindVertexArray(m_vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
  
  	/* Prepare buffer objects. */
  	gl.genBuffers(s_bo_ids_count, m_bo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
  
  	for (glw::GLuint i = 0; i < s_bo_ids_count; ++i)
  	{
  		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id[i]);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  		gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, s_bo_size, NULL, GL_DYNAMIC_COPY); /* allocation */
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
  
  		gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, m_bo_id[i]);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange call failed.");
  	}
  }
  
  void gl3cts::TransformFeedback::CaptureSpecialInterleaved::draw()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.enable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable 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.disable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable call failed.");
  }
  
  bool gl3cts::TransformFeedback::CaptureSpecialInterleaved::check()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	bool is_ok = true;
  
  	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id[0]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	glw::GLfloat* results =
  		(glw::GLfloat*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, s_bo_size, GL_MAP_READ_BIT);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange call failed.");
  
  	if ((results[0] != 1.0) || (results[1] != 2.0) || (results[2] != 3.0) || (results[3] != 4.0) ||
  		/* gl_SkipComponents4 here */
  		(results[8] != 5.0) || (results[9] != 6.0) || (results[10] != 7.0) || (results[11] != 8.0))
  	{
  		is_ok = false;
  	}
  
  	gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
  
  	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id[1]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	results = (glw::GLfloat*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, s_bo_size, GL_MAP_READ_BIT);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange call failed.");
  
  	if ((results[0] != 9.0) || (results[1] != 10.0) || (results[2] != 11.0) || (results[3] != 12.0) ||
  		/* gl_SkipComponents4 here */
  		(results[8] != 13.0) || (results[9] != 14.0) || (results[10] != 15.0) || (results[11] != 16.0))
  	{
  		is_ok = false;
  	}
  
  	gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
  
  	return is_ok;
  }
  
  void gl3cts::TransformFeedback::CaptureSpecialInterleaved::clean()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.useProgram(0);
  
  	if (m_program_id)
  	{
  		gl.deleteProgram(m_program_id);
  
  		m_program_id = 0;
  	}
  
  	if (m_xfb_id)
  	{
  		gl.deleteTransformFeedbacks(1, &m_xfb_id);
  
  		m_xfb_id = 0;
  	}
  
  	for (glw::GLuint i = 0; i < s_bo_ids_count; ++i)
  	{
  		if (m_bo_id[i])
  		{
  			gl.deleteBuffers(1, &m_bo_id[i]);
  
  			m_bo_id[i] = 0;
  		}
  	}
  
  	if (m_vao_id)
  	{
  		gl.deleteVertexArrays(1, &m_vao_id);
  
  		m_vao_id = 0;
  	}
  }
  
  const glw::GLchar* gl3cts::TransformFeedback::CaptureSpecialInterleaved::s_vertex_shader =
  	"#version 130\n"
  	"\n"
  	"out vec4 variable_1;\n"
  	"out vec4 variable_2;\n"
  	"out vec4 variable_3;\n"
  	"out vec4 variable_4;\n"
  	"\n"
  	"void main()\n"
  	"{\n"
  	"    variable_1 = vec4(1.0, 2.0, 3.0, 4.0);\n"
  	"    variable_2 = vec4(5.0, 6.0, 7.0, 8.0);\n"
  	"    variable_3 = vec4(9.0, 10.0, 11.0, 12.0);\n"
  	"    variable_4 = vec4(13.0, 14.0, 15.0, 16.0);\n"
  	"\n"
  	"    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
  	"}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::CaptureSpecialInterleaved::s_fragment_shader = "#version 130\n"
  																							 "\n"
  																							 "out vec4 pixel;\n"
  																							 "\n"
  																							 "void main()\n"
  																							 "{\n"
  																							 "    pixel = vec4(1.0);\n"
  																							 "}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::CaptureSpecialInterleaved::s_xfb_varyings[] =
  	{ "variable_1", "gl_SkipComponents4", "variable_2", "gl_NextBuffer",
  	  "variable_3", "gl_SkipComponents4", "variable_4" };
  
  const glw::GLuint gl3cts::TransformFeedback::CaptureSpecialInterleaved::s_xfb_varyings_count =
  	sizeof(s_xfb_varyings) / sizeof(s_xfb_varyings[0]);
  
  const glw::GLuint gl3cts::TransformFeedback::CaptureSpecialInterleaved::s_bo_size =
  	3 /*number of variables / empty places */ * 4 /* vec4 */
  	* sizeof(glw::GLfloat);
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::DrawXFBStream::DrawXFBStream(deqp::Context& context, const char* test_name,
  														const char* test_description)
  	: deqp::TestCase(context, test_name, test_description)
  	, m_context(context)
  	, m_program_id_generate(0)
  	, m_program_id_draw(0)
  	, m_vao_id(0)
  	, m_xfb_id(0)
  	, m_fbo_id(0)
  	, m_rbo_id(0)
  {
  	memset(m_bo_id, 0, sizeof(m_bo_id));
  	memset(m_qo_id, 0, sizeof(m_qo_id));
  }
  
  gl3cts::TransformFeedback::DrawXFBStream::~DrawXFBStream(void)
  {
  }
  
  tcu::TestNode::IterateResult gl3cts::TransformFeedback::DrawXFBStream::iterate(void)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Initializations. */
  	bool is_at_least_gl_40  = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 0)));
  	bool is_arb_tf_3		= m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback3");
  	bool is_arb_gpu_shader5 = m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader5");
  
  	glw::GLint max_vertex_streams = 0;
  
  	bool is_ok		= true;
  	bool test_error = false;
  
  	/* Tests. */
  	try
  	{
  		if (is_at_least_gl_40 || (is_arb_tf_3 && is_arb_gpu_shader5))
  		{
  			gl.getIntegerv(GL_MAX_VERTEX_STREAMS, &max_vertex_streams);
  			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv call failed.");
  
  			if (max_vertex_streams >= 2)
  			{
  				prepareObjects();
  
  				useProgram(m_program_id_generate);
  
  				drawForXFB();
  
  				is_ok = is_ok && inspectQueries();
  
  				useProgram(m_program_id_draw);
  
  				setupVertexArray(m_bo_id[0]);
  
  				drawForFramebuffer(0);
  
  				setupVertexArray(m_bo_id[1]);
  
  				drawForFramebuffer(1);
  
  				is_ok = is_ok && check();
  			}
  		}
  	}
  	catch (...)
  	{
  		is_ok	  = false;
  		test_error = true;
  	}
  
  	/* Clean GL objects. */
  	clean();
  
  	/* Result's setup. */
  	if (is_ok)
  	{
  		/* Log success. */
  		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Stream have passed."
  											<< tcu::TestLog::EndMessage;
  
  		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
  	}
  	else
  	{
  		if (test_error)
  		{
  			/* Log error. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Stream have approached error."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
  		}
  		else
  		{
  			/* Log fail. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Stream have failed."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
  		}
  	}
  
  	return STOP;
  }
  
  void gl3cts::TransformFeedback::DrawXFBStream::prepareObjects()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Prepare programs. */
  	m_program_id_generate = gl3cts::TransformFeedback::Utilities::buildProgram(
  		gl, m_context.getTestContext().getLog(), s_geometry_shader, NULL, NULL, s_vertex_shader_blank,
  		s_fragment_shader, s_xfb_varyings, s_xfb_varyings_count, GL_INTERLEAVED_ATTRIBS);
  
  	if (0 == m_program_id_generate)
  	{
  		throw 0;
  	}
  
  	m_program_id_draw = gl3cts::TransformFeedback::Utilities::buildProgram(
  		gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, s_vertex_shader_pass, s_fragment_shader, NULL, 0,
  		GL_INTERLEAVED_ATTRIBS);
  
  	if (0 == m_program_id_draw)
  	{
  		throw 0;
  	}
  
  	/* Prepare transform feedbacks. */
  	gl.genTransformFeedbacks(1, &m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks call failed.");
  
  	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedbacks call failed.");
  
  	/* Create empty Vertex Array Object */
  	gl.genVertexArrays(1, &m_vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
  
  	gl.bindVertexArray(m_vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
  
  	/* Prepare buffer objects. */
  	gl.genBuffers(s_bo_ids_count, m_bo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
  
  	for (glw::GLuint i = 0; i < s_bo_ids_count; ++i)
  	{
  		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id[i]);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  		gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, s_bo_size, NULL, GL_DYNAMIC_COPY); /* allocation */
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
  
  		gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, m_bo_id[i]);
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange call failed.");
  	}
  
  	/* Generate queries */
  	gl.genQueries(s_qo_ids_count, m_qo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries call failed.");
  
  	/* Prepare framebuffer. */
  	gl.clearColor(0.f, 0.f, 0.f, 1.f);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
  
  	gl.genFramebuffers(1, &m_fbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed.");
  
  	gl.genRenderbuffers(1, &m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed.");
  
  	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed.");
  
  	gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed.");
  
  	gl.renderbufferStorage(GL_RENDERBUFFER, GL_R8, s_view_size, s_view_size);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed.");
  
  	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed.");
  
  	if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  	{
  		throw 0;
  	}
  
  	gl.viewport(0, 0, s_view_size, s_view_size);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFBStream::setupVertexArray(glw::GLuint bo_id)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.bindBuffer(GL_ARRAY_BUFFER, bo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	glw::GLuint position_location = gl.getAttribLocation(m_program_id_draw, "position");
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation call failed.");
  
  	gl.vertexAttribPointer(position_location, 4, GL_FLOAT, GL_FALSE, 0, NULL);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer call failed.");
  
  	gl.enableVertexAttribArray(position_location);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFBStream::useProgram(glw::GLuint program_id)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.useProgram(program_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFBStream::drawForXFB()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.enable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable call failed.");
  
  	gl.beginTransformFeedback(GL_POINTS);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
  
  	gl.beginQueryIndexed(GL_PRIMITIVES_GENERATED, 0, m_qo_id[0]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQueryIndexed call failed.");
  
  	gl.beginQueryIndexed(GL_PRIMITIVES_GENERATED, 1, m_qo_id[1]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQueryIndexed call failed.");
  
  	gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, 0, m_qo_id[2]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQueryIndexed call failed.");
  
  	gl.beginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, 1, m_qo_id[3]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQueryIndexed call failed.");
  
  	gl.drawArrays(GL_POINTS, 0, 1);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
  
  	gl.endQueryIndexed(GL_PRIMITIVES_GENERATED, 0);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQueryIndexed call failed.");
  
  	gl.endQueryIndexed(GL_PRIMITIVES_GENERATED, 1);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQueryIndexed call failed.");
  
  	gl.endQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, 0);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQueryIndexed call failed.");
  
  	gl.endQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, 1);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQueryIndexed call failed.");
  
  	gl.endTransformFeedback();
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
  
  	gl.disable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFBStream::drawForFramebuffer(glw::GLuint stream)
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.drawTransformFeedbackStream(GL_TRIANGLES, m_xfb_id, stream);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawTransformFeedbackStream call failed.");
  }
  
  bool gl3cts::TransformFeedback::DrawXFBStream::inspectQueries()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	glw::GLint generated_primitives_to_stream_0 = 0;
  	glw::GLint generated_primitives_to_stream_1 = 0;
  
  	gl.getQueryObjectiv(m_qo_id[0], GL_QUERY_RESULT, &generated_primitives_to_stream_0);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryIndexediv call failed.");
  
  	gl.getQueryObjectiv(m_qo_id[1], GL_QUERY_RESULT, &generated_primitives_to_stream_1);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryIndexediv call failed.");
  
  	glw::GLint primitives_written_to_xfb_to_stream_0 = 0;
  	glw::GLint primitives_written_to_xfb_to_stream_1 = 0;
  
  	gl.getQueryObjectiv(m_qo_id[2], GL_QUERY_RESULT, &primitives_written_to_xfb_to_stream_0);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryIndexediv call failed.");
  
  	gl.getQueryObjectiv(m_qo_id[3], GL_QUERY_RESULT, &primitives_written_to_xfb_to_stream_1);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryIndexediv call failed.");
  
  	if ((generated_primitives_to_stream_0 == 3) && (generated_primitives_to_stream_1 == 3) &&
  		(primitives_written_to_xfb_to_stream_0 == 3) && (primitives_written_to_xfb_to_stream_1 == 3))
  	{
  		return true;
  	}
  
  	return false;
  }
  
  bool gl3cts::TransformFeedback::DrawXFBStream::check()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Number of pixels. */
  	const glw::GLuint number_of_pixels = s_view_size * s_view_size;
  
  	/* Fetch framebuffer. */
  	std::vector<glw::GLfloat> pixels(number_of_pixels);
  
  	gl.readPixels(0, 0, s_view_size, s_view_size, GL_RED, GL_FLOAT, &pixels[0]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels call failed.");
  
  	/* Check results. */
  	for (glw::GLuint i = 0; i < number_of_pixels; ++i)
  	{
  		if (fabs(pixels[i] - 1.f) > 0.0625 /* precision, expected result == 1.0 */)
  		{
  			return false;
  		}
  	}
  
  	return true;
  }
  
  void gl3cts::TransformFeedback::DrawXFBStream::clean()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.useProgram(0);
  
  	if (m_program_id_generate)
  	{
  		gl.deleteProgram(m_program_id_generate);
  
  		m_program_id_generate = 0;
  	}
  
  	if (m_program_id_draw)
  	{
  		glw::GLuint position_location = gl.getAttribLocation(m_program_id_draw, "position");
  
  		gl.disableVertexAttribArray(position_location);
  
  		gl.deleteProgram(m_program_id_draw);
  
  		m_program_id_draw = 0;
  	}
  
  	if (m_xfb_id)
  	{
  		gl.deleteTransformFeedbacks(1, &m_xfb_id);
  
  		m_xfb_id = 0;
  	}
  
  	for (glw::GLuint i = 0; i < s_bo_ids_count; ++i)
  	{
  		if (m_bo_id[i])
  		{
  			gl.deleteBuffers(1, &m_bo_id[i]);
  
  			m_bo_id[i] = 0;
  		}
  	}
  
  	if (m_vao_id)
  	{
  		gl.deleteVertexArrays(1, &m_vao_id);
  
  		m_vao_id = 0;
  	}
  
  	if (m_fbo_id)
  	{
  		gl.deleteFramebuffers(1, &m_fbo_id);
  
  		m_fbo_id = 0;
  	}
  
  	if (m_rbo_id)
  	{
  		gl.deleteRenderbuffers(1, &m_rbo_id);
  
  		m_rbo_id = 0;
  	}
  }
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStream::s_vertex_shader_blank = "#version 130\n"
  																					 "\n"
  																					 "void main()\n"
  																					 "{\n"
  																					 "}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStream::s_vertex_shader_pass = "#version 130\n"
  																					"\n"
  																					"in vec4 position;\n"
  																					"\n"
  																					"void main()\n"
  																					"{\n"
  																					"    gl_Position = position;\n"
  																					"}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStream::s_geometry_shader =
  	"#version 400\n"
  	"\n"
  	"layout(points) in;\n"
  	"layout(points, max_vertices = 6) out;\n"
  	"\n"
  	"layout(stream = 1) out vec4 position;\n"
  	"\n"
  	"void main()\n"
  	"{\n"
  	"    gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
  	"    EmitStreamVertex(0);\n"
  	"    gl_Position = vec4( 1.0, -1.0, 0.0, 1.0);\n"
  	"    EmitStreamVertex(0);\n"
  	"    gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
  	"    EmitStreamVertex(0);\n"
  	"\n"
  	"    position = vec4( 1.0, -1.0, 0.0, 1.0);\n"
  	"    EmitStreamVertex(1);\n"
  	"    position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
  	"    EmitStreamVertex(1);\n"
  	"    position = vec4( 1.0,  1.0, 0.0, 1.0);\n"
  	"    EmitStreamVertex(1);\n"
  	"}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStream::s_fragment_shader = "#version 130\n"
  																				 "\n"
  																				 "out vec4 pixel;\n"
  																				 "\n"
  																				 "void main()\n"
  																				 "{\n"
  																				 "    pixel = vec4(1.0);\n"
  																				 "}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStream::s_xfb_varyings[] = { "gl_Position", "gl_NextBuffer",
  																				  "position" };
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBStream::s_xfb_varyings_count =
  	sizeof(s_xfb_varyings) / sizeof(s_xfb_varyings[0]);
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBStream::s_bo_size =
  	3 /* triangles */ * 4 /* vec4 */ * sizeof(glw::GLfloat);
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBStream::s_view_size = 2;
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::DrawXFBInstanced::DrawXFBInstanced(deqp::Context& context, const char* test_name,
  															  const char* test_description)
  	: deqp::TestCase(context, test_name, test_description)
  	, m_context(context)
  	, m_program_id_generate(0)
  	, m_program_id_draw(0)
  	, m_vao_id(0)
  	, m_xfb_id(0)
  	, m_bo_id_xfb(0)
  	, m_bo_id_uniform(0)
  	, m_fbo_id(0)
  	, m_rbo_id(0)
  	, m_glGetUniformBlockIndex(DE_NULL)
  	, m_glUniformBlockBinding(DE_NULL)
  {
  }
  
  gl3cts::TransformFeedback::DrawXFBInstanced::~DrawXFBInstanced(void)
  {
  }
  
  tcu::TestNode::IterateResult gl3cts::TransformFeedback::DrawXFBInstanced::iterate(void)
  {
  	/* Initializations. */
  	bool is_at_least_gl_42   = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 2)));
  	bool is_at_least_gl_31   = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 1)));
  	bool is_arb_tf_instanced = m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback_instanced");
  	bool is_arb_ubo			 = m_context.getContextInfo().isExtensionSupported("GL_ARB_uniform_buffer_object");
  
  	bool is_ok		= true;
  	bool test_error = false;
  
  	if (is_arb_ubo)
  	{
  		m_glGetUniformBlockIndex =
  			(GetUniformBlockIndex_ProcAddress)m_context.getRenderContext().getProcAddress("glGetUniformBlockIndex");
  
  		m_glUniformBlockBinding =
  			(UniformBlockBinding_ProcAddress)m_context.getRenderContext().getProcAddress("glUniformBlockBinding");
  
  		if (DE_NULL == m_glGetUniformBlockIndex || DE_NULL == m_glUniformBlockBinding)
  		{
  			throw 0;
  		}
  	}
  
  	try
  	{
  		if (is_at_least_gl_42 || ((is_at_least_gl_31 || is_arb_ubo) && is_arb_tf_instanced))
  		{
  			prepareObjects();
  			drawForXFB();
  			drawInstanced();
  
  			is_ok = is_ok && check();
  		}
  	}
  	catch (...)
  	{
  		is_ok	  = false;
  		test_error = true;
  	}
  
  	/* Clean GL objects */
  	clean();
  
  	/* Result's setup. */
  	if (is_ok)
  	{
  		/* Log success. */
  		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Instanced have passed."
  											<< tcu::TestLog::EndMessage;
  
  		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
  	}
  	else
  	{
  		if (test_error)
  		{
  			/* Log error. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Instanced have approached error."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
  		}
  		else
  		{
  			/* Log fail. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Instanced have failed."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
  		}
  	}
  
  	return STOP;
  }
  
  void gl3cts::TransformFeedback::DrawXFBInstanced::prepareObjects()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Prepare programs. */
  	m_program_id_generate = gl3cts::TransformFeedback::Utilities::buildProgram(
  		gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, s_vertex_shader_generate, s_fragment_shader,
  		&s_xfb_varying, 1, GL_INTERLEAVED_ATTRIBS);
  
  	if (0 == m_program_id_generate)
  	{
  		throw 0;
  	}
  
  	m_program_id_draw = gl3cts::TransformFeedback::Utilities::buildProgram(
  		gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, s_vertex_shader_draw, s_fragment_shader, NULL, 0,
  		GL_INTERLEAVED_ATTRIBS);
  
  	if (0 == m_program_id_draw)
  	{
  		throw 0;
  	}
  
  	/* Prepare transform feedbacks. */
  	gl.genTransformFeedbacks(1, &m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks call failed.");
  
  	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedbacks call failed.");
  
  	/* Create empty Vertex Array Object */
  	gl.genVertexArrays(1, &m_vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
  
  	gl.bindVertexArray(m_vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
  
  	/* Prepare xfb buffer object. */
  	gl.genBuffers(1, &m_bo_id_xfb);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
  
  	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_xfb);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, s_bo_xfb_size, NULL, GL_DYNAMIC_COPY); /* allocation */
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
  
  	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_id_xfb);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange call failed.");
  
  	/* Prepare uniform buffer object. */
  	gl.genBuffers(1, &m_bo_id_uniform);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
  
  	gl.bindBuffer(GL_UNIFORM_BUFFER, m_bo_id_uniform);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	gl.bufferData(GL_UNIFORM_BUFFER, s_bo_uniform_size, s_bo_uniform_data, GL_DYNAMIC_COPY); /* allocation */
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
  
  	gl.bindBufferBase(GL_UNIFORM_BUFFER, 0, m_bo_id_uniform);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange call failed.");
  
  	glw::GLuint uniform_index = m_glGetUniformBlockIndex(m_program_id_draw, s_uniform);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex call failed.");
  
  	if (GL_INVALID_INDEX == uniform_index)
  	{
  		throw 0;
  	}
  
  	m_glUniformBlockBinding(m_program_id_draw, uniform_index, 0);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformBlockBinding call failed.");
  
  	/* Prepare framebuffer. */
  	gl.clearColor(0.f, 0.f, 0.f, 1.f);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
  
  	gl.genFramebuffers(1, &m_fbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed.");
  
  	gl.genRenderbuffers(1, &m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed.");
  
  	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed.");
  
  	gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed.");
  
  	gl.renderbufferStorage(GL_RENDERBUFFER, GL_R8, s_view_size, s_view_size);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed.");
  
  	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed.");
  
  	if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  	{
  		throw 0;
  	}
  
  	gl.viewport(0, 0, s_view_size, s_view_size);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFBInstanced::drawForXFB()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.useProgram(m_program_id_generate);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
  
  	gl.enable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable call failed.");
  
  	gl.beginTransformFeedback(GL_POINTS);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
  
  	gl.drawArrays(GL_POINTS, 0, 4 /* quad vertex count */);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
  
  	gl.endTransformFeedback();
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
  
  	gl.disable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFBInstanced::drawInstanced()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id_xfb);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	glw::GLuint position_location = gl.getAttribLocation(m_program_id_draw, "position");
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation call failed.");
  
  	gl.vertexAttribPointer(position_location, 4, GL_FLOAT, GL_FALSE, 0, NULL);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer call failed.");
  
  	gl.enableVertexAttribArray(position_location);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
  
  	gl.clear(GL_COLOR_BUFFER_BIT);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
  
  	gl.useProgram(m_program_id_draw);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
  
  	gl.drawTransformFeedbackInstanced(GL_TRIANGLE_STRIP, m_xfb_id, 4);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
  }
  
  bool gl3cts::TransformFeedback::DrawXFBInstanced::check()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Number of pixels. */
  	const glw::GLuint number_of_pixels = s_view_size * s_view_size;
  
  	/* Fetch framebuffer. */
  	std::vector<glw::GLfloat> pixels(number_of_pixels);
  
  	gl.readPixels(0, 0, s_view_size, s_view_size, GL_RED, GL_FLOAT, &pixels[0]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels call failed.");
  
  	/* Check results. */
  	for (glw::GLuint i = 0; i < number_of_pixels; ++i)
  	{
  		if (fabs(pixels[i] - 1.f) > 0.0625 /* precision, expected result == 1.0 */)
  		{
  			return false;
  		}
  	}
  
  	return true;
  }
  
  void gl3cts::TransformFeedback::DrawXFBInstanced::clean()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.useProgram(0);
  
  	if (m_program_id_generate)
  	{
  		gl.deleteProgram(m_program_id_generate);
  
  		m_program_id_generate = 0;
  	}
  
  	if (m_program_id_draw)
  	{
  		glw::GLuint position_location = gl.getAttribLocation(m_program_id_draw, "position");
  
  		gl.disableVertexAttribArray(position_location);
  
  		gl.deleteProgram(m_program_id_draw);
  
  		m_program_id_draw = 0;
  	}
  
  	if (m_xfb_id)
  	{
  		gl.deleteTransformFeedbacks(1, &m_xfb_id);
  
  		m_xfb_id = 0;
  	}
  
  	if (m_bo_id_xfb)
  	{
  		gl.deleteBuffers(1, &m_bo_id_xfb);
  
  		m_bo_id_xfb = 0;
  	}
  
  	if (m_bo_id_uniform)
  	{
  		gl.deleteBuffers(1, &m_bo_id_uniform);
  
  		m_bo_id_uniform = 0;
  	}
  
  	if (m_vao_id)
  	{
  		gl.deleteVertexArrays(1, &m_vao_id);
  
  		m_vao_id = 0;
  	}
  
  	if (m_fbo_id)
  	{
  		gl.deleteFramebuffers(1, &m_fbo_id);
  
  		m_fbo_id = 0;
  	}
  
  	if (m_rbo_id)
  	{
  		gl.deleteRenderbuffers(1, &m_rbo_id);
  
  		m_rbo_id = 0;
  	}
  }
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBInstanced::s_vertex_shader_generate =
  	"#version 140\n"
  	"\n"
  	"void main()\n"
  	"{\n"
  	"    switch(gl_VertexID % 4)\n"
  	"    {\n"
  	"    case 0:\n"
  	"       gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
  	"       break;\n"
  	"    case 1:\n"
  	"       gl_Position = vec4( 1.0, -1.0, 0.0, 1.0);\n"
  	"       break;\n"
  	"    case 2:\n"
  	"       gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
  	"       break;\n"
  	"    case 3:\n"
  	"       gl_Position = vec4( 1.0,  1.0, 0.0, 1.0);\n"
  	"       break;\n"
  	"    }\n"
  	"}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBInstanced::s_vertex_shader_draw =
  	"#version 140\n"
  	"\n"
  	"uniform MatrixBlock\n"
  	"{\n"
  	"    mat4 transformation_0;\n"
  	"    mat4 transformation_1;\n"
  	"    mat4 transformation_2;\n"
  	"    mat4 transformation_3;\n"
  	"};\n"
  	"\n"
  	"in vec4 position;\n"
  	"\n"
  	"void main()\n"
  	"{\n"
  	"    switch(gl_InstanceID % 4)\n"
  	"    {\n"
  	"    case 0:\n"
  	"       gl_Position = position * transformation_0;\n"
  	"       break;\n"
  	"    case 1:\n"
  	"       gl_Position = position * transformation_1;\n"
  	"       break;\n"
  	"    case 2:\n"
  	"       gl_Position = position * transformation_2;\n"
  	"       break;\n"
  	"    case 3:\n"
  	"       gl_Position = position * transformation_3;\n"
  	"       break;\n"
  	"    }\n"
  	"}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBInstanced::s_fragment_shader = "#version 130\n"
  																					"\n"
  																					"out vec4 pixel;\n"
  																					"\n"
  																					"void main()\n"
  																					"{\n"
  																					"    pixel = vec4(1.0);\n"
  																					"}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBInstanced::s_xfb_varying = "gl_Position";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBInstanced::s_uniform = "MatrixBlock";
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBInstanced::s_bo_xfb_size =
  	4 /* vertex count */ * 4 /* vec4 components */
  	* sizeof(glw::GLfloat) /* data type size */;
  
  const glw::GLfloat gl3cts::TransformFeedback::DrawXFBInstanced::s_bo_uniform_data[] = {
  	0.5f, 0.0f, 0.0f, 0.5f,  0.0f, 0.5f, 0.0f, 0.5f,  0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
  
  	0.5f, 0.0f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, 0.5f,  0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
  
  	0.5f, 0.0f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
  
  	0.5f, 0.0f, 0.0f, 0.5f,  0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
  };
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBInstanced::s_bo_uniform_size = sizeof(s_bo_uniform_data);
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBInstanced::s_view_size = 4;
  
  /*-----------------------------------------------------------------------------------------------*/
  
  gl3cts::TransformFeedback::DrawXFBStreamInstanced::DrawXFBStreamInstanced(deqp::Context& context, const char* test_name,
  																		  const char* test_description)
  	: deqp::TestCase(context, test_name, test_description)
  	, m_context(context)
  	, m_program_id_generate(0)
  	, m_program_id_draw(0)
  	, m_vao_id(0)
  	, m_xfb_id(0)
  	, m_bo_id_xfb_position(0)
  	, m_bo_id_xfb_color(0)
  	, m_bo_id_uniform(0)
  	, m_fbo_id(0)
  	, m_rbo_id(0)
  	, m_glGetUniformBlockIndex(DE_NULL)
  	, m_glUniformBlockBinding(DE_NULL)
  {
  }
  
  gl3cts::TransformFeedback::DrawXFBStreamInstanced::~DrawXFBStreamInstanced(void)
  {
  }
  
  tcu::TestNode::IterateResult gl3cts::TransformFeedback::DrawXFBStreamInstanced::iterate(void)
  {
  	/* Initializations. */
  	bool is_at_least_gl_31   = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(3, 1)));
  	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_arb_tf_instanced = m_context.getContextInfo().isExtensionSupported("GL_ARB_transform_feedback_instanced");
  	bool is_arb_ubo			 = m_context.getContextInfo().isExtensionSupported("GL_ARB_uniform_buffer_object");
  	bool is_arb_gpu_shader5  = m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader5");
  
  	bool is_ok		= true;
  	bool test_error = false;
  
  	if (is_arb_ubo)
  	{
  		m_glGetUniformBlockIndex =
  			(GetUniformBlockIndex_ProcAddress)m_context.getRenderContext().getProcAddress("glGetUniformBlockIndex");
  
  		m_glUniformBlockBinding =
  			(UniformBlockBinding_ProcAddress)m_context.getRenderContext().getProcAddress("glUniformBlockBinding");
  
  		if (DE_NULL == m_glGetUniformBlockIndex || DE_NULL == m_glUniformBlockBinding)
  		{
  			throw 0;
  		}
  	}
  
  	/* Test. */
  	try
  	{
  		if (is_at_least_gl_42 || ((is_at_least_gl_31 || is_arb_ubo) && is_arb_gpu_shader5 && is_arb_tf_instanced) ||
  			(is_at_least_gl_40 && is_arb_tf_instanced))
  		{
  			prepareObjects();
  			drawForXFB();
  			drawStreamInstanced();
  
  			is_ok = is_ok && check();
  		}
  	}
  	catch (...)
  	{
  		is_ok	  = false;
  		test_error = true;
  	}
  
  	/* Clean GL objects */
  	clean();
  
  	/* Result's setup. */
  	if (is_ok)
  	{
  		/* Log success. */
  		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Stream Instanced have passed."
  											<< tcu::TestLog::EndMessage;
  
  		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
  	}
  	else
  	{
  		if (test_error)
  		{
  			/* Log error. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message
  												<< "Draw XFB Stream Instanced have approached error."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error");
  		}
  		else
  		{
  			/* Log fail. */
  			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Draw XFB Stream Instanced have failed."
  												<< tcu::TestLog::EndMessage;
  
  			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
  		}
  	}
  
  	return STOP;
  }
  
  void gl3cts::TransformFeedback::DrawXFBStreamInstanced::prepareObjects()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Prepare programs. */
  	m_program_id_generate = gl3cts::TransformFeedback::Utilities::buildProgram(
  		gl, m_context.getTestContext().getLog(), s_geometry_shader_generate, NULL, NULL, s_vertex_shader_blank,
  		s_fragment_shader_blank, s_xfb_varyings, s_xfb_varyings_count, GL_INTERLEAVED_ATTRIBS);
  
  	if (0 == m_program_id_generate)
  	{
  		throw 0;
  	}
  
  	m_program_id_draw = gl3cts::TransformFeedback::Utilities::buildProgram(
  		gl, m_context.getTestContext().getLog(), NULL, NULL, NULL, s_vertex_shader_draw, s_fragment_shader_draw, NULL,
  		0, GL_INTERLEAVED_ATTRIBS);
  
  	if (0 == m_program_id_draw)
  	{
  		throw 0;
  	}
  
  	/* Prepare transform feedbacks. */
  	gl.genTransformFeedbacks(1, &m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks call failed.");
  
  	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_xfb_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedbacks call failed.");
  
  	/* Create empty Vertex Array Object */
  	gl.genVertexArrays(1, &m_vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed.");
  
  	gl.bindVertexArray(m_vao_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed.");
  
  	/* Prepare xfb buffer objects. */
  	gl.genBuffers(1, &m_bo_id_xfb_position);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
  
  	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_xfb_position);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, s_bo_xfb_size, NULL, GL_DYNAMIC_COPY); /* allocation */
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
  
  	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_id_xfb_position);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange call failed.");
  
  	gl.genBuffers(1, &m_bo_id_xfb_color);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
  
  	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id_xfb_color);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, s_bo_xfb_size, NULL, GL_DYNAMIC_COPY); /* allocation */
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
  
  	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, m_bo_id_xfb_color);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange call failed.");
  
  	/* Prepare uniform buffer object. */
  	gl.genBuffers(1, &m_bo_id_uniform);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers call failed.");
  
  	gl.bindBuffer(GL_UNIFORM_BUFFER, m_bo_id_uniform);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	gl.bufferData(GL_UNIFORM_BUFFER, s_bo_uniform_size, s_bo_uniform_data, GL_DYNAMIC_COPY); /* allocation */
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData call failed.");
  
  	gl.bindBufferBase(GL_UNIFORM_BUFFER, 0, m_bo_id_uniform);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange call failed.");
  
  	glw::GLuint uniform_index = m_glGetUniformBlockIndex(m_program_id_draw, s_uniform);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex call failed.");
  
  	if (GL_INVALID_INDEX == uniform_index)
  	{
  		throw 0;
  	}
  
  	m_glUniformBlockBinding(m_program_id_draw, uniform_index, 0);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformBlockBinding call failed.");
  
  	/* Prepare framebuffer. */
  	gl.clearColor(0.f, 0.f, 0.f, 1.f);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
  
  	gl.genFramebuffers(1, &m_fbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed.");
  
  	gl.genRenderbuffers(1, &m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed.");
  
  	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed.");
  
  	gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed.");
  
  	gl.renderbufferStorage(GL_RENDERBUFFER, GL_R8, s_view_size, s_view_size);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed.");
  
  	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo_id);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed.");
  
  	if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  	{
  		throw 0;
  	}
  
  	gl.viewport(0, 0, s_view_size, s_view_size);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFBStreamInstanced::drawForXFB()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.useProgram(m_program_id_generate);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
  
  	gl.enable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable call failed.");
  
  	gl.beginTransformFeedback(GL_POINTS);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed.");
  
  	gl.drawArrays(GL_POINTS, 0, 4 /* quad vertex count */);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
  
  	gl.endTransformFeedback();
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed.");
  
  	gl.disable(GL_RASTERIZER_DISCARD);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable call failed.");
  }
  
  void gl3cts::TransformFeedback::DrawXFBStreamInstanced::drawStreamInstanced()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id_xfb_position);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	glw::GLuint position_location = gl.getAttribLocation(m_program_id_draw, "position");
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation call failed.");
  
  	gl.vertexAttribPointer(position_location, 4, GL_FLOAT, GL_FALSE, 0, NULL);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer call failed.");
  
  	gl.enableVertexAttribArray(position_location);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
  
  	gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id_xfb_color);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed.");
  
  	glw::GLuint color_location = gl.getAttribLocation(m_program_id_draw, "color");
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttribLocation call failed.");
  
  	gl.vertexAttribPointer(color_location, 4, GL_FLOAT, GL_FALSE, 0, NULL);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer call failed.");
  
  	gl.enableVertexAttribArray(color_location);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray call failed.");
  
  	gl.useProgram(m_program_id_draw);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed.");
  
  	gl.drawTransformFeedbackStreamInstanced(GL_TRIANGLE_STRIP, m_xfb_id, 0, 4);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed.");
  }
  
  bool gl3cts::TransformFeedback::DrawXFBStreamInstanced::check()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	/* Number of pixels. */
  	const glw::GLuint number_of_pixels = s_view_size * s_view_size;
  
  	/* Fetch framebuffer. */
  	std::vector<glw::GLfloat> pixels(number_of_pixels);
  
  	gl.readPixels(0, 0, s_view_size, s_view_size, GL_RED, GL_FLOAT, &pixels[0]);
  	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels call failed.");
  
  	/* Check results. */
  	for (glw::GLuint i = 0; i < number_of_pixels; ++i)
  	{
  		if (fabs(pixels[i] - 1.f) > 0.0625 /* precision, expected result == 1.0 */)
  		{
  			return false;
  		}
  	}
  
  	return true;
  }
  
  void gl3cts::TransformFeedback::DrawXFBStreamInstanced::clean()
  {
  	/* Functions handler */
  	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
  
  	gl.useProgram(0);
  
  	if (m_program_id_generate)
  	{
  		gl.deleteProgram(m_program_id_generate);
  
  		m_program_id_generate = 0;
  	}
  
  	if (m_program_id_draw)
  	{
  		glw::GLuint position_location = gl.getAttribLocation(m_program_id_draw, "position");
  
  		gl.disableVertexAttribArray(position_location);
  
  		glw::GLuint color_location = gl.getAttribLocation(m_program_id_draw, "color");
  
  		gl.disableVertexAttribArray(color_location);
  
  		gl.deleteProgram(m_program_id_draw);
  
  		m_program_id_draw = 0;
  	}
  
  	if (m_xfb_id)
  	{
  		gl.deleteTransformFeedbacks(1, &m_xfb_id);
  
  		m_xfb_id = 0;
  	}
  
  	if (m_bo_id_xfb_position)
  	{
  		gl.deleteBuffers(1, &m_bo_id_xfb_position);
  
  		m_bo_id_xfb_position = 0;
  	}
  
  	if (m_bo_id_xfb_color)
  	{
  		gl.deleteBuffers(1, &m_bo_id_xfb_color);
  
  		m_bo_id_xfb_position = 0;
  	}
  
  	if (m_bo_id_uniform)
  	{
  		gl.deleteBuffers(1, &m_bo_id_uniform);
  
  		m_bo_id_uniform = 0;
  	}
  
  	if (m_vao_id)
  	{
  		gl.deleteVertexArrays(1, &m_vao_id);
  
  		m_vao_id = 0;
  	}
  
  	if (m_fbo_id)
  	{
  		gl.deleteFramebuffers(1, &m_fbo_id);
  
  		m_fbo_id = 0;
  	}
  
  	if (m_rbo_id)
  	{
  		gl.deleteRenderbuffers(1, &m_rbo_id);
  
  		m_rbo_id = 0;
  	}
  }
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_vertex_shader_blank = "#version 140\n"
  																							  "\n"
  																							  "void main()\n"
  																							  "{\n"
  																							  "}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_geometry_shader_generate =
  	"#version 400\n"
  	"\n"
  	"layout(points) in;\n"
  	"layout(points, max_vertices = 8) out;\n"
  	"\n"
  	"layout(stream = 1) out vec4 color;\n"
  	"\n"
  	"void main()\n"
  	"{\n"
  	"    gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
  	"    EmitStreamVertex(0);\n"
  	"    gl_Position = vec4( 1.0, -1.0, 0.0, 1.0);\n"
  	"    EmitStreamVertex(0);\n"
  	"    gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
  	"    EmitStreamVertex(0);\n"
  	"    gl_Position = vec4( 1.0,  1.0, 0.0, 1.0);\n"
  	"    EmitStreamVertex(0);\n"
  	"\n"
  	"    color = vec4(1.0, 1.0, 1.0, 1.0);\n"
  	"    EmitStreamVertex(1);\n"
  	"    color = vec4(1.0, 1.0, 1.0, 1.0);\n"
  	"    EmitStreamVertex(1);\n"
  	"    color = vec4(1.0, 1.0, 1.0, 1.0);\n"
  	"    EmitStreamVertex(1);\n"
  	"    color = vec4(1.0, 1.0, 1.0, 1.0);\n"
  	"    EmitStreamVertex(1);\n"
  	"}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_vertex_shader_draw =
  	"#version 140\n"
  	"\n"
  	"uniform MatrixBlock\n"
  	"{\n"
  	"    mat4 transformation_0;\n"
  	"    mat4 transformation_1;\n"
  	"    mat4 transformation_2;\n"
  	"    mat4 transformation_3;\n"
  	"};\n"
  	"\n"
  	"in  vec4 position;\n"
  	"in  vec4 color;\n"
  	"out vec4 colour;\n"
  	"\n"
  	"void main()\n"
  	"{\n"
  	"    switch(gl_InstanceID % 4)\n"
  	"    {\n"
  	"    case 0:\n"
  	"       gl_Position = position * transformation_0;\n"
  	"       break;\n"
  	"    case 1:\n"
  	"       gl_Position = position * transformation_1;\n"
  	"       break;\n"
  	"    case 2:\n"
  	"       gl_Position = position * transformation_2;\n"
  	"       break;\n"
  	"    case 3:\n"
  	"       gl_Position = position * transformation_3;\n"
  	"       break;\n"
  	"    }\n"
  	"    colour = color;\n"
  	"}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_fragment_shader_blank =
  	"#version 130\n"
  	"\n"
  	"out vec4 pixel;\n"
  	"\n"
  	"void main()\n"
  	"{\n"
  	"    pixel = vec4(1.0);\n"
  	"}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_fragment_shader_draw = "#version 130\n"
  																							   "\n"
  																							   "in vec4 colour;\n"
  																							   "out vec4 pixel;\n"
  																							   "\n"
  																							   "void main()\n"
  																							   "{\n"
  																							   "    pixel = colour;\n"
  																							   "}\n";
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_xfb_varyings[] = { "gl_Position",
  																						   "gl_NextBuffer", "color" };
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_xfb_varyings_count =
  	sizeof(s_xfb_varyings) / sizeof(s_xfb_varyings[0]);
  
  const glw::GLchar* gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_uniform = "MatrixBlock";
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_bo_xfb_size =
  	4 /* vertex count */ * 4 /* vec4 components */
  	* sizeof(glw::GLfloat) /* data type size */;
  
  const glw::GLfloat gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_bo_uniform_data[] = {
  	0.5f, 0.0f, 0.0f, 0.5f,  0.0f, 0.5f, 0.0f, 0.5f,  0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
  
  	0.5f, 0.0f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, 0.5f,  0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
  
  	0.5f, 0.0f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
  
  	0.5f, 0.0f, 0.0f, 0.5f,  0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f
  };
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_bo_uniform_size = sizeof(s_bo_uniform_data);
  
  const glw::GLuint gl3cts::TransformFeedback::DrawXFBStreamInstanced::s_view_size = 4;
  
  /*-----------------------------------------------------------------------------------------------*/
  
  glw::GLuint gl3cts::TransformFeedback::Utilities::buildProgram(
  	glw::Functions const& gl, tcu::TestLog& log, glw::GLchar const* const geometry_shader_source,
  	glw::GLchar const* const tessellation_control_shader_source,
  	glw::GLchar const* const tessellation_evaluation_shader_source, glw::GLchar const* const vertex_shader_source,
  	glw::GLchar const* const fragment_shader_source, glw::GLchar const* const* const transform_feedback_varyings,
  	glw::GLsizei const transform_feedback_varyings_count, glw::GLenum const transform_feedback_varyings_mode,
  	bool const do_not_detach, glw::GLint* linking_status)
  {
  	glw::GLuint program = 0;
  
  	struct Shader
  	{
  		glw::GLchar const* const source;
  		glw::GLenum const		 type;
  		glw::GLuint				 id;
  	} shader[] = { { geometry_shader_source, GL_GEOMETRY_SHADER, 0 },
  				   { tessellation_control_shader_source, GL_TESS_CONTROL_SHADER, 0 },
  				   { tessellation_evaluation_shader_source, GL_TESS_EVALUATION_SHADER, 0 },
  				   { vertex_shader_source, GL_VERTEX_SHADER, 0 },
  				   { fragment_shader_source, GL_FRAGMENT_SHADER, 0 } };
  
  	glw::GLuint const shader_count = sizeof(shader) / sizeof(shader[0]);
  
  	try
  	{
  		/* Create program. */
  		program = gl.createProgram();
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed.");
  
  		/* Shader compilation. */
  
  		for (glw::GLuint i = 0; i < shader_count; ++i)
  		{
  			if (DE_NULL != shader[i].source)
  			{
  				shader[i].id = gl.createShader(shader[i].type);
  
  				GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed.");
  
  				gl.attachShader(program, shader[i].id);
  
  				GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed.");
  
  				gl.shaderSource(shader[i].id, 1, &(shader[i].source), NULL);
  
  				GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed.");
  
  				gl.compileShader(shader[i].id);
  
  				GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed.");
  
  				glw::GLint status = GL_FALSE;
  
  				gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status);
  				GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
  
  				if (GL_FALSE == status)
  				{
  					glw::GLint log_size = 0;
  					gl.getShaderiv(shader[i].id, GL_INFO_LOG_LENGTH, &log_size);
  					GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed.");
  
  					glw::GLchar* log_text = new glw::GLchar[log_size];
  
  					gl.getShaderInfoLog(shader[i].id, log_size, NULL, &log_text[0]);
  
  					log << tcu::TestLog::Message << "Shader compilation has failed.\n"
  						<< "Shader type: " << glu::getShaderTypeStr(shader[i].type) << "\n"
  						<< "Shader compilation error log:\n"
  						<< log_text << "\n"
  						<< "Shader source code:\n"
  						<< shader[i].source << "\n"
  						<< tcu::TestLog::EndMessage;
  
  					delete[] log_text;
  
  					GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog call failed.");
  
  					throw 0;
  				}
  			}
  		}
  
  		/* Link. */
  		if (transform_feedback_varyings_count)
  		{
  			gl.transformFeedbackVaryings(program, transform_feedback_varyings_count, transform_feedback_varyings,
  										 transform_feedback_varyings_mode);
  			GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
  		}
  
  		gl.linkProgram(program);
  
  		GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed.");
  
  		glw::GLint status = GL_FALSE;
  
  		gl.getProgramiv(program, GL_LINK_STATUS, &status);
  
  		if (DE_NULL != linking_status)
  		{
  			*linking_status = status;
  		}
  
  		if (GL_TRUE == status)
  		{
  			if (!do_not_detach)
  			{
  				for (glw::GLuint i = 0; i < shader_count; ++i)
  				{
  					if (shader[i].id)
  					{
  						gl.detachShader(program, shader[i].id);
  
  						GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed.");
  					}
  				}
  			}
  		}
  		else
  		{
  			glw::GLint log_size = 0;
  
  			gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &log_size);
  
  			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed.");
  
  			glw::GLchar* log_text = new glw::GLchar[log_size];
  
  			gl.getProgramInfoLog(program, log_size, NULL, &log_text[0]);
  
  			log << tcu::TestLog::Message << "Program linkage has failed due to:\n"
  				<< log_text << "\n"
  				<< tcu::TestLog::EndMessage;
  
  			delete[] log_text;
  
  			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed.");
  
  			throw 0;
  		}
  	}
  	catch (...)
  	{
  		if (program)
  		{
  			gl.deleteProgram(program);
  
  			program = 0;
  		}
  	}
  
  	for (glw::GLuint i = 0; i < shader_count; ++i)
  	{
  		if (0 != shader[i].id)
  		{
  			gl.deleteShader(shader[i].id);
  
  			shader[i].id = 0;
  		}
  	}
  
  	return program;
  }
  
  /** @brief Substitute key with value within source code.
   *
   *  @param [in] source      Source code to be prerocessed.
   *  @param [in] key         Key to be substituted.
   *  @param [in] value       Value to be inserted.
   *
   *  @return Resulting string.
   */
  std::string gl3cts::TransformFeedback::Utilities::preprocessCode(std::string source, std::string key, std::string value)
  {
  	std::string destination = source;
  
  	while (true)
  	{
  		/* Find token in source code. */
  		size_t position = destination.find(key, 0);
  
  		/* No more occurences of this key. */
  		if (position == std::string::npos)
  		{
  			break;
  		}
  
  		/* Replace token with sub_code. */
  		destination.replace(position, key.size(), value);
  	}
  
  	return destination;
  }
  
  /** @brief Convert an integer to a string.
   *
   *  @param [in] i       Integer to be converted.
   *
   *  @return String representing integer.
   */
  std::string gl3cts::TransformFeedback::Utilities::itoa(glw::GLint i)
  {
  	std::stringstream stream;
  
  	stream << i;
  
  	return stream.str();
  }
  
  /** @brief Convert an float to a string.
   *
   *  @param [in] f       Float to be converted.
   *
   *  @return String representing integer.
   */
  std::string gl3cts::TransformFeedback::Utilities::ftoa(glw::GLfloat f)
  {
  	std::stringstream stream;
  
  	stream << f;
  
  	return stream.str();
  }
  