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