1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 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 Tessellation and geometry shader interaction stress tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31sTessellationGeometryInteractionTests.hpp" 25 26 #include "tcuTestLog.hpp" 27 #include "tcuRenderTarget.hpp" 28 #include "tcuSurface.hpp" 29 #include "tcuTextureUtil.hpp" 30 #include "gluRenderContext.hpp" 31 #include "gluShaderProgram.hpp" 32 #include "gluContextInfo.hpp" 33 #include "gluObjectWrapper.hpp" 34 #include "gluPixelTransfer.hpp" 35 #include "glwFunctions.hpp" 36 #include "glwEnums.hpp" 37 #include "deStringUtil.hpp" 38 #include "deUniquePtr.hpp" 39 40 #include <sstream> 41 42 namespace deqp 43 { 44 namespace gles31 45 { 46 namespace Stress 47 { 48 namespace 49 { 50 51 class AllowedRenderFailureException : public std::runtime_error 52 { 53 public: 54 AllowedRenderFailureException (const char* message) : std::runtime_error(message) { } 55 }; 56 57 class GridRenderCase : public TestCase 58 { 59 public: 60 enum Flags 61 { 62 FLAG_TESSELLATION_MAX_SPEC = 0x0001, 63 FLAG_TESSELLATION_MAX_IMPLEMENTATION = 0x0002, 64 FLAG_GEOMETRY_MAX_SPEC = 0x0004, 65 FLAG_GEOMETRY_MAX_IMPLEMENTATION = 0x0008, 66 FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC = 0x0010, 67 FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION = 0x0020, 68 }; 69 70 GridRenderCase (Context& context, const char* name, const char* description, int flags); 71 ~GridRenderCase (void); 72 73 private: 74 void init (void); 75 void deinit (void); 76 IterateResult iterate (void); 77 78 void renderTo (std::vector<tcu::Surface>& dst); 79 bool verifyResultLayer (int layerNdx, const tcu::Surface& dst); 80 81 const char* getVertexSource (void); 82 const char* getFragmentSource (void); 83 std::string getTessellationControlSource (int tessLevel); 84 std::string getTessellationEvaluationSource (int tessLevel); 85 std::string getGeometryShaderSource (int numPrimitives, int numInstances); 86 87 enum 88 { 89 RENDER_SIZE = 256 90 }; 91 92 const int m_flags; 93 94 glu::ShaderProgram* m_program; 95 int m_numLayers; 96 }; 97 98 GridRenderCase::GridRenderCase (Context& context, const char* name, const char* description, int flags) 99 : TestCase (context, name, description) 100 , m_flags (flags) 101 , m_program (DE_NULL) 102 , m_numLayers (1) 103 { 104 DE_ASSERT(((m_flags & FLAG_TESSELLATION_MAX_SPEC) == 0) || ((m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION) == 0)); 105 DE_ASSERT(((m_flags & FLAG_GEOMETRY_MAX_SPEC) == 0) || ((m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION) == 0)); 106 DE_ASSERT(((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC) == 0) || ((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION) == 0)); 107 } 108 109 GridRenderCase::~GridRenderCase (void) 110 { 111 deinit(); 112 } 113 114 void GridRenderCase::init (void) 115 { 116 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 117 118 // Requirements 119 120 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") || 121 !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader")) 122 throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions"); 123 124 if (m_context.getRenderTarget().getWidth() < RENDER_SIZE || 125 m_context.getRenderTarget().getHeight() < RENDER_SIZE) 126 throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target."); 127 128 // Log 129 130 m_testCtx.getLog() 131 << tcu::TestLog::Message 132 << "Testing tessellation and geometry shaders that output a large number of primitives.\n" 133 << getDescription() 134 << tcu::TestLog::EndMessage; 135 136 // Gen program 137 { 138 glu::ProgramSources sources; 139 int tessGenLevel = -1; 140 141 sources << glu::VertexSource(getVertexSource()) 142 << glu::FragmentSource(getFragmentSource()); 143 144 // Tessellation limits 145 { 146 if (m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION) 147 { 148 gl.getIntegerv(GL_MAX_TESS_GEN_LEVEL, &tessGenLevel); 149 GLU_EXPECT_NO_ERROR(gl.getError(), "query tessellation limits"); 150 } 151 else if (m_flags & FLAG_TESSELLATION_MAX_SPEC) 152 { 153 tessGenLevel = 64; 154 } 155 else 156 { 157 tessGenLevel = 5; 158 } 159 160 m_testCtx.getLog() 161 << tcu::TestLog::Message 162 << "Tessellation level: " << tessGenLevel << ", mode = quad.\n" 163 << "\tEach input patch produces " << (tessGenLevel*tessGenLevel) << " (" << (tessGenLevel*tessGenLevel*2) << " triangles)\n" 164 << tcu::TestLog::EndMessage; 165 166 sources << glu::TessellationControlSource(getTessellationControlSource(tessGenLevel)) 167 << glu::TessellationEvaluationSource(getTessellationEvaluationSource(tessGenLevel)); 168 } 169 170 // Geometry limits 171 { 172 int geometryOutputComponents = -1; 173 int geometryOutputVertices = -1; 174 int geometryTotalOutputComponents = -1; 175 int geometryShaderInvocations = -1; 176 bool logGeometryLimits = false; 177 bool logInvocationLimits = false; 178 179 if (m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION) 180 { 181 m_testCtx.getLog() << tcu::TestLog::Message << "Using implementation maximum geometry shader output limits." << tcu::TestLog::EndMessage; 182 183 gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &geometryOutputComponents); 184 gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &geometryOutputVertices); 185 gl.getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &geometryTotalOutputComponents); 186 GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry limits"); 187 188 logGeometryLimits = true; 189 } 190 else if (m_flags & FLAG_GEOMETRY_MAX_SPEC) 191 { 192 m_testCtx.getLog() << tcu::TestLog::Message << "Using geometry shader extension minimum maximum output limits." << tcu::TestLog::EndMessage; 193 194 geometryOutputComponents = 128; 195 geometryOutputVertices = 256; 196 geometryTotalOutputComponents = 1024; 197 logGeometryLimits = true; 198 } 199 else 200 { 201 geometryOutputComponents = 128; 202 geometryOutputVertices = 16; 203 geometryTotalOutputComponents = 1024; 204 } 205 206 if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION) 207 { 208 gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, &geometryShaderInvocations); 209 GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry invocation limits"); 210 211 logInvocationLimits = true; 212 } 213 else if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC) 214 { 215 geometryShaderInvocations = 32; 216 logInvocationLimits = true; 217 } 218 else 219 { 220 geometryShaderInvocations = 4; 221 } 222 223 if (logGeometryLimits || logInvocationLimits) 224 { 225 tcu::MessageBuilder msg(&m_testCtx.getLog()); 226 227 msg << "Geometry shader, targeting following limits:\n"; 228 229 if (logGeometryLimits) 230 msg << "\tGL_MAX_GEOMETRY_OUTPUT_COMPONENTS = " << geometryOutputComponents << "\n" 231 << "\tGL_MAX_GEOMETRY_OUTPUT_VERTICES = " << geometryOutputVertices << "\n" 232 << "\tGL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << geometryTotalOutputComponents << "\n"; 233 234 if (logInvocationLimits) 235 msg << "\tGL_MAX_GEOMETRY_SHADER_INVOCATIONS = " << geometryShaderInvocations; 236 237 msg << tcu::TestLog::EndMessage; 238 } 239 240 241 { 242 const int numComponentsPerVertex = 8; // vec4 pos, vec4 color 243 244 // If FLAG_GEOMETRY_SEPARATE_PRIMITIVES is not set, geometry shader fills a rectangle area in slices. 245 // Each slice is a triangle strip and is generated by a single shader invocation. 246 // One slice with 4 segment ends (nodes) and 3 segments: 247 // .__.__.__. 248 // |\ |\ |\ | 249 // |_\|_\|_\| 250 251 const int numSliceNodesComponentLimit = geometryTotalOutputComponents / (2 * numComponentsPerVertex); // each node 2 vertices 252 const int numSliceNodesOutputLimit = geometryOutputVertices / 2; // each node 2 vertices 253 const int numSliceNodes = de::min(numSliceNodesComponentLimit, numSliceNodesOutputLimit); 254 255 const int numVerticesPerInvocation = numSliceNodes * 2; 256 const int numPrimitivesPerInvocation = (numSliceNodes - 1) * 2; 257 258 const int geometryVerticesPerPrimitive = numVerticesPerInvocation * geometryShaderInvocations; 259 const int geometryPrimitivesOutPerPrimitive = numPrimitivesPerInvocation * geometryShaderInvocations; 260 261 m_testCtx.getLog() 262 << tcu::TestLog::Message 263 << "Geometry shader:\n" 264 << "\tTotal output vertex count per invocation: " << (numVerticesPerInvocation) << "\n" 265 << "\tTotal output primitive count per invocation: " << (numPrimitivesPerInvocation) << "\n" 266 << "\tNumber of invocations per primitive: " << geometryShaderInvocations << "\n" 267 << "\tTotal output vertex count per input primitive: " << (geometryVerticesPerPrimitive) << "\n" 268 << "\tTotal output primitive count per input primitive: " << (geometryPrimitivesOutPerPrimitive) << "\n" 269 << tcu::TestLog::EndMessage; 270 271 sources << glu::GeometrySource(getGeometryShaderSource(numPrimitivesPerInvocation, geometryShaderInvocations)); 272 273 m_testCtx.getLog() 274 << tcu::TestLog::Message 275 << "Program:\n" 276 << "\tTotal program output vertices count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryVerticesPerPrimitive) << "\n" 277 << "\tTotal program output primitive count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryPrimitivesOutPerPrimitive) << "\n" 278 << tcu::TestLog::EndMessage; 279 } 280 } 281 282 m_program = new glu::ShaderProgram(m_context.getRenderContext(), sources); 283 m_testCtx.getLog() << *m_program; 284 if (!m_program->isOk()) 285 throw tcu::TestError("failed to build program"); 286 } 287 } 288 289 void GridRenderCase::deinit (void) 290 { 291 delete m_program; 292 m_program = DE_NULL; 293 } 294 295 GridRenderCase::IterateResult GridRenderCase::iterate (void) 296 { 297 std::vector<tcu::Surface> renderedLayers (m_numLayers); 298 bool allLayersOk = true; 299 300 for (int ndx = 0; ndx < m_numLayers; ++ndx) 301 renderedLayers[ndx].setSize(RENDER_SIZE, RENDER_SIZE); 302 303 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering single point at the origin. Expecting yellow and green colored grid-like image. (High-frequency grid may appear unicolored)." << tcu::TestLog::EndMessage; 304 305 try 306 { 307 renderTo(renderedLayers); 308 } 309 catch (const AllowedRenderFailureException& ex) 310 { 311 // Got accepted failure 312 m_testCtx.getLog() 313 << tcu::TestLog::Message 314 << "Could not render, reason: " << ex.what() << "\n" 315 << "Failure is allowed." 316 << tcu::TestLog::EndMessage; 317 318 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 319 return STOP; 320 } 321 322 for (int ndx = 0; ndx < m_numLayers; ++ndx) 323 allLayersOk &= verifyResultLayer(ndx, renderedLayers[ndx]); 324 325 if (allLayersOk) 326 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 327 else 328 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed"); 329 return STOP; 330 } 331 332 void GridRenderCase::renderTo (std::vector<tcu::Surface>& dst) 333 { 334 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 335 const int positionLocation = gl.getAttribLocation(m_program->getProgram(), "a_position"); 336 const glu::VertexArray vao (m_context.getRenderContext()); 337 338 if (positionLocation == -1) 339 throw tcu::TestError("Attribute a_position location was -1"); 340 341 gl.viewport(0, 0, dst.front().getWidth(), dst.front().getHeight()); 342 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 343 GLU_EXPECT_NO_ERROR(gl.getError(), "viewport"); 344 345 gl.bindVertexArray(*vao); 346 GLU_EXPECT_NO_ERROR(gl.getError(), "bind vao"); 347 348 gl.useProgram(m_program->getProgram()); 349 GLU_EXPECT_NO_ERROR(gl.getError(), "use program"); 350 351 gl.patchParameteri(GL_PATCH_VERTICES, 1); 352 GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param"); 353 354 gl.vertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f); 355 356 // clear viewport 357 gl.clear(GL_COLOR_BUFFER_BIT); 358 359 // draw 360 { 361 glw::GLenum glerror; 362 363 gl.drawArrays(GL_PATCHES, 0, 1); 364 365 // allow always OOM 366 glerror = gl.getError(); 367 if (glerror == GL_OUT_OF_MEMORY) 368 throw AllowedRenderFailureException("got GL_OUT_OF_MEMORY while drawing"); 369 370 GLU_EXPECT_NO_ERROR(glerror, "draw patches"); 371 } 372 373 // Read layers 374 375 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.front().getAccess()); 376 GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels"); 377 } 378 379 bool GridRenderCase::verifyResultLayer (int layerNdx, const tcu::Surface& image) 380 { 381 tcu::Surface errorMask (image.getWidth(), image.getHeight()); 382 bool foundError = false; 383 384 tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); 385 386 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output layer " << layerNdx << tcu::TestLog::EndMessage; 387 388 for (int y = 0; y < image.getHeight(); ++y) 389 for (int x = 0; x < image.getWidth(); ++x) 390 { 391 const int threshold = 8; 392 const tcu::RGBA color = image.getPixel(x, y); 393 394 // Color must be a linear combination of green and yellow 395 if (color.getGreen() < 255 - threshold || color.getBlue() > threshold) 396 { 397 errorMask.setPixel(x, y, tcu::RGBA::red); 398 foundError = true; 399 } 400 } 401 402 if (!foundError) 403 { 404 m_testCtx.getLog() 405 << tcu::TestLog::Message << "Image valid." << tcu::TestLog::EndMessage 406 << tcu::TestLog::ImageSet("ImageVerification", "Image verification") 407 << tcu::TestLog::Image("Result", "Rendered result", image.getAccess()) 408 << tcu::TestLog::EndImageSet; 409 return true; 410 } 411 else 412 { 413 m_testCtx.getLog() 414 << tcu::TestLog::Message << "Image verification failed, found invalid pixels." << tcu::TestLog::EndMessage 415 << tcu::TestLog::ImageSet("ImageVerification", "Image verification") 416 << tcu::TestLog::Image("Result", "Rendered result", image.getAccess()) 417 << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess()) 418 << tcu::TestLog::EndImageSet; 419 return false; 420 } 421 } 422 423 const char* GridRenderCase::getVertexSource (void) 424 { 425 return "#version 310 es\n" 426 "in highp vec4 a_position;\n" 427 "void main (void)\n" 428 "{\n" 429 " gl_Position = a_position;\n" 430 "}\n"; 431 } 432 433 const char* GridRenderCase::getFragmentSource (void) 434 { 435 return "#version 310 es\n" 436 "flat in mediump vec4 v_color;\n" 437 "layout(location = 0) out mediump vec4 fragColor;\n" 438 "void main (void)\n" 439 "{\n" 440 " fragColor = v_color;\n" 441 "}\n"; 442 } 443 444 std::string GridRenderCase::getTessellationControlSource (int tessLevel) 445 { 446 std::ostringstream buf; 447 448 buf << "#version 310 es\n" 449 "#extension GL_EXT_tessellation_shader : require\n" 450 "layout(vertices=1) out;\n" 451 "\n" 452 "void main()\n" 453 "{\n" 454 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 455 " gl_TessLevelOuter[0] = " << tessLevel << ".0;\n" 456 " gl_TessLevelOuter[1] = " << tessLevel << ".0;\n" 457 " gl_TessLevelOuter[2] = " << tessLevel << ".0;\n" 458 " gl_TessLevelOuter[3] = " << tessLevel << ".0;\n" 459 " gl_TessLevelInner[0] = " << tessLevel << ".0;\n" 460 " gl_TessLevelInner[1] = " << tessLevel << ".0;\n" 461 "}\n"; 462 463 return buf.str(); 464 } 465 466 std::string GridRenderCase::getTessellationEvaluationSource (int tessLevel) 467 { 468 std::ostringstream buf; 469 470 buf << "#version 310 es\n" 471 "#extension GL_EXT_tessellation_shader : require\n" 472 "layout(quads) in;\n" 473 "\n" 474 "out mediump ivec2 v_tessellationGridPosition;\n" 475 "\n" 476 "// note: No need to use precise gl_Position since position does not depend on order\n" 477 "void main (void)\n" 478 "{\n" 479 " // Fill the whole viewport\n" 480 " gl_Position = vec4(gl_TessCoord.x * 2.0 - 1.0, gl_TessCoord.y * 2.0 - 1.0, 0.0, 1.0);\n" 481 " // Calculate position in tessellation grid\n" 482 " v_tessellationGridPosition = ivec2(round(gl_TessCoord.xy * float(" << tessLevel << ")));\n" 483 "}\n"; 484 485 return buf.str(); 486 } 487 488 std::string GridRenderCase::getGeometryShaderSource (int numPrimitives, int numInstances) 489 { 490 std::ostringstream buf; 491 492 buf << "#version 310 es\n" 493 "#extension GL_EXT_geometry_shader : require\n" 494 "layout(triangles, invocations=" << numInstances << ") in;\n" 495 "layout(triangle_strip, max_vertices=" << (numPrimitives + 2) << ") out;\n" 496 "\n" 497 "in mediump ivec2 v_tessellationGridPosition[];\n" 498 "flat out highp vec4 v_color;\n" 499 "\n" 500 "void main ()\n" 501 "{\n" 502 " const float equalThreshold = 0.001;\n" 503 " const float gapOffset = 0.0001; // subdivision performed by the geometry shader might produce gaps. Fill potential gaps by enlarging the output slice a little.\n" 504 "\n" 505 " // Input triangle is generated from an axis-aligned rectangle by splitting it in half\n" 506 " // Original rectangle can be found by finding the bounding AABB of the triangle\n" 507 " vec4 aabb = vec4(min(gl_in[0].gl_Position.x, min(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n" 508 " min(gl_in[0].gl_Position.y, min(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)),\n" 509 " max(gl_in[0].gl_Position.x, max(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n" 510 " max(gl_in[0].gl_Position.y, max(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)));\n" 511 "\n" 512 " // Location in tessellation grid\n" 513 " ivec2 gridPosition = ivec2(min(v_tessellationGridPosition[0], min(v_tessellationGridPosition[1], v_tessellationGridPosition[2])));\n" 514 "\n" 515 " // Which triangle of the two that split the grid cell\n" 516 " int numVerticesOnBottomEdge = 0;\n" 517 " for (int ndx = 0; ndx < 3; ++ndx)\n" 518 " if (abs(gl_in[ndx].gl_Position.y - aabb.w) < equalThreshold)\n" 519 " ++numVerticesOnBottomEdge;\n" 520 " bool isBottomTriangle = numVerticesOnBottomEdge == 2;\n" 521 "\n" 522 " // Fill the input area with slices\n" 523 " // Upper triangle produces slices only to the upper half of the quad and vice-versa\n" 524 " float triangleOffset = (isBottomTriangle) ? ((aabb.w + aabb.y) / 2.0) : (aabb.y);\n" 525 " // Each slice is a invocation\n" 526 " float sliceHeight = (aabb.w - aabb.y) / float(2 * " << numInstances << ");\n" 527 " float invocationOffset = float(gl_InvocationID) * sliceHeight;\n" 528 "\n" 529 " vec4 outputSliceArea;\n" 530 " outputSliceArea.x = aabb.x - gapOffset;\n" 531 " outputSliceArea.y = triangleOffset + invocationOffset - gapOffset;\n" 532 " outputSliceArea.z = aabb.z + gapOffset;\n" 533 " outputSliceArea.w = triangleOffset + invocationOffset + sliceHeight + gapOffset;\n""\n" 534 " // Draw slice\n" 535 " for (int ndx = 0; ndx < " << ((numPrimitives+2)/2) << "; ++ndx)\n" 536 " {\n" 537 " vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n" 538 " vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n" 539 " vec4 outputColor = (((gl_InvocationID + ndx) % 2) == 0) ? (green) : (yellow);\n" 540 " float xpos = mix(outputSliceArea.x, outputSliceArea.z, float(ndx) / float(" << (numPrimitives/2) << "));\n" 541 "\n" 542 " gl_Position = vec4(xpos, outputSliceArea.y, 0.0, 1.0);\n" 543 " v_color = outputColor;\n" 544 " EmitVertex();\n" 545 "\n" 546 " gl_Position = vec4(xpos, outputSliceArea.w, 0.0, 1.0);\n" 547 " v_color = outputColor;\n" 548 " EmitVertex();\n" 549 " }\n" 550 "}\n"; 551 552 return buf.str(); 553 } 554 555 } // anonymous 556 557 TessellationGeometryInteractionTests::TessellationGeometryInteractionTests (Context& context) 558 : TestCaseGroup(context, "tessellation_geometry_interaction", "Tessellation and geometry shader interaction stress tests") 559 { 560 } 561 562 TessellationGeometryInteractionTests::~TessellationGeometryInteractionTests (void) 563 { 564 } 565 566 void TessellationGeometryInteractionTests::init (void) 567 { 568 tcu::TestCaseGroup* const multilimitGroup = new tcu::TestCaseGroup(m_testCtx, "render_multiple_limits", "Various render tests"); 569 570 addChild(multilimitGroup); 571 572 // .render_multiple_limits 573 { 574 static const struct LimitCaseDef 575 { 576 const char* name; 577 const char* desc; 578 int flags; 579 } cases[] = 580 { 581 // Test multiple limits at the same time 582 583 { 584 "output_required_max_tessellation_max_geometry", 585 "Minimum maximum tessellation level and geometry shader output vertices", 586 GridRenderCase::FLAG_TESSELLATION_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_MAX_SPEC 587 }, 588 { 589 "output_implementation_max_tessellation_max_geometry", 590 "Maximum tessellation level and geometry shader output vertices supported by the implementation", 591 GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION 592 }, 593 { 594 "output_required_max_tessellation_max_invocations", 595 "Minimum maximum tessellation level and geometry shader invocations", 596 GridRenderCase::FLAG_TESSELLATION_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC 597 }, 598 { 599 "output_implementation_max_tessellation_max_invocations", 600 "Maximum tessellation level and geometry shader invocations supported by the implementation", 601 GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION 602 }, 603 { 604 "output_required_max_geometry_max_invocations", 605 "Minimum maximum geometry shader output vertices and invocations", 606 GridRenderCase::FLAG_GEOMETRY_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC 607 }, 608 { 609 "output_implementation_max_geometry_max_invocations", 610 "Maximum geometry shader output vertices and invocations invocations supported by the implementation", 611 GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION 612 }, 613 614 // Test all limits simultaneously 615 { 616 "output_max_required", 617 "Output minimum maximum number of vertices", 618 GridRenderCase::FLAG_TESSELLATION_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC 619 }, 620 { 621 "output_max_implementation", 622 "Output maximum number of vertices supported by the implementation", 623 GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION 624 }, 625 }; 626 627 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ++ndx) 628 multilimitGroup->addChild(new GridRenderCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].flags)); 629 } 630 } 631 632 } // Stress 633 } // gles31 634 } // deqp 635