xref: /aosp_15_r20/external/deqp/modules/gles31/stress/es31sTessellationGeometryInteractionTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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