Merge vk-gl-cts/vulkan-cts-1.0.1 into vk-gl-cts/vulkan-cts-1.0.2
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / stress / es31sTessellationGeometryInteractionTests.cpp
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