blob: ea0d0e289663aa68658e344a72ee36c22eaccbe6 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2014-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
*/ /*-------------------------------------------------------------------*/
#include "esextcGeometryShaderPrimitiveCounter.hpp"
#include "deMath.h"
#include "gluContextInfo.hpp"
#include "gluDefs.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuTestLog.hpp"
#include <string.h>
namespace glcts
{
/* Fragment shader code */
const char* GeometryShaderPrimitiveCounter::m_fragment_shader_code = "${VERSION}\n"
"\n"
"precision highp float;\n"
"\n"
"layout(location = 0) out vec4 color;\n"
"\n"
"flat in int test_gl_PrimitiveIDIn;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1, 1, 1, 1);\n"
"}\n";
/* Vertex shader code */
const char* GeometryShaderPrimitiveCounter::m_vertex_shader_code = "${VERSION}\n"
"\n"
"precision highp float;\n"
"\n"
"in vec4 vertex_position;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vertex_position;\n"
"}\n";
/** Constructor
*
* @param context Test context
* @param name Test group's name
* @param description Test group's desricption
**/
GeometryShaderPrimitiveCounterTestGroup::GeometryShaderPrimitiveCounterTestGroup(Context& context,
const ExtParameters& extParams,
const char* name,
const char* description)
: TestCaseGroupBase(context, extParams, name, description)
{
/* Left blank on purpose */
}
/** Initializes the test group creating test cases that this group consists of
**/
void GeometryShaderPrimitiveCounterTestGroup::init(void)
{
DataPrimitiveIDInCounter testConfiguration;
/* Test case 6.1 */
/* Points-to-Points Configuration */
testConfiguration.m_drawMode = GL_POINTS;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_POINTS;
testConfiguration.m_layoutIn = "points";
testConfiguration.m_layoutOut = "points";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 1;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 1;
addChild(new GeometryShaderPrimitiveCounter(getContext(), m_extParams, "point_to_point",
"Test Group 6.1 points to points", testConfiguration));
/* Points-to-Line Strip Configuration*/
testConfiguration.m_drawMode = GL_POINTS;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_LINES;
testConfiguration.m_layoutIn = "points";
testConfiguration.m_layoutOut = "line_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 2;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 1;
addChild(new GeometryShaderPrimitiveCounter(getContext(), m_extParams, "points_to_line_strip",
"Test Group 6.1 points to line strip", testConfiguration));
/* Points-to-Triangle Strip Configuration */
testConfiguration.m_drawMode = GL_POINTS;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_TRIANGLES;
testConfiguration.m_layoutIn = "points";
testConfiguration.m_layoutOut = "triangle_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 3;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 1;
addChild(new GeometryShaderPrimitiveCounter(getContext(), m_extParams, "points_to_triangle_strip",
"Test Group 6.1 points to triangle strip", testConfiguration));
/* Lines-to-Points Configuration */
testConfiguration.m_drawMode = GL_LINES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_POINTS;
testConfiguration.m_layoutIn = "lines";
testConfiguration.m_layoutOut = "points";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 1;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 2;
addChild(new GeometryShaderPrimitiveCounter(getContext(), m_extParams, "lines_to_points",
"Test Group 6.1 lines to points", testConfiguration));
/* Lines-to-Line Strip Configuration */
testConfiguration.m_drawMode = GL_LINES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[1].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_LINES;
testConfiguration.m_layoutIn = "lines";
testConfiguration.m_layoutOut = "line_strip";
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 2;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 2;
testConfiguration.m_numberOfDrawnPrimitives = 1024;
addChild(new GeometryShaderPrimitiveCounter(getContext(), m_extParams, "lines_to_line_strip",
"Test Group 6.1 lines to line strip", testConfiguration));
/* Lines-to-Triangle Strip Configuration */
testConfiguration.m_drawMode = GL_LINES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[1].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_TRIANGLES;
testConfiguration.m_layoutIn = "lines";
testConfiguration.m_layoutOut = "triangle_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 3;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 2;
addChild(new GeometryShaderPrimitiveCounter(getContext(), m_extParams, "lines_to_triangle_strip",
"Test Group 6.1 lines to triangle strip", testConfiguration));
/* Triangles-to-Points Configuration */
testConfiguration.m_drawMode = GL_TRIANGLES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_POINTS;
testConfiguration.m_layoutIn = "triangles";
testConfiguration.m_layoutOut = "points";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 1;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 3;
addChild(new GeometryShaderPrimitiveCounter(getContext(), m_extParams, "triangles_to_points",
"Test Group 6.1 triangles to points", testConfiguration));
/* Triangles-to-Line Strip Configuration */
testConfiguration.m_drawMode = GL_TRIANGLES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[1].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_LINES;
testConfiguration.m_layoutIn = "triangles";
testConfiguration.m_layoutOut = "line_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 2;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 3;
addChild(new GeometryShaderPrimitiveCounter(getContext(), m_extParams, "triangles_to_line_strip",
"Test Group 6.1 triangles to line strip", testConfiguration));
/* Triangles-to-Triangle Strip Configuration */
testConfiguration.m_drawMode = GL_TRIANGLES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn=gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn=gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[1].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn=gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[2].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_TRIANGLES;
testConfiguration.m_layoutIn = "triangles";
testConfiguration.m_layoutOut = "triangle_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 3;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 3;
addChild(new GeometryShaderPrimitiveCounter(getContext(), m_extParams, "triangles_to_triangle_strip",
"Test Group 6.1 triangles to triangle strip", testConfiguration));
/* Test case 6.2 */
/* Points-to-Points Configuration */
testConfiguration.m_drawMode = GL_POINTS;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_POINTS;
testConfiguration.m_layoutIn = "points";
testConfiguration.m_layoutOut = "points";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 1;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 1;
addChild(new GeometryShaderPrimitiveCounterRestartingPrimitive(
getContext(), m_extParams, "points_to_points_rp", "Test Group 6.2 points to points", testConfiguration));
/* Points-to-Line Strip Configuration */
testConfiguration.m_drawMode = GL_POINTS;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_LINES;
testConfiguration.m_layoutIn = "points";
testConfiguration.m_layoutOut = "line_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 2;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 1;
addChild(new GeometryShaderPrimitiveCounterRestartingPrimitive(getContext(), m_extParams, "points_to_line_strip_rp",
"Test Group 6.2 point to line", testConfiguration));
/* Points-to-Triangle Strip Configuration */
testConfiguration.m_drawMode = GL_POINTS;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_TRIANGLES;
testConfiguration.m_layoutIn = "points";
testConfiguration.m_layoutOut = "triangle_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 3;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 1;
addChild(new GeometryShaderPrimitiveCounterRestartingPrimitive(
getContext(), m_extParams, "points_to_triangle_strip_rp", "Test Group 6.2 points to triangle strip",
testConfiguration));
/* Lines-to-Points Configuration */
testConfiguration.m_layoutIn = "lines";
testConfiguration.m_layoutOut = "points";
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 1;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 2;
testConfiguration.m_feedbackMode = GL_POINTS;
testConfiguration.m_drawMode = GL_LINES;
testConfiguration.m_numberOfDrawnPrimitives = 1024;
addChild(new GeometryShaderPrimitiveCounterRestartingPrimitive(
getContext(), m_extParams, "lines_to_points_rp", "Test Group 6.2 lines to points", testConfiguration));
/* Lines to Line Strip Configuration*/
testConfiguration.m_drawMode = GL_LINES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[1].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_LINES;
testConfiguration.m_layoutIn = "lines";
testConfiguration.m_layoutOut = "line_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 2;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 2;
addChild(new GeometryShaderPrimitiveCounterRestartingPrimitive(
getContext(), m_extParams, "lines_to_line_strip_rp", "Test Group 6.2 lines to line strip", testConfiguration));
/* Lines to Triangle Strip Configuration */
testConfiguration.m_drawMode = GL_LINES;
testConfiguration.m_feedbackMode = GL_TRIANGLES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[1].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_layoutIn = "lines";
testConfiguration.m_layoutOut = "triangle_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 3;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 2;
addChild(new GeometryShaderPrimitiveCounterRestartingPrimitive(
getContext(), m_extParams, "lines_to_triangle_strip_rp", "Test Group 6.2 line to triangle", testConfiguration));
/* Triangles to Points Configuration */
testConfiguration.m_drawMode = GL_TRIANGLES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_POINTS;
testConfiguration.m_layoutIn = "triangles";
testConfiguration.m_layoutOut = "points";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 1;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 3;
addChild(new GeometryShaderPrimitiveCounterRestartingPrimitive(
getContext(), m_extParams, "triangles_to_points_rp", "Test Group 6.2 triangles to points", testConfiguration));
/* Triangles to Line Strip Configuration */
testConfiguration.m_drawMode = GL_TRIANGLES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[1].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_LINES;
testConfiguration.m_layoutIn = "triangles";
testConfiguration.m_layoutOut = "line_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 2;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 3;
addChild(new GeometryShaderPrimitiveCounterRestartingPrimitive(
getContext(), m_extParams, "triangles_to_line_strip_rp", "Test Group 6.2 triangles to line strip",
testConfiguration));
/* Triangles to Triangle Strip Configuration*/
testConfiguration.m_drawMode = GL_TRIANGLES;
testConfiguration.m_emitVertexCodeForGeometryShader = " test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[1].gl_Position;\n"
" EmitVertex();\n"
"\n"
" test_gl_PrimitiveIDIn = gl_PrimitiveIDIn;\n"
" gl_Position = gl_in[2].gl_Position;\n"
" EmitVertex();\n";
testConfiguration.m_feedbackMode = GL_TRIANGLES;
testConfiguration.m_layoutIn = "triangles";
testConfiguration.m_layoutOut = "triangle_strip";
testConfiguration.m_numberOfDrawnPrimitives = 1024;
testConfiguration.m_numberOfVerticesPerOneOutputPrimitive = 3;
testConfiguration.m_numberOfVerticesPerOneInputPrimitive = 3;
addChild(new GeometryShaderPrimitiveCounterRestartingPrimitive(
getContext(), m_extParams, "triangles_to_triangle_strip_rp", "Test Group 6.2 triangles to triangle strip",
testConfiguration));
/* Test case 6.3 */
addChild(new GeometryShaderPrimitiveIDFromFragmentShader(getContext(), m_extParams, "primitive_id_from_fragment",
"Test Group 6.3 gl_PrimitiveID from fragment shader"));
}
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's description
* @param testConfiguration Configuration that specifies the "in" and "out" primitive types
* for the geometry shader and the shader itself
**/
GeometryShaderPrimitiveCounter::GeometryShaderPrimitiveCounter(Context& context, const ExtParameters& extParams,
const char* name, const char* description,
const DataPrimitiveIDInCounter& testConfiguration)
: TestCaseBase(context, extParams, name, description)
, m_testConfiguration(testConfiguration)
, m_nrVaryings(0)
, m_sizeOfDataArray(0)
, m_sizeOfFeedbackBuffer(0)
, m_n_components(4)
, m_maxGeometryOutputVertices(0)
, m_fragment_shader_id(0)
, m_geometry_shader_id(0)
, m_vertex_shader_id(0)
, m_program_id(0)
, m_tbo(0)
, m_vao(0)
, m_vbo(0)
{
/* Left blank on purpose */
}
/** Verifies the data generated by XFB during a draw call.
*
* @param data Input data. Must not be NULL.
*
* @return true if successful, false otherwise.
*/
bool GeometryShaderPrimitiveCounter::checkResult(const glw::GLint* data)
{
bool testPassed = true;
for (unsigned int nDrawnPrimitive = 0; nDrawnPrimitive < m_testConfiguration.m_numberOfDrawnPrimitives;
nDrawnPrimitive++)
{
unsigned int nEmittedValuesPerPrimitive = m_maxGeometryOutputVertices * m_nrVaryings;
for (unsigned int nValue = (nEmittedValuesPerPrimitive * (nDrawnPrimitive));
nValue < (nEmittedValuesPerPrimitive * (nDrawnPrimitive + 1)); nValue++)
{
if ((unsigned int)data[nValue] != nDrawnPrimitive)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Rendered value at index "
<< "[" << nValue << "/" << (m_testConfiguration.m_numberOfDrawnPrimitives *
m_maxGeometryOutputVertices * m_nrVaryings)
<< "]: " << data[nValue] << " != " << nEmittedValuesPerPrimitive
<< tcu::TestLog::EndMessage;
testPassed = false;
}
} /* for (all values) */
} /* for (all primitives) */
return testPassed;
}
/** Creates a program object using predefined fragment & vertex shaders
* and a geometry shader that is constructed on-the-fly, according
* to testConfiguration parameters. The function also sets up transform
* feedback varyings, prior to linking.
**/
void GeometryShaderPrimitiveCounter::createAndBuildProgramWithFeedback(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create a program object */
m_program_id = gl.createProgram();
/* Specify transform feedback varyings */
const char* feedbackVaryings[] = { "test_gl_PrimitiveIDIn" };
m_nrVaryings = sizeof(feedbackVaryings) / sizeof(char*);
gl.transformFeedbackVaryings(m_program_id, m_nrVaryings, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set transform feedback varyings!");
/* Create shader objects that will make up the program object */
m_geometry_shader_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
/* Retrieve GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT pname value and use it as argument for
* max_vertices layout qualifier of the geometry shader. */
std::stringstream max_vertices_sstream;
std::string max_vertices_string;
gl.getIntegerv(m_glExtTokens.MAX_GEOMETRY_OUTPUT_VERTICES, &m_maxGeometryOutputVertices);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not query GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT!");
m_maxGeometryOutputVertices = m_maxGeometryOutputVertices / (m_n_components + m_nrVaryings);
max_vertices_sstream << m_maxGeometryOutputVertices;
max_vertices_string = max_vertices_sstream.str();
/* Calculate the possible for loops count in Geometry Shader */
glw::GLint n_loop_iterations =
m_maxGeometryOutputVertices / m_testConfiguration.m_numberOfVerticesPerOneOutputPrimitive;
/* adjust the m_maxGeometryOutputVertices to be the number of emitted vertices */
m_maxGeometryOutputVertices = n_loop_iterations * m_testConfiguration.m_numberOfVerticesPerOneOutputPrimitive;
std::stringstream n_loop_iterations_sstream;
std::string n_loop_iterations_string;
n_loop_iterations_sstream << n_loop_iterations;
n_loop_iterations_string = n_loop_iterations_sstream.str();
/* Construct geometry shader code */
std::string geometry_shader_code =
GetGeometryShaderCode(max_vertices_string, m_testConfiguration.m_layoutIn, m_testConfiguration.m_layoutOut,
m_testConfiguration.m_emitVertexCodeForGeometryShader, n_loop_iterations_string);
const char* geometry_shader_code_ptr = (const char*)geometry_shader_code.c_str();
/* Build program */
if (!buildProgram(m_program_id, m_fragment_shader_id, 1, &m_fragment_shader_code, m_geometry_shader_id, 1,
&geometry_shader_code_ptr, m_vertex_shader_id, 1, &m_vertex_shader_code))
{
TCU_FAIL("Program could not have been created sucessfully");
}
}
/** Deinitializes GLES objects created during the test.
*
*/
void GeometryShaderPrimitiveCounter::deinit(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Reset OpenGL ES state */
gl.useProgram(0);
gl.bindBuffer(GL_ARRAY_BUFFER, 0);
gl.bindVertexArray(0);
/* Delete program object and shader objects */
if (m_program_id != 0)
{
gl.deleteProgram(m_program_id);
}
if (m_vertex_shader_id != 0)
{
gl.deleteShader(m_vertex_shader_id);
}
if (m_geometry_shader_id != 0)
{
gl.deleteShader(m_geometry_shader_id);
}
if (m_fragment_shader_id != 0)
{
gl.deleteShader(m_fragment_shader_id);
}
if (m_vbo != 0)
{
gl.deleteBuffers(1, &m_vbo);
}
if (m_tbo != 0)
{
gl.deleteBuffers(1, &m_tbo);
}
if (m_vao != 0)
{
gl.deleteVertexArrays(1, &m_vao);
}
/* Deinitialize base class */
TestCaseBase::deinit();
}
/** Render a test geometry and retrieve data generated by XFB.
*
* @param feedbackResult Will be filled with data generated by XFB.
* Must provide m_sizeOfFeedbackBuffer bytes of space.
* Must not be NULL.
*/
void GeometryShaderPrimitiveCounter::drawAndGetFeedback(glw::GLint* feedbackResult)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(m_program_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed!");
gl.enable(GL_RASTERIZER_DISCARD);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed!");
/* Perform transform feedback */
gl.beginTransformFeedback(m_testConfiguration.m_feedbackMode);
{
drawFunction();
}
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
gl.disable(GL_RASTERIZER_DISCARD);
GLU_EXPECT_NO_ERROR(gl.getError(), "giDisable(GL_RASTERIZER_DISCARD) failed");
/* Fetch the generated data */
glw::GLint* feedback = NULL;
feedback = (glw::GLint*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
m_sizeOfFeedbackBuffer, GL_MAP_READ_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
memcpy(feedbackResult, feedback, m_sizeOfFeedbackBuffer);
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
}
/** Renders the test geometry.
*
*/
void GeometryShaderPrimitiveCounter::drawFunction()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.drawArrays(m_testConfiguration.m_drawMode, 0, /* first */
m_testConfiguration.m_numberOfDrawnPrimitives *
m_testConfiguration.m_numberOfVerticesPerOneInputPrimitive);
}
/** Fill geometry shader template
*
* @param max_vertices String in "max_vertices=N" format (where N is a valid value);
* @param layout_in String storing an "in" layout qualifier definition;
* @param layout_out String storing an "out" layout qualifier definition;
* @param emit_vertices String storing the vertex emitting code;
* @param n_iterations String storing a number of vertex emitting iterations;
*/
std::string GeometryShaderPrimitiveCounter::GetGeometryShaderCode(const std::string& max_vertices,
const std::string& layout_in,
const std::string& layout_out,
const std::string& emit_vertices,
const std::string& n_iterations)
{
/* Geometry shader template code */
std::string m_geometry_shader_template = "${VERSION}\n"
"\n"
"${GEOMETRY_SHADER_REQUIRE}\n"
"\n"
"precision highp float;\n"
"\n"
"layout(<-LAYOUT-IN->) in;\n"
"layout(<-LAYOUT-OUT->, max_vertices =<-MAX-VERTICES->) out;\n"
"\n"
"flat out int test_gl_PrimitiveIDIn;\n"
"\n"
"void main()\n"
"{\n"
" for (int i=0; i<<-N_ITERATIONS->; i++)\n"
" {\n"
" <-EMIT-VERTICES->\n"
" EndPrimitive();\n"
" }\n"
"}\n";
/* Max number of emited vertices */
std::string template_name = "<-MAX-VERTICES->";
std::size_t template_position = m_geometry_shader_template.find(template_name);
while (template_position != std::string::npos)
{
m_geometry_shader_template =
m_geometry_shader_template.replace(template_position, template_name.length(), max_vertices);
template_position = m_geometry_shader_template.find(template_name);
}
/* In primitive type */
template_name = "<-LAYOUT-IN->";
template_position = m_geometry_shader_template.find(template_name);
while (template_position != std::string::npos)
{
m_geometry_shader_template =
m_geometry_shader_template.replace(template_position, template_name.length(), layout_in);
template_position = m_geometry_shader_template.find(template_name);
}
/* Out primitive type */
template_name = "<-LAYOUT-OUT->";
template_position = m_geometry_shader_template.find(template_name);
while (template_position != std::string::npos)
{
m_geometry_shader_template =
m_geometry_shader_template.replace(template_position, template_name.length(), layout_out);
template_position = m_geometry_shader_template.find(template_name);
}
/* Vertex emit code */
template_name = "<-EMIT-VERTICES->";
template_position = m_geometry_shader_template.find(template_name);
while (template_position != std::string::npos)
{
m_geometry_shader_template =
m_geometry_shader_template.replace(template_position, template_name.length(), emit_vertices);
template_position = m_geometry_shader_template.find(template_name);
}
/* Number of iterations, during which we'll be emitting vertices */
template_name = "<-N_ITERATIONS->";
template_position = m_geometry_shader_template.find(template_name);
while (template_position != std::string::npos)
{
m_geometry_shader_template =
m_geometry_shader_template.replace(template_position, template_name.length(), n_iterations);
template_position = m_geometry_shader_template.find(template_name);
}
return m_geometry_shader_template;
}
/** Executes the test.
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
* @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
* Note the function throws exception should an error occur!
**/
tcu::TestNode::IterateResult GeometryShaderPrimitiveCounter::iterate(void)
{
if (!m_is_geometry_shader_extension_supported)
{
throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* Set up */
glw::GLint* feedbackResult = NULL;
createAndBuildProgramWithFeedback();
prepareBufferObjects();
feedbackResult = new glw::GLint[m_sizeOfFeedbackBuffer];
/* Execute the test */
drawAndGetFeedback(feedbackResult);
/* Set the CTS test result, depending on the outcome */
if (checkResult(feedbackResult))
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
if (feedbackResult != NULL)
{
delete[] feedbackResult;
feedbackResult = DE_NULL;
}
return STOP;
}
/** Prepare buffer objects and initialize their storage. It will
* later be used as vertex attribute array data source, as well
* as transform feedback destination.
**/
void GeometryShaderPrimitiveCounter::prepareBufferObjects()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create a VAO */
gl.genVertexArrays(1, &m_vao);
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create a VAO!");
m_sizeOfDataArray = m_testConfiguration.m_numberOfDrawnPrimitives * m_n_components *
m_testConfiguration.m_numberOfVerticesPerOneInputPrimitive;
gl.genBuffers(1, &m_vbo);
gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
gl.bufferData(GL_ARRAY_BUFFER, m_sizeOfDataArray * sizeof(glw::GLfloat), NULL, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(),
"Could not initialize a buffer object to hold data for vertex_position attribute!");
/* Set up "vertex_position" vertex attribute array */
glw::GLint vertex_position_attribute_location = -1;
vertex_position_attribute_location = gl.getAttribLocation(m_program_id, "vertex_position");
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not retrieve vertex_position attribute location!");
gl.vertexAttribPointer(vertex_position_attribute_location, 4, /* size */
GL_FLOAT, GL_FALSE, /* normalized */
0, /* stride */
0); /* pointer */
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() failed for vertex_position attribute!");
gl.enableVertexAttribArray(vertex_position_attribute_location);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() failed for vertex_position attribute!");
/* Set up buffer object to hold result transform feedback data */
m_sizeOfFeedbackBuffer = static_cast<glw::GLuint>(m_testConfiguration.m_numberOfDrawnPrimitives *
m_maxGeometryOutputVertices * m_nrVaryings * sizeof(glw::GLint));
gl.genBuffers(1, &m_tbo);
gl.bindBuffer(GL_ARRAY_BUFFER, m_tbo);
gl.bufferData(GL_ARRAY_BUFFER, m_sizeOfFeedbackBuffer, DE_NULL, GL_STATIC_COPY);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a buffer object to hold transform feedback data!");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_tbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not bind a buffer object to transform feedback binding point!");
}
/** Constructor
*
* @param context Test context;
* @param name Test case's name;
* @param description Test case's description;
* @param testConfiguration Configuration that specifies the "in" and "out" primitive type
* for the geometry shader, as well as defines other miscellaneous
* properties of the test the shader.
**/
GeometryShaderPrimitiveCounterRestartingPrimitive::GeometryShaderPrimitiveCounterRestartingPrimitive(
Context& context, const ExtParameters& extParams, const char* name, const char* description,
const DataPrimitiveIDInCounter& testConfiguration)
: GeometryShaderPrimitiveCounter(context, extParams, name, description, testConfiguration)
, m_bo_id(0)
, m_numberOfRestarts(2)
{
}
/** Deinitializes GLES objects created during the test.
*
*/
void GeometryShaderPrimitiveCounterRestartingPrimitive::deinit(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_bo_id != 0)
{
gl.deleteBuffers(1, &m_bo_id);
m_bo_id = 0;
}
/* Call base class' deinit() */
GeometryShaderPrimitiveCounter::deinit();
}
/** Renders the test geometry.
*
*/
void GeometryShaderPrimitiveCounterRestartingPrimitive::drawFunction()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.drawElements(m_testConfiguration.m_drawMode, (m_testConfiguration.m_numberOfDrawnPrimitives *
m_testConfiguration.m_numberOfVerticesPerOneInputPrimitive +
m_numberOfRestarts),
GL_UNSIGNED_INT, 0 /* indices */);
}
/** Executes the test.
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
* @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
* Note the function throws exception should an error occur!
**/
tcu::TestNode::IterateResult GeometryShaderPrimitiveCounterRestartingPrimitive::iterate(void)
{
if (!m_is_geometry_shader_extension_supported)
{
throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* Set up */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
createAndBuildProgramWithFeedback();
prepareBufferObjects();
glw::GLenum restart_token;
if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
{
restart_token = GL_PRIMITIVE_RESTART;
}
else
{
restart_token = GL_PRIMITIVE_RESTART_FIXED_INDEX;
}
gl.enable(restart_token);
GLU_EXPECT_NO_ERROR(gl.getError(), "Enabling primitive restart failed");
setUpVertexAttributeArrays();
/* Render the test geometry */
glw::GLint* feedbackResult = NULL;
feedbackResult = new glw::GLint[m_sizeOfFeedbackBuffer];
try
{
drawAndGetFeedback(feedbackResult);
}
catch (...)
{
delete[] feedbackResult;
feedbackResult = NULL;
throw;
}
gl.disable(restart_token);
int error = gl.getError();
if (error != GL_NO_ERROR)
{
delete[] feedbackResult;
feedbackResult = NULL;
GLU_EXPECT_NO_ERROR(error, "Disabling primitive restart failed");
}
/* Check the result and update the DEQP test result accordingly */
if (checkResult(feedbackResult))
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
delete[] feedbackResult;
feedbackResult = NULL;
return STOP;
}
/** Prepare the element vertex attribute array data. Make sure to
* use primitive index functionality.
*/
void GeometryShaderPrimitiveCounterRestartingPrimitive::setUpVertexAttributeArrays()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create a buffer object to hold the element data */
glw::GLuint* indices = DE_NULL;
const unsigned int nIndices =
m_testConfiguration.m_numberOfDrawnPrimitives * m_testConfiguration.m_numberOfVerticesPerOneInputPrimitive +
m_numberOfRestarts;
unsigned int restartIndex;
if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
{
restartIndex = nIndices;
}
else
{
restartIndex = 0xFFFFFFFF;
}
gl.genBuffers(1, &m_bo_id);
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate a buffer object");
/* Prepare the data we will later use for configuring buffer object storage contents */
indices = new unsigned int[nIndices];
memset(indices, 0, nIndices * sizeof(unsigned int));
for (unsigned int restartNr = 0; restartNr < m_numberOfRestarts; ++restartNr)
{
for (unsigned int i = m_testConfiguration.m_numberOfVerticesPerOneInputPrimitive * restartNr + 1; i < nIndices;
i++)
{
if (i < m_testConfiguration.m_numberOfVerticesPerOneInputPrimitive * (restartNr + 1) + restartNr)
{
indices[i] = i - restartNr;
}
else if (i > m_testConfiguration.m_numberOfVerticesPerOneInputPrimitive * (restartNr + 1) + restartNr)
{
indices[i] = (i - 1 - restartNr);
}
}
indices[m_testConfiguration.m_numberOfVerticesPerOneInputPrimitive * (restartNr + 1) + restartNr] =
restartIndex;
}
/*
m_testCtx.getLog() << tcu::TestLog::Message << "Indices table [ " << tcu::TestLog::EndMessage;
for (unsigned int i = 0; i < nIndices; i++)
{
m_testCtx.getLog() << tcu::TestLog::Message << indices[i] << ", " << tcu::TestLog::EndMessage;
}
m_testCtx.getLog() << tcu::TestLog::Message << " ]" << tcu::TestLog::EndMessage;
*/
/* Set up buffer object data storage */
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(glw::GLuint) * nIndices, indices, GL_STATIC_DRAW);
/* Free the buffer we no longer need */
delete[] indices;
indices = NULL;
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create element array buffer object");
if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
{
/* Set up primitive restarting */
gl.primitiveRestartIndex(restartIndex);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set primitive restart index");
}
}
/* Vertex shader code */
const char* GeometryShaderPrimitiveIDFromFragmentShader::m_vertex_shader_code = "${VERSION}\n"
"\n"
"precision highp float;\n"
"\n"
"flat out int vs_vertex_id;"
"\n"
" in vec4 vertex_position;\n"
"\n"
"void main()\n"
"{\n"
" vs_vertex_id = gl_VertexID;"
"}\n";
/* Geometry Shader code */
const char* GeometryShaderPrimitiveIDFromFragmentShader::m_geometry_shader_code =
"${VERSION}\n"
"\n"
"${GEOMETRY_SHADER_REQUIRE}\n"
"\n"
"precision highp float;\n"
"\n"
"layout(points) in;\n"
"layout(triangle_strip, max_vertices = 4) out;\n"
"\n"
"flat in int vs_vertex_id[1];\n"
"\n"
"void main()\n"
"{\n"
" int column = vs_vertex_id[0] % 64;\n"
" int row = vs_vertex_id[0] / 64;\n"
"\n"
" gl_PrimitiveID = vs_vertex_id[0];\n"
" gl_Position = vec4(-1.0 + float(column+1) / 32.0, -1.0 + float(row + 1) / 32.0, 0, 1);\n"
" EmitVertex();\n"
"\n"
" gl_PrimitiveID = vs_vertex_id[0];\n"
" gl_Position = vec4(-1.0 + float(column+1) / 32.0, -1.0 + float(row) / 32.0, 0, 1);\n"
" EmitVertex();\n"
"\n"
" gl_PrimitiveID = vs_vertex_id[0];\n"
" gl_Position = vec4(-1.0 + float(column) / 32.0, -1.0 + float(row + 1) / 32.0, 0, 1);\n"
" EmitVertex();\n"
"\n"
" gl_PrimitiveID = vs_vertex_id[0];\n"
" gl_Position = vec4(-1.0 + float(column)/ 32.0, -1.0 + float(row)/ 32.0, 0, 1);\n"
" EmitVertex();\n"
"\n"
" EndPrimitive();\n"
"}\n";
/* Fragment shader code */
const char* GeometryShaderPrimitiveIDFromFragmentShader::m_fragment_shader_code =
"${VERSION}\n"
"\n"
"${GEOMETRY_SHADER_REQUIRE}\n"
"\n"
"precision highp float;\n"
"\n"
"layout(location = 0) out vec4 result;\n"
"\n"
"void main()\n"
"{\n"
" result.x = float(gl_PrimitiveID % 64) / 64.0f;\n"
" result.y = floor(float(gl_PrimitiveID) / 64.0f) / 64.0f;\n"
" result.z = float(gl_PrimitiveID) / 4096.0f;\n"
" result.w = ((gl_PrimitiveID % 2) == 0) ? 1.0f : 0.0f;\n"
"}\n";
/** Constructor
*
* @param context Test context;
* @param name Test case's name;
* @param description Test case's description;
**/
GeometryShaderPrimitiveIDFromFragmentShader::GeometryShaderPrimitiveIDFromFragmentShader(Context& context,
const ExtParameters& extParams,
const char* name,
const char* description)
: TestCaseBase(context, extParams, name, description)
, m_n_drawn_vertices(4096)
, m_squareEdgeSize(16)
, m_texture_height(1024)
, m_texture_n_components(4)
, m_texture_n_levels(1)
, m_texture_width(1024)
, m_fbo_id(0)
, m_fragment_shader_id(0)
, m_geometry_shader_id(0)
, m_program_id(0)
, m_texture_id(0)
, m_vao_id(0)
, m_vbo_id(0)
, m_vertex_shader_id(0)
{
}
/** Deinitializes GLES objects created during the test.
*
*/
void GeometryShaderPrimitiveIDFromFragmentShader::deinit(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Reset OpenGL ES state */
gl.useProgram(0);
gl.bindTexture(GL_TEXTURE_2D, 0);
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
gl.bindVertexArray(0);
if (m_program_id != 0)
{
gl.deleteProgram(m_program_id);
m_program_id = 0;
}
if (m_fragment_shader_id != 0)
{
gl.deleteShader(m_fragment_shader_id);
m_fragment_shader_id = 0;
}
if (m_geometry_shader_id != 0)
{
gl.deleteShader(m_geometry_shader_id);
m_geometry_shader_id = 0;
}
if (m_vertex_shader_id != 0)
{
gl.deleteShader(m_vertex_shader_id);
m_vertex_shader_id = 0;
}
if (m_texture_id != 0)
{
gl.deleteTextures(1, &m_texture_id);
m_texture_id = 0;
}
if (m_fbo_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_id);
m_fbo_id = 0;
}
if (m_vao_id != 0)
{
gl.deleteVertexArrays(1, &m_vao_id);
m_vao_id = 0;
}
if (m_vbo_id != 0)
{
gl.deleteBuffers(1, &m_vbo_id);
m_vbo_id = 0;
}
/* Release base class */
TestCaseBase::deinit();
}
/** Executes the test.
* Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
* @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
* Note the function throws exception should an error occur!
**/
tcu::TestNode::IterateResult GeometryShaderPrimitiveIDFromFragmentShader::iterate(void)
{
const float epsilon = 1.0f / 256.0f;
if (!m_is_geometry_shader_extension_supported)
{
throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create a program object */
m_program_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
/* Create shader objects */
m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
m_geometry_shader_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
/* Build the program object */
if (!buildProgram(m_program_id, m_fragment_shader_id, 1, &m_fragment_shader_code, m_geometry_shader_id, 1,
&m_geometry_shader_code, m_vertex_shader_id, 1, &m_vertex_shader_code))
{
TCU_FAIL("Program could not have been created sucessfully");
}
/* Create and configure a texture object we'll be rendering to */
gl.genTextures(1, &m_texture_id);
gl.bindTexture(GL_TEXTURE_2D, m_texture_id);
gl.texStorage2D(GL_TEXTURE_2D, m_texture_n_levels, GL_RGBA8, m_texture_width, m_texture_height);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating a texture object!");
/* Create and configure the framebuffer object */
gl.genFramebuffers(1, &m_fbo_id);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id);
gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring framebuffer object!");
/* Create and bind a vertex array object */
gl.genVertexArrays(1, &m_vao_id);
gl.bindVertexArray(m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error configuring a vertex array object");
/* Set up a buffer object we will use to hold vertex_position attribute data */
const glw::GLuint sizeOfDataArray =
static_cast<glw::GLuint>(m_n_drawn_vertices * m_texture_n_components * sizeof(glw::GLfloat));
gl.genBuffers(1, &m_vbo_id);
gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
gl.bufferData(GL_ARRAY_BUFFER, sizeOfDataArray, DE_NULL, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up a buffer object to hold vertex_position attribute data!");
/* Set up the viewport */
gl.viewport(0 /* x */, 0 /* y */, m_texture_width, m_texture_height);
GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed");
/* Clear the color buffer */
gl.clearColor(1.0f, 1.0f, 1.0f, 1.0f);
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "Could not clear the color buffer!");
/* Render the test geometry */
gl.useProgram(m_program_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
gl.drawArrays(GL_POINTS, 0 /* first */, m_n_drawn_vertices);
GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed!");
/* Read the rendered data */
glw::GLubyte* resultBuffer = new glw::GLubyte[m_texture_width * m_texture_height * m_texture_n_components];
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_id);
int error = gl.getError();
if (error != GL_NO_ERROR)
{
delete[] resultBuffer;
resultBuffer = NULL;
GLU_EXPECT_NO_ERROR(error, "glBindFramebuffer() call failed");
}
gl.readPixels(0 /* x */, 0 /* y */, m_texture_width, m_texture_height, GL_RGBA, GL_UNSIGNED_BYTE, resultBuffer);
error = gl.getError();
if (error != GL_NO_ERROR)
{
delete[] resultBuffer;
resultBuffer = NULL;
GLU_EXPECT_NO_ERROR(error, "Reading pixels failed!");
}
/* Loop over all pixels and compare the rendered data with reference values */
for (glw::GLuint y = 0; y < m_texture_height; ++y)
{
glw::GLubyte* data_row = resultBuffer + y * m_texture_width * m_texture_n_components;
for (glw::GLuint x = 0; x < m_texture_width; ++x)
{
glw::GLuint column = (x / m_squareEdgeSize);
glw::GLubyte* data = data_row + x * m_texture_n_components;
glw::GLuint row = (y / m_squareEdgeSize);
glw::GLuint primitiveID = column + (row * (m_texture_width / m_squareEdgeSize));
/* Calculate expected and rendered pixel color */
float rendered_rgba[4] = { 0 };
float expected_rgba[4];
for (unsigned int n_channel = 0; n_channel < 4 /* RGBA */; ++n_channel)
{
rendered_rgba[n_channel] = float(data[n_channel]) / 255.0f;
}
expected_rgba[0] = (glw::GLfloat)(primitiveID % 64) / 64.0f;
expected_rgba[1] = deFloatFloor((glw::GLfloat)(primitiveID) / 64.0f) / 64.0f;
expected_rgba[2] = (glw::GLfloat)(primitiveID) / 4096.0f;
expected_rgba[3] = (((primitiveID % 2) == 0) ? 1.0f : 0.0f);
/* Compare the data */
if (de::abs(rendered_rgba[0] - expected_rgba[0]) > epsilon ||
de::abs(rendered_rgba[1] - expected_rgba[1]) > epsilon ||
de::abs(rendered_rgba[2] - expected_rgba[2]) > epsilon ||
de::abs(rendered_rgba[3] - expected_rgba[3]) > epsilon)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Primitive ID: " << primitiveID << "Rendered data"
<< "equal (" << rendered_rgba[0] << ", " << rendered_rgba[1] << ", "
<< rendered_rgba[2] << ", " << rendered_rgba[3] << ") "
<< "exceeds allowed epsilon when compared to expected data equal ("
<< expected_rgba[0] << ", " << expected_rgba[1] << ", " << expected_rgba[2] << ", "
<< expected_rgba[3] << ")." << tcu::TestLog::EndMessage;
delete[] resultBuffer;
resultBuffer = NULL;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
} /* if (rendered data is invalid) */
} /* for (all columns) */
} /* for (all rows) */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
delete[] resultBuffer;
resultBuffer = NULL;
return STOP;
}
} // namespace glcts