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