1/*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2014-2016 The Khronos Group Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 */ /*! 20 * \file 21 * \brief 22 */ /*-------------------------------------------------------------------*/ 23 24#include "esextcGeometryShaderPrimitiveQueries.hpp" 25 26#include "gluDefs.hpp" 27#include "glwEnums.hpp" 28#include "glwFunctions.hpp" 29#include "tcuTestLog.hpp" 30 31namespace glcts 32{ 33 34/* Fragment shader */ 35const char* GeometryShaderPrimitiveQueries::m_fs_code = "${VERSION}\n" 36 "\n" 37 "precision highp float;\n" 38 "\n" 39 "void main()\n" 40 "{\n" 41 "}\n"; 42 43/* Vertex shader */ 44const char* GeometryShaderPrimitiveQueries::m_vs_code = "${VERSION}\n" 45 "\n" 46 "precision highp float;\n" 47 "\n" 48 "void main()\n" 49 "{\n" 50 " gl_Position = vec4(gl_VertexID, 0, 0, 1);\n" 51 "}\n"; 52 53/* Geometry shader */ 54const char* GeometryShaderPrimitiveQueriesPoints::m_gs_code = 55 "${VERSION}\n" 56 "\n" 57 "${GEOMETRY_SHADER_REQUIRE}\n" 58 "\n" 59 "precision highp float;\n" 60 "\n" 61 "layout(points) in;\n" 62 "layout(points, max_vertices=8) out;\n" 63 "\n" 64 "void main()\n" 65 "{\n" 66 " for (int n = 0; n < 8; ++n)\n" 67 " {\n" 68 " gl_Position = vec4(1.0 / (float(n) + 1.0), 1.0 / (float(n) + 2.0), 0.0, 1.0);\n" 69 " EmitVertex();\n" 70 " }\n" 71 "\n" 72 " EndPrimitive();\n" 73 "}\n"; 74 75/* Geometry shader */ 76const char* GeometryShaderPrimitiveQueriesLines::m_gs_code = 77 "${VERSION}\n" 78 "\n" 79 "${GEOMETRY_SHADER_REQUIRE}\n" 80 "\n" 81 "precision highp float;\n" 82 "\n" 83 "layout(points) in;\n" 84 "layout(line_strip, max_vertices=10) out;\n" 85 "\n" 86 "void main()\n" 87 "{\n" 88 " for (int n = 0; n < 10; ++n)\n" 89 " {\n" 90 " gl_Position = vec4(1.0 / (float(n) + 1.0), 1.0 / (float(n) + 2.0), 0.0, 1.0);\n" 91 " EmitVertex();\n" 92 " }\n" 93 "\n" 94 " EndPrimitive();\n" 95 "}\n"; 96 97/* Geometry shader */ 98const char* GeometryShaderPrimitiveQueriesTriangles::m_gs_code = 99 "${VERSION}\n" 100 "\n" 101 "${GEOMETRY_SHADER_REQUIRE}\n" 102 "\n" 103 "precision highp float;\n" 104 "\n" 105 "layout(points) in;\n" 106 "layout(triangle_strip, max_vertices=12) out;\n" 107 "\n" 108 "void main()\n" 109 "{\n" 110 " for (int n = 0; n < 12; ++n)\n" 111 " {\n" 112 " gl_Position = vec4(1.0 / (float(n) + 1.0), 1.0 / (float(n) + 2.0), 0.0, 1.0);\n" 113 " EmitVertex();\n" 114 " }\n" 115 "\n" 116 " EndPrimitive();\n" 117 "}\n"; 118 119/** Constructor 120 * 121 * @param context Test context 122 * @param name Test case's name 123 * @param description Test case's description 124 **/ 125GeometryShaderPrimitiveQueriesPoints::GeometryShaderPrimitiveQueriesPoints(Context& context, 126 const ExtParameters& extParams, 127 const char* name, const char* description) 128 : GeometryShaderPrimitiveQueries(context, extParams, name, description) 129{ 130} 131 132/** Gets geometry shader code 133 * 134 * @return geometry shader code 135 **/ 136const char* GeometryShaderPrimitiveQueriesPoints::getGeometryShaderCode() 137{ 138 return m_gs_code; 139} 140 141/** Gets the number of emitted vertices 142 * 143 * @return number of emitted vertices 144 **/ 145glw::GLint GeometryShaderPrimitiveQueriesPoints::getAmountOfEmittedVertices() 146{ 147 return 8; 148} 149 150/** Gets the transform feedback mode 151 * 152 * @return transform feedback mode 153 **/ 154glw::GLenum GeometryShaderPrimitiveQueriesPoints::getTFMode() 155{ 156 return GL_POINTS; 157} 158 159/** Constructor 160 * 161 * @param context Test context 162 * @param name Test case's name 163 * @param description Test case's desricption 164 **/ 165GeometryShaderPrimitiveQueriesLines::GeometryShaderPrimitiveQueriesLines(Context& context, 166 const ExtParameters& extParams, 167 const char* name, const char* description) 168 : GeometryShaderPrimitiveQueries(context, extParams, name, description) 169{ 170} 171 172/** Gets geometry shader code 173 * 174 * @return geometry shader code 175 **/ 176const char* GeometryShaderPrimitiveQueriesLines::getGeometryShaderCode() 177{ 178 return m_gs_code; 179} 180 181/** Gets the number of emitted vertices 182 * 183 * @return number of emitted vertices 184 **/ 185glw::GLint GeometryShaderPrimitiveQueriesLines::getAmountOfEmittedVertices() 186{ 187 return 18; 188} 189 190/** Gets the transform feedback mode 191 * 192 * @return transform feedback mode 193 **/ 194glw::GLenum GeometryShaderPrimitiveQueriesLines::getTFMode() 195{ 196 return GL_LINES; 197} 198 199/** Constructor 200 * 201 * @param context Test context 202 * @param name Test case's name 203 * @param description Test case's desricption 204 **/ 205GeometryShaderPrimitiveQueriesTriangles::GeometryShaderPrimitiveQueriesTriangles(Context& context, 206 const ExtParameters& extParams, 207 const char* name, 208 const char* description) 209 : GeometryShaderPrimitiveQueries(context, extParams, name, description) 210{ 211} 212 213/** Gets geometry shader code 214 * 215 * @return geometry shader code 216 **/ 217const char* GeometryShaderPrimitiveQueriesTriangles::getGeometryShaderCode() 218{ 219 return m_gs_code; 220} 221 222/** Gets the number of emitted vertices 223 * 224 * @return number of emitted vertices 225 **/ 226glw::GLint GeometryShaderPrimitiveQueriesTriangles::getAmountOfEmittedVertices() 227{ 228 return 30; 229} 230 231/** Gets the transform feedback mode 232 * 233 * @return transform feedback mode 234 **/ 235glw::GLenum GeometryShaderPrimitiveQueriesTriangles::getTFMode() 236{ 237 return GL_TRIANGLES; 238} 239 240/** Constructor 241 * 242 * @param context Test context 243 * @param name Test case's name 244 * @param description Test case's desricption 245 **/ 246GeometryShaderPrimitiveQueries::GeometryShaderPrimitiveQueries(Context& context, const ExtParameters& extParams, 247 const char* name, const char* description) 248 : TestCaseBase(context, extParams, name, description) 249 , m_n_texture_components(4) 250 , m_bo_large_id(0) 251 , m_bo_small_id(0) 252 , m_fs_id(0) 253 , m_gs_id(0) 254 , m_po_id(0) 255 , m_qo_primitives_generated_id(0) 256 , m_qo_tf_primitives_written_id(0) 257 , m_vao_id(0) 258 , m_vs_id(0) 259{ 260 /* Nothing to be done here */ 261} 262 263/** Deinitializes GLES objects created during the test. 264 * 265 */ 266void GeometryShaderPrimitiveQueries::deinit(void) 267{ 268 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 269 270 /* Reset OpenGL ES state */ 271 gl.useProgram(0); 272 gl.bindBuffer(GL_ARRAY_BUFFER, 0); 273 gl.bindVertexArray(0); 274 275 if (m_po_id != 0) 276 { 277 gl.deleteProgram(m_po_id); 278 } 279 280 if (m_fs_id != 0) 281 { 282 gl.deleteShader(m_fs_id); 283 } 284 285 if (m_gs_id != 0) 286 { 287 gl.deleteShader(m_gs_id); 288 } 289 290 if (m_vs_id != 0) 291 { 292 gl.deleteShader(m_vs_id); 293 } 294 295 if (m_bo_small_id != 0) 296 { 297 gl.deleteBuffers(1, &m_bo_small_id); 298 } 299 300 if (m_bo_large_id != 0) 301 { 302 gl.deleteBuffers(1, &m_bo_large_id); 303 } 304 305 if (m_qo_primitives_generated_id != 0) 306 { 307 gl.deleteQueries(1, &m_qo_primitives_generated_id); 308 } 309 310 if (m_qo_tf_primitives_written_id != 0) 311 { 312 gl.deleteQueries(1, &m_qo_tf_primitives_written_id); 313 } 314 315 if (m_vao_id != 0) 316 { 317 gl.deleteVertexArrays(1, &m_vao_id); 318 } 319 320 /* Release base class */ 321 TestCaseBase::deinit(); 322} 323 324/** Executes the test. 325 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise. 326 * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again. 327 * Note the function throws exception should an error occur! 328 **/ 329tcu::TestNode::IterateResult GeometryShaderPrimitiveQueries::iterate(void) 330{ 331 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 332 333 /* Check if geometry_shader extension is supported */ 334 if (!m_is_geometry_shader_extension_supported) 335 { 336 throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__); 337 } 338 339 /* Create shader objects and a program object */ 340 m_vs_id = gl.createShader(GL_VERTEX_SHADER); 341 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER); 342 m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER); 343 m_po_id = gl.createProgram(); 344 345 GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program/shader objects."); 346 347 /* Try to build test-specific program object */ 348 const char* tf_varyings[] = { "gl_Position" }; 349 const char* gs_code = getGeometryShaderCode(); 350 351 gl.transformFeedbackVaryings(m_po_id, sizeof(tf_varyings) / sizeof(tf_varyings[0]), tf_varyings, 352 GL_SEPARATE_ATTRIBS); 353 354 if (!buildProgram(m_po_id, m_fs_id, 1 /* part */, &m_fs_code, m_gs_id, 1 /* part */, &gs_code, m_vs_id, 355 1 /* part */, &m_vs_code)) 356 { 357 TCU_FAIL("Could not create a program for GeometryShaderPrimitiveQueries!"); 358 } 359 360 /* Create and bind a vertex array object */ 361 gl.genVertexArrays(1, &m_vao_id); 362 gl.bindVertexArray(m_vao_id); 363 364 GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating a vertex array object."); 365 366 /* Create two buffer objects 367 * 368 * One with sufficiently large storage space to hold position data for particular output. 369 * Another one of insufficient size. 370 */ 371 gl.genBuffers(1, &m_bo_large_id); 372 gl.genBuffers(1, &m_bo_small_id); 373 374 gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_large_id); 375 gl.bufferData(GL_ARRAY_BUFFER, 376 getAmountOfEmittedVertices() * m_n_texture_components /* components */ * sizeof(float), NULL, 377 GL_STATIC_DRAW); 378 379 gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_small_id); 380 gl.bufferData(GL_ARRAY_BUFFER, 381 (getAmountOfEmittedVertices() / 2) * m_n_texture_components /* components */ * sizeof(float), NULL, 382 GL_STATIC_DRAW); 383 384 GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating buffer objects."); 385 386 /* Create primitive query objects */ 387 gl.genQueries(1, &m_qo_tf_primitives_written_id); 388 gl.genQueries(1, &m_qo_primitives_generated_id); 389 390 glw::GLuint nPrimitivesGenerated = 0; 391 glw::GLuint nTFPrimitivesWritten = 0; 392 393 /* Test case 13.1 */ 394 readPrimitiveQueryValues(m_bo_large_id, &nPrimitivesGenerated, &nTFPrimitivesWritten); 395 396 if (nPrimitivesGenerated == 0) 397 { 398 m_testCtx.getLog() 399 << tcu::TestLog::Message 400 << "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value is zero which should never happen." 401 << tcu::TestLog::EndMessage; 402 403 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 404 return STOP; 405 } 406 407 if (nTFPrimitivesWritten == 0) 408 { 409 m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query " 410 "object value is zero which should never happen." 411 << tcu::TestLog::EndMessage; 412 413 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 414 return STOP; 415 } 416 417 if (nPrimitivesGenerated != nTFPrimitivesWritten) 418 { 419 m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value(" 420 << nPrimitivesGenerated 421 << ") is different than for GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN (" 422 << nTFPrimitivesWritten << ")" << tcu::TestLog::EndMessage; 423 424 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 425 return STOP; 426 } 427 428 /* Test case 13.2 */ 429 nPrimitivesGenerated = 0; 430 nTFPrimitivesWritten = 0; 431 432 readPrimitiveQueryValues(m_bo_small_id, &nPrimitivesGenerated, &nTFPrimitivesWritten); 433 434 if (nPrimitivesGenerated == 0) 435 { 436 m_testCtx.getLog() 437 << tcu::TestLog::Message 438 << "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value is zero which should never happen." 439 << tcu::TestLog::EndMessage; 440 441 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 442 return STOP; 443 } 444 445 if (nTFPrimitivesWritten == 0) 446 { 447 m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query " 448 "object value is zero which should never happen." 449 << tcu::TestLog::EndMessage; 450 451 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 452 return STOP; 453 } 454 455 if ((nPrimitivesGenerated / 2) != nTFPrimitivesWritten) 456 { 457 m_testCtx.getLog() << tcu::TestLog::Message 458 << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object value(" 459 << nPrimitivesGenerated << ") should be half the amount of GL_PRIMITIVES_GENERATED_EXT (" 460 << nTFPrimitivesWritten << ")" << tcu::TestLog::EndMessage; 461 462 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 463 return STOP; 464 } 465 466 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 467 return STOP; 468} 469 470/** 471 * The function binds the provided bufferId to transform feedback target and sets up a query 472 * for GL_PRIMITIVES_GENERATED_EXT GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN. 473 * It then issues a draw call to execute the vertex and geometry shaders. Then results 474 * of the queries are written to nPrimitivesGenerated and nPrimitivesWritten variables. 475 * 476 * @param context bufferId id of the buffer to be bound to transform feedback target 477 * @return nPrimitivesGenerated the result of GL_PRIMITIVES_GENERATED_EXT query 478 * @return nPrimitivesWritten the result of GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query 479 */ 480void GeometryShaderPrimitiveQueries::readPrimitiveQueryValues(glw::GLint bufferId, glw::GLuint* nPrimitivesGenerated, 481 glw::GLuint* nPrimitivesWritten) 482{ 483 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 484 485 /* Bind the buffer object to hold the captured data.*/ 486 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bufferId); 487 488 /* Activate the program object */ 489 gl.useProgram(m_po_id); 490 GLU_EXPECT_NO_ERROR(gl.getError(), "Error using program object"); 491 492 gl.beginTransformFeedback(getTFMode()); 493 GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting transform feedback"); 494 495 /* Activate the queries */ 496 gl.beginQuery(m_glExtTokens.PRIMITIVES_GENERATED, m_qo_primitives_generated_id); 497 GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting GL_PRIMITIVES_GENERATED_EXT query"); 498 499 gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_qo_tf_primitives_written_id); 500 GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query"); 501 502 /* Render */ 503 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); 504 GLU_EXPECT_NO_ERROR(gl.getError(), "Error executing draw call"); 505 506 gl.endTransformFeedback(); 507 GLU_EXPECT_NO_ERROR(gl.getError(), "Error finishing transform feedback"); 508 509 /* Query objects end here. */ 510 gl.endQuery(m_glExtTokens.PRIMITIVES_GENERATED); 511 gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); 512 513 /* Retrieve query values */ 514 gl.getQueryObjectuiv(m_qo_primitives_generated_id, GL_QUERY_RESULT, nPrimitivesGenerated); 515 gl.getQueryObjectuiv(m_qo_tf_primitives_written_id, GL_QUERY_RESULT, nPrimitivesWritten); 516 517 GLU_EXPECT_NO_ERROR(gl.getError(), "Error retrieving query values."); 518} 519 520} // namespace glcts 521