blob: 729cb78cb487309e94d0ac6c0dbe85adc7fbeee6 [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 "esextcGeometryShaderPrimitiveQueries.hpp"
#include "gluDefs.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuTestLog.hpp"
namespace glcts
{
/* Fragment shader */
const char* GeometryShaderPrimitiveQueries::m_fs_code = "${VERSION}\n"
"\n"
"precision highp float;\n"
"\n"
"void main()\n"
"{\n"
"}\n";
/* Vertex shader */
const char* GeometryShaderPrimitiveQueries::m_vs_code = "${VERSION}\n"
"\n"
"precision highp float;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(gl_VertexID, 0, 0, 1);\n"
"}\n";
/* Geometry shader */
const char* GeometryShaderPrimitiveQueriesPoints::m_gs_code =
"${VERSION}\n"
"\n"
"${GEOMETRY_SHADER_REQUIRE}\n"
"\n"
"precision highp float;\n"
"\n"
"layout(points) in;\n"
"layout(points, max_vertices=8) out;\n"
"\n"
"void main()\n"
"{\n"
" for (int n = 0; n < 8; ++n)\n"
" {\n"
" gl_Position = vec4(1.0 / (float(n) + 1.0), 1.0 / (float(n) + 2.0), 0.0, 1.0);\n"
" EmitVertex();\n"
" }\n"
"\n"
" EndPrimitive();\n"
"}\n";
/* Geometry shader */
const char* GeometryShaderPrimitiveQueriesLines::m_gs_code =
"${VERSION}\n"
"\n"
"${GEOMETRY_SHADER_REQUIRE}\n"
"\n"
"precision highp float;\n"
"\n"
"layout(points) in;\n"
"layout(line_strip, max_vertices=10) out;\n"
"\n"
"void main()\n"
"{\n"
" for (int n = 0; n < 10; ++n)\n"
" {\n"
" gl_Position = vec4(1.0 / (float(n) + 1.0), 1.0 / (float(n) + 2.0), 0.0, 1.0);\n"
" EmitVertex();\n"
" }\n"
"\n"
" EndPrimitive();\n"
"}\n";
/* Geometry shader */
const char* GeometryShaderPrimitiveQueriesTriangles::m_gs_code =
"${VERSION}\n"
"\n"
"${GEOMETRY_SHADER_REQUIRE}\n"
"\n"
"precision highp float;\n"
"\n"
"layout(points) in;\n"
"layout(triangle_strip, max_vertices=12) out;\n"
"\n"
"void main()\n"
"{\n"
" for (int n = 0; n < 12; ++n)\n"
" {\n"
" gl_Position = vec4(1.0 / (float(n) + 1.0), 1.0 / (float(n) + 2.0), 0.0, 1.0);\n"
" EmitVertex();\n"
" }\n"
"\n"
" EndPrimitive();\n"
"}\n";
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's description
**/
GeometryShaderPrimitiveQueriesPoints::GeometryShaderPrimitiveQueriesPoints(Context& context,
const ExtParameters& extParams,
const char* name, const char* description)
: GeometryShaderPrimitiveQueries(context, extParams, name, description)
{
}
/** Gets geometry shader code
*
* @return geometry shader code
**/
const char* GeometryShaderPrimitiveQueriesPoints::getGeometryShaderCode()
{
return m_gs_code;
}
/** Gets the number of emitted vertices
*
* @return number of emitted vertices
**/
glw::GLint GeometryShaderPrimitiveQueriesPoints::getAmountOfEmittedVertices()
{
return 8;
}
/** Gets the transform feedback mode
*
* @return transform feedback mode
**/
glw::GLenum GeometryShaderPrimitiveQueriesPoints::getTFMode()
{
return GL_POINTS;
}
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's desricption
**/
GeometryShaderPrimitiveQueriesLines::GeometryShaderPrimitiveQueriesLines(Context& context,
const ExtParameters& extParams,
const char* name, const char* description)
: GeometryShaderPrimitiveQueries(context, extParams, name, description)
{
}
/** Gets geometry shader code
*
* @return geometry shader code
**/
const char* GeometryShaderPrimitiveQueriesLines::getGeometryShaderCode()
{
return m_gs_code;
}
/** Gets the number of emitted vertices
*
* @return number of emitted vertices
**/
glw::GLint GeometryShaderPrimitiveQueriesLines::getAmountOfEmittedVertices()
{
return 18;
}
/** Gets the transform feedback mode
*
* @return transform feedback mode
**/
glw::GLenum GeometryShaderPrimitiveQueriesLines::getTFMode()
{
return GL_LINES;
}
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's desricption
**/
GeometryShaderPrimitiveQueriesTriangles::GeometryShaderPrimitiveQueriesTriangles(Context& context,
const ExtParameters& extParams,
const char* name,
const char* description)
: GeometryShaderPrimitiveQueries(context, extParams, name, description)
{
}
/** Gets geometry shader code
*
* @return geometry shader code
**/
const char* GeometryShaderPrimitiveQueriesTriangles::getGeometryShaderCode()
{
return m_gs_code;
}
/** Gets the number of emitted vertices
*
* @return number of emitted vertices
**/
glw::GLint GeometryShaderPrimitiveQueriesTriangles::getAmountOfEmittedVertices()
{
return 30;
}
/** Gets the transform feedback mode
*
* @return transform feedback mode
**/
glw::GLenum GeometryShaderPrimitiveQueriesTriangles::getTFMode()
{
return GL_TRIANGLES;
}
/** Constructor
*
* @param context Test context
* @param name Test case's name
* @param description Test case's desricption
**/
GeometryShaderPrimitiveQueries::GeometryShaderPrimitiveQueries(Context& context, const ExtParameters& extParams,
const char* name, const char* description)
: TestCaseBase(context, extParams, name, description)
, m_n_texture_components(4)
, m_bo_large_id(0)
, m_bo_small_id(0)
, m_fs_id(0)
, m_gs_id(0)
, m_po_id(0)
, m_qo_primitives_generated_id(0)
, m_qo_tf_primitives_written_id(0)
, m_vao_id(0)
, m_vs_id(0)
{
/* Nothing to be done here */
}
/** Deinitializes GLES objects created during the test.
*
*/
void GeometryShaderPrimitiveQueries::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);
if (m_po_id != 0)
{
gl.deleteProgram(m_po_id);
}
if (m_fs_id != 0)
{
gl.deleteShader(m_fs_id);
}
if (m_gs_id != 0)
{
gl.deleteShader(m_gs_id);
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
}
if (m_bo_small_id != 0)
{
gl.deleteBuffers(1, &m_bo_small_id);
}
if (m_bo_large_id != 0)
{
gl.deleteBuffers(1, &m_bo_large_id);
}
if (m_qo_primitives_generated_id != 0)
{
gl.deleteQueries(1, &m_qo_primitives_generated_id);
}
if (m_qo_tf_primitives_written_id != 0)
{
gl.deleteQueries(1, &m_qo_tf_primitives_written_id);
}
if (m_vao_id != 0)
{
gl.deleteVertexArrays(1, &m_vao_id);
}
/* 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 GeometryShaderPrimitiveQueries::iterate(void)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Check if geometry_shader extension is supported */
if (!m_is_geometry_shader_extension_supported)
{
throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
}
/* Create shader objects and a program object */
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
m_po_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program/shader objects.");
/* Try to build test-specific program object */
const char* tf_varyings[] = { "gl_Position" };
const char* gs_code = getGeometryShaderCode();
gl.transformFeedbackVaryings(m_po_id, sizeof(tf_varyings) / sizeof(tf_varyings[0]), tf_varyings,
GL_SEPARATE_ATTRIBS);
if (!buildProgram(m_po_id, m_fs_id, 1 /* part */, &m_fs_code, m_gs_id, 1 /* part */, &gs_code, m_vs_id,
1 /* part */, &m_vs_code))
{
TCU_FAIL("Could not create a program for GeometryShaderPrimitiveQueries!");
}
/* 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 creating a vertex array object.");
/* Create two buffer objects
*
* One with sufficiently large storage space to hold position data for particular output.
* Another one of insufficient size.
*/
gl.genBuffers(1, &m_bo_large_id);
gl.genBuffers(1, &m_bo_small_id);
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_large_id);
gl.bufferData(GL_ARRAY_BUFFER,
getAmountOfEmittedVertices() * m_n_texture_components /* components */ * sizeof(float), NULL,
GL_STATIC_DRAW);
gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_small_id);
gl.bufferData(GL_ARRAY_BUFFER,
(getAmountOfEmittedVertices() / 2) * m_n_texture_components /* components */ * sizeof(float), NULL,
GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating buffer objects.");
/* Create primitive query objects */
gl.genQueries(1, &m_qo_tf_primitives_written_id);
gl.genQueries(1, &m_qo_primitives_generated_id);
glw::GLuint nPrimitivesGenerated = 0;
glw::GLuint nTFPrimitivesWritten = 0;
/* Test case 13.1 */
readPrimitiveQueryValues(m_bo_large_id, &nPrimitivesGenerated, &nTFPrimitivesWritten);
if (nPrimitivesGenerated == 0)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value is zero which should never happen."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
if (nTFPrimitivesWritten == 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query "
"object value is zero which should never happen."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
if (nPrimitivesGenerated != nTFPrimitivesWritten)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value("
<< nPrimitivesGenerated
<< ") is different than for GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN ("
<< nTFPrimitivesWritten << ")" << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
/* Test case 13.2 */
nPrimitivesGenerated = 0;
nTFPrimitivesWritten = 0;
readPrimitiveQueryValues(m_bo_small_id, &nPrimitivesGenerated, &nTFPrimitivesWritten);
if (nPrimitivesGenerated == 0)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value is zero which should never happen."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
if (nTFPrimitivesWritten == 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query "
"object value is zero which should never happen."
<< tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
if ((nPrimitivesGenerated / 2) != nTFPrimitivesWritten)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object value("
<< nPrimitivesGenerated << ") should be half the amount of GL_PRIMITIVES_GENERATED_EXT ("
<< nTFPrimitivesWritten << ")" << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
return STOP;
}
/**
* The function binds the provided bufferId to transform feedback target and sets up a query
* for GL_PRIMITIVES_GENERATED_EXT GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN.
* It then issues a draw call to execute the vertex and geometry shaders. Then results
* of the queries are written to nPrimitivesGenerated and nPrimitivesWritten variables.
*
* @param context bufferId id of the buffer to be bound to transform feedback target
* @return nPrimitivesGenerated the result of GL_PRIMITIVES_GENERATED_EXT query
* @return nPrimitivesWritten the result of GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query
*/
void GeometryShaderPrimitiveQueries::readPrimitiveQueryValues(glw::GLint bufferId, glw::GLuint* nPrimitivesGenerated,
glw::GLuint* nPrimitivesWritten)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Bind the buffer object to hold the captured data.*/
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bufferId);
/* Activate the program object */
gl.useProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error using program object");
gl.beginTransformFeedback(getTFMode());
GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting transform feedback");
/* Activate the queries */
gl.beginQuery(m_glExtTokens.PRIMITIVES_GENERATED, m_qo_primitives_generated_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting GL_PRIMITIVES_GENERATED_EXT query");
gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_qo_tf_primitives_written_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query");
/* Render */
gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error executing draw call");
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "Error finishing transform feedback");
/* Query objects end here. */
gl.endQuery(m_glExtTokens.PRIMITIVES_GENERATED);
gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
/* Retrieve query values */
gl.getQueryObjectuiv(m_qo_primitives_generated_id, GL_QUERY_RESULT, nPrimitivesGenerated);
gl.getQueryObjectuiv(m_qo_tf_primitives_written_id, GL_QUERY_RESULT, nPrimitivesWritten);
GLU_EXPECT_NO_ERROR(gl.getError(), "Error retrieving query values.");
}
} // namespace glcts