Merge Vulkan CTS 1.0.2.5 into aosp/master
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fTessellationTests.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 Tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fTessellationTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "glsShaderLibrary.hpp"
27 #include "glsStateQueryUtil.hpp"
28 #include "gluShaderProgram.hpp"
29 #include "gluRenderContext.hpp"
30 #include "gluPixelTransfer.hpp"
31 #include "gluDrawUtil.hpp"
32 #include "gluObjectWrapper.hpp"
33 #include "gluStrUtil.hpp"
34 #include "gluContextInfo.hpp"
35 #include "gluVarType.hpp"
36 #include "gluVarTypeUtil.hpp"
37 #include "gluCallLogWrapper.hpp"
38 #include "tcuTestLog.hpp"
39 #include "tcuRenderTarget.hpp"
40 #include "tcuSurface.hpp"
41 #include "tcuTextureUtil.hpp"
42 #include "tcuVectorUtil.hpp"
43 #include "tcuImageIO.hpp"
44 #include "tcuResource.hpp"
45 #include "tcuImageCompare.hpp"
46 #include "deRandom.hpp"
47 #include "deStringUtil.hpp"
48 #include "deSharedPtr.hpp"
49 #include "deString.h"
50 #include "deMath.h"
51
52 #include "glwEnums.hpp"
53 #include "glwDefs.hpp"
54 #include "glwFunctions.hpp"
55
56 #include <vector>
57 #include <string>
58 #include <algorithm>
59 #include <functional>
60 #include <set>
61 #include <limits>
62
63 using glu::ShaderProgram;
64 using glu::RenderContext;
65 using tcu::RenderTarget;
66 using tcu::TestLog;
67 using tcu::Vec2;
68 using tcu::Vec3;
69 using tcu::Vec4;
70 using de::Random;
71 using de::SharedPtr;
72
73 using std::vector;
74 using std::string;
75
76 using namespace glw; // For GL types.
77
78 namespace deqp
79 {
80
81 using gls::TextureTestUtil::RandomViewport;
82
83 namespace gles31
84 {
85 namespace Functional
86 {
87
88 using namespace gls::StateQueryUtil;
89
90 enum
91 {
92         MINIMUM_MAX_TESS_GEN_LEVEL = 64 //!< GL-defined minimum for GL_MAX_TESS_GEN_LEVEL.
93 };
94
95 static inline bool vec3XLessThan (const Vec3& a, const Vec3& b) { return a.x() < b.x(); }
96
97 template <typename IterT>
98 static string elemsStr (const IterT& begin, const IterT& end, int wrapLengthParam = 0, int numIndentationSpaces = 0)
99 {
100         const string    baseIndentation = string(numIndentationSpaces, ' ');
101         const string    deepIndentation = baseIndentation + string(4, ' ');
102         const int               wrapLength              = wrapLengthParam > 0 ? wrapLengthParam : std::numeric_limits<int>::max();
103         const int               length                  = (int)std::distance(begin, end);
104         string                  result;
105
106         if (length > wrapLength)
107                 result += "(amount: " + de::toString(length) + ") ";
108         result += string() + "{" + (length > wrapLength ? "\n"+deepIndentation : " ");
109
110         {
111                 int index = 0;
112                 for (IterT it = begin; it != end; ++it)
113                 {
114                         if (it != begin)
115                                 result += string() + ", " + (index % wrapLength == 0 ? "\n"+deepIndentation : "");
116                         result += de::toString(*it);
117                         index++;
118                 }
119
120                 result += length > wrapLength ? "\n"+baseIndentation : " ";
121         }
122
123         result += "}";
124         return result;
125 }
126
127 template <typename ContainerT>
128 static string containerStr (const ContainerT& c, int wrapLengthParam = 0, int numIndentationSpaces = 0)
129 {
130         return elemsStr(c.begin(), c.end(), wrapLengthParam, numIndentationSpaces);
131 }
132
133 template <typename T, int N>
134 static string arrayStr (const T (&arr)[N], int wrapLengthParam = 0, int numIndentationSpaces = 0)
135 {
136         return elemsStr(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr), wrapLengthParam, numIndentationSpaces);
137 }
138
139 template <typename T, int N>
140 static T arrayMax (const T (&arr)[N])
141 {
142         return *std::max_element(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr));
143 }
144
145 template <typename T, typename MembT>
146 static vector<MembT> members (const vector<T>& objs, MembT T::* membP)
147 {
148         vector<MembT> result(objs.size());
149         for (int i = 0; i < (int)objs.size(); i++)
150                 result[i] = objs[i].*membP;
151         return result;
152 }
153
154 template <typename T, int N>
155 static vector<T> arrayToVector (const T (&arr)[N])
156 {
157         return vector<T>(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr));
158 }
159
160 template <typename ContainerT, typename T>
161 static inline bool contains (const ContainerT& c, const T& key)
162 {
163         return c.find(key) != c.end();
164 }
165
166 template <int Size>
167 static inline tcu::Vector<bool, Size> singleTrueMask (int index)
168 {
169         DE_ASSERT(de::inBounds(index, 0, Size));
170         tcu::Vector<bool, Size> result;
171         result[index] = true;
172         return result;
173 }
174
175 static int intPow (int base, int exp)
176 {
177         DE_ASSERT(exp >= 0);
178         if (exp == 0)
179                 return 1;
180         else
181         {
182                 const int sub = intPow(base, exp/2);
183                 if (exp % 2 == 0)
184                         return sub*sub;
185                 else
186                         return sub*sub*base;
187         }
188 }
189
190 tcu::Surface getPixels (const glu::RenderContext& rCtx, int x, int y, int width, int height)
191 {
192         tcu::Surface result(width, height);
193         glu::readPixels(rCtx, x, y, result.getAccess());
194         return result;
195 }
196
197 tcu::Surface getPixels (const glu::RenderContext& rCtx, const RandomViewport& vp)
198 {
199         return getPixels(rCtx, vp.x, vp.y, vp.width, vp.height);
200 }
201
202 static inline void checkRenderTargetSize (const RenderTarget& renderTarget, int minSize)
203 {
204         if (renderTarget.getWidth() < minSize || renderTarget.getHeight() < minSize)
205                 throw tcu::NotSupportedError("Render target width and height must be at least " + de::toString(minSize));
206 }
207
208 tcu::TextureLevel getPNG (const tcu::Archive& archive, const string& filename)
209 {
210         tcu::TextureLevel result;
211         tcu::ImageIO::loadPNG(result, archive, filename.c_str());
212         return result;
213 }
214
215 static int numBasicSubobjects (const glu::VarType& type)
216 {
217         if (type.isBasicType())
218                 return 1;
219         else if (type.isArrayType())
220                 return type.getArraySize()*numBasicSubobjects(type.getElementType());
221         else if (type.isStructType())
222         {
223                 const glu::StructType&  structType      = *type.getStructPtr();
224                 int                                             result          = 0;
225                 for (int i = 0; i < structType.getNumMembers(); i++)
226                         result += numBasicSubobjects(structType.getMember(i).getType());
227                 return result;
228         }
229         else
230         {
231                 DE_ASSERT(false);
232                 return -1;
233         }
234 }
235
236 static inline int numVerticesPerPrimitive (deUint32 primitiveTypeGL)
237 {
238         switch (primitiveTypeGL)
239         {
240                 case GL_POINTS:         return 1;
241                 case GL_TRIANGLES:      return 3;
242                 case GL_LINES:          return 2;
243                 default:
244                         DE_ASSERT(false);
245                         return -1;
246         }
247 }
248
249 static inline void setViewport (const glw::Functions& gl, const RandomViewport& vp)
250 {
251         gl.viewport(vp.x, vp.y, vp.width, vp.height);
252 }
253
254 static inline deUint32 getQueryResult (const glw::Functions& gl, deUint32 queryObject)
255 {
256         deUint32 result = (deUint32)-1;
257         gl.getQueryObjectuiv(queryObject, GL_QUERY_RESULT, &result);
258         TCU_CHECK(result != (deUint32)-1);
259         return result;
260 }
261
262 template <typename T>
263 static void readDataMapped (const glw::Functions& gl, deUint32 bufferTarget, int numElems, T* dst)
264 {
265         const int                                                       numBytes        = numElems*(int)sizeof(T);
266         const T* const                                          mappedData      = (const T*)gl.mapBufferRange(bufferTarget, 0, numBytes, GL_MAP_READ_BIT);
267         GLU_EXPECT_NO_ERROR(gl.getError(), (string() + "glMapBufferRange(" + glu::getBufferTargetName((int)bufferTarget) + ", 0, " + de::toString(numBytes) + ", GL_MAP_READ_BIT)").c_str());
268         TCU_CHECK(mappedData != DE_NULL);
269
270         for (int i = 0; i < numElems; i++)
271                 dst[i] = mappedData[i];
272
273         gl.unmapBuffer(bufferTarget);
274 }
275
276 template <typename T>
277 static vector<T> readDataMapped (const glw::Functions& gl, deUint32 bufferTarget, int numElems)
278 {
279         vector<T> result(numElems);
280         readDataMapped(gl, bufferTarget, numElems, &result[0]);
281         return result;
282 }
283
284 namespace
285 {
286
287 template <typename ArgT, bool res>
288 struct ConstantUnaryPredicate
289 {
290         bool operator() (const ArgT&) const { return res; }
291 };
292
293 //! Helper for handling simple, one-varying transform feedbacks.
294 template <typename VaryingT>
295 class TransformFeedbackHandler
296 {
297 public:
298         struct Result
299         {
300                 int                                     numPrimitives;
301                 vector<VaryingT>        varying;
302
303                 Result (void)                                                           : numPrimitives(-1) {}
304                 Result (int n, const vector<VaryingT>& v)       : numPrimitives(n), varying(v) {}
305         };
306
307                                                                         TransformFeedbackHandler        (const glu::RenderContext& renderCtx, int maxNumVertices);
308
309         Result                                                  renderAndGetPrimitives          (deUint32 programGL, deUint32 tfPrimTypeGL, int numBindings, const glu::VertexArrayBinding* bindings, int numVertices) const;
310
311 private:
312         const glu::RenderContext&               m_renderCtx;
313         const glu::TransformFeedback    m_tf;
314         const glu::Buffer                               m_tfBuffer;
315         const glu::Query                                m_tfPrimQuery;
316 };
317
318 template <typename AttribType>
319 TransformFeedbackHandler<AttribType>::TransformFeedbackHandler (const glu::RenderContext& renderCtx, int maxNumVertices)
320         : m_renderCtx           (renderCtx)
321         , m_tf                          (renderCtx)
322         , m_tfBuffer            (renderCtx)
323         , m_tfPrimQuery         (renderCtx)
324 {
325         const glw::Functions&   gl                      = m_renderCtx.getFunctions();
326         // \note Room for 1 extra triangle, to detect if GL returns too many primitives.
327         const int                               bufferSize      = (maxNumVertices + 3) * (int)sizeof(AttribType);
328
329         gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, *m_tfBuffer);
330         gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_READ);
331 }
332
333 template <typename AttribType>
334 typename TransformFeedbackHandler<AttribType>::Result TransformFeedbackHandler<AttribType>::renderAndGetPrimitives (deUint32 programGL, deUint32 tfPrimTypeGL, int numBindings, const glu::VertexArrayBinding* bindings, int numVertices) const
335 {
336         DE_ASSERT(tfPrimTypeGL == GL_POINTS || tfPrimTypeGL == GL_LINES || tfPrimTypeGL == GL_TRIANGLES);
337
338         const glw::Functions& gl = m_renderCtx.getFunctions();
339
340         gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, *m_tf);
341         gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, *m_tfBuffer);
342         gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, *m_tfBuffer);
343
344         gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, *m_tfPrimQuery);
345         gl.beginTransformFeedback(tfPrimTypeGL);
346
347         glu::draw(m_renderCtx, programGL, numBindings, bindings, glu::pr::Patches(numVertices));
348         GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
349
350         gl.endTransformFeedback();
351         gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
352
353         {
354                 const int numPrimsWritten = (int)getQueryResult(gl, *m_tfPrimQuery);
355                 return Result(numPrimsWritten, readDataMapped<AttribType>(gl, GL_TRANSFORM_FEEDBACK_BUFFER, numPrimsWritten * numVerticesPerPrimitive(tfPrimTypeGL)));
356         }
357 }
358
359 template <typename T>
360 class SizeLessThan
361 {
362 public:
363         bool operator() (const T& a, const T& b) const { return a.size() < b.size(); }
364 };
365
366 //! Predicate functor for comparing structs by their members.
367 template <typename Pred, typename T, typename MembT>
368 class MemberPred
369 {
370 public:
371                                 MemberPred      (MembT T::* membP) : m_membP(membP), m_pred(Pred()) {}
372         bool            operator()      (const T& a, const T& b) const { return m_pred(a.*m_membP, b.*m_membP); }
373
374 private:
375         MembT T::*      m_membP;
376         Pred            m_pred;
377 };
378
379 //! Convenience wrapper for MemberPred, because class template arguments aren't deduced based on constructor arguments.
380 template <template <typename> class Pred, typename T, typename MembT>
381 static MemberPred<Pred<MembT>, T, MembT> memberPred (MembT T::* membP) { return MemberPred<Pred<MembT>, T, MembT>(membP); }
382
383 template <typename SeqT, int Size, typename Pred>
384 class LexCompare
385 {
386 public:
387         LexCompare (void) : m_pred(Pred()) {}
388
389         bool operator() (const SeqT& a, const SeqT& b) const
390         {
391                 for (int i = 0; i < Size; i++)
392                 {
393                         if (m_pred(a[i], b[i]))
394                                 return true;
395                         if (m_pred(b[i], a[i]))
396                                 return false;
397                 }
398                 return false;
399         }
400
401 private:
402         Pred m_pred;
403 };
404
405 template <int Size>
406 class VecLexLessThan : public LexCompare<tcu::Vector<float, Size>, Size, std::less<float> >
407 {
408 };
409
410 enum TessPrimitiveType
411 {
412         TESSPRIMITIVETYPE_TRIANGLES = 0,
413         TESSPRIMITIVETYPE_QUADS,
414         TESSPRIMITIVETYPE_ISOLINES,
415
416         TESSPRIMITIVETYPE_LAST
417 };
418
419 enum SpacingMode
420 {
421         SPACINGMODE_EQUAL,
422         SPACINGMODE_FRACTIONAL_ODD,
423         SPACINGMODE_FRACTIONAL_EVEN,
424
425         SPACINGMODE_LAST
426 };
427
428 enum Winding
429 {
430         WINDING_CCW = 0,
431         WINDING_CW,
432
433         WINDING_LAST
434 };
435
436 static inline const char* getTessPrimitiveTypeShaderName (TessPrimitiveType type)
437 {
438         switch (type)
439         {
440                 case TESSPRIMITIVETYPE_TRIANGLES:       return "triangles";
441                 case TESSPRIMITIVETYPE_QUADS:           return "quads";
442                 case TESSPRIMITIVETYPE_ISOLINES:        return "isolines";
443                 default:
444                         DE_ASSERT(false);
445                         return DE_NULL;
446         }
447 }
448
449 static inline const char* getSpacingModeShaderName (SpacingMode mode)
450 {
451         switch (mode)
452         {
453                 case SPACINGMODE_EQUAL:                         return "equal_spacing";
454                 case SPACINGMODE_FRACTIONAL_ODD:        return "fractional_odd_spacing";
455                 case SPACINGMODE_FRACTIONAL_EVEN:       return "fractional_even_spacing";
456                 default:
457                         DE_ASSERT(false);
458                         return DE_NULL;
459         }
460 }
461
462 static inline const char* getWindingShaderName (Winding winding)
463 {
464         switch (winding)
465         {
466                 case WINDING_CCW:       return "ccw";
467                 case WINDING_CW:        return "cw";
468                 default:
469                         DE_ASSERT(false);
470                         return DE_NULL;
471         }
472 }
473
474 static inline string getTessellationEvaluationInLayoutString (TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode=false)
475 {
476         return string() + "layout (" + getTessPrimitiveTypeShaderName(primType)
477                                                                  + ", " + getSpacingModeShaderName(spacing)
478                                                                  + ", " + getWindingShaderName(winding)
479                                                                  + (usePointMode ? ", point_mode" : "")
480                                                                  + ") in;\n";
481 }
482
483 static inline string getTessellationEvaluationInLayoutString (TessPrimitiveType primType, SpacingMode spacing, bool usePointMode=false)
484 {
485         return string() + "layout (" + getTessPrimitiveTypeShaderName(primType)
486                                                                  + ", " + getSpacingModeShaderName(spacing)
487                                                                  + (usePointMode ? ", point_mode" : "")
488                                                                  + ") in;\n";
489 }
490
491 static inline string getTessellationEvaluationInLayoutString (TessPrimitiveType primType, Winding winding, bool usePointMode=false)
492 {
493         return string() + "layout (" + getTessPrimitiveTypeShaderName(primType)
494                                                                  + ", " + getWindingShaderName(winding)
495                                                                  + (usePointMode ? ", point_mode" : "")
496                                                                  + ") in;\n";
497 }
498
499 static inline string getTessellationEvaluationInLayoutString (TessPrimitiveType primType, bool usePointMode=false)
500 {
501         return string() + "layout (" + getTessPrimitiveTypeShaderName(primType)
502                                                                  + (usePointMode ? ", point_mode" : "")
503                                                                  + ") in;\n";
504 }
505
506 static inline deUint32 outputPrimitiveTypeGL (TessPrimitiveType tessPrimType, bool usePointMode)
507 {
508         if (usePointMode)
509                 return GL_POINTS;
510         else
511         {
512                 switch (tessPrimType)
513                 {
514                         case TESSPRIMITIVETYPE_TRIANGLES:       return GL_TRIANGLES;
515                         case TESSPRIMITIVETYPE_QUADS:           return GL_TRIANGLES;
516                         case TESSPRIMITIVETYPE_ISOLINES:        return GL_LINES;
517                         default:
518                                 DE_ASSERT(false);
519                                 return (deUint32)-1;
520                 }
521         }
522 }
523
524 static inline int numInnerTessellationLevels (TessPrimitiveType primType)
525 {
526         switch (primType)
527         {
528                 case TESSPRIMITIVETYPE_TRIANGLES:       return 1;
529                 case TESSPRIMITIVETYPE_QUADS:           return 2;
530                 case TESSPRIMITIVETYPE_ISOLINES:        return 0;
531                 default: DE_ASSERT(false); return -1;
532         }
533 }
534
535 static inline int numOuterTessellationLevels (TessPrimitiveType primType)
536 {
537         switch (primType)
538         {
539                 case TESSPRIMITIVETYPE_TRIANGLES:       return 3;
540                 case TESSPRIMITIVETYPE_QUADS:           return 4;
541                 case TESSPRIMITIVETYPE_ISOLINES:        return 2;
542                 default: DE_ASSERT(false); return -1;
543         }
544 }
545
546 static string tessellationLevelsString (const float* inner, int numInner, const float* outer, int numOuter)
547 {
548         DE_ASSERT(numInner >= 0 && numOuter >= 0);
549         return "inner: " + elemsStr(inner, inner+numInner) + ", outer: " + elemsStr(outer, outer+numOuter);
550 }
551
552 static string tessellationLevelsString (const float* inner, const float* outer, TessPrimitiveType primType)
553 {
554         return tessellationLevelsString(inner, numInnerTessellationLevels(primType), outer, numOuterTessellationLevels(primType));
555 }
556
557 static string tessellationLevelsString (const float* inner, const float* outer)
558 {
559         return tessellationLevelsString(inner, 2, outer, 4);
560 }
561
562 static inline float getClampedTessLevel (SpacingMode mode, float tessLevel)
563 {
564         switch (mode)
565         {
566                 case SPACINGMODE_EQUAL:                         return de::max(1.0f, tessLevel);
567                 case SPACINGMODE_FRACTIONAL_ODD:        return de::max(1.0f, tessLevel);
568                 case SPACINGMODE_FRACTIONAL_EVEN:       return de::max(2.0f, tessLevel);
569                 default:
570                         DE_ASSERT(false);
571                         return -1.0f;
572         }
573 }
574
575 static inline int getRoundedTessLevel (SpacingMode mode, float clampedTessLevel)
576 {
577         int result = (int)deFloatCeil(clampedTessLevel);
578
579         switch (mode)
580         {
581                 case SPACINGMODE_EQUAL:                                                                                 break;
582                 case SPACINGMODE_FRACTIONAL_ODD:        result += 1 - result % 2;       break;
583                 case SPACINGMODE_FRACTIONAL_EVEN:       result += result % 2;           break;
584                 default:
585                         DE_ASSERT(false);
586         }
587         DE_ASSERT(de::inRange<int>(result, 1, MINIMUM_MAX_TESS_GEN_LEVEL));
588
589         return result;
590 }
591
592 static int getClampedRoundedTessLevel (SpacingMode mode, float tessLevel)
593 {
594         return getRoundedTessLevel(mode, getClampedTessLevel(mode, tessLevel));
595 }
596
597 //! A description of an outer edge of a triangle, quad or isolines.
598 //! An outer edge can be described by the index of a u/v/w coordinate
599 //! and the coordinate's value along that edge.
600 struct OuterEdgeDescription
601 {
602         int             constantCoordinateIndex;
603         float   constantCoordinateValueChoices[2];
604         int             numConstantCoordinateValueChoices;
605
606         OuterEdgeDescription (int i, float c0)                  : constantCoordinateIndex(i), numConstantCoordinateValueChoices(1) { constantCoordinateValueChoices[0] = c0; }
607         OuterEdgeDescription (int i, float c0, float c1)        : constantCoordinateIndex(i), numConstantCoordinateValueChoices(2) { constantCoordinateValueChoices[0] = c0; constantCoordinateValueChoices[1] = c1; }
608
609         string description (void) const
610         {
611                 static const char* const        coordinateNames[] = { "u", "v", "w" };
612                 string                                          result;
613                 for (int i = 0; i < numConstantCoordinateValueChoices; i++)
614                         result += string() + (i > 0 ? " or " : "") + coordinateNames[constantCoordinateIndex] + "=" + de::toString(constantCoordinateValueChoices[i]);
615                 return result;
616         }
617
618         bool contains (const Vec3& v) const
619         {
620                 for (int i = 0; i < numConstantCoordinateValueChoices; i++)
621                         if (v[constantCoordinateIndex] == constantCoordinateValueChoices[i])
622                                 return true;
623                 return false;
624         }
625 };
626
627 static vector<OuterEdgeDescription> outerEdgeDescriptions (TessPrimitiveType primType)
628 {
629         static const OuterEdgeDescription triangleOuterEdgeDescriptions[3] =
630         {
631                 OuterEdgeDescription(0, 0.0f),
632                 OuterEdgeDescription(1, 0.0f),
633                 OuterEdgeDescription(2, 0.0f)
634         };
635
636         static const OuterEdgeDescription quadOuterEdgeDescriptions[4] =
637         {
638                 OuterEdgeDescription(0, 0.0f),
639                 OuterEdgeDescription(1, 0.0f),
640                 OuterEdgeDescription(0, 1.0f),
641                 OuterEdgeDescription(1, 1.0f)
642         };
643
644         static const OuterEdgeDescription isolinesOuterEdgeDescriptions[1] =
645         {
646                 OuterEdgeDescription(0, 0.0f, 1.0f),
647         };
648
649         switch (primType)
650         {
651                 case TESSPRIMITIVETYPE_TRIANGLES:       return arrayToVector(triangleOuterEdgeDescriptions);
652                 case TESSPRIMITIVETYPE_QUADS:           return arrayToVector(quadOuterEdgeDescriptions);
653                 case TESSPRIMITIVETYPE_ISOLINES:        return arrayToVector(isolinesOuterEdgeDescriptions);
654                 default: DE_ASSERT(false); return vector<OuterEdgeDescription>();
655         }
656 }
657
658 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec (e.g. it may not exactly hold that u+v+w == 1.0f, or [uvw] + (1.0f-[uvw]) == 1.0f).
659 static vector<Vec3> generateReferenceTriangleTessCoords (SpacingMode spacingMode, int inner, int outer0, int outer1, int outer2)
660 {
661         vector<Vec3> tessCoords;
662
663         if (inner == 1)
664         {
665                 if (outer0 == 1 && outer1 == 1 && outer2 == 1)
666                 {
667                         tessCoords.push_back(Vec3(1.0f, 0.0f, 0.0f));
668                         tessCoords.push_back(Vec3(0.0f, 1.0f, 0.0f));
669                         tessCoords.push_back(Vec3(0.0f, 0.0f, 1.0f));
670                         return tessCoords;
671                 }
672                 else
673                         return generateReferenceTriangleTessCoords(spacingMode, spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
674                                                                                                                                         outer0, outer1, outer2);
675         }
676         else
677         {
678                 for (int i = 0; i < outer0; i++) { const float v = (float)i / (float)outer0; tessCoords.push_back(Vec3(    0.0f,                   v,   1.0f - v)); }
679                 for (int i = 0; i < outer1; i++) { const float v = (float)i / (float)outer1; tessCoords.push_back(Vec3(1.0f - v,                0.0f,              v)); }
680                 for (int i = 0; i < outer2; i++) { const float v = (float)i / (float)outer2; tessCoords.push_back(Vec3(           v,    1.0f - v,               0.0f)); }
681
682                 const int numInnerTriangles = inner/2;
683                 for (int innerTriangleNdx = 0; innerTriangleNdx < numInnerTriangles; innerTriangleNdx++)
684                 {
685                         const int curInnerTriangleLevel = inner - 2*(innerTriangleNdx+1);
686
687                         if (curInnerTriangleLevel == 0)
688                                 tessCoords.push_back(Vec3(1.0f/3.0f));
689                         else
690                         {
691                                 const float             minUVW          = (float)(2 * (innerTriangleNdx + 1)) / (float)(3 * inner);
692                                 const float             maxUVW          = 1.0f - 2.0f*minUVW;
693                                 const Vec3              corners[3]      =
694                                 {
695                                         Vec3(maxUVW, minUVW, minUVW),
696                                         Vec3(minUVW, maxUVW, minUVW),
697                                         Vec3(minUVW, minUVW, maxUVW)
698                                 };
699
700                                 for (int i = 0; i < curInnerTriangleLevel; i++)
701                                 {
702                                         const float f = (float)i / (float)curInnerTriangleLevel;
703                                         for (int j = 0; j < 3; j++)
704                                                 tessCoords.push_back((1.0f - f)*corners[j] + f*corners[(j+1)%3]);
705                                 }
706                         }
707                 }
708
709                 return tessCoords;
710         }
711 }
712
713 static int referenceTriangleNonPointModePrimitiveCount (SpacingMode spacingMode, int inner, int outer0, int outer1, int outer2)
714 {
715         if (inner == 1)
716         {
717                 if (outer0 == 1 && outer1 == 1 && outer2 == 1)
718                         return 1;
719                 else
720                         return referenceTriangleNonPointModePrimitiveCount(spacingMode, spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
721                                                                                                                                                         outer0, outer1, outer2);
722         }
723         else
724         {
725                 int result = outer0 + outer1 + outer2;
726
727                 const int numInnerTriangles = inner/2;
728                 for (int innerTriangleNdx = 0; innerTriangleNdx < numInnerTriangles; innerTriangleNdx++)
729                 {
730                         const int curInnerTriangleLevel = inner - 2*(innerTriangleNdx+1);
731
732                         if (curInnerTriangleLevel == 1)
733                                 result += 4;
734                         else
735                                 result += 2*3*curInnerTriangleLevel;
736                 }
737
738                 return result;
739         }
740 }
741
742 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec (e.g. it may not exactly hold that [uv] + (1.0f-[uv]) == 1.0f).
743 static vector<Vec3> generateReferenceQuadTessCoords (SpacingMode spacingMode, int inner0, int inner1, int outer0, int outer1, int outer2, int outer3)
744 {
745         vector<Vec3> tessCoords;
746
747         if (inner0 == 1 || inner1 == 1)
748         {
749                 if (inner0 == 1 && inner1 == 1 && outer0 == 1 && outer1 == 1 && outer2 == 1 && outer3 == 1)
750                 {
751                         tessCoords.push_back(Vec3(0.0f, 0.0f, 0.0f));
752                         tessCoords.push_back(Vec3(1.0f, 0.0f, 0.0f));
753                         tessCoords.push_back(Vec3(0.0f, 1.0f, 0.0f));
754                         tessCoords.push_back(Vec3(1.0f, 1.0f, 0.0f));
755                         return tessCoords;
756                 }
757                 else
758                         return generateReferenceQuadTessCoords(spacingMode, inner0 > 1 ? inner0 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
759                                                                                                                                 inner1 > 1 ? inner1 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
760                                                                                                                                 outer0, outer1, outer2, outer3);
761         }
762         else
763         {
764                 for (int i = 0; i < outer0; i++) { const float v = (float)i / (float)outer0; tessCoords.push_back(Vec3(0.0f,    v,                      0.0f)); }
765                 for (int i = 0; i < outer1; i++) { const float v = (float)i / (float)outer1; tessCoords.push_back(Vec3(1.0f-v,  0.0f,           0.0f)); }
766                 for (int i = 0; i < outer2; i++) { const float v = (float)i / (float)outer2; tessCoords.push_back(Vec3(1.0f,    1.0f-v,         0.0f)); }
767                 for (int i = 0; i < outer3; i++) { const float v = (float)i / (float)outer3; tessCoords.push_back(Vec3(v,               1.0f,           0.0f)); }
768
769                 for (int innerVtxY = 0; innerVtxY < inner1-1; innerVtxY++)
770                 for (int innerVtxX = 0; innerVtxX < inner0-1; innerVtxX++)
771                         tessCoords.push_back(Vec3((float)(innerVtxX + 1) / (float)inner0,
772                                                                           (float)(innerVtxY + 1) / (float)inner1,
773                                                                           0.0f));
774
775                 return tessCoords;
776         }
777 }
778
779 static int referenceQuadNonPointModePrimitiveCount (SpacingMode spacingMode, int inner0, int inner1, int outer0, int outer1, int outer2, int outer3)
780 {
781         vector<Vec3> tessCoords;
782
783         if (inner0 == 1 || inner1 == 1)
784         {
785                 if (inner0 == 1 && inner1 == 1 && outer0 == 1 && outer1 == 1 && outer2 == 1 && outer3 == 1)
786                         return 2;
787                 else
788                         return referenceQuadNonPointModePrimitiveCount(spacingMode, inner0 > 1 ? inner0 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
789                                                                                                                                                 inner1 > 1 ? inner1 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
790                                                                                                                                                 outer0, outer1, outer2, outer3);
791         }
792         else
793                 return 2*(inner0-2)*(inner1-2) + 2*(inner0-2) + 2*(inner1-2) + outer0+outer1+outer2+outer3;
794 }
795
796 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec (e.g. it may not exactly hold that [uv] + (1.0f-[uv]) == 1.0f).
797 static vector<Vec3> generateReferenceIsolineTessCoords (int outer0, int outer1)
798 {
799         vector<Vec3> tessCoords;
800
801         for (int y = 0; y < outer0;             y++)
802         for (int x = 0; x < outer1+1;   x++)
803                 tessCoords.push_back(Vec3((float)x / (float)outer1,
804                                                                                                   (float)y / (float)outer0,
805                                                                                                   0.0f));
806
807         return tessCoords;
808 }
809
810 static int referenceIsolineNonPointModePrimitiveCount (int outer0, int outer1)
811 {
812         return outer0*outer1;
813 }
814
815 static void getClampedRoundedTriangleTessLevels (SpacingMode spacingMode, const float* innerSrc, const float* outerSrc, int* innerDst, int *outerDst)
816 {
817         innerDst[0] = getClampedRoundedTessLevel(spacingMode, innerSrc[0]);
818         for (int i = 0; i < 3; i++)
819                 outerDst[i] = getClampedRoundedTessLevel(spacingMode, outerSrc[i]);
820 }
821
822 static void getClampedRoundedQuadTessLevels (SpacingMode spacingMode, const float* innerSrc, const float* outerSrc, int* innerDst, int *outerDst)
823 {
824         for (int i = 0; i < 2; i++)
825                 innerDst[i] = getClampedRoundedTessLevel(spacingMode, innerSrc[i]);
826         for (int i = 0; i < 4; i++)
827                 outerDst[i] = getClampedRoundedTessLevel(spacingMode, outerSrc[i]);
828 }
829
830 static void getClampedRoundedIsolineTessLevels (SpacingMode spacingMode, const float* outerSrc, int* outerDst)
831 {
832         outerDst[0] = getClampedRoundedTessLevel(SPACINGMODE_EQUAL,     outerSrc[0]);
833         outerDst[1] = getClampedRoundedTessLevel(spacingMode,           outerSrc[1]);
834 }
835
836 static inline bool isPatchDiscarded (TessPrimitiveType primitiveType, const float* outerLevels)
837 {
838         const int numOuterLevels = numOuterTessellationLevels(primitiveType);
839         for (int i = 0; i < numOuterLevels; i++)
840                 if (outerLevels[i] <= 0.0f)
841                         return true;
842         return false;
843 }
844
845 static vector<Vec3> generateReferenceTessCoords (TessPrimitiveType primitiveType, SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)
846 {
847         if (isPatchDiscarded(primitiveType, outerLevels))
848                 return vector<Vec3>();
849
850         switch (primitiveType)
851         {
852                 case TESSPRIMITIVETYPE_TRIANGLES:
853                 {
854                         int inner;
855                         int outer[3];
856                         getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
857
858                         if (spacingMode != SPACINGMODE_EQUAL)
859                         {
860                                 // \note For fractional spacing modes, exact results are implementation-defined except in special cases.
861                                 DE_ASSERT(de::abs(innerLevels[0] - (float)inner) < 0.001f);
862                                 for (int i = 0; i < 3; i++)
863                                         DE_ASSERT(de::abs(outerLevels[i] - (float)outer[i]) < 0.001f);
864                                 DE_ASSERT(inner > 1 || (outer[0] == 1 && outer[1] == 1 && outer[2] == 1));
865                         }
866
867                         return generateReferenceTriangleTessCoords(spacingMode, inner, outer[0], outer[1], outer[2]);
868                 }
869
870                 case TESSPRIMITIVETYPE_QUADS:
871                 {
872                         int inner[2];
873                         int outer[4];
874                         getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
875
876                         if (spacingMode != SPACINGMODE_EQUAL)
877                         {
878                                 // \note For fractional spacing modes, exact results are implementation-defined except in special cases.
879                                 for (int i = 0; i < 2; i++)
880                                         DE_ASSERT(de::abs(innerLevels[i] - (float)inner[i]) < 0.001f);
881                                 for (int i = 0; i < 4; i++)
882                                         DE_ASSERT(de::abs(outerLevels[i] - (float)outer[i]) < 0.001f);
883
884                                 DE_ASSERT((inner[0] > 1 && inner[1] > 1) || (inner[0] == 1 && inner[1] == 1 && outer[0] == 1 && outer[1] == 1 && outer[2] == 1 && outer[3] == 1));
885                         }
886
887                         return generateReferenceQuadTessCoords(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]);
888                 }
889
890                 case TESSPRIMITIVETYPE_ISOLINES:
891                 {
892                         int outer[2];
893                         getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
894
895                         if (spacingMode != SPACINGMODE_EQUAL)
896                         {
897                                 // \note For fractional spacing modes, exact results are implementation-defined except in special cases.
898                                 DE_ASSERT(de::abs(outerLevels[1] - (float)outer[1]) < 0.001f);
899                         }
900
901                         return generateReferenceIsolineTessCoords(outer[0], outer[1]);
902                 }
903
904                 default:
905                         DE_ASSERT(false);
906                         return vector<Vec3>();
907         }
908 }
909
910 static int referencePointModePrimitiveCount (TessPrimitiveType primitiveType, SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)
911 {
912         if (isPatchDiscarded(primitiveType, outerLevels))
913                 return 0;
914
915         switch (primitiveType)
916         {
917                 case TESSPRIMITIVETYPE_TRIANGLES:
918                 {
919                         int inner;
920                         int outer[3];
921                         getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
922                         return (int)generateReferenceTriangleTessCoords(spacingMode, inner, outer[0], outer[1], outer[2]).size();
923                 }
924
925                 case TESSPRIMITIVETYPE_QUADS:
926                 {
927                         int inner[2];
928                         int outer[4];
929                         getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
930                         return (int)generateReferenceQuadTessCoords(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]).size();
931                 }
932
933                 case TESSPRIMITIVETYPE_ISOLINES:
934                 {
935                         int outer[2];
936                         getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
937                         return (int)generateReferenceIsolineTessCoords(outer[0], outer[1]).size();
938                 }
939
940                 default:
941                         DE_ASSERT(false);
942                         return -1;
943         }
944 }
945
946 static int referenceNonPointModePrimitiveCount (TessPrimitiveType primitiveType, SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)
947 {
948         if (isPatchDiscarded(primitiveType, outerLevels))
949                 return 0;
950
951         switch (primitiveType)
952         {
953                 case TESSPRIMITIVETYPE_TRIANGLES:
954                 {
955                         int inner;
956                         int outer[3];
957                         getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
958                         return referenceTriangleNonPointModePrimitiveCount(spacingMode, inner, outer[0], outer[1], outer[2]);
959                 }
960
961                 case TESSPRIMITIVETYPE_QUADS:
962                 {
963                         int inner[2];
964                         int outer[4];
965                         getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
966                         return referenceQuadNonPointModePrimitiveCount(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]);
967                 }
968
969                 case TESSPRIMITIVETYPE_ISOLINES:
970                 {
971                         int outer[2];
972                         getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
973                         return referenceIsolineNonPointModePrimitiveCount(outer[0], outer[1]);
974                 }
975
976                 default:
977                         DE_ASSERT(false);
978                         return -1;
979         }
980 }
981
982 static int referencePrimitiveCount (TessPrimitiveType primitiveType, SpacingMode spacingMode, bool usePointMode, const float* innerLevels, const float* outerLevels)
983 {
984         return usePointMode ? referencePointModePrimitiveCount          (primitiveType, spacingMode, innerLevels, outerLevels)
985                                                 : referenceNonPointModePrimitiveCount   (primitiveType, spacingMode, innerLevels, outerLevels);
986 }
987
988 static int referenceVertexCount (TessPrimitiveType primitiveType, SpacingMode spacingMode, bool usePointMode, const float* innerLevels, const float* outerLevels)
989 {
990         return referencePrimitiveCount(primitiveType, spacingMode, usePointMode, innerLevels, outerLevels)
991                    * numVerticesPerPrimitive(outputPrimitiveTypeGL(primitiveType, usePointMode));
992 }
993
994 //! Helper for calling referenceVertexCount multiple times with different tessellation levels.
995 //! \note Levels contains inner and outer levels, per patch, in order IIOOOO. The full 6 levels must always be present, irrespective of primitiveType.
996 static int multiplePatchReferenceVertexCount (TessPrimitiveType primitiveType, SpacingMode spacingMode, bool usePointMode, const float* levels, int numPatches)
997 {
998         int result = 0;
999         for (int patchNdx = 0; patchNdx < numPatches; patchNdx++)
1000                 result += referenceVertexCount(primitiveType, spacingMode, usePointMode, &levels[6*patchNdx + 0], &levels[6*patchNdx + 2]);
1001         return result;
1002 }
1003
1004 vector<float> generateRandomPatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel, de::Random& rnd)
1005 {
1006         vector<float> tessLevels(numPatches*6);
1007
1008         for (int patchNdx = 0; patchNdx < numPatches; patchNdx++)
1009         {
1010                 float* const inner = &tessLevels[patchNdx*6 + 0];
1011                 float* const outer = &tessLevels[patchNdx*6 + 2];
1012
1013                 for (int j = 0; j < 2; j++)
1014                         inner[j] = rnd.getFloat(1.0f, 62.0f);
1015                 for (int j = 0; j < 4; j++)
1016                         outer[j] = j == constantOuterLevelIndex ? constantOuterLevel : rnd.getFloat(1.0f, 62.0f);
1017         }
1018
1019         return tessLevels;
1020 }
1021
1022 static inline void drawPoint (tcu::Surface& dst, int centerX, int centerY, const tcu::RGBA& color, int size)
1023 {
1024         const int width         = dst.getWidth();
1025         const int height        = dst.getHeight();
1026         DE_ASSERT(de::inBounds(centerX, 0, width) && de::inBounds(centerY, 0, height));
1027         DE_ASSERT(size > 0);
1028
1029         for (int yOff = -((size-1)/2); yOff <= size/2; yOff++)
1030         for (int xOff = -((size-1)/2); xOff <= size/2; xOff++)
1031         {
1032                 const int pixX = centerX + xOff;
1033                 const int pixY = centerY + yOff;
1034                 if (de::inBounds(pixX, 0, width) && de::inBounds(pixY, 0, height))
1035                         dst.setPixel(pixX, pixY, color);
1036         }
1037 }
1038
1039 static void drawTessCoordPoint (tcu::Surface& dst, TessPrimitiveType primitiveType, const Vec3& pt, const tcu::RGBA& color, int size)
1040 {
1041         // \note These coordinates should match the description in the log message in TessCoordCase::iterate.
1042
1043         static const Vec2 triangleCorners[3] =
1044         {
1045                 Vec2(0.95f, 0.95f),
1046                 Vec2(0.5f,  0.95f - 0.9f*deFloatSqrt(3.0f/4.0f)),
1047                 Vec2(0.05f, 0.95f)
1048         };
1049
1050         static const float quadIsolineLDRU[4] =
1051         {
1052                 0.1f, 0.9f, 0.9f, 0.1f
1053         };
1054
1055         const Vec2 dstPos = primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? pt.x()*triangleCorners[0]
1056                                                                                                                                          + pt.y()*triangleCorners[1]
1057                                                                                                                                          + pt.z()*triangleCorners[2]
1058
1059                                           : primitiveType == TESSPRIMITIVETYPE_QUADS ||
1060                                                 primitiveType == TESSPRIMITIVETYPE_ISOLINES ? Vec2((1.0f - pt.x())*quadIsolineLDRU[0] + pt.x()*quadIsolineLDRU[2],
1061                                                                                                                                                    (1.0f - pt.y())*quadIsolineLDRU[1] + pt.y()*quadIsolineLDRU[3])
1062
1063                                           : Vec2(-1.0f);
1064
1065         drawPoint(dst, (int)(dstPos.x() * (float)dst.getWidth()), (int)(dstPos.y() * (float)dst.getHeight()), color, size);
1066 }
1067
1068 static void drawTessCoordVisualization (tcu::Surface& dst, TessPrimitiveType primitiveType, const vector<Vec3>& coords)
1069 {
1070         const int               imageWidth              = 256;
1071         const int               imageHeight             = 256;
1072         dst.setSize(imageWidth, imageHeight);
1073
1074         tcu::clear(dst.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1075
1076         for (int i = 0; i < (int)coords.size(); i++)
1077                 drawTessCoordPoint(dst, primitiveType, coords[i], tcu::RGBA::white(), 2);
1078 }
1079
1080 static int binarySearchFirstVec3WithXAtLeast (const vector<Vec3>& sorted, float x)
1081 {
1082         const Vec3 ref(x, 0.0f, 0.0f);
1083         const vector<Vec3>::const_iterator first = std::lower_bound(sorted.begin(), sorted.end(), ref, vec3XLessThan);
1084         if (first == sorted.end())
1085                 return -1;
1086         return (int)std::distance(sorted.begin(), first);
1087 }
1088
1089 template <typename T, typename P>
1090 static vector<T> sorted (const vector<T>& unsorted, P pred)
1091 {
1092         vector<T> result = unsorted;
1093         std::sort(result.begin(), result.end(), pred);
1094         return result;
1095 }
1096
1097 template <typename T>
1098 static vector<T> sorted (const vector<T>& unsorted)
1099 {
1100         vector<T> result = unsorted;
1101         std::sort(result.begin(), result.end());
1102         return result;
1103 }
1104
1105 // Check that all points in subset are (approximately) present also in superset.
1106 static bool oneWayComparePointSets (TestLog&                            log,
1107                                                                         tcu::Surface&                   errorDst,
1108                                                                         TessPrimitiveType               primitiveType,
1109                                                                         const vector<Vec3>&             subset,
1110                                                                         const vector<Vec3>&             superset,
1111                                                                         const char*                             subsetName,
1112                                                                         const char*                             supersetName,
1113                                                                         const tcu::RGBA&                errorColor)
1114 {
1115         const vector<Vec3>      supersetSorted                  = sorted(superset, vec3XLessThan);
1116         const float                     epsilon                                 = 0.01f;
1117         const int                       maxNumFailurePrints             = 5;
1118         int                                     numFailuresDetected             = 0;
1119
1120         for (int subNdx = 0; subNdx < (int)subset.size(); subNdx++)
1121         {
1122                 const Vec3& subPt = subset[subNdx];
1123
1124                 bool matchFound = false;
1125
1126                 {
1127                         // Binary search the index of the first point in supersetSorted with x in the [subPt.x() - epsilon, subPt.x() + epsilon] range.
1128                         const Vec3      matchMin                        = subPt - epsilon;
1129                         const Vec3      matchMax                        = subPt + epsilon;
1130                         int                     firstCandidateNdx       = binarySearchFirstVec3WithXAtLeast(supersetSorted, matchMin.x());
1131
1132                         if (firstCandidateNdx >= 0)
1133                         {
1134                                 // Compare subPt to all points in supersetSorted with x in the [subPt.x() - epsilon, subPt.x() + epsilon] range.
1135                                 for (int superNdx = firstCandidateNdx; superNdx < (int)supersetSorted.size() && supersetSorted[superNdx].x() <= matchMax.x(); superNdx++)
1136                                 {
1137                                         const Vec3& superPt = supersetSorted[superNdx];
1138
1139                                         if (tcu::boolAll(tcu::greaterThanEqual  (superPt, matchMin)) &&
1140                                                 tcu::boolAll(tcu::lessThanEqual         (superPt, matchMax)))
1141                                         {
1142                                                 matchFound = true;
1143                                                 break;
1144                                         }
1145                                 }
1146                         }
1147                 }
1148
1149                 if (!matchFound)
1150                 {
1151                         numFailuresDetected++;
1152                         if (numFailuresDetected < maxNumFailurePrints)
1153                                 log << TestLog::Message << "Failure: no matching " << supersetName << " point found for " << subsetName << " point " << subPt << TestLog::EndMessage;
1154                         else if (numFailuresDetected == maxNumFailurePrints)
1155                                 log << TestLog::Message << "Note: More errors follow" << TestLog::EndMessage;
1156
1157                         drawTessCoordPoint(errorDst, primitiveType, subPt, errorColor, 4);
1158                 }
1159         }
1160
1161         return numFailuresDetected == 0;
1162 }
1163
1164 static bool compareTessCoords (TestLog& log, TessPrimitiveType primitiveType, const vector<Vec3>& refCoords, const vector<Vec3>& resCoords)
1165 {
1166         tcu::Surface    refVisual;
1167         tcu::Surface    resVisual;
1168         bool                    success = true;
1169
1170         drawTessCoordVisualization(refVisual, primitiveType, refCoords);
1171         drawTessCoordVisualization(resVisual, primitiveType, resCoords);
1172
1173         // Check that all points in reference also exist in result.
1174         success = oneWayComparePointSets(log, refVisual, primitiveType, refCoords, resCoords, "reference", "result", tcu::RGBA::blue()) && success;
1175         // Check that all points in result also exist in reference.
1176         success = oneWayComparePointSets(log, resVisual, primitiveType, resCoords, refCoords, "result", "reference", tcu::RGBA::red()) && success;
1177
1178         if (!success)
1179         {
1180                 log << TestLog::Message << "Note: in the following reference visualization, points that are missing in result point set are blue (if any)" << TestLog::EndMessage
1181                         << TestLog::Image("RefTessCoordVisualization", "Reference tessCoord visualization", refVisual)
1182                         << TestLog::Message << "Note: in the following result visualization, points that are missing in reference point set are red (if any)" << TestLog::EndMessage;
1183         }
1184
1185         log << TestLog::Image("ResTessCoordVisualization", "Result tessCoord visualization", resVisual);
1186
1187         return success;
1188 }
1189
1190 namespace VerifyFractionalSpacingSingleInternal
1191 {
1192
1193 struct Segment
1194 {
1195         int             index; //!< Index of left coordinate in sortedXCoords.
1196         float   length;
1197         Segment (void)                                          : index(-1),            length(-1.0f)   {}
1198         Segment (int index_, float length_)     : index(index_),        length(length_) {}
1199
1200         static vector<float> lengths (const vector<Segment>& segments) { return members(segments, &Segment::length); }
1201 };
1202
1203 }
1204
1205 /*--------------------------------------------------------------------*//*!
1206  * \brief Verify fractional spacing conditions for a single line
1207  *
1208  * Verify that the splitting of an edge (resulting from e.g. an isoline
1209  * with outer levels { 1.0, tessLevel }) with a given fractional spacing
1210  * mode fulfills certain conditions given in the spec.
1211  *
1212  * Note that some conditions can't be checked from just one line
1213  * (specifically, that the additional segment decreases monotonically
1214  * length and the requirement that the additional segments be placed
1215  * identically for identical values of clamped level).
1216  *
1217  * Therefore, the function stores some values to additionalSegmentLengthDst
1218  * and additionalSegmentLocationDst that can later be given to
1219  * verifyFractionalSpacingMultiple(). A negative value in length means that
1220  * no additional segments are present, i.e. there's just one segment.
1221  * A negative value in location means that the value wasn't determinable,
1222  * i.e. all segments had same length.
1223  * The values are not stored if false is returned.
1224  *//*--------------------------------------------------------------------*/
1225 static bool verifyFractionalSpacingSingle (TestLog& log, SpacingMode spacingMode, float tessLevel, const vector<float>& coords, float& additionalSegmentLengthDst, int& additionalSegmentLocationDst)
1226 {
1227         using namespace VerifyFractionalSpacingSingleInternal;
1228
1229         DE_ASSERT(spacingMode == SPACINGMODE_FRACTIONAL_ODD || spacingMode == SPACINGMODE_FRACTIONAL_EVEN);
1230
1231         const float                             clampedLevel    = getClampedTessLevel(spacingMode, tessLevel);
1232         const int                               finalLevel              = getRoundedTessLevel(spacingMode, clampedLevel);
1233         const vector<float>             sortedCoords    = sorted(coords);
1234         string                                  failNote                = "Note: tessellation level is " + de::toString(tessLevel) + "\nNote: sorted coordinates are:\n    " + containerStr(sortedCoords);
1235
1236         if ((int)coords.size() != finalLevel + 1)
1237         {
1238                 log << TestLog::Message << "Failure: number of vertices is " << coords.size() << "; expected " << finalLevel + 1
1239                         << " (clamped tessellation level is " << clampedLevel << ")"
1240                         << "; final level (clamped level rounded up to " << (spacingMode == SPACINGMODE_FRACTIONAL_EVEN ? "even" : "odd") << ") is " << finalLevel
1241                         << " and should equal the number of segments, i.e. number of vertices minus 1" << TestLog::EndMessage
1242                         << TestLog::Message << failNote << TestLog::EndMessage;
1243                 return false;
1244         }
1245
1246         if (sortedCoords[0] != 0.0f || sortedCoords.back() != 1.0f)
1247         {
1248                 log << TestLog::Message << "Failure: smallest coordinate should be 0.0 and biggest should be 1.0" << TestLog::EndMessage
1249                         << TestLog::Message << failNote << TestLog::EndMessage;
1250                 return false;
1251         }
1252
1253         {
1254                 vector<Segment> segments(finalLevel);
1255                 for (int i = 0; i < finalLevel; i++)
1256                         segments[i] = Segment(i, sortedCoords[i+1] - sortedCoords[i]);
1257
1258                 failNote += "\nNote: segment lengths are, from left to right:\n    " + containerStr(Segment::lengths(segments));
1259
1260                 {
1261                         // Divide segments to two different groups based on length.
1262
1263                         vector<Segment> segmentsA;
1264                         vector<Segment> segmentsB;
1265                         segmentsA.push_back(segments[0]);
1266
1267                         for (int segNdx = 1; segNdx < (int)segments.size(); segNdx++)
1268                         {
1269                                 const float             epsilon         = 0.001f;
1270                                 const Segment&  seg                     = segments[segNdx];
1271
1272                                 if (de::abs(seg.length - segmentsA[0].length) < epsilon)
1273                                         segmentsA.push_back(seg);
1274                                 else if (segmentsB.empty() || de::abs(seg.length - segmentsB[0].length) < epsilon)
1275                                         segmentsB.push_back(seg);
1276                                 else
1277                                 {
1278                                         log << TestLog::Message << "Failure: couldn't divide segments to 2 groups by length; "
1279                                                                                         << "e.g. segment of length " << seg.length << " isn't approximately equal to either "
1280                                                                                         << segmentsA[0].length << " or " << segmentsB[0].length << TestLog::EndMessage
1281                                                                                         << TestLog::Message << failNote << TestLog::EndMessage;
1282                                         return false;
1283                                 }
1284                         }
1285
1286                         if (clampedLevel == (float)finalLevel)
1287                         {
1288                                 // All segments should be of equal length.
1289                                 if (!segmentsA.empty() && !segmentsB.empty())
1290                                 {
1291                                         log << TestLog::Message << "Failure: clamped and final tessellation level are equal, but not all segments are of equal length." << TestLog::EndMessage
1292                                                 << TestLog::Message << failNote << TestLog::EndMessage;
1293                                         return false;
1294                                 }
1295                         }
1296
1297                         if (segmentsA.empty() || segmentsB.empty()) // All segments have same length. This is ok.
1298                         {
1299                                 additionalSegmentLengthDst              = segments.size() == 1 ? -1.0f : segments[0].length;
1300                                 additionalSegmentLocationDst    = -1;
1301                                 return true;
1302                         }
1303
1304                         if (segmentsA.size() != 2 && segmentsB.size() != 2)
1305                         {
1306                                 log << TestLog::Message << "Failure: when dividing the segments to 2 groups by length, neither of the two groups has exactly 2 or 0 segments in it" << TestLog::EndMessage
1307                                         << TestLog::Message << failNote << TestLog::EndMessage;
1308                                 return false;
1309                         }
1310
1311                         // For convenience, arrange so that the 2-segment group is segmentsB.
1312                         if (segmentsB.size() != 2)
1313                                 std::swap(segmentsA, segmentsB);
1314
1315                         // \note For 4-segment lines both segmentsA and segmentsB have 2 segments each.
1316                         //               Thus, we can't be sure which ones were meant as the additional segments.
1317                         //               We give the benefit of the doubt by assuming that they're the shorter
1318                         //               ones (as they should).
1319
1320                         if (segmentsA.size() != 2)
1321                         {
1322                                 if (segmentsB[0].length > segmentsA[0].length + 0.001f)
1323                                 {
1324                                         log << TestLog::Message << "Failure: the two additional segments are longer than the other segments" << TestLog::EndMessage
1325                                                 << TestLog::Message << failNote << TestLog::EndMessage;
1326                                         return false;
1327                                 }
1328                         }
1329                         else
1330                         {
1331                                 // We have 2 segmentsA and 2 segmentsB, ensure segmentsB has the shorter lengths
1332                                 if (segmentsB[0].length > segmentsA[0].length)
1333                                         std::swap(segmentsA, segmentsB);
1334                         }
1335
1336                         // Check that the additional segments are placed symmetrically.
1337                         if (segmentsB[0].index + segmentsB[1].index + 1 != (int)segments.size())
1338                         {
1339                                 log << TestLog::Message << "Failure: the two additional segments aren't placed symmetrically; "
1340                                                                                 << "one is at index " << segmentsB[0].index << " and other is at index " << segmentsB[1].index
1341                                                                                 << " (note: the two indexes should sum to " << (int)segments.size()-1 << ", i.e. numberOfSegments-1)" << TestLog::EndMessage
1342                                         << TestLog::Message << failNote << TestLog::EndMessage;
1343                                 return false;
1344                         }
1345
1346                         additionalSegmentLengthDst = segmentsB[0].length;
1347                         if (segmentsA.size() != 2)
1348                                 additionalSegmentLocationDst = de::min(segmentsB[0].index, segmentsB[1].index);
1349                         else
1350                                 additionalSegmentLocationDst = segmentsB[0].length < segmentsA[0].length - 0.001f ? de::min(segmentsB[0].index, segmentsB[1].index)
1351                                                                                          : -1; // \note -1 when can't reliably decide which ones are the additional segments, a or b.
1352
1353                         return true;
1354                 }
1355         }
1356 }
1357
1358 namespace VerifyFractionalSpacingMultipleInternal
1359 {
1360
1361 struct LineData
1362 {
1363         float   tessLevel;
1364         float   additionalSegmentLength;
1365         int             additionalSegmentLocation;
1366         LineData (float lev, float len, int loc) : tessLevel(lev), additionalSegmentLength(len), additionalSegmentLocation(loc) {}
1367 };
1368
1369 }
1370
1371 /*--------------------------------------------------------------------*//*!
1372  * \brief Verify fractional spacing conditions between multiple lines
1373  *
1374  * Verify the fractional spacing conditions that are not checked in
1375  * verifyFractionalSpacingSingle(). Uses values given by said function
1376  * as parameters, in addition to the spacing mode and tessellation level.
1377  *//*--------------------------------------------------------------------*/
1378 static bool verifyFractionalSpacingMultiple (TestLog& log, SpacingMode spacingMode, const vector<float>& tessLevels, const vector<float>& additionalSegmentLengths, const vector<int>& additionalSegmentLocations)
1379 {
1380         using namespace VerifyFractionalSpacingMultipleInternal;
1381
1382         DE_ASSERT(spacingMode == SPACINGMODE_FRACTIONAL_ODD || spacingMode == SPACINGMODE_FRACTIONAL_EVEN);
1383         DE_ASSERT(tessLevels.size() == additionalSegmentLengths.size() &&
1384                           tessLevels.size() == additionalSegmentLocations.size());
1385
1386         vector<LineData> lineDatas;
1387
1388         for (int i = 0; i < (int)tessLevels.size(); i++)
1389                 lineDatas.push_back(LineData(tessLevels[i], additionalSegmentLengths[i], additionalSegmentLocations[i]));
1390
1391         {
1392                 const vector<LineData> lineDatasSortedByLevel = sorted(lineDatas, memberPred<std::less>(&LineData::tessLevel));
1393
1394                 // Check that lines with identical clamped tessellation levels have identical additionalSegmentLocation.
1395
1396                 for (int lineNdx = 1; lineNdx < (int)lineDatasSortedByLevel.size(); lineNdx++)
1397                 {
1398                         const LineData& curData         = lineDatasSortedByLevel[lineNdx];
1399                         const LineData& prevData        = lineDatasSortedByLevel[lineNdx-1];
1400
1401                         if (curData.additionalSegmentLocation < 0 || prevData.additionalSegmentLocation < 0)
1402                                 continue; // Unknown locations, skip.
1403
1404                         if (getClampedTessLevel(spacingMode, curData.tessLevel) == getClampedTessLevel(spacingMode, prevData.tessLevel) &&
1405                                 curData.additionalSegmentLocation != prevData.additionalSegmentLocation)
1406                         {
1407                                 log << TestLog::Message << "Failure: additional segments not located identically for two edges with identical clamped tessellation levels" << TestLog::EndMessage
1408                                         << TestLog::Message << "Note: tessellation levels are " << curData.tessLevel << " and " << prevData.tessLevel
1409                                                                                 << " (clamped level " << getClampedTessLevel(spacingMode, curData.tessLevel) << ")"
1410                                                                                 << "; but first additional segments located at indices "
1411                                                                                 << curData.additionalSegmentLocation << " and " << prevData.additionalSegmentLocation << ", respectively" << TestLog::EndMessage;
1412                                 return false;
1413                         }
1414                 }
1415
1416                 // Check that, among lines with same clamped rounded tessellation level, additionalSegmentLength is monotonically decreasing with "clampedRoundedTessLevel - clampedTessLevel" (the "fraction").
1417
1418                 for (int lineNdx = 1; lineNdx < (int)lineDatasSortedByLevel.size(); lineNdx++)
1419                 {
1420                         const LineData&         curData                         = lineDatasSortedByLevel[lineNdx];
1421                         const LineData&         prevData                        = lineDatasSortedByLevel[lineNdx-1];
1422
1423                         if (curData.additionalSegmentLength < 0.0f || prevData.additionalSegmentLength < 0.0f)
1424                                 continue; // Unknown segment lengths, skip.
1425
1426                         const float                     curClampedLevel         = getClampedTessLevel(spacingMode, curData.tessLevel);
1427                         const float                     prevClampedLevel        = getClampedTessLevel(spacingMode, prevData.tessLevel);
1428                         const int                       curFinalLevel           = getRoundedTessLevel(spacingMode, curClampedLevel);
1429                         const int                       prevFinalLevel          = getRoundedTessLevel(spacingMode, prevClampedLevel);
1430
1431                         if (curFinalLevel != prevFinalLevel)
1432                                 continue;
1433
1434                         const float                     curFraction             = (float)curFinalLevel - curClampedLevel;
1435                         const float                     prevFraction    = (float)prevFinalLevel - prevClampedLevel;
1436
1437                         if (curData.additionalSegmentLength < prevData.additionalSegmentLength ||
1438                                 (curClampedLevel == prevClampedLevel && curData.additionalSegmentLength != prevData.additionalSegmentLength))
1439                         {
1440                                 log << TestLog::Message << "Failure: additional segment length isn't monotonically decreasing with the fraction <n> - <f>, among edges with same final tessellation level" << TestLog::EndMessage
1441                                         << TestLog::Message << "Note: <f> stands for the clamped tessellation level and <n> for the final (rounded and clamped) tessellation level" << TestLog::EndMessage
1442                                         << TestLog::Message << "Note: two edges have tessellation levels " << prevData.tessLevel << " and " << curData.tessLevel << " respectively"
1443                                                                                 << ", clamped " << prevClampedLevel << " and " << curClampedLevel << ", final " << prevFinalLevel << " and " << curFinalLevel
1444                                                                                 << "; fractions are " << prevFraction << " and " << curFraction
1445                                                                                 << ", but resulted in segment lengths " << prevData.additionalSegmentLength << " and " << curData.additionalSegmentLength << TestLog::EndMessage;
1446                                 return false;
1447                         }
1448                 }
1449         }
1450
1451         return true;
1452 }
1453
1454 //! Compare triangle sets, ignoring triangle order and vertex order within triangle, and possibly exclude some triangles too.
1455 template <typename IsTriangleRelevantT>
1456 static bool compareTriangleSets (const vector<Vec3>&                    coordsA,
1457                                                                  const vector<Vec3>&                    coordsB,
1458                                                                  TestLog&                                               log,
1459                                                                  const IsTriangleRelevantT&             isTriangleRelevant,
1460                                                                  const char*                                    ignoredTriangleDescription = DE_NULL)
1461 {
1462         typedef tcu::Vector<Vec3, 3>                                                    Triangle;
1463         typedef LexCompare<Triangle, 3, VecLexLessThan<3> >             TriangleLexLessThan;
1464         typedef std::set<Triangle, TriangleLexLessThan>                 TriangleSet;
1465
1466         DE_ASSERT(coordsA.size() % 3 == 0 && coordsB.size() % 3 == 0);
1467
1468         const int               numTrianglesA = (int)coordsA.size()/3;
1469         const int               numTrianglesB = (int)coordsB.size()/3;
1470         TriangleSet             trianglesA;
1471         TriangleSet             trianglesB;
1472
1473         for (int aOrB = 0; aOrB < 2; aOrB++)
1474         {
1475                 const vector<Vec3>&             coords                  = aOrB == 0 ? coordsA                   : coordsB;
1476                 const int                               numTriangles    = aOrB == 0 ? numTrianglesA             : numTrianglesB;
1477                 TriangleSet&                    triangles               = aOrB == 0 ? trianglesA                : trianglesB;
1478
1479                 for (int triNdx = 0; triNdx < numTriangles; triNdx++)
1480                 {
1481                         Triangle triangle(coords[3*triNdx + 0],
1482                                                           coords[3*triNdx + 1],
1483                                                           coords[3*triNdx + 2]);
1484
1485                         if (isTriangleRelevant(triangle.getPtr()))
1486                         {
1487                                 std::sort(triangle.getPtr(), triangle.getPtr()+3, VecLexLessThan<3>());
1488                                 triangles.insert(triangle);
1489                         }
1490                 }
1491         }
1492
1493         {
1494                 TriangleSet::const_iterator aIt = trianglesA.begin();
1495                 TriangleSet::const_iterator bIt = trianglesB.begin();
1496
1497                 while (aIt != trianglesA.end() || bIt != trianglesB.end())
1498                 {
1499                         const bool aEnd = aIt == trianglesA.end();
1500                         const bool bEnd = bIt == trianglesB.end();
1501
1502                         if (aEnd || bEnd || *aIt != *bIt)
1503                         {
1504                                 log << TestLog::Message << "Failure: triangle sets in two cases are not equal (when ignoring triangle and vertex order"
1505                                         << (ignoredTriangleDescription == DE_NULL ? "" : string() + ", and " + ignoredTriangleDescription) << ")" << TestLog::EndMessage;
1506
1507                                 if (!aEnd && (bEnd || TriangleLexLessThan()(*aIt, *bIt)))
1508                                         log << TestLog::Message << "Note: e.g. triangle " << *aIt << " exists for first case but not for second" << TestLog::EndMessage;
1509                                 else
1510                                         log << TestLog::Message << "Note: e.g. triangle " << *bIt << " exists for second case but not for first" << TestLog::EndMessage;
1511
1512                                 return false;
1513                         }
1514
1515                         ++aIt;
1516                         ++bIt;
1517                 }
1518
1519                 return true;
1520         }
1521 }
1522
1523 static bool compareTriangleSets (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, TestLog& log)
1524 {
1525         return compareTriangleSets(coordsA, coordsB, log, ConstantUnaryPredicate<const Vec3*, true>());
1526 }
1527
1528 static void checkExtensionSupport (Context& context, const char* extName)
1529 {
1530         if (!context.getContextInfo().isExtensionSupported(extName))
1531                 throw tcu::NotSupportedError(string(extName) + " not supported");
1532 }
1533
1534 static void checkTessellationSupport (Context& context)
1535 {
1536         checkExtensionSupport(context, "GL_EXT_tessellation_shader");
1537 }
1538
1539 // Draw primitives with shared edges and check that no cracks are visible at the shared edges.
1540 class CommonEdgeCase : public TestCase
1541 {
1542 public:
1543         enum CaseType
1544         {
1545                 CASETYPE_BASIC = 0,             //!< Order patch vertices such that when two patches share a vertex, it's at the same index for both.
1546                 CASETYPE_PRECISE,               //!< Vertex indices don't match like for CASETYPE_BASIC, but other measures are taken, using the 'precise' qualifier.
1547
1548                 CASETYPE_LAST
1549         };
1550
1551         CommonEdgeCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing, CaseType caseType)
1552                 : TestCase                      (context, name, description)
1553                 , m_primitiveType       (primitiveType)
1554                 , m_spacing                     (spacing)
1555                 , m_caseType            (caseType)
1556         {
1557                 DE_ASSERT(m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES || m_primitiveType == TESSPRIMITIVETYPE_QUADS);
1558         }
1559
1560         void                                                    init            (void);
1561         void                                                    deinit          (void);
1562         IterateResult                                   iterate         (void);
1563
1564 private:
1565         static const int                                RENDER_SIZE = 256;
1566
1567         const TessPrimitiveType                 m_primitiveType;
1568         const SpacingMode                               m_spacing;
1569         const CaseType                                  m_caseType;
1570
1571         SharedPtr<const ShaderProgram>  m_program;
1572 };
1573
1574 void CommonEdgeCase::init (void)
1575 {
1576         checkTessellationSupport(m_context);
1577
1578         if (m_caseType == CASETYPE_PRECISE)
1579                 checkExtensionSupport(m_context, "GL_EXT_gpu_shader5");
1580
1581         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
1582
1583         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
1584                         << glu::VertexSource                                    ("#version 310 es\n"
1585                                                                                                          "\n"
1586                                                                                                          "in highp vec2 in_v_position;\n"
1587                                                                                                          "in highp float in_v_tessParam;\n"
1588                                                                                                          "\n"
1589                                                                                                          "out highp vec2 in_tc_position;\n"
1590                                                                                                          "out highp float in_tc_tessParam;\n"
1591                                                                                                          "\n"
1592                                                                                                          "void main (void)\n"
1593                                                                                                          "{\n"
1594                                                                                                          "      in_tc_position = in_v_position;\n"
1595                                                                                                          "      in_tc_tessParam = in_v_tessParam;\n"
1596                                                                                                          "}\n")
1597
1598                         << glu::TessellationControlSource               ("#version 310 es\n"
1599                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
1600                                                                                                          + string(m_caseType == CASETYPE_PRECISE ? "#extension GL_EXT_gpu_shader5 : require\n" : "") +
1601                                                                                                          "\n"
1602                                                                                                          "layout (vertices = " + string(m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "3" : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? "4" : DE_NULL) + ") out;\n"
1603                                                                                                          "\n"
1604                                                                                                          "in highp vec2 in_tc_position[];\n"
1605                                                                                                          "in highp float in_tc_tessParam[];\n"
1606                                                                                                          "\n"
1607                                                                                                          "out highp vec2 in_te_position[];\n"
1608                                                                                                          "\n"
1609                                                                                                          + (m_caseType == CASETYPE_PRECISE ? "precise gl_TessLevelOuter;\n\n" : "") +
1610                                                                                                          "void main (void)\n"
1611                                                                                                          "{\n"
1612                                                                                                          "      in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
1613                                                                                                          "\n"
1614                                                                                                          "      gl_TessLevelInner[0] = 5.0;\n"
1615                                                                                                          "      gl_TessLevelInner[1] = 5.0;\n"
1616                                                                                                          "\n"
1617                                                                                                          + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
1618                                                                                                                 "       gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[2]);\n"
1619                                                                                                                 "       gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[0]);\n"
1620                                                                                                                 "       gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[1]);\n"
1621                                                                                                           : m_primitiveType == TESSPRIMITIVETYPE_QUADS ?
1622                                                                                                                 "       gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[2]);\n"
1623                                                                                                                 "       gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[0]);\n"
1624                                                                                                                 "       gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[3] + in_tc_tessParam[1]);\n"
1625                                                                                                                 "       gl_TessLevelOuter[3] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[3]);\n"
1626                                                                                                           : DE_NULL) +
1627                                                                                                          "}\n")
1628
1629                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
1630                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
1631                                                                                                          + string(m_caseType == CASETYPE_PRECISE ? "#extension GL_EXT_gpu_shader5 : require\n" : "") +
1632                                                                                                          "\n"
1633                                                                                                          + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing) +
1634                                                                                                          "\n"
1635                                                                                                          "in highp vec2 in_te_position[];\n"
1636                                                                                                          "\n"
1637                                                                                                          "out mediump vec4 in_f_color;\n"
1638                                                                                                          "\n"
1639                                                                                                          + (m_caseType == CASETYPE_PRECISE ? "precise gl_Position;\n\n" : "") +
1640                                                                                                          "void main (void)\n"
1641                                                                                                          "{\n"
1642                                                                                                          + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
1643                                                                                                                 "       highp vec2 pos = gl_TessCoord.x*in_te_position[0] + gl_TessCoord.y*in_te_position[1] + gl_TessCoord.z*in_te_position[2];\n"
1644                                                                                                                 "\n"
1645                                                                                                                 "       highp float f = sqrt(3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z))) * 0.5 + 0.5;\n"
1646                                                                                                                 "       in_f_color = vec4(gl_TessCoord*f, 1.0);\n"
1647                                                                                                           : m_primitiveType == TESSPRIMITIVETYPE_QUADS ?
1648                                                                                                             string()
1649                                                                                                                 + (m_caseType == CASETYPE_BASIC ?
1650                                                                                                                         "       highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[0]\n"
1651                                                                                                                         "                      + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[1]\n"
1652                                                                                                                         "                      + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[2]\n"
1653                                                                                                                         "                      + (    gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[3];\n"
1654                                                                                                                  : m_caseType == CASETYPE_PRECISE ?
1655                                                                                                                         "       highp vec2 a = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[0];\n"
1656                                                                                                                         "       highp vec2 b = (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[1];\n"
1657                                                                                                                         "       highp vec2 c = (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[2];\n"
1658                                                                                                                         "       highp vec2 d = (    gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[3];\n"
1659                                                                                                                         "       highp vec2 pos = a+b+c+d;\n"
1660                                                                                                                  : DE_NULL) +
1661                                                                                                                 "\n"
1662                                                                                                                 "       highp float f = sqrt(1.0 - 2.0 * max(abs(gl_TessCoord.x - 0.5), abs(gl_TessCoord.y - 0.5)))*0.5 + 0.5;\n"
1663                                                                                                                 "       in_f_color = vec4(0.1, gl_TessCoord.xy*f, 1.0);\n"
1664                                                                                                           : DE_NULL) +
1665                                                                                                          "\n"
1666                                                                                                          "      // Offset the position slightly, based on the parity of the bits in the float representation.\n"
1667                                                                                                          "      // This is done to detect possible small differences in edge vertex positions between patches.\n"
1668                                                                                                          "      uvec2 bits = floatBitsToUint(pos);\n"
1669                                                                                                          "      uint numBits = 0u;\n"
1670                                                                                                          "      for (uint i = 0u; i < 32u; i++)\n"
1671                                                                                                          "              numBits += ((bits[0] >> i) & 1u) + ((bits[1] >> i) & 1u);\n"
1672                                                                                                          "      pos += float(numBits&1u)*0.04;\n"
1673                                                                                                          "\n"
1674                                                                                                          "      gl_Position = vec4(pos, 0.0, 1.0);\n"
1675                                                                                                          "}\n")
1676
1677                         << glu::FragmentSource                                  ("#version 310 es\n"
1678                                                                                                          "\n"
1679                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
1680                                                                                                          "\n"
1681                                                                                                          "in mediump vec4 in_f_color;\n"
1682                                                                                                          "\n"
1683                                                                                                          "void main (void)\n"
1684                                                                                                          "{\n"
1685                                                                                                          "      o_color = in_f_color;\n"
1686                                                                                                          "}\n")));
1687
1688         m_testCtx.getLog() << *m_program;
1689         if (!m_program->isOk())
1690                 TCU_FAIL("Program compilation failed");
1691 }
1692
1693 void CommonEdgeCase::deinit (void)
1694 {
1695         m_program.clear();
1696 }
1697
1698 CommonEdgeCase::IterateResult CommonEdgeCase::iterate (void)
1699 {
1700         TestLog&                                        log                                             = m_testCtx.getLog();
1701         const RenderContext&            renderCtx                               = m_context.getRenderContext();
1702         const RandomViewport            viewport                                (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
1703         const deUint32                          programGL                               = m_program->getProgram();
1704         const glw::Functions&           gl                                              = renderCtx.getFunctions();
1705
1706         const int                                       gridWidth                               = 4;
1707         const int                                       gridHeight                              = 4;
1708         const int                                       numVertices                             = (gridWidth+1)*(gridHeight+1);
1709         const int                                       numIndices                              = gridWidth*gridHeight * (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3*2 : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? 4 : -1);
1710         const int                                       numPosCompsPerVertex    = 2;
1711         const int                                       totalNumPosComps                = numPosCompsPerVertex*numVertices;
1712         vector<float>                           gridPosComps;
1713         vector<float>                           gridTessParams;
1714         vector<deUint16>                        gridIndices;
1715
1716         gridPosComps.reserve(totalNumPosComps);
1717         gridTessParams.reserve(numVertices);
1718         gridIndices.reserve(numIndices);
1719
1720         {
1721                 for (int i = 0; i < gridHeight+1; i++)
1722                 for (int j = 0; j < gridWidth+1; j++)
1723                 {
1724                         gridPosComps.push_back(-1.0f + 2.0f * ((float)j + 0.5f) / (float)(gridWidth+1));
1725                         gridPosComps.push_back(-1.0f + 2.0f * ((float)i + 0.5f) / (float)(gridHeight+1));
1726                         gridTessParams.push_back((float)(i*(gridWidth+1) + j) / (float)(numVertices-1));
1727                 }
1728         }
1729
1730         // Generate patch vertex indices.
1731         // \note If CASETYPE_BASIC, the vertices are ordered such that when multiple
1732         //               triangles/quads share a vertex, it's at the same index for everyone.
1733
1734         if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
1735         {
1736                 for (int i = 0; i < gridHeight; i++)
1737                 for (int j = 0; j < gridWidth; j++)
1738                 {
1739                         const deUint16 corners[4] =
1740                         {
1741                                 (deUint16)((i+0)*(gridWidth+1) + j+0),
1742                                 (deUint16)((i+0)*(gridWidth+1) + j+1),
1743                                 (deUint16)((i+1)*(gridWidth+1) + j+0),
1744                                 (deUint16)((i+1)*(gridWidth+1) + j+1)
1745                         };
1746
1747                         const int secondTriangleVertexIndexOffset = m_caseType == CASETYPE_BASIC        ? 0
1748                                                                                                           : m_caseType == CASETYPE_PRECISE      ? 1
1749                                                                                                           : -1;
1750                         DE_ASSERT(secondTriangleVertexIndexOffset != -1);
1751
1752                         for (int k = 0; k < 3; k++)
1753                                 gridIndices.push_back(corners[(k+0 + i + (2-j%3)) % 3]);
1754                         for (int k = 0; k < 3; k++)
1755                                 gridIndices.push_back(corners[(k+2 + i + (2-j%3) + secondTriangleVertexIndexOffset) % 3 + 1]);
1756                 }
1757         }
1758         else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
1759         {
1760                 for (int i = 0; i < gridHeight; i++)
1761                 for (int j = 0; j < gridWidth; j++)
1762                 {
1763                         // \note The vertices are ordered such that when multiple quads
1764                         //               share a vertices, it's at the same index for everyone.
1765                         for (int m = 0; m < 2; m++)
1766                         for (int n = 0; n < 2; n++)
1767                                 gridIndices.push_back((deUint16)((i+(i+m)%2)*(gridWidth+1) + j+(j+n)%2));
1768
1769                         if(m_caseType == CASETYPE_PRECISE && (i+j) % 2 == 0)
1770                                 std::reverse(gridIndices.begin() + (gridIndices.size() - 4),
1771                                                          gridIndices.begin() + gridIndices.size());
1772                 }
1773         }
1774         else
1775                 DE_ASSERT(false);
1776
1777         DE_ASSERT((int)gridPosComps.size() == totalNumPosComps);
1778         DE_ASSERT((int)gridTessParams.size() == numVertices);
1779         DE_ASSERT((int)gridIndices.size() == numIndices);
1780
1781         setViewport(gl, viewport);
1782         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1783         gl.useProgram(programGL);
1784
1785         {
1786                 gl.patchParameteri(GL_PATCH_VERTICES, m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? 4 : -1);
1787                 gl.clear(GL_COLOR_BUFFER_BIT);
1788
1789                 const glu::VertexArrayBinding attrBindings[] =
1790                 {
1791                         glu::va::Float("in_v_position", numPosCompsPerVertex, numVertices, 0, &gridPosComps[0]),
1792                         glu::va::Float("in_v_tessParam", 1, numVertices, 0, &gridTessParams[0])
1793                 };
1794
1795                 glu::draw(renderCtx, programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
1796                         glu::pr::Patches((int)gridIndices.size(), &gridIndices[0]));
1797                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
1798         }
1799
1800         {
1801                 const tcu::Surface rendered = getPixels(renderCtx, viewport);
1802
1803                 log << TestLog::Image("RenderedImage", "Rendered Image", rendered)
1804                         << TestLog::Message << "Note: coloring is done to clarify the positioning and orientation of the "
1805                                                                 << (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "triangles" : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? "quads" : DE_NULL)
1806                                                                 << "; the color of a vertex corresponds to the index of that vertex in the patch"
1807                                                                 << TestLog::EndMessage;
1808
1809                 if (m_caseType == CASETYPE_BASIC)
1810                         log << TestLog::Message << "Note: each shared vertex has the same index among the primitives it belongs to" << TestLog::EndMessage;
1811                 else if (m_caseType == CASETYPE_PRECISE)
1812                         log << TestLog::Message << "Note: the 'precise' qualifier is used to avoid cracks between primitives" << TestLog::EndMessage;
1813                 else
1814                         DE_ASSERT(false);
1815
1816                 // Ad-hoc result verification - check that a certain rectangle in the image contains no black pixels.
1817
1818                 const int startX        = (int)(0.15f * (float)rendered.getWidth());
1819                 const int endX          = (int)(0.85f * (float)rendered.getWidth());
1820                 const int startY        = (int)(0.15f * (float)rendered.getHeight());
1821                 const int endY          = (int)(0.85f * (float)rendered.getHeight());
1822
1823                 for (int y = startY; y < endY; y++)
1824                 for (int x = startX; x < endX; x++)
1825                 {
1826                         const tcu::RGBA pixel = rendered.getPixel(x, y);
1827
1828                         if (pixel.getRed() == 0 && pixel.getGreen() == 0 && pixel.getBlue() == 0)
1829                         {
1830                                 log << TestLog::Message << "Failure: there seem to be cracks in the rendered result" << TestLog::EndMessage
1831                                         << TestLog::Message << "Note: pixel with zero r, g and b channels found at " << tcu::IVec2(x, y) << TestLog::EndMessage;
1832
1833                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1834                                 return STOP;
1835                         }
1836                 }
1837
1838                 log << TestLog::Message << "Success: there seem to be no cracks in the rendered result" << TestLog::EndMessage;
1839         }
1840
1841         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1842         return STOP;
1843 }
1844
1845 // Check tessellation coordinates (read with transform feedback).
1846 class TessCoordCase : public TestCase
1847 {
1848 public:
1849                                         TessCoordCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing)
1850                                                 : TestCase                      (context, name, description)
1851                                                 , m_primitiveType       (primitiveType)
1852                                                 , m_spacing                     (spacing)
1853                                         {
1854                                         }
1855
1856         void                    init            (void);
1857         void                    deinit          (void);
1858         IterateResult   iterate         (void);
1859
1860 private:
1861         struct TessLevels
1862         {
1863                 float inner[2];
1864                 float outer[4];
1865         };
1866
1867         static const int                                RENDER_SIZE = 16;
1868
1869         vector<TessLevels>                              genTessLevelCases (void) const;
1870
1871         const TessPrimitiveType                 m_primitiveType;
1872         const SpacingMode                               m_spacing;
1873
1874         SharedPtr<const ShaderProgram>  m_program;
1875 };
1876
1877 void TessCoordCase::init (void)
1878 {
1879         checkTessellationSupport(m_context);
1880         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
1881
1882         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
1883                         << glu::VertexSource                                    ("#version 310 es\n"
1884                                                                                                          "\n"
1885                                                                                                          "void main (void)\n"
1886                                                                                                          "{\n"
1887                                                                                                          "}\n")
1888
1889                         << glu::TessellationControlSource               ("#version 310 es\n"
1890                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
1891                                                                                                          "\n"
1892                                                                                                          "layout (vertices = 1) out;\n"
1893                                                                                                          "\n"
1894                                                                                                          "uniform mediump float u_tessLevelInner0;\n"
1895                                                                                                          "uniform mediump float u_tessLevelInner1;\n"
1896                                                                                                          "\n"
1897                                                                                                          "uniform mediump float u_tessLevelOuter0;\n"
1898                                                                                                          "uniform mediump float u_tessLevelOuter1;\n"
1899                                                                                                          "uniform mediump float u_tessLevelOuter2;\n"
1900                                                                                                          "uniform mediump float u_tessLevelOuter3;\n"
1901                                                                                                          "\n"
1902                                                                                                          "void main (void)\n"
1903                                                                                                          "{\n"
1904                                                                                                          "      gl_TessLevelInner[0] = u_tessLevelInner0;\n"
1905                                                                                                          "      gl_TessLevelInner[1] = u_tessLevelInner1;\n"
1906                                                                                                          "\n"
1907                                                                                                          "      gl_TessLevelOuter[0] = u_tessLevelOuter0;\n"
1908                                                                                                          "      gl_TessLevelOuter[1] = u_tessLevelOuter1;\n"
1909                                                                                                          "      gl_TessLevelOuter[2] = u_tessLevelOuter2;\n"
1910                                                                                                          "      gl_TessLevelOuter[3] = u_tessLevelOuter3;\n"
1911                                                                                                          "}\n")
1912
1913                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
1914                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
1915                                                                                                          "\n"
1916                                                                                                          + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, true) +
1917                                                                                                          "\n"
1918                                                                                                          "out highp vec3 out_te_tessCoord;\n"
1919                                                                                                          "\n"
1920                                                                                                          "void main (void)\n"
1921                                                                                                          "{\n"
1922                                                                                                          "      out_te_tessCoord = gl_TessCoord;\n"
1923                                                                                                          "      gl_Position = vec4(gl_TessCoord.xy*1.6 - 0.8, 0.0, 1.0);\n"
1924                                                                                                          "}\n")
1925
1926                         << glu::FragmentSource                                  ("#version 310 es\n"
1927                                                                                                          "\n"
1928                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
1929                                                                                                          "\n"
1930                                                                                                          "void main (void)\n"
1931                                                                                                          "{\n"
1932                                                                                                          "      o_color = vec4(1.0);\n"
1933                                                                                                          "}\n")
1934
1935                         << glu::TransformFeedbackVarying                ("out_te_tessCoord")
1936                         << glu::TransformFeedbackMode                   (GL_INTERLEAVED_ATTRIBS)));
1937
1938         m_testCtx.getLog() << *m_program;
1939         if (!m_program->isOk())
1940                 TCU_FAIL("Program compilation failed");
1941 }
1942
1943 void TessCoordCase::deinit (void)
1944 {
1945         m_program.clear();
1946 }
1947
1948 vector<TessCoordCase::TessLevels> TessCoordCase::genTessLevelCases (void) const
1949 {
1950         static const TessLevels rawTessLevelCases[] =
1951         {
1952                 { { 1.0f,       1.0f    },      { 1.0f,         1.0f,   1.0f,   1.0f    } },
1953                 { { 63.0f,      24.0f   },      { 15.0f,        42.0f,  10.0f,  12.0f   } },
1954                 { { 3.0f,       2.0f    },      { 6.0f,         8.0f,   7.0f,   9.0f    } },
1955                 { { 4.0f,       6.0f    },      { 2.0f,         3.0f,   1.0f,   4.0f    } },
1956                 { { 2.0f,       2.0f    },      { 6.0f,         8.0f,   7.0f,   9.0f    } },
1957                 { { 5.0f,       6.0f    },      { 1.0f,         1.0f,   1.0f,   1.0f    } },
1958                 { { 1.0f,       6.0f    },      { 2.0f,         3.0f,   1.0f,   4.0f    } },
1959                 { { 5.0f,       1.0f    },      { 2.0f,         3.0f,   1.0f,   4.0f    } },
1960                 { { 5.2f,       1.6f    },      { 2.9f,         3.4f,   1.5f,   4.1f    } }
1961         };
1962
1963         if (m_spacing == SPACINGMODE_EQUAL)
1964                 return vector<TessLevels>(DE_ARRAY_BEGIN(rawTessLevelCases), DE_ARRAY_END(rawTessLevelCases));
1965         else
1966         {
1967                 vector<TessLevels> result;
1968                 result.reserve(DE_LENGTH_OF_ARRAY(rawTessLevelCases));
1969
1970                 for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(rawTessLevelCases); tessLevelCaseNdx++)
1971                 {
1972                         TessLevels curTessLevelCase = rawTessLevelCases[tessLevelCaseNdx];
1973
1974                         float* const inner = &curTessLevelCase.inner[0];
1975                         float* const outer = &curTessLevelCase.outer[0];
1976
1977                         for (int j = 0; j < 2; j++) inner[j] = (float)getClampedRoundedTessLevel(m_spacing, inner[j]);
1978                         for (int j = 0; j < 4; j++) outer[j] = (float)getClampedRoundedTessLevel(m_spacing, outer[j]);
1979
1980                         if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
1981                         {
1982                                 if (outer[0] > 1.0f || outer[1] > 1.0f || outer[2] > 1.0f)
1983                                 {
1984                                         if (inner[0] == 1.0f)
1985                                                 inner[0] = (float)getClampedRoundedTessLevel(m_spacing, inner[0] + 0.1f);
1986                                 }
1987                         }
1988                         else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
1989                         {
1990                                 if (outer[0] > 1.0f || outer[1] > 1.0f || outer[2] > 1.0f || outer[3] > 1.0f)
1991                                 {
1992                                         if (inner[0] == 1.0f) inner[0] = (float)getClampedRoundedTessLevel(m_spacing, inner[0] + 0.1f);
1993                                         if (inner[1] == 1.0f) inner[1] = (float)getClampedRoundedTessLevel(m_spacing, inner[1] + 0.1f);
1994                                 }
1995                         }
1996
1997                         result.push_back(curTessLevelCase);
1998                 }
1999
2000                 DE_ASSERT((int)result.size() == DE_LENGTH_OF_ARRAY(rawTessLevelCases));
2001                 return result;
2002         }
2003 }
2004
2005 TessCoordCase::IterateResult TessCoordCase::iterate (void)
2006 {
2007         typedef TransformFeedbackHandler<Vec3> TFHandler;
2008
2009         TestLog&                                                log                                                     = m_testCtx.getLog();
2010         const RenderContext&                    renderCtx                                       = m_context.getRenderContext();
2011         const RandomViewport                    viewport                                        (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2012         const deUint32                                  programGL                                       = m_program->getProgram();
2013         const glw::Functions&                   gl                                                      = renderCtx.getFunctions();
2014
2015         const int                                               tessLevelInner0Loc                      = gl.getUniformLocation(programGL, "u_tessLevelInner0");
2016         const int                                               tessLevelInner1Loc                      = gl.getUniformLocation(programGL, "u_tessLevelInner1");
2017         const int                                               tessLevelOuter0Loc                      = gl.getUniformLocation(programGL, "u_tessLevelOuter0");
2018         const int                                               tessLevelOuter1Loc                      = gl.getUniformLocation(programGL, "u_tessLevelOuter1");
2019         const int                                               tessLevelOuter2Loc                      = gl.getUniformLocation(programGL, "u_tessLevelOuter2");
2020         const int                                               tessLevelOuter3Loc                      = gl.getUniformLocation(programGL, "u_tessLevelOuter3");
2021
2022         const vector<TessLevels>                tessLevelCases                          = genTessLevelCases();
2023         vector<vector<Vec3> >                   caseReferences                          (tessLevelCases.size());
2024
2025         for (int i = 0; i < (int)tessLevelCases.size(); i++)
2026                 caseReferences[i] = generateReferenceTessCoords(m_primitiveType, m_spacing, &tessLevelCases[i].inner[0], &tessLevelCases[i].outer[0]);
2027
2028         const int                                               maxNumVertices                          = (int)std::max_element(caseReferences.begin(), caseReferences.end(), SizeLessThan<vector<Vec3> >())->size();
2029         const TFHandler                                 tfHandler                                       (m_context.getRenderContext(), maxNumVertices);
2030
2031         bool                                                    success                                         = true;
2032
2033         setViewport(gl, viewport);
2034         gl.useProgram(programGL);
2035
2036         gl.patchParameteri(GL_PATCH_VERTICES, 1);
2037
2038         for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < (int)tessLevelCases.size(); tessLevelCaseNdx++)
2039         {
2040                 const float* const innerLevels = &tessLevelCases[tessLevelCaseNdx].inner[0];
2041                 const float* const outerLevels = &tessLevelCases[tessLevelCaseNdx].outer[0];
2042
2043                 log << TestLog::Message << "Tessellation levels: " << tessellationLevelsString(innerLevels, outerLevels, m_primitiveType) << TestLog::EndMessage;
2044
2045                 gl.uniform1f(tessLevelInner0Loc, innerLevels[0]);
2046                 gl.uniform1f(tessLevelInner1Loc, innerLevels[1]);
2047                 gl.uniform1f(tessLevelOuter0Loc, outerLevels[0]);
2048                 gl.uniform1f(tessLevelOuter1Loc, outerLevels[1]);
2049                 gl.uniform1f(tessLevelOuter2Loc, outerLevels[2]);
2050                 gl.uniform1f(tessLevelOuter3Loc, outerLevels[3]);
2051                 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
2052
2053                 {
2054                         const vector<Vec3>&                     tessCoordsRef   = caseReferences[tessLevelCaseNdx];
2055                         const TFHandler::Result         tfResult                = tfHandler.renderAndGetPrimitives(programGL, GL_POINTS, 0, DE_NULL, 1);
2056
2057                         if (tfResult.numPrimitives != (int)tessCoordsRef.size())
2058                         {
2059                                 log << TestLog::Message << "Failure: GL reported GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN to be "
2060                                                                                 << tfResult.numPrimitives << ", reference value is " << tessCoordsRef.size()
2061                                                                                 << " (logging further info anyway)" << TestLog::EndMessage;
2062                                 success = false;
2063                         }
2064                         else
2065                                 log << TestLog::Message << "Note: GL reported GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN to be " << tfResult.numPrimitives << TestLog::EndMessage;
2066
2067                         if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2068                                 log << TestLog::Message << "Note: in the following visualization(s), the u=1, v=1, w=1 corners are at the right, top, and left corners, respectively" << TestLog::EndMessage;
2069                         else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS || m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
2070                                 log << TestLog::Message << "Note: in the following visualization(s), u and v coordinate go left-to-right and bottom-to-top, respectively" << TestLog::EndMessage;
2071                         else
2072                                 DE_ASSERT(false);
2073
2074                         success = compareTessCoords(log, m_primitiveType, tessCoordsRef, tfResult.varying) && success;
2075                 }
2076
2077                 if (!success)
2078                         break;
2079                 else
2080                         log << TestLog::Message << "All OK" << TestLog::EndMessage;
2081         }
2082
2083         m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Invalid tessellation coordinates");
2084         return STOP;
2085 }
2086
2087 // Check validity of fractional spacing modes. Draws a single isoline, reads tesscoords with transform feedback.
2088 class FractionalSpacingModeCase : public TestCase
2089 {
2090 public:
2091                                         FractionalSpacingModeCase (Context& context, const char* name, const char* description, SpacingMode spacing)
2092                                                 : TestCase      (context, name, description)
2093                                                 , m_spacing     (spacing)
2094                                         {
2095                                                 DE_ASSERT(m_spacing == SPACINGMODE_FRACTIONAL_EVEN || m_spacing == SPACINGMODE_FRACTIONAL_ODD);
2096                                         }
2097
2098         void                    init            (void);
2099         void                    deinit          (void);
2100         IterateResult   iterate         (void);
2101
2102 private:
2103         static const int                                RENDER_SIZE = 16;
2104
2105         static vector<float>                    genTessLevelCases (void);
2106
2107         const SpacingMode                               m_spacing;
2108
2109         SharedPtr<const ShaderProgram>  m_program;
2110 };
2111
2112 void FractionalSpacingModeCase::init (void)
2113 {
2114         checkTessellationSupport(m_context);
2115         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2116
2117         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2118                         << glu::VertexSource                                    ("#version 310 es\n"
2119                                                                                                          "\n"
2120                                                                                                          "void main (void)\n"
2121                                                                                                          "{\n"
2122                                                                                                          "}\n")
2123
2124                         << glu::TessellationControlSource               ("#version 310 es\n"
2125                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
2126                                                                                                          "\n"
2127                                                                                                          "layout (vertices = 1) out;\n"
2128                                                                                                          "\n"
2129                                                                                                          "uniform mediump float u_tessLevelOuter1;\n"
2130                                                                                                          "\n"
2131                                                                                                          "void main (void)\n"
2132                                                                                                          "{\n"
2133                                                                                                          "      gl_TessLevelOuter[0] = 1.0;\n"
2134                                                                                                          "      gl_TessLevelOuter[1] = u_tessLevelOuter1;\n"
2135                                                                                                          "}\n")
2136
2137                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
2138                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
2139                                                                                                          "\n"
2140                                                                                                          + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_ISOLINES, m_spacing, true) +
2141                                                                                                          "\n"
2142                                                                                                          "out highp float out_te_tessCoord;\n"
2143                                                                                                          "\n"
2144                                                                                                          "void main (void)\n"
2145                                                                                                          "{\n"
2146                                                                                                          "      out_te_tessCoord = gl_TessCoord.x;\n"
2147                                                                                                          "      gl_Position = vec4(gl_TessCoord.xy*1.6 - 0.8, 0.0, 1.0);\n"
2148                                                                                                          "}\n")
2149
2150                         << glu::FragmentSource                                  ("#version 310 es\n"
2151                                                                                                          "\n"
2152                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
2153                                                                                                          "\n"
2154                                                                                                          "void main (void)\n"
2155                                                                                                          "{\n"
2156                                                                                                          "      o_color = vec4(1.0);\n"
2157                                                                                                          "}\n")
2158
2159                         << glu::TransformFeedbackVarying                ("out_te_tessCoord")
2160                         << glu::TransformFeedbackMode                   (GL_INTERLEAVED_ATTRIBS)));
2161
2162         m_testCtx.getLog() << *m_program;
2163         if (!m_program->isOk())
2164                 TCU_FAIL("Program compilation failed");
2165 }
2166
2167 void FractionalSpacingModeCase::deinit (void)
2168 {
2169         m_program.clear();
2170 }
2171
2172 vector<float> FractionalSpacingModeCase::genTessLevelCases (void)
2173 {
2174         vector<float> result;
2175
2176         // Ranges [7.0 .. 8.0), [8.0 .. 9.0) and [9.0 .. 10.0)
2177         {
2178                 static const float      rangeStarts[]           = { 7.0f, 8.0f, 9.0f };
2179                 const int                       numSamplesPerRange      = 10;
2180
2181                 for (int rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(rangeStarts); rangeNdx++)
2182                         for (int i = 0; i < numSamplesPerRange; i++)
2183                                 result.push_back(rangeStarts[rangeNdx] + (float)i/(float)numSamplesPerRange);
2184         }
2185
2186         // 0.3, 1.3, 2.3,  ... , 62.3
2187         for (int i = 0; i <= 62; i++)
2188                 result.push_back((float)i + 0.3f);
2189
2190         return result;
2191 }
2192
2193 FractionalSpacingModeCase::IterateResult FractionalSpacingModeCase::iterate (void)
2194 {
2195         typedef TransformFeedbackHandler<float> TFHandler;
2196
2197         TestLog&                                                log                                                     = m_testCtx.getLog();
2198         const RenderContext&                    renderCtx                                       = m_context.getRenderContext();
2199         const RandomViewport                    viewport                                        (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2200         const deUint32                                  programGL                                       = m_program->getProgram();
2201         const glw::Functions&                   gl                                                      = renderCtx.getFunctions();
2202
2203         const int                                               tessLevelOuter1Loc                      = gl.getUniformLocation(programGL, "u_tessLevelOuter1");
2204
2205         // Second outer tessellation levels.
2206         const vector<float>                             tessLevelCases                          = genTessLevelCases();
2207         const int                                               maxNumVertices                          = 1 + getClampedRoundedTessLevel(m_spacing, *std::max_element(tessLevelCases.begin(), tessLevelCases.end()));
2208         vector<float>                                   additionalSegmentLengths;
2209         vector<int>                                             additionalSegmentLocations;
2210
2211         const TFHandler                                 tfHandler                                       (m_context.getRenderContext(), maxNumVertices);
2212
2213         bool                                                    success                                         = true;
2214
2215         setViewport(gl, viewport);
2216         gl.useProgram(programGL);
2217
2218         gl.patchParameteri(GL_PATCH_VERTICES, 1);
2219
2220         for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < (int)tessLevelCases.size(); tessLevelCaseNdx++)
2221         {
2222                 const float outerLevel1 = tessLevelCases[tessLevelCaseNdx];
2223
2224                 gl.uniform1f(tessLevelOuter1Loc, outerLevel1);
2225                 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
2226
2227                 {
2228                         const TFHandler::Result         tfResult = tfHandler.renderAndGetPrimitives(programGL, GL_POINTS, 0, DE_NULL, 1);
2229                         float                                           additionalSegmentLength;
2230                         int                                                     additionalSegmentLocation;
2231
2232                         success = verifyFractionalSpacingSingle(log, m_spacing, outerLevel1, tfResult.varying,
2233                                                                                                         additionalSegmentLength, additionalSegmentLocation);
2234
2235                         if (!success)
2236                                 break;
2237
2238                         additionalSegmentLengths.push_back(additionalSegmentLength);
2239                         additionalSegmentLocations.push_back(additionalSegmentLocation);
2240                 }
2241         }
2242
2243         if (success)
2244                 success = verifyFractionalSpacingMultiple(log, m_spacing, tessLevelCases, additionalSegmentLengths, additionalSegmentLocations);
2245
2246         m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Invalid tessellation coordinates");
2247         return STOP;
2248 }
2249
2250 // Base class for a case with one input attribute (in_v_position) and optionally a TCS; tests with a couple of different sets of tessellation levels.
2251 class BasicVariousTessLevelsPosAttrCase : public TestCase
2252 {
2253 public:
2254                                         BasicVariousTessLevelsPosAttrCase (Context&                             context,
2255                                                                                                            const char*                  name,
2256                                                                                                            const char*                  description,
2257                                                                                                            TessPrimitiveType    primitiveType,
2258                                                                                                            SpacingMode                  spacing,
2259                                                                                                            const char*                  referenceImagePathPrefix)
2260                                                 : TestCase                                              (context, name, description)
2261                                                 , m_primitiveType                               (primitiveType)
2262                                                 , m_spacing                                             (spacing)
2263                                                 , m_referenceImagePathPrefix    (referenceImagePathPrefix)
2264                                         {
2265                                         }
2266
2267         void                    init                    (void);
2268         void                    deinit                  (void);
2269         IterateResult   iterate                 (void);
2270
2271 protected:
2272         virtual const glu::ProgramSources       makeSources (TessPrimitiveType, SpacingMode, const char* vtxOutPosAttrName) const = DE_NULL;
2273
2274 private:
2275         static const int                                        RENDER_SIZE = 256;
2276
2277         const TessPrimitiveType                         m_primitiveType;
2278         const SpacingMode                                       m_spacing;
2279         const string                                            m_referenceImagePathPrefix;
2280
2281         SharedPtr<const ShaderProgram>          m_program;
2282 };
2283
2284 void BasicVariousTessLevelsPosAttrCase::init (void)
2285 {
2286         checkTessellationSupport(m_context);
2287         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2288
2289         {
2290                 glu::ProgramSources sources = makeSources(m_primitiveType, m_spacing, "in_tc_position");
2291                 DE_ASSERT(sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty());
2292
2293                 sources << glu::TessellationControlSource(      "#version 310 es\n"
2294                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
2295                                                                                                         "\n"
2296                                                                                                         "layout (vertices = " + string(m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "3" : "4") + ") out;\n"
2297                                                                                                         "\n"
2298                                                                                                         "in highp vec2 in_tc_position[];\n"
2299                                                                                                         "\n"
2300                                                                                                         "out highp vec2 in_te_position[];\n"
2301                                                                                                         "\n"
2302                                                                                                         "uniform mediump float u_tessLevelInner0;\n"
2303                                                                                                         "uniform mediump float u_tessLevelInner1;\n"
2304                                                                                                         "uniform mediump float u_tessLevelOuter0;\n"
2305                                                                                                         "uniform mediump float u_tessLevelOuter1;\n"
2306                                                                                                         "uniform mediump float u_tessLevelOuter2;\n"
2307                                                                                                         "uniform mediump float u_tessLevelOuter3;\n"
2308                                                                                                         "\n"
2309                                                                                                         "void main (void)\n"
2310                                                                                                         "{\n"
2311                                                                                                         "       in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
2312                                                                                                         "\n"
2313                                                                                                         "       gl_TessLevelInner[0] = u_tessLevelInner0;\n"
2314                                                                                                         "       gl_TessLevelInner[1] = u_tessLevelInner1;\n"
2315                                                                                                         "\n"
2316                                                                                                         "       gl_TessLevelOuter[0] = u_tessLevelOuter0;\n"
2317                                                                                                         "       gl_TessLevelOuter[1] = u_tessLevelOuter1;\n"
2318                                                                                                         "       gl_TessLevelOuter[2] = u_tessLevelOuter2;\n"
2319                                                                                                         "       gl_TessLevelOuter[3] = u_tessLevelOuter3;\n"
2320                                                                                                         "}\n");
2321
2322                 m_program = SharedPtr<const ShaderProgram>(new glu::ShaderProgram(m_context.getRenderContext(), sources));
2323         }
2324
2325         m_testCtx.getLog() << *m_program;
2326         if (!m_program->isOk())
2327                 TCU_FAIL("Program compilation failed");
2328 }
2329
2330 void BasicVariousTessLevelsPosAttrCase::deinit (void)
2331 {
2332         m_program.clear();
2333 }
2334
2335 BasicVariousTessLevelsPosAttrCase::IterateResult BasicVariousTessLevelsPosAttrCase::iterate (void)
2336 {
2337         static const struct
2338         {
2339                 float inner[2];
2340                 float outer[4];
2341         } tessLevelCases[] =
2342         {
2343                 { { 9.0f,       9.0f    },      { 9.0f,         9.0f,   9.0f,   9.0f    } },
2344                 { { 8.0f,       11.0f   },      { 13.0f,        15.0f,  18.0f,  21.0f   } },
2345                 { { 17.0f,      14.0f   },      { 3.0f,         6.0f,   9.0f,   12.0f   } }
2346         };
2347
2348         TestLog&                                log                                     = m_testCtx.getLog();
2349         const RenderContext&    renderCtx                       = m_context.getRenderContext();
2350         const RandomViewport    viewport                        (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2351         const deUint32                  programGL                       = m_program->getProgram();
2352         const glw::Functions&   gl                                      = renderCtx.getFunctions();
2353         const int                               patchSize                       = m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES        ? 3
2354                                                                                                 : m_primitiveType == TESSPRIMITIVETYPE_QUADS            ? 4
2355                                                                                                 : m_primitiveType == TESSPRIMITIVETYPE_ISOLINES         ? 4
2356                                                                                                 : -1;
2357
2358         setViewport(gl, viewport);
2359         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2360         gl.useProgram(programGL);
2361
2362         gl.patchParameteri(GL_PATCH_VERTICES, patchSize);
2363
2364         for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(tessLevelCases); tessLevelCaseNdx++)
2365         {
2366                 float innerLevels[2];
2367                 float outerLevels[4];
2368
2369                 for (int i = 0; i < DE_LENGTH_OF_ARRAY(innerLevels); i++)
2370                         innerLevels[i] = (float)getClampedRoundedTessLevel(m_spacing, tessLevelCases[tessLevelCaseNdx].inner[i]);
2371
2372                 for (int i = 0; i < DE_LENGTH_OF_ARRAY(outerLevels); i++)
2373                         outerLevels[i] = (float)getClampedRoundedTessLevel(m_spacing, tessLevelCases[tessLevelCaseNdx].outer[i]);
2374
2375                 log << TestLog::Message << "Tessellation levels: " << tessellationLevelsString(&innerLevels[0], &outerLevels[0], m_primitiveType) << TestLog::EndMessage;
2376
2377                 gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelInner0"), innerLevels[0]);
2378                 gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelInner1"), innerLevels[1]);
2379                 gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter0"), outerLevels[0]);
2380                 gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter1"), outerLevels[1]);
2381                 gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter2"), outerLevels[2]);
2382                 gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter3"), outerLevels[3]);
2383
2384                 gl.clear(GL_COLOR_BUFFER_BIT);
2385
2386                 {
2387                         vector<Vec2> positions;
2388                         positions.reserve(4);
2389
2390                         if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2391                         {
2392                                 positions.push_back(Vec2( 0.8f,    0.6f));
2393                                 positions.push_back(Vec2( 0.0f, -0.786f));
2394                                 positions.push_back(Vec2(-0.8f,    0.6f));
2395                         }
2396                         else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS || m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
2397                         {
2398                                 positions.push_back(Vec2(-0.8f, -0.8f));
2399                                 positions.push_back(Vec2( 0.8f, -0.8f));
2400                                 positions.push_back(Vec2(-0.8f,  0.8f));
2401                                 positions.push_back(Vec2( 0.8f,  0.8f));
2402                         }
2403                         else
2404                                 DE_ASSERT(false);
2405
2406                         DE_ASSERT((int)positions.size() == patchSize);
2407
2408                         const glu::VertexArrayBinding attrBindings[] =
2409                         {
2410                                 glu::va::Float("in_v_position", 2, (int)positions.size(), 0, &positions[0].x())
2411                         };
2412
2413                         glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
2414                                 glu::pr::Patches(patchSize));
2415                         GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
2416                 }
2417
2418                 {
2419                         const tcu::Surface                      rendered        = getPixels(renderCtx, viewport);
2420                         const tcu::TextureLevel         reference       = getPNG(m_testCtx.getArchive(), m_referenceImagePathPrefix + "_" + de::toString(tessLevelCaseNdx) + ".png");
2421                         const bool                                      success         = tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.002f, tcu::COMPARE_LOG_RESULT);
2422
2423                         if (!success)
2424                         {
2425                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
2426                                 return STOP;
2427                         }
2428                 }
2429         }
2430
2431         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2432         return STOP;
2433 }
2434
2435 // Test that there are no obvious gaps in the triangulation of a tessellated triangle or quad.
2436 class BasicTriangleFillCoverCase : public BasicVariousTessLevelsPosAttrCase
2437 {
2438 public:
2439         BasicTriangleFillCoverCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing, const char* referenceImagePathPrefix)
2440                 : BasicVariousTessLevelsPosAttrCase (context, name, description, primitiveType, spacing, referenceImagePathPrefix)
2441         {
2442                 DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
2443         }
2444
2445 protected:
2446         void init (void)
2447         {
2448                 checkExtensionSupport(m_context, "GL_EXT_gpu_shader5");
2449                 BasicVariousTessLevelsPosAttrCase::init();
2450         }
2451
2452         const glu::ProgramSources makeSources (TessPrimitiveType primitiveType, SpacingMode spacing, const char* vtxOutPosAttrName) const
2453         {
2454                 return glu::ProgramSources()
2455                         << glu::VertexSource                                    ("#version 310 es\n"
2456                                                                                                          "\n"
2457                                                                                                          "in highp vec2 in_v_position;\n"
2458                                                                                                          "\n"
2459                                                                                                          "out highp vec2 " + string(vtxOutPosAttrName) + ";\n"
2460                                                                                                          "\n"
2461                                                                                                          "void main (void)\n"
2462                                                                                                          "{\n"
2463                                                                                                          "      " + vtxOutPosAttrName + " = in_v_position;\n"
2464                                                                                                          "}\n")
2465
2466                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
2467                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
2468                                                                                                          "#extension GL_EXT_gpu_shader5 : require\n"
2469                                                                                                          "\n"
2470                                                                                                          + getTessellationEvaluationInLayoutString(primitiveType, spacing) +
2471                                                                                                          "\n"
2472                                                                                                          "in highp vec2 in_te_position[];\n"
2473                                                                                                          "\n"
2474                                                                                                          "precise gl_Position;\n"
2475                                                                                                          "void main (void)\n"
2476                                                                                                          "{\n"
2477                                                                                                          + (primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
2478                                                                                                                 "\n"
2479                                                                                                                 "       highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
2480                                                                                                                 "       highp vec2 corner0 = in_te_position[0];\n"
2481                                                                                                                 "       highp vec2 corner1 = in_te_position[1];\n"
2482                                                                                                                 "       highp vec2 corner2 = in_te_position[2];\n"
2483                                                                                                                 "       highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
2484                                                                                                                 "       highp vec2 fromCenter = pos - (corner0 + corner1 + corner2) / 3.0;\n"
2485                                                                                                                 "       highp float f = (1.0 - length(fromCenter)) * (1.5 - d);\n"
2486                                                                                                                 "       pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
2487                                                                                                                 "       gl_Position = vec4(pos, 0.0, 1.0);\n"
2488                                                                                                           : primitiveType == TESSPRIMITIVETYPE_QUADS ?
2489                                                                                                                 "       highp vec2 corner0 = in_te_position[0];\n"
2490                                                                                                                 "       highp vec2 corner1 = in_te_position[1];\n"
2491                                                                                                                 "       highp vec2 corner2 = in_te_position[2];\n"
2492                                                                                                                 "       highp vec2 corner3 = in_te_position[3];\n"
2493                                                                                                                 "       highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
2494                                                                                                                 "                      + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
2495                                                                                                                 "                      + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
2496                                                                                                                 "                      + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
2497                                                                                                                 "       highp float d = 2.0 * min(abs(gl_TessCoord.x-0.5), abs(gl_TessCoord.y-0.5));\n"
2498                                                                                                                 "       highp vec2 fromCenter = pos - (corner0 + corner1 + corner2 + corner3) / 4.0;\n"
2499                                                                                                                 "       highp float f = (1.0 - length(fromCenter)) * sqrt(1.7 - d);\n"
2500                                                                                                                 "       pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
2501                                                                                                                 "       gl_Position = vec4(pos, 0.0, 1.0);\n"
2502                                                                                                           : DE_NULL) +
2503                                                                                                          "}\n")
2504
2505                         << glu::FragmentSource                                  ("#version 310 es\n"
2506                                                                                                          "\n"
2507                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
2508                                                                                                          "\n"
2509                                                                                                          "void main (void)\n"
2510                                                                                                          "{\n"
2511                                                                                                          "      o_color = vec4(1.0);\n"
2512                                                                                                          "}\n");
2513         }
2514 };
2515
2516 // Check that there are no obvious overlaps in the triangulation of a tessellated triangle or quad.
2517 class BasicTriangleFillNonOverlapCase : public BasicVariousTessLevelsPosAttrCase
2518 {
2519 public:
2520         BasicTriangleFillNonOverlapCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing, const char* referenceImagePathPrefix)
2521                 : BasicVariousTessLevelsPosAttrCase (context, name, description, primitiveType, spacing, referenceImagePathPrefix)
2522         {
2523                 DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
2524         }
2525
2526 protected:
2527         const glu::ProgramSources makeSources (TessPrimitiveType primitiveType, SpacingMode spacing, const char* vtxOutPosAttrName) const
2528         {
2529                 return glu::ProgramSources()
2530                         << glu::VertexSource                                    ("#version 310 es\n"
2531                                                                                                          "\n"
2532                                                                                                          "in highp vec2 in_v_position;\n"
2533                                                                                                          "\n"
2534                                                                                                          "out highp vec2 " + string(vtxOutPosAttrName) + ";\n"
2535                                                                                                          "\n"
2536                                                                                                          "void main (void)\n"
2537                                                                                                          "{\n"
2538                                                                                                          "      " + vtxOutPosAttrName + " = in_v_position;\n"
2539                                                                                                          "}\n")
2540
2541                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
2542                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
2543                                                                                                          "\n"
2544                                                                                                          + getTessellationEvaluationInLayoutString(primitiveType, spacing) +
2545                                                                                                          "\n"
2546                                                                                                          "in highp vec2 in_te_position[];\n"
2547                                                                                                          "\n"
2548                                                                                                          "out mediump vec4 in_f_color;\n"
2549                                                                                                          "\n"
2550                                                                                                          "uniform mediump float u_tessLevelInner0;\n"
2551                                                                                                          "uniform mediump float u_tessLevelInner1;\n"
2552                                                                                                          "\n"
2553                                                                                                          "void main (void)\n"
2554                                                                                                          "{\n"
2555                                                                                                          + (primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
2556                                                                                                                 "\n"
2557                                                                                                                 "       highp vec2 corner0 = in_te_position[0];\n"
2558                                                                                                                 "       highp vec2 corner1 = in_te_position[1];\n"
2559                                                                                                                 "       highp vec2 corner2 = in_te_position[2];\n"
2560                                                                                                                 "       highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
2561                                                                                                                 "       gl_Position = vec4(pos, 0.0, 1.0);\n"
2562                                                                                                                 "       highp int numConcentricTriangles = int(round(u_tessLevelInner0)) / 2 + 1;\n"
2563                                                                                                                 "       highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
2564                                                                                                                 "       highp int phase = int(d*float(numConcentricTriangles)) % 3;\n"
2565                                                                                                                 "       in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
2566                                                                                                                 "                  : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
2567                                                                                                                 "                  :              vec4(0.0, 0.0, 1.0, 1.0);\n"
2568                                                                                                           : primitiveType == TESSPRIMITIVETYPE_QUADS ?
2569                                                                                                                 "       highp vec2 corner0 = in_te_position[0];\n"
2570                                                                                                                 "       highp vec2 corner1 = in_te_position[1];\n"
2571                                                                                                                 "       highp vec2 corner2 = in_te_position[2];\n"
2572                                                                                                                 "       highp vec2 corner3 = in_te_position[3];\n"
2573                                                                                                                 "       highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
2574                                                                                                                 "                      + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
2575                                                                                                                 "                      + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
2576                                                                                                                 "                      + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
2577                                                                                                                 "       gl_Position = vec4(pos, 0.0, 1.0);\n"
2578                                                                                                                 "       highp int phaseX = int(round((0.5 - abs(gl_TessCoord.x-0.5)) * u_tessLevelInner0));\n"
2579                                                                                                                 "       highp int phaseY = int(round((0.5 - abs(gl_TessCoord.y-0.5)) * u_tessLevelInner1));\n"
2580                                                                                                                 "       highp int phase = min(phaseX, phaseY) % 3;\n"
2581                                                                                                                 "       in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
2582                                                                                                                 "                  : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
2583                                                                                                                 "                  :              vec4(0.0, 0.0, 1.0, 1.0);\n"
2584                                                                                                           : DE_NULL) +
2585                                                                                                          "}\n")
2586
2587                         << glu::FragmentSource                                  ("#version 310 es\n"
2588                                                                                                          "\n"
2589                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
2590                                                                                                          "\n"
2591                                                                                                          "in mediump vec4 in_f_color;\n"
2592                                                                                                          "\n"
2593                                                                                                          "void main (void)\n"
2594                                                                                                          "{\n"
2595                                                                                                          "      o_color = in_f_color;\n"
2596                                                                                                          "}\n");
2597         }
2598 };
2599
2600 // Basic isolines rendering case.
2601 class IsolinesRenderCase : public BasicVariousTessLevelsPosAttrCase
2602 {
2603 public:
2604         IsolinesRenderCase (Context& context, const char* name, const char* description, SpacingMode spacing, const char* referenceImagePathPrefix)
2605                 : BasicVariousTessLevelsPosAttrCase (context, name, description, TESSPRIMITIVETYPE_ISOLINES, spacing, referenceImagePathPrefix)
2606         {
2607         }
2608
2609 protected:
2610         const glu::ProgramSources makeSources (TessPrimitiveType primitiveType, SpacingMode spacing, const char* vtxOutPosAttrName) const
2611         {
2612                 DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_ISOLINES);
2613                 DE_UNREF(primitiveType);
2614
2615                 return glu::ProgramSources()
2616                         << glu::VertexSource                                    ("#version 310 es\n"
2617                                                                                                          "\n"
2618                                                                                                          "in highp vec2 in_v_position;\n"
2619                                                                                                          "\n"
2620                                                                                                          "out highp vec2 " + string(vtxOutPosAttrName) + ";\n"
2621                                                                                                          "\n"
2622                                                                                                          "void main (void)\n"
2623                                                                                                          "{\n"
2624                                                                                                          "      " + vtxOutPosAttrName + " = in_v_position;\n"
2625                                                                                                          "}\n")
2626
2627                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
2628                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
2629                                                                                                          "\n"
2630                                                                                                          + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_ISOLINES, spacing) +
2631                                                                                                          "\n"
2632                                                                                                          "in highp vec2 in_te_position[];\n"
2633                                                                                                          "\n"
2634                                                                                                          "out mediump vec4 in_f_color;\n"
2635                                                                                                          "\n"
2636                                                                                                          "uniform mediump float u_tessLevelOuter0;\n"
2637                                                                                                          "uniform mediump float u_tessLevelOuter1;\n"
2638                                                                                                          "\n"
2639                                                                                                          "void main (void)\n"
2640                                                                                                          "{\n"
2641                                                                                                          "      highp vec2 corner0 = in_te_position[0];\n"
2642                                                                                                          "      highp vec2 corner1 = in_te_position[1];\n"
2643                                                                                                          "      highp vec2 corner2 = in_te_position[2];\n"
2644                                                                                                          "      highp vec2 corner3 = in_te_position[3];\n"
2645                                                                                                          "      highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
2646                                                                                                          "                     + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
2647                                                                                                          "                     + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
2648                                                                                                          "                     + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
2649                                                                                                          "      pos.y += 0.15*sin(gl_TessCoord.x*10.0);\n"
2650                                                                                                          "      gl_Position = vec4(pos, 0.0, 1.0);\n"
2651                                                                                                          "      highp int phaseX = int(round(gl_TessCoord.x*u_tessLevelOuter1));\n"
2652                                                                                                          "      highp int phaseY = int(round(gl_TessCoord.y*u_tessLevelOuter0));\n"
2653                                                                                                          "      highp int phase = (phaseX + phaseY) % 3;\n"
2654                                                                                                          "      in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
2655                                                                                                          "                 : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
2656                                                                                                          "                 :              vec4(0.0, 0.0, 1.0, 1.0);\n"
2657                                                                                                          "}\n")
2658
2659                         << glu::FragmentSource                                  ("#version 310 es\n"
2660                                                                                                          "\n"
2661                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
2662                                                                                                          "\n"
2663                                                                                                          "in mediump vec4 in_f_color;\n"
2664                                                                                                          "\n"
2665                                                                                                          "void main (void)\n"
2666                                                                                                          "{\n"
2667                                                                                                          "      o_color = in_f_color;\n"
2668                                                                                                          "}\n");
2669         }
2670 };
2671
2672 // Test the "cw" and "ccw" TES input layout qualifiers.
2673 class WindingCase : public TestCase
2674 {
2675 public:
2676                                         WindingCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, Winding winding)
2677                                                 : TestCase                      (context, name, description)
2678                                                 , m_primitiveType       (primitiveType)
2679                                                 , m_winding                     (winding)
2680                                         {
2681                                                 DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
2682                                         }
2683
2684         void                    init            (void);
2685         void                    deinit          (void);
2686         IterateResult   iterate         (void);
2687
2688 private:
2689         static const int                                RENDER_SIZE = 64;
2690
2691         const TessPrimitiveType                 m_primitiveType;
2692         const Winding                                   m_winding;
2693
2694         SharedPtr<const ShaderProgram>  m_program;
2695 };
2696
2697 void WindingCase::init (void)
2698 {
2699         checkTessellationSupport(m_context);
2700         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2701
2702         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2703                         << glu::VertexSource                                    ("#version 310 es\n"
2704                                                                                                          "\n"
2705                                                                                                          "void main (void)\n"
2706                                                                                                          "{\n"
2707                                                                                                          "}\n")
2708
2709                         << glu::TessellationControlSource               ("#version 310 es\n"
2710                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
2711                                                                                                          "\n"
2712                                                                                                          "layout (vertices = 1) out;\n"
2713                                                                                                          "\n"
2714                                                                                                          "void main (void)\n"
2715                                                                                                          "{\n"
2716                                                                                                          "      gl_TessLevelInner[0] = 5.0;\n"
2717                                                                                                          "      gl_TessLevelInner[1] = 5.0;\n"
2718                                                                                                          "\n"
2719                                                                                                          "      gl_TessLevelOuter[0] = 5.0;\n"
2720                                                                                                          "      gl_TessLevelOuter[1] = 5.0;\n"
2721                                                                                                          "      gl_TessLevelOuter[2] = 5.0;\n"
2722                                                                                                          "      gl_TessLevelOuter[3] = 5.0;\n"
2723                                                                                                          "}\n")
2724
2725                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
2726                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
2727                                                                                                          "\n"
2728                                                                                                          + getTessellationEvaluationInLayoutString(m_primitiveType, m_winding) +
2729                                                                                                          "\n"
2730                                                                                                          "void main (void)\n"
2731                                                                                                          "{\n"
2732                                                                                                          "      gl_Position = vec4(gl_TessCoord.xy*2.0 - 1.0, 0.0, 1.0);\n"
2733                                                                                                          "}\n")
2734
2735                         << glu::FragmentSource                                  ("#version 310 es\n"
2736                                                                                                          "\n"
2737                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
2738                                                                                                          "\n"
2739                                                                                                          "void main (void)\n"
2740                                                                                                          "{\n"
2741                                                                                                          "      o_color = vec4(1.0);\n"
2742                                                                                                          "}\n")));
2743
2744         m_testCtx.getLog() << *m_program;
2745         if (!m_program->isOk())
2746                 TCU_FAIL("Program compilation failed");
2747 }
2748
2749 void WindingCase::deinit (void)
2750 {
2751         m_program.clear();
2752 }
2753
2754 WindingCase::IterateResult WindingCase::iterate (void)
2755 {
2756         TestLog&                                                log                                                     = m_testCtx.getLog();
2757         const RenderContext&                    renderCtx                                       = m_context.getRenderContext();
2758         const RandomViewport                    viewport                                        (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2759         const deUint32                                  programGL                                       = m_program->getProgram();
2760         const glw::Functions&                   gl                                                      = renderCtx.getFunctions();
2761         const glu::VertexArray                  vao                                                     (renderCtx);
2762
2763         bool                                                    success                                         = true;
2764
2765         setViewport(gl, viewport);
2766         gl.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
2767         gl.useProgram(programGL);
2768
2769         gl.patchParameteri(GL_PATCH_VERTICES, 1);
2770
2771         gl.enable(GL_CULL_FACE);
2772
2773         gl.bindVertexArray(*vao);
2774
2775         log << TestLog::Message << "Face culling enabled" << TestLog::EndMessage;
2776
2777         for (int frontFaceWinding = 0; frontFaceWinding < WINDING_LAST; frontFaceWinding++)
2778         {
2779                 log << TestLog::Message << "Setting glFrontFace(" << (frontFaceWinding == WINDING_CW ? "GL_CW" : "GL_CCW") << ")" << TestLog::EndMessage;
2780
2781                 gl.frontFace(frontFaceWinding == WINDING_CW ? GL_CW : GL_CCW);
2782
2783                 gl.clear(GL_COLOR_BUFFER_BIT);
2784                 gl.drawArrays(GL_PATCHES, 0, 1);
2785                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
2786
2787                 {
2788                         const tcu::Surface rendered = getPixels(renderCtx, viewport);
2789                         log << TestLog::Image("RenderedImage", "Rendered Image", rendered);
2790
2791                         {
2792                                 const int totalNumPixels                = rendered.getWidth()*rendered.getHeight();
2793                                 const int badPixelTolerance             = m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 5*de::max(rendered.getWidth(), rendered.getHeight()) : 0;
2794
2795                                 int numWhitePixels      = 0;
2796                                 int numRedPixels        = 0;
2797                                 for (int y = 0; y < rendered.getHeight();       y++)
2798                                 for (int x = 0; x < rendered.getWidth();        x++)
2799                                 {
2800                                         numWhitePixels  += rendered.getPixel(x, y) == tcu::RGBA::white()        ? 1 : 0;
2801                                         numRedPixels    += rendered.getPixel(x, y) == tcu::RGBA::red()  ? 1 : 0;
2802                                 }
2803
2804                                 DE_ASSERT(numWhitePixels + numRedPixels <= totalNumPixels);
2805
2806                                 log << TestLog::Message << "Note: got " << numWhitePixels << " white and " << numRedPixels << " red pixels" << TestLog::EndMessage;
2807
2808                                 if (totalNumPixels - numWhitePixels - numRedPixels > badPixelTolerance)
2809                                 {
2810                                         log << TestLog::Message << "Failure: Got " << totalNumPixels - numWhitePixels - numRedPixels << " other than white or red pixels (maximum tolerance " << badPixelTolerance << ")" << TestLog::EndMessage;
2811                                         success = false;
2812                                         break;
2813                                 }
2814
2815                                 if ((Winding)frontFaceWinding == m_winding)
2816                                 {
2817                                         if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2818                                         {
2819                                                 if (de::abs(numWhitePixels - totalNumPixels/2) > badPixelTolerance)
2820                                                 {
2821                                                         log << TestLog::Message << "Failure: wrong number of white pixels; expected approximately " << totalNumPixels/2 << TestLog::EndMessage;
2822                                                         success = false;
2823                                                         break;
2824                                                 }
2825                                         }
2826                                         else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
2827                                         {
2828                                                 if (numWhitePixels != totalNumPixels)
2829                                                 {
2830                                                         log << TestLog::Message << "Failure: expected only white pixels (full-viewport quad)" << TestLog::EndMessage;
2831                                                         success = false;
2832                                                         break;
2833                                                 }
2834                                         }
2835                                         else
2836                                                 DE_ASSERT(false);
2837                                 }
2838                                 else
2839                                 {
2840                                         if (numWhitePixels != 0)
2841                                         {
2842                                                 log << TestLog::Message << "Failure: expected only red pixels (everything culled)" << TestLog::EndMessage;
2843                                                 success = false;
2844                                                 break;
2845                                         }
2846                                 }
2847                         }
2848                 }
2849         }
2850
2851         m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image verification failed");
2852         return STOP;
2853 }
2854
2855 // Test potentially differing input and output patch sizes.
2856 class PatchVertexCountCase : public TestCase
2857 {
2858 public:
2859         PatchVertexCountCase (Context& context, const char* name, const char* description, int inputPatchSize, int outputPatchSize, const char* referenceImagePath)
2860                 : TestCase                              (context, name, description)
2861                 , m_inputPatchSize              (inputPatchSize)
2862                 , m_outputPatchSize             (outputPatchSize)
2863                 , m_referenceImagePath  (referenceImagePath)
2864         {
2865         }
2866
2867         void                                                    init                            (void);
2868         void                                                    deinit                          (void);
2869         IterateResult                                   iterate                         (void);
2870
2871 private:
2872         static const int                                RENDER_SIZE = 256;
2873
2874         const int                                               m_inputPatchSize;
2875         const int                                               m_outputPatchSize;
2876
2877         const string                                    m_referenceImagePath;
2878
2879         SharedPtr<const ShaderProgram>  m_program;
2880 };
2881
2882 void PatchVertexCountCase::init (void)
2883 {
2884         checkTessellationSupport(m_context);
2885         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2886
2887         const string inSizeStr          = de::toString(m_inputPatchSize);
2888         const string outSizeStr         = de::toString(m_outputPatchSize);
2889
2890         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2891                         << glu::VertexSource                                    ("#version 310 es\n"
2892                                                                                                          "\n"
2893                                                                                                          "in highp float in_v_attr;\n"
2894                                                                                                          "\n"
2895                                                                                                          "out highp float in_tc_attr;\n"
2896                                                                                                          "\n"
2897                                                                                                          "void main (void)\n"
2898                                                                                                          "{\n"
2899                                                                                                          "      in_tc_attr = in_v_attr;\n"
2900                                                                                                          "}\n")
2901
2902                         << glu::TessellationControlSource               ("#version 310 es\n"
2903                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
2904                                                                                                          "\n"
2905                                                                                                          "layout (vertices = " + outSizeStr + ") out;\n"
2906                                                                                                          "\n"
2907                                                                                                          "in highp float in_tc_attr[];\n"
2908                                                                                                          "\n"
2909                                                                                                          "out highp float in_te_attr[];\n"
2910                                                                                                          "\n"
2911                                                                                                          "void main (void)\n"
2912                                                                                                          "{\n"
2913                                                                                                          "      in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID*" + inSizeStr + "/" + outSizeStr + "];\n"
2914                                                                                                          "\n"
2915                                                                                                          "      gl_TessLevelInner[0] = 5.0;\n"
2916                                                                                                          "      gl_TessLevelInner[1] = 5.0;\n"
2917                                                                                                          "\n"
2918                                                                                                         "       gl_TessLevelOuter[0] = 5.0;\n"
2919                                                                                                         "       gl_TessLevelOuter[1] = 5.0;\n"
2920                                                                                                         "       gl_TessLevelOuter[2] = 5.0;\n"
2921                                                                                                         "       gl_TessLevelOuter[3] = 5.0;\n"
2922                                                                                                          "}\n")
2923
2924                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
2925                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
2926                                                                                                          "\n"
2927                                                                                                          + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_QUADS) +
2928                                                                                                          "\n"
2929                                                                                                          "in highp float in_te_attr[];\n"
2930                                                                                                          "\n"
2931                                                                                                          "out mediump vec4 in_f_color;\n"
2932                                                                                                          "\n"
2933                                                                                                          "void main (void)\n"
2934                                                                                                          "{\n"
2935                                                                                                          "      highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
2936                                                                                                          "      highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" + outSizeStr + "-1)))];\n"
2937                                                                                                          "      gl_Position = vec4(x, y, 0.0, 1.0);\n"
2938                                                                                                          "      in_f_color = vec4(1.0);\n"
2939                                                                                                          "}\n")
2940
2941                         << glu::FragmentSource                                  ("#version 310 es\n"
2942                                                                                                          "\n"
2943                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
2944                                                                                                          "\n"
2945                                                                                                          "in mediump vec4 in_f_color;\n"
2946                                                                                                          "\n"
2947                                                                                                          "void main (void)\n"
2948                                                                                                          "{\n"
2949                                                                                                          "      o_color = in_f_color;\n"
2950                                                                                                          "}\n")));
2951
2952         m_testCtx.getLog() << *m_program;
2953         if (!m_program->isOk())
2954                 TCU_FAIL("Program compilation failed");
2955 }
2956
2957 void PatchVertexCountCase::deinit (void)
2958 {
2959         m_program.clear();
2960 }
2961
2962 PatchVertexCountCase::IterateResult PatchVertexCountCase::iterate (void)
2963 {
2964         TestLog&                                        log                                             = m_testCtx.getLog();
2965         const RenderContext&            renderCtx                               = m_context.getRenderContext();
2966         const RandomViewport            viewport                                (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2967         const deUint32                          programGL                               = m_program->getProgram();
2968         const glw::Functions&           gl                                              = renderCtx.getFunctions();
2969
2970         setViewport(gl, viewport);
2971         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2972         gl.useProgram(programGL);
2973
2974         log << TestLog::Message << "Note: input patch size is " << m_inputPatchSize << ", output patch size is " << m_outputPatchSize << TestLog::EndMessage;
2975
2976         {
2977                 vector<float> attributeData;
2978                 attributeData.reserve(m_inputPatchSize);
2979
2980                 for (int i = 0; i < m_inputPatchSize; i++)
2981                 {
2982                         const float f = (float)i / (float)(m_inputPatchSize-1);
2983                         attributeData.push_back(f*f);
2984                 }
2985
2986                 gl.patchParameteri(GL_PATCH_VERTICES, m_inputPatchSize);
2987                 gl.clear(GL_COLOR_BUFFER_BIT);
2988
2989                 const glu::VertexArrayBinding attrBindings[] =
2990                 {
2991                         glu::va::Float("in_v_attr", 1, (int)attributeData.size(), 0, &attributeData[0])
2992                 };
2993
2994                 glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
2995                         glu::pr::Patches(m_inputPatchSize));
2996                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
2997         }
2998
2999         {
3000                 const tcu::Surface                      rendered        = getPixels(renderCtx, viewport);
3001                 const tcu::TextureLevel         reference       = getPNG(m_testCtx.getArchive(), m_referenceImagePath);
3002                 const bool                                      success         = tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
3003
3004                 m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image comparison failed");
3005                 return STOP;
3006         }
3007 }
3008
3009 // Test per-patch inputs/outputs.
3010 class PerPatchDataCase : public TestCase
3011 {
3012 public:
3013         enum CaseType
3014         {
3015                 CASETYPE_PRIMITIVE_ID_TCS = 0,
3016                 CASETYPE_PRIMITIVE_ID_TES,
3017                 CASETYPE_PATCH_VERTICES_IN_TCS,
3018                 CASETYPE_PATCH_VERTICES_IN_TES,
3019                 CASETYPE_TESS_LEVEL_INNER0_TES,
3020                 CASETYPE_TESS_LEVEL_INNER1_TES,
3021                 CASETYPE_TESS_LEVEL_OUTER0_TES,
3022                 CASETYPE_TESS_LEVEL_OUTER1_TES,
3023                 CASETYPE_TESS_LEVEL_OUTER2_TES,
3024                 CASETYPE_TESS_LEVEL_OUTER3_TES,
3025
3026                 CASETYPE_LAST
3027         };
3028
3029         PerPatchDataCase (Context& context, const char* name, const char* description, CaseType caseType, const char* referenceImagePath)
3030                 : TestCase                              (context, name, description)
3031                 , m_caseType                    (caseType)
3032                 , m_referenceImagePath  (caseTypeUsesRefImageFromFile(caseType) ? referenceImagePath : "")
3033         {
3034                 DE_ASSERT(caseTypeUsesRefImageFromFile(caseType) == (referenceImagePath != DE_NULL));
3035         }
3036
3037         void                                                    init                                                    (void);
3038         void                                                    deinit                                                  (void);
3039         IterateResult                                   iterate                                                 (void);
3040
3041         static const char*                              getCaseTypeName                                 (CaseType);
3042         static const char*                              getCaseTypeDescription                  (CaseType);
3043         static bool                                             caseTypeUsesRefImageFromFile    (CaseType);
3044
3045 private:
3046         static const int                                RENDER_SIZE = 256;
3047         static const int                                INPUT_PATCH_SIZE;
3048         static const int                                OUTPUT_PATCH_SIZE;
3049
3050         const CaseType                                  m_caseType;
3051         const string                                    m_referenceImagePath;
3052
3053         SharedPtr<const ShaderProgram>  m_program;
3054 };
3055
3056 const int PerPatchDataCase::INPUT_PATCH_SIZE    = 10;
3057 const int PerPatchDataCase::OUTPUT_PATCH_SIZE   = 5;
3058
3059 const char* PerPatchDataCase::getCaseTypeName (CaseType type)
3060 {
3061         switch (type)
3062         {
3063                 case CASETYPE_PRIMITIVE_ID_TCS:                 return "primitive_id_tcs";
3064                 case CASETYPE_PRIMITIVE_ID_TES:                 return "primitive_id_tes";
3065                 case CASETYPE_PATCH_VERTICES_IN_TCS:    return "patch_vertices_in_tcs";
3066                 case CASETYPE_PATCH_VERTICES_IN_TES:    return "patch_vertices_in_tes";
3067                 case CASETYPE_TESS_LEVEL_INNER0_TES:    return "tess_level_inner_0_tes";
3068                 case CASETYPE_TESS_LEVEL_INNER1_TES:    return "tess_level_inner_1_tes";
3069                 case CASETYPE_TESS_LEVEL_OUTER0_TES:    return "tess_level_outer_0_tes";
3070                 case CASETYPE_TESS_LEVEL_OUTER1_TES:    return "tess_level_outer_1_tes";
3071                 case CASETYPE_TESS_LEVEL_OUTER2_TES:    return "tess_level_outer_2_tes";
3072                 case CASETYPE_TESS_LEVEL_OUTER3_TES:    return "tess_level_outer_3_tes";
3073                 default:
3074                         DE_ASSERT(false);
3075                         return DE_NULL;
3076         }
3077 }
3078
3079 const char* PerPatchDataCase::getCaseTypeDescription (CaseType type)
3080 {
3081         switch (type)
3082         {
3083                 case CASETYPE_PRIMITIVE_ID_TCS:                 return "Read gl_PrimitiveID in TCS and pass it as patch output to TES";
3084                 case CASETYPE_PRIMITIVE_ID_TES:                 return "Read gl_PrimitiveID in TES";
3085                 case CASETYPE_PATCH_VERTICES_IN_TCS:    return "Read gl_PatchVerticesIn in TCS and pass it as patch output to TES";
3086                 case CASETYPE_PATCH_VERTICES_IN_TES:    return "Read gl_PatchVerticesIn in TES";
3087                 case CASETYPE_TESS_LEVEL_INNER0_TES:    return "Read gl_TessLevelInner[0] in TES";
3088                 case CASETYPE_TESS_LEVEL_INNER1_TES:    return "Read gl_TessLevelInner[1] in TES";
3089                 case CASETYPE_TESS_LEVEL_OUTER0_TES:    return "Read gl_TessLevelOuter[0] in TES";
3090                 case CASETYPE_TESS_LEVEL_OUTER1_TES:    return "Read gl_TessLevelOuter[1] in TES";
3091                 case CASETYPE_TESS_LEVEL_OUTER2_TES:    return "Read gl_TessLevelOuter[2] in TES";
3092                 case CASETYPE_TESS_LEVEL_OUTER3_TES:    return "Read gl_TessLevelOuter[3] in TES";
3093                 default:
3094                         DE_ASSERT(false);
3095                         return DE_NULL;
3096         }
3097 }
3098
3099 bool PerPatchDataCase::caseTypeUsesRefImageFromFile (CaseType type)
3100 {
3101         switch (type)
3102         {
3103                 case CASETYPE_PRIMITIVE_ID_TCS:
3104                 case CASETYPE_PRIMITIVE_ID_TES:
3105                         return true;
3106
3107                 default:
3108                         return false;
3109         }
3110 }
3111
3112 void PerPatchDataCase::init (void)
3113 {
3114         checkTessellationSupport(m_context);
3115         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3116
3117         DE_ASSERT(OUTPUT_PATCH_SIZE < INPUT_PATCH_SIZE);
3118
3119         const string inSizeStr          = de::toString(INPUT_PATCH_SIZE);
3120         const string outSizeStr         = de::toString(OUTPUT_PATCH_SIZE);
3121
3122         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3123                         << glu::VertexSource                                    ("#version 310 es\n"
3124                                                                                                          "\n"
3125                                                                                                          "in highp float in_v_attr;\n"
3126                                                                                                          "\n"
3127                                                                                                          "out highp float in_tc_attr;\n"
3128                                                                                                          "\n"
3129                                                                                                          "void main (void)\n"
3130                                                                                                          "{\n"
3131                                                                                                          "      in_tc_attr = in_v_attr;\n"
3132                                                                                                          "}\n")
3133
3134                         << glu::TessellationControlSource               ("#version 310 es\n"
3135                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
3136                                                                                                          "\n"
3137                                                                                                          "layout (vertices = " + outSizeStr + ") out;\n"
3138                                                                                                          "\n"
3139                                                                                                          "in highp float in_tc_attr[];\n"
3140                                                                                                          "\n"
3141                                                                                                          "out highp float in_te_attr[];\n"
3142                                                                                                          + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS                     ? "patch out mediump int in_te_primitiveIDFromTCS;\n"
3143                                                                                                           : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS        ? "patch out mediump int in_te_patchVerticesInFromTCS;\n"
3144                                                                                                           : "") +
3145                                                                                                          "\n"
3146                                                                                                          "void main (void)\n"
3147                                                                                                          "{\n"
3148                                                                                                          "      in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
3149                                                                                                          + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS                     ? "\tin_te_primitiveIDFromTCS = gl_PrimitiveID;\n"
3150                                                                                                           : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS        ? "\tin_te_patchVerticesInFromTCS = gl_PatchVerticesIn;\n"
3151                                                                                                           : "") +
3152                                                                                                          "\n"
3153                                                                                                          "      gl_TessLevelInner[0] = 9.0;\n"
3154                                                                                                          "      gl_TessLevelInner[1] = 8.0;\n"
3155                                                                                                          "\n"
3156                                                                                                         "       gl_TessLevelOuter[0] = 7.0;\n"
3157                                                                                                         "       gl_TessLevelOuter[1] = 6.0;\n"
3158                                                                                                         "       gl_TessLevelOuter[2] = 5.0;\n"
3159                                                                                                         "       gl_TessLevelOuter[3] = 4.0;\n"
3160                                                                                                          "}\n")
3161
3162                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
3163                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
3164                                                                                                          "\n"
3165                                                                                                          + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_QUADS) +
3166                                                                                                          "\n"
3167                                                                                                          "in highp float in_te_attr[];\n"
3168                                                                                                          + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS                     ? "patch in mediump int in_te_primitiveIDFromTCS;\n"
3169                                                                                                           : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS        ? "patch in mediump int in_te_patchVerticesInFromTCS;\n"
3170                                                                                                           : string()) +
3171                                                                                                          "\n"
3172                                                                                                          "out mediump vec4 in_f_color;\n"
3173                                                                                                          "\n"
3174                                                                                                          "uniform highp float u_xScale;\n"
3175                                                                                                          "\n"
3176                                                                                                          "void main (void)\n"
3177                                                                                                          "{\n"
3178                                                                                                          "      highp float x = (gl_TessCoord.x*u_xScale + in_te_attr[0]) * 2.0 - 1.0;\n"
3179                                                                                                          "      highp float y = gl_TessCoord.y*2.0 - 1.0;\n"
3180                                                                                                          "      gl_Position = vec4(x, y, 0.0, 1.0);\n"
3181                                                                                                          + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS                     ? "\tbool ok = in_te_primitiveIDFromTCS == 3;\n"
3182                                                                                                           : m_caseType == CASETYPE_PRIMITIVE_ID_TES                     ? "\tbool ok = gl_PrimitiveID == 3;\n"
3183                                                                                                           : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS        ? "\tbool ok = in_te_patchVerticesInFromTCS == " + inSizeStr + ";\n"
3184                                                                                                           : m_caseType == CASETYPE_PATCH_VERTICES_IN_TES        ? "\tbool ok = gl_PatchVerticesIn == " + outSizeStr + ";\n"
3185                                                                                                           : m_caseType == CASETYPE_TESS_LEVEL_INNER0_TES        ? "\tbool ok = abs(gl_TessLevelInner[0] - 9.0) < 0.1f;\n"
3186                                                                                                           : m_caseType == CASETYPE_TESS_LEVEL_INNER1_TES        ? "\tbool ok = abs(gl_TessLevelInner[1] - 8.0) < 0.1f;\n"
3187                                                                                                           : m_caseType == CASETYPE_TESS_LEVEL_OUTER0_TES        ? "\tbool ok = abs(gl_TessLevelOuter[0] - 7.0) < 0.1f;\n"
3188                                                                                                           : m_caseType == CASETYPE_TESS_LEVEL_OUTER1_TES        ? "\tbool ok = abs(gl_TessLevelOuter[1] - 6.0) < 0.1f;\n"
3189                                                                                                           : m_caseType == CASETYPE_TESS_LEVEL_OUTER2_TES        ? "\tbool ok = abs(gl_TessLevelOuter[2] - 5.0) < 0.1f;\n"
3190                                                                                                           : m_caseType == CASETYPE_TESS_LEVEL_OUTER3_TES        ? "\tbool ok = abs(gl_TessLevelOuter[3] - 4.0) < 0.1f;\n"
3191                                                                                                           : DE_NULL) +
3192                                                                                                           "     in_f_color = ok ? vec4(1.0) : vec4(vec3(0.0), 1.0);\n"
3193                                                                                                          "}\n")
3194
3195                         << glu::FragmentSource                                  ("#version 310 es\n"
3196                                                                                                          "\n"
3197                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
3198                                                                                                          "\n"
3199                                                                                                          "in mediump vec4 in_f_color;\n"
3200                                                                                                          "\n"
3201                                                                                                          "void main (void)\n"
3202                                                                                                          "{\n"
3203                                                                                                          "      o_color = in_f_color;\n"
3204                                                                                                          "}\n")));
3205
3206         m_testCtx.getLog() << *m_program;
3207         if (!m_program->isOk())
3208                 TCU_FAIL("Program compilation failed");
3209 }
3210
3211 void PerPatchDataCase::deinit (void)
3212 {
3213         m_program.clear();
3214 }
3215
3216 PerPatchDataCase::IterateResult PerPatchDataCase::iterate (void)
3217 {
3218         TestLog&                                        log                                             = m_testCtx.getLog();
3219         const RenderContext&            renderCtx                               = m_context.getRenderContext();
3220         const RandomViewport            viewport                                (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3221         const deUint32                          programGL                               = m_program->getProgram();
3222         const glw::Functions&           gl                                              = renderCtx.getFunctions();
3223
3224         setViewport(gl, viewport);
3225         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3226         gl.useProgram(programGL);
3227
3228         log << TestLog::Message << "Note: input patch size is " << INPUT_PATCH_SIZE << ", output patch size is " << OUTPUT_PATCH_SIZE << TestLog::EndMessage;
3229
3230         {
3231                 const int numPrimitives = m_caseType == CASETYPE_PRIMITIVE_ID_TCS || m_caseType == CASETYPE_PRIMITIVE_ID_TES ? 8 : 1;
3232
3233                 vector<float> attributeData;
3234                 attributeData.reserve(numPrimitives*INPUT_PATCH_SIZE);
3235
3236                 for (int i = 0; i < numPrimitives; i++)
3237                 {
3238                         attributeData.push_back((float)i / (float)numPrimitives);
3239                         for (int j = 0; j < INPUT_PATCH_SIZE-1; j++)
3240                                 attributeData.push_back(0.0f);
3241                 }
3242
3243                 gl.patchParameteri(GL_PATCH_VERTICES, INPUT_PATCH_SIZE);
3244                 gl.clear(GL_COLOR_BUFFER_BIT);
3245
3246                 gl.uniform1f(gl.getUniformLocation(programGL, "u_xScale"), 1.0f / (float)numPrimitives);
3247
3248                 const glu::VertexArrayBinding attrBindings[] =
3249                 {
3250                         glu::va::Float("in_v_attr", 1, (int)attributeData.size(), 0, &attributeData[0])
3251                 };
3252
3253                 glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
3254                         glu::pr::Patches(numPrimitives*INPUT_PATCH_SIZE));
3255                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
3256         }
3257
3258         {
3259                 const tcu::Surface rendered = getPixels(renderCtx, viewport);
3260
3261                 if (m_caseType == CASETYPE_PRIMITIVE_ID_TCS || m_caseType == CASETYPE_PRIMITIVE_ID_TES)
3262                 {
3263                         DE_ASSERT(caseTypeUsesRefImageFromFile(m_caseType));
3264
3265                         const tcu::TextureLevel         reference       = getPNG(m_testCtx.getArchive(), m_referenceImagePath);
3266                         const bool                                      success         = tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
3267
3268                         m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image comparison failed");
3269                         return STOP;
3270                 }
3271                 else
3272                 {
3273                         DE_ASSERT(!caseTypeUsesRefImageFromFile(m_caseType));
3274
3275                         log << TestLog::Image("RenderedImage", "Rendered Image", rendered);
3276
3277                         for (int y = 0; y < rendered.getHeight();       y++)
3278                         for (int x = 0; x < rendered.getWidth();        x++)
3279                         {
3280                                 if (rendered.getPixel(x, y) != tcu::RGBA::white())
3281                                 {
3282                                         log << TestLog::Message << "Failure: expected all white pixels" << TestLog::EndMessage;
3283                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
3284                                         return STOP;
3285                                 }
3286                         }
3287
3288                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3289                         return STOP;
3290                 }
3291         }
3292 }
3293
3294 // Basic barrier() usage in TCS.
3295 class BarrierCase : public TestCase
3296 {
3297 public:
3298         BarrierCase (Context& context, const char* name, const char* description, const char* referenceImagePath)
3299                 : TestCase                              (context, name, description)
3300                 , m_referenceImagePath  (referenceImagePath)
3301         {
3302         }
3303
3304         void                                                    init            (void);
3305         void                                                    deinit          (void);
3306         IterateResult                                   iterate         (void);
3307
3308 private:
3309         static const int                                RENDER_SIZE = 256;
3310         static const int                                NUM_VERTICES;
3311
3312         const string                                    m_referenceImagePath;
3313
3314         SharedPtr<const ShaderProgram>  m_program;
3315 };
3316
3317 const int BarrierCase::NUM_VERTICES = 32;
3318
3319 void BarrierCase::init (void)
3320 {
3321         checkTessellationSupport(m_context);
3322         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3323
3324         const string numVertsStr = de::toString(NUM_VERTICES);
3325
3326         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3327                         << glu::VertexSource                                    ("#version 310 es\n"
3328                                                                                                          "\n"
3329                                                                                                          "in highp float in_v_attr;\n"
3330                                                                                                          "\n"
3331                                                                                                          "out highp float in_tc_attr;\n"
3332                                                                                                          "\n"
3333                                                                                                          "void main (void)\n"
3334                                                                                                          "{\n"
3335                                                                                                          "      in_tc_attr = in_v_attr;\n"
3336                                                                                                          "}\n")
3337
3338                         << glu::TessellationControlSource               ("#version 310 es\n"
3339                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
3340                                                                                                          "\n"
3341                                                                                                          "layout (vertices = " + numVertsStr + ") out;\n"
3342                                                                                                          "\n"
3343                                                                                                          "in highp float in_tc_attr[];\n"
3344                                                                                                          "\n"
3345                                                                                                          "out highp float in_te_attr[];\n"
3346                                                                                                          "patch out highp float in_te_patchAttr;\n"
3347                                                                                                          "\n"
3348                                                                                                          "void main (void)\n"
3349                                                                                                          "{\n"
3350                                                                                                          "      in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
3351                                                                                                          "      in_te_patchAttr = 0.0f;\n"
3352                                                                                                          "      barrier();\n"
3353                                                                                                          "      if (gl_InvocationID == 5)\n"
3354                                                                                                          "              in_te_patchAttr = float(gl_InvocationID)*0.1;\n"
3355                                                                                                          "      barrier();\n"
3356                                                                                                          "      highp float temp = in_te_patchAttr + in_te_attr[gl_InvocationID];\n"
3357                                                                                                          "      barrier();\n"
3358                                                                                                          "      if (gl_InvocationID == " + numVertsStr + "-1)\n"
3359                                                                                                          "              in_te_patchAttr = float(gl_InvocationID);\n"
3360                                                                                                          "      barrier();\n"
3361                                                                                                          "      in_te_attr[gl_InvocationID] = temp;\n"
3362                                                                                                          "      barrier();\n"
3363                                                                                                          "      temp = temp + in_te_attr[(gl_InvocationID+1) % " + numVertsStr + "];\n"
3364                                                                                                          "      barrier();\n"
3365                                                                                                          "      in_te_attr[gl_InvocationID] = 0.25*temp;\n"
3366                                                                                                          "\n"
3367                                                                                                          "      gl_TessLevelInner[0] = 32.0;\n"
3368                                                                                                          "      gl_TessLevelInner[1] = 32.0;\n"
3369                                                                                                          "\n"
3370                                                                                                          "      gl_TessLevelOuter[0] = 32.0;\n"
3371                                                                                                          "      gl_TessLevelOuter[1] = 32.0;\n"
3372                                                                                                          "      gl_TessLevelOuter[2] = 32.0;\n"
3373                                                                                                          "      gl_TessLevelOuter[3] = 32.0;\n"
3374                                                                                                          "}\n")
3375
3376                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
3377                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
3378                                                                                                          "\n"
3379                                                                                                          + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_QUADS) +
3380                                                                                                          "\n"
3381                                                                                                          "in highp float in_te_attr[];\n"
3382                                                                                                          "patch in highp float in_te_patchAttr;\n"
3383                                                                                                          "\n"
3384                                                                                                          "out highp float in_f_blue;\n"
3385                                                                                                          "\n"
3386                                                                                                          "void main (void)\n"
3387                                                                                                          "{\n"
3388                                                                                                          "      highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
3389                                                                                                          "      highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" + numVertsStr + "-1)))];\n"
3390                                                                                                          "      gl_Position = vec4(x, y, 0.0, 1.0);\n"
3391                                                                                                          "      in_f_blue = abs(in_te_patchAttr - float(" + numVertsStr + "-1));\n"
3392                                                                                                          "}\n")
3393
3394                         << glu::FragmentSource                                  ("#version 310 es\n"
3395                                                                                                          "\n"
3396                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
3397                                                                                                          "\n"
3398                                                                                                          "in highp float in_f_blue;\n"
3399                                                                                                          "\n"
3400                                                                                                          "void main (void)\n"
3401                                                                                                          "{\n"
3402                                                                                                          "      o_color = vec4(1.0, 0.0, in_f_blue, 1.0);\n"
3403                                                                                                          "}\n")));
3404
3405         m_testCtx.getLog() << *m_program;
3406         if (!m_program->isOk())
3407                 TCU_FAIL("Program compilation failed");
3408 }
3409
3410 void BarrierCase::deinit (void)
3411 {
3412         m_program.clear();
3413 }
3414
3415 BarrierCase::IterateResult BarrierCase::iterate (void)
3416 {
3417         TestLog&                                        log                                             = m_testCtx.getLog();
3418         const RenderContext&            renderCtx                               = m_context.getRenderContext();
3419         const RandomViewport            viewport                                (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3420         const deUint32                          programGL                               = m_program->getProgram();
3421         const glw::Functions&           gl                                              = renderCtx.getFunctions();
3422
3423         setViewport(gl, viewport);
3424         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3425         gl.useProgram(programGL);
3426
3427         {
3428                 vector<float> attributeData(NUM_VERTICES);
3429
3430                 for (int i = 0; i < NUM_VERTICES; i++)
3431                         attributeData[i] = (float)i / (float)(NUM_VERTICES-1);
3432
3433                 gl.patchParameteri(GL_PATCH_VERTICES, NUM_VERTICES);
3434                 gl.clear(GL_COLOR_BUFFER_BIT);
3435
3436                 const glu::VertexArrayBinding attrBindings[] =
3437                 {
3438                         glu::va::Float("in_v_attr", 1, (int)attributeData.size(), 0, &attributeData[0])
3439                 };
3440
3441                 glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
3442                         glu::pr::Patches(NUM_VERTICES));
3443                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
3444         }
3445
3446         {
3447                 const tcu::Surface                      rendered        = getPixels(renderCtx, viewport);
3448                 const tcu::TextureLevel         reference       = getPNG(m_testCtx.getArchive(), m_referenceImagePath);
3449                 const bool                                      success         = tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
3450
3451                 m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image comparison failed");
3452                 return STOP;
3453         }
3454 }
3455
3456 /*--------------------------------------------------------------------*//*!
3457  * \brief Base class for testing invariance of entire primitive set
3458  *
3459  * Draws two patches with identical tessellation levels and compares the
3460  * results. Repeats the same with other programs that are only different
3461  * in irrelevant ways; compares the results between these two programs.
3462  * Also potentially compares to results produced by different tessellation
3463  * levels (see e.g. invariance rule #6).
3464  * Furthermore, repeats the above with multiple different tessellation
3465  * value sets.
3466  *
3467  * The manner of primitive set comparison is defined by subclass. E.g.
3468  * case for invariance rule #1 tests that same vertices come out, in same
3469  * order; rule #5 only requires that the same triangles are output, but
3470  * not necessarily in the same order.
3471  *//*--------------------------------------------------------------------*/
3472 class PrimitiveSetInvarianceCase : public TestCase
3473 {
3474 public:
3475         enum WindingUsage
3476         {
3477                 WINDINGUSAGE_CCW = 0,
3478                 WINDINGUSAGE_CW,
3479                 WINDINGUSAGE_VARY,
3480
3481                 WINDINGUSAGE_LAST
3482         };
3483
3484         PrimitiveSetInvarianceCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, bool usePointMode, WindingUsage windingUsage)
3485                 : TestCase                      (context, name, description)
3486                 , m_primitiveType       (primType)
3487                 , m_spacing                     (spacing)
3488                 , m_usePointMode        (usePointMode)
3489                 , m_windingUsage        (windingUsage)
3490         {
3491         }
3492
3493         void                                                                    init                            (void);
3494         void                                                                    deinit                          (void);
3495         IterateResult                                                   iterate                         (void);
3496
3497 protected:
3498         struct TessLevels
3499         {
3500                 float inner[2];
3501                 float outer[4];
3502                 string description (void) const { return tessellationLevelsString(&inner[0], &outer[0]); }
3503         };
3504         struct LevelCase
3505         {
3506                 vector<TessLevels>      levels;
3507                 int                                     mem; //!< Subclass-defined arbitrary piece of data, for type of the levelcase, if needed. Passed to compare().
3508                 LevelCase (const TessLevels& lev) : levels(vector<TessLevels>(1, lev)), mem(0) {}
3509                 LevelCase (void) : mem(0) {}
3510         };
3511
3512         virtual vector<LevelCase>       genTessLevelCases       (void) const;
3513         virtual bool                            compare                         (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int levelCaseMem) const = 0;
3514
3515         const TessPrimitiveType         m_primitiveType;
3516
3517 private:
3518         struct Program
3519         {
3520                 Winding                                                 winding;
3521                 SharedPtr<const ShaderProgram>  program;
3522
3523                                 Program                 (Winding w, const SharedPtr<const ShaderProgram>& prog) : winding(w), program(prog) {}
3524
3525                 string  description             (void) const { return string() + "winding mode " + getWindingShaderName(winding); };
3526         };
3527
3528         static const int                        RENDER_SIZE = 16;
3529
3530         const SpacingMode                       m_spacing;
3531         const bool                                      m_usePointMode;
3532         const WindingUsage                      m_windingUsage;
3533
3534         vector<Program>                         m_programs;
3535 };
3536
3537 vector<PrimitiveSetInvarianceCase::LevelCase> PrimitiveSetInvarianceCase::genTessLevelCases (void) const
3538 {
3539         static const TessLevels basicTessLevelCases[] =
3540         {
3541                 { { 1.0f,       1.0f    },      { 1.0f,         1.0f,   1.0f,   1.0f    } },
3542                 { { 63.0f,      24.0f   },      { 15.0f,        42.0f,  10.0f,  12.0f   } },
3543                 { { 3.0f,       2.0f    },      { 6.0f,         8.0f,   7.0f,   9.0f    } },
3544                 { { 4.0f,       6.0f    },      { 2.0f,         3.0f,   1.0f,   4.0f    } },
3545                 { { 2.0f,       2.0f    },      { 6.0f,         8.0f,   7.0f,   9.0f    } },
3546                 { { 5.0f,       6.0f    },      { 1.0f,         1.0f,   1.0f,   1.0f    } },
3547                 { { 1.0f,       6.0f    },      { 2.0f,         3.0f,   1.0f,   4.0f    } },
3548                 { { 5.0f,       1.0f    },      { 2.0f,         3.0f,   1.0f,   4.0f    } },
3549                 { { 5.2f,       1.6f    },      { 2.9f,         3.4f,   1.5f,   4.1f    } }
3550         };
3551
3552         vector<LevelCase> result;
3553         for (int i = 0; i < DE_LENGTH_OF_ARRAY(basicTessLevelCases); i++)
3554                 result.push_back(LevelCase(basicTessLevelCases[i]));
3555
3556         {
3557                 de::Random rnd(123);
3558                 for (int i = 0; i < 10; i++)
3559                 {
3560                         TessLevels levels;
3561                         for (int j = 0; j < DE_LENGTH_OF_ARRAY(levels.inner); j++)
3562                                 levels.inner[j] = rnd.getFloat(1.0f, 16.0f);
3563                         for (int j = 0; j < DE_LENGTH_OF_ARRAY(levels.outer); j++)
3564                                 levels.outer[j] = rnd.getFloat(1.0f, 16.0f);
3565                         result.push_back(LevelCase(levels));
3566                 }
3567         }
3568
3569         return result;
3570 }
3571
3572 void PrimitiveSetInvarianceCase::init (void)
3573 {
3574         const int                       numDifferentConstantExprCases = 2;
3575         vector<Winding>         windings;
3576         switch (m_windingUsage)
3577         {
3578                 case WINDINGUSAGE_CCW:          windings.push_back(WINDING_CCW); break;
3579                 case WINDINGUSAGE_CW:           windings.push_back(WINDING_CW); break;
3580                 case WINDINGUSAGE_VARY:         windings.push_back(WINDING_CCW);
3581                                                                         windings.push_back(WINDING_CW); break;
3582                 default: DE_ASSERT(false);
3583         }
3584
3585         checkTessellationSupport(m_context);
3586         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3587
3588         for (int constantExprCaseNdx = 0; constantExprCaseNdx < numDifferentConstantExprCases; constantExprCaseNdx++)
3589         {
3590                 for (int windingCaseNdx = 0; windingCaseNdx < (int)windings.size(); windingCaseNdx++)
3591                 {
3592                         const string    floatLit01 = de::floatToString(10.0f / (float)(constantExprCaseNdx + 10), 2);
3593                         const int               programNdx = (int)m_programs.size();
3594
3595                         m_programs.push_back(Program(windings[windingCaseNdx],
3596                                                                                  SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3597                                         << glu::VertexSource                                    ("#version 310 es\n"
3598                                                                                                                          "\n"
3599                                                                                                                          "in highp float in_v_attr;\n"
3600                                                                                                                          "out highp float in_tc_attr;\n"
3601                                                                                                                          "\n"
3602                                                                                                                          "void main (void)\n"
3603                                                                                                                          "{\n"
3604                                                                                                                          "      in_tc_attr = in_v_attr;\n"
3605                                                                                                                          "}\n")
3606
3607                                         << glu::TessellationControlSource               ("#version 310 es\n"
3608                                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
3609                                                                                                                          "\n"
3610                                                                                                                          "layout (vertices = " + de::toString(constantExprCaseNdx+1) + ") out;\n"
3611                                                                                                                          "\n"
3612                                                                                                                          "in highp float in_tc_attr[];\n"
3613                                                                                                                          "\n"
3614                                                                                                                          "patch out highp float in_te_positionOffset;\n"
3615                                                                                                                          "\n"
3616                                                                                                                          "void main (void)\n"
3617                                                                                                                          "{\n"
3618                                                                                                                          "      in_te_positionOffset = in_tc_attr[6];\n"
3619                                                                                                                          "\n"
3620                                                                                                                          "      gl_TessLevelInner[0] = in_tc_attr[0];\n"
3621                                                                                                                          "      gl_TessLevelInner[1] = in_tc_attr[1];\n"
3622                                                                                                                          "\n"
3623                                                                                                                          "      gl_TessLevelOuter[0] = in_tc_attr[2];\n"
3624                                                                                                                          "      gl_TessLevelOuter[1] = in_tc_attr[3];\n"
3625                                                                                                                          "      gl_TessLevelOuter[2] = in_tc_attr[4];\n"
3626                                                                                                                          "      gl_TessLevelOuter[3] = in_tc_attr[5];\n"
3627                                                                                                                          "}\n")
3628
3629                                         << glu::TessellationEvaluationSource    ("#version 310 es\n"
3630                                                                                                                          "#extension GL_EXT_tessellation_shader : require\n"
3631                                                                                                                          "\n"
3632                                                                                                                          + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, windings[windingCaseNdx], m_usePointMode) +
3633                                                                                                                          "\n"
3634                                                                                                                          "patch in highp float in_te_positionOffset;\n"
3635                                                                                                                          "\n"
3636                                                                                                                          "out highp vec4 in_f_color;\n"
3637                                                                                                                          "invariant out highp vec3 out_te_tessCoord;\n"
3638                                                                                                                          "\n"
3639                                                                                                                          "void main (void)\n"
3640                                                                                                                          "{\n"
3641                                                                                                                          "      gl_Position = vec4(gl_TessCoord.xy*" + floatLit01 + " - in_te_positionOffset + float(gl_PrimitiveID)*0.1, 0.0, 1.0);\n"
3642                                                                                                                          "      in_f_color = vec4(" + floatLit01 + ");\n"
3643                                                                                                                          "      out_te_tessCoord = gl_TessCoord;\n"
3644                                                                                                                          "}\n")
3645
3646                                         << glu::FragmentSource                                  ("#version 310 es\n"
3647                                                                                                                          "\n"
3648                                                                                                                          "layout (location = 0) out mediump vec4 o_color;\n"
3649                                                                                                                          "\n"
3650                                                                                                                          "in highp vec4 in_f_color;\n"
3651                                                                                                                          "\n"
3652                                                                                                                          "void main (void)\n"
3653                                                                                                                          "{\n"
3654                                                                                                                          "      o_color = in_f_color;\n"
3655                                                                                                                          "}\n")
3656
3657                                         << glu::TransformFeedbackVarying                ("out_te_tessCoord")
3658                                         << glu::TransformFeedbackMode                   (GL_INTERLEAVED_ATTRIBS)))));
3659
3660                         {
3661                                 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program" + de::toString(programNdx), "Program " + de::toString(programNdx));
3662
3663                                 if (programNdx == 0 || !m_programs.back().program->isOk())
3664                                         m_testCtx.getLog() << *m_programs.back().program;
3665
3666                                 if (!m_programs.back().program->isOk())
3667                                         TCU_FAIL("Program compilation failed");
3668
3669                                 if (programNdx > 0)
3670                                         m_testCtx.getLog() << TestLog::Message << "Note: program " << programNdx << " is similar to above, except some constants are different, and: " << m_programs.back().description() << TestLog::EndMessage;
3671                         }
3672                 }
3673         }
3674 }
3675
3676 void PrimitiveSetInvarianceCase::deinit (void)
3677 {
3678         m_programs.clear();
3679 }
3680
3681 PrimitiveSetInvarianceCase::IterateResult PrimitiveSetInvarianceCase::iterate (void)
3682 {
3683         typedef TransformFeedbackHandler<Vec3> TFHandler;
3684
3685         TestLog&                                        log                                     = m_testCtx.getLog();
3686         const RenderContext&            renderCtx                       = m_context.getRenderContext();
3687         const RandomViewport            viewport                        (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3688         const glw::Functions&           gl                                      = renderCtx.getFunctions();
3689         const vector<LevelCase>         tessLevelCases          = genTessLevelCases();
3690         vector<vector<int> >            primitiveCounts;
3691         int                                                     maxNumPrimitives        = -1;
3692
3693         for (int caseNdx = 0; caseNdx < (int)tessLevelCases.size(); caseNdx++)
3694         {
3695                 primitiveCounts.push_back(vector<int>());
3696                 for (int i = 0; i < (int)tessLevelCases[caseNdx].levels.size(); i++)
3697                 {
3698                         const int primCount = referencePrimitiveCount(m_primitiveType, m_spacing, m_usePointMode,
3699                                                                                                                   &tessLevelCases[caseNdx].levels[i].inner[0], &tessLevelCases[caseNdx].levels[i].outer[0]);
3700                         primitiveCounts.back().push_back(primCount);
3701                         maxNumPrimitives = de::max(maxNumPrimitives, primCount);
3702                 }
3703         }
3704
3705         const deUint32                          primitiveTypeGL         = outputPrimitiveTypeGL(m_primitiveType, m_usePointMode);
3706         const TFHandler                         transformFeedback       (m_context.getRenderContext(), 2*maxNumPrimitives*numVerticesPerPrimitive(primitiveTypeGL));
3707
3708         setViewport(gl, viewport);
3709         gl.patchParameteri(GL_PATCH_VERTICES, 7);
3710
3711         for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < (int)tessLevelCases.size(); tessLevelCaseNdx++)
3712         {
3713                 const LevelCase&        levelCase = tessLevelCases[tessLevelCaseNdx];
3714                 vector<Vec3>            firstPrimVertices;
3715
3716                 {
3717                         string tessLevelsStr;
3718                         for (int i = 0; i < (int)levelCase.levels.size(); i++)
3719                                 tessLevelsStr += (levelCase.levels.size() > 1 ? "\n" : "") + levelCase.levels[i].description();
3720                         log << TestLog::Message << "Tessellation level sets: " << tessLevelsStr << TestLog::EndMessage;
3721                 }
3722
3723                 for (int subTessLevelCaseNdx = 0; subTessLevelCaseNdx < (int)levelCase.levels.size(); subTessLevelCaseNdx++)
3724                 {
3725                         const TessLevels&                               tessLevels              = levelCase.levels[subTessLevelCaseNdx];
3726                         const float                                             (&inner)[2]             = tessLevels.inner;
3727                         const float                                             (&outer)[4]             = tessLevels.outer;
3728                         const float                                             attribute[2*7]  = { inner[0], inner[1], outer[0], outer[1], outer[2], outer[3], 0.0f,
3729                                                                                                                                 inner[0], inner[1], outer[0], outer[1], outer[2], outer[3], 0.5f };
3730                         const glu::VertexArrayBinding   bindings[]              = { glu::va::Float("in_v_attr", 1, DE_LENGTH_OF_ARRAY(attribute), 0, &attribute[0]) };
3731
3732                         for (int programNdx = 0; programNdx < (int)m_programs.size(); programNdx++)
3733                         {
3734                                 const deUint32                          programGL       = m_programs[programNdx].program->getProgram();
3735                                 gl.useProgram(programGL);
3736                                 const TFHandler::Result         tfResult        = transformFeedback.renderAndGetPrimitives(programGL, primitiveTypeGL, DE_LENGTH_OF_ARRAY(bindings), &bindings[0], DE_LENGTH_OF_ARRAY(attribute));
3737
3738                                 if (tfResult.numPrimitives != 2*primitiveCounts[tessLevelCaseNdx][subTessLevelCaseNdx])
3739                                 {
3740                                         log << TestLog::Message << "Failure: GL reported GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN to be "
3741                                                                                         << tfResult.numPrimitives << ", reference value is " << 2*primitiveCounts[tessLevelCaseNdx][subTessLevelCaseNdx]
3742                                                                                         << TestLog::EndMessage;
3743
3744                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of primitives");
3745                                         return STOP;
3746                                 }
3747
3748                                 {
3749                                         const int                       half                    = (int)tfResult.varying.size()/2;
3750                                         const vector<Vec3>      prim0Vertices   = vector<Vec3>(tfResult.varying.begin(), tfResult.varying.begin() + half);
3751                                         const Vec3* const       prim1Vertices   = &tfResult.varying[half];
3752
3753                                         for (int vtxNdx = 0; vtxNdx < (int)prim0Vertices.size(); vtxNdx++)
3754                                         {
3755                                                 if (prim0Vertices[vtxNdx] != prim1Vertices[vtxNdx])
3756                                                 {
3757                                                         log << TestLog::Message << "Failure: tessellation coordinate at index " << vtxNdx << " differs between two primitives drawn in one draw call" << TestLog::EndMessage
3758                                                                 << TestLog::Message << "Note: the coordinate is " << prim0Vertices[vtxNdx] << " for the first primitive and " << prim1Vertices[vtxNdx] << " for the second" << TestLog::EndMessage
3759                                                                 << TestLog::Message << "Note: tessellation levels for both primitives were: " << tessellationLevelsString(&inner[0], &outer[0]) << TestLog::EndMessage;
3760                                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of primitives");
3761                                                         return STOP;
3762                                                 }
3763                                         }
3764
3765                                         if (programNdx == 0 && subTessLevelCaseNdx == 0)
3766                                                 firstPrimVertices = prim0Vertices;
3767                                         else
3768                                         {
3769                                                 const bool compareOk = compare(firstPrimVertices, prim0Vertices, levelCase.mem);
3770                                                 if (!compareOk)
3771                                                 {
3772                                                         log << TestLog::Message << "Note: comparison of tessellation coordinates failed; comparison was made between following cases:\n"
3773                                                                                                         << "  - case A: program 0, tessellation levels: " << tessLevelCases[tessLevelCaseNdx].levels[0].description() << "\n"
3774                                                                                                         << "  - case B: program " << programNdx << ", tessellation levels: " << tessLevels.description() << TestLog::EndMessage;
3775                                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of primitives");
3776                                                         return STOP;
3777                                                 }
3778                                         }
3779                                 }
3780                         }
3781                 }
3782         }
3783
3784         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3785         return STOP;
3786 }
3787
3788 /*--------------------------------------------------------------------*//*!
3789  * \brief Test invariance rule #1
3790  *
3791  * Test that the sequence of primitives input to the TES only depends on
3792  * the tessellation levels, tessellation mode, spacing mode, winding, and
3793  * point mode.
3794  *//*--------------------------------------------------------------------*/
3795 class InvariantPrimitiveSetCase : public PrimitiveSetInvarianceCase
3796 {
3797 public:
3798         InvariantPrimitiveSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
3799                 : PrimitiveSetInvarianceCase(context, name, description, primType, spacing, usePointMode, winding == WINDING_CCW        ? WINDINGUSAGE_CCW
3800                                                                                                                                                                                                 : winding == WINDING_CW         ? WINDINGUSAGE_CW
3801                                                                                                                                                                                                 : WINDINGUSAGE_LAST)
3802         {
3803         }
3804
3805 protected:
3806         virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int) const
3807         {
3808                 for (int vtxNdx = 0; vtxNdx < (int)coordsA.size(); vtxNdx++)
3809                 {
3810                         if (coordsA[vtxNdx] != coordsB[vtxNdx])
3811                         {
3812                                 m_testCtx.getLog() << TestLog::Message << "Failure: tessellation coordinate at index " << vtxNdx << " differs between two programs" << TestLog::EndMessage
3813                                                                    << TestLog::Message << "Note: the coordinate is " << coordsA[vtxNdx] << " for the first program and " << coordsB[vtxNdx] << " for the other" << TestLog::EndMessage;
3814                                 return false;
3815                         }
3816                 }
3817                 return true;
3818         }
3819 };
3820
3821 /*--------------------------------------------------------------------*//*!
3822  * \brief Test invariance rule #2
3823  *
3824  * Test that the set of vertices along an outer edge of a quad or triangle
3825  * only depends on that edge's tessellation level, and spacing.
3826  *
3827  * For each (outer) edge in the quad or triangle, draw multiple patches
3828  * with identical tessellation levels for that outer edge but with
3829  * different values for the other outer edges; compare, among the
3830  * primitives, the vertices generated for that outer edge. Repeat with
3831  * different programs, using different winding etc. settings. Compare
3832  * the edge's vertices between different programs.
3833  *//*--------------------------------------------------------------------*/
3834 class InvariantOuterEdgeCase : public TestCase
3835 {
3836 public:
3837         InvariantOuterEdgeCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
3838                 : TestCase                      (context, name, description)
3839                 , m_primitiveType       (primType)
3840                 , m_spacing                     (spacing)
3841         {
3842                 DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
3843         }
3844
3845         void                                            init            (void);
3846         void                                            deinit          (void);
3847         IterateResult                           iterate         (void);
3848
3849 private:
3850         struct Program
3851         {
3852                 Winding                                                 winding;
3853                 bool                                                    usePointMode;
3854                 SharedPtr<const ShaderProgram>  program;
3855
3856                                 Program                 (Winding w, bool point, const SharedPtr<const ShaderProgram>& prog) : winding(w), usePointMode(point), program(prog) {}
3857
3858                 string  description             (void) const { return string() + "winding mode " + getWindingShaderName(winding) + ", " + (usePointMode ? "" : "don't ") + "use point mode"; };
3859         };
3860
3861         static vector<float>            generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel);
3862
3863         static const int                        RENDER_SIZE = 16;
3864
3865         const TessPrimitiveType         m_primitiveType;
3866         const SpacingMode                       m_spacing;
3867
3868         vector<Program>                         m_programs;
3869 };
3870
3871 vector<float> InvariantOuterEdgeCase::generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel)
3872 {
3873         de::Random rnd(123);
3874         return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
3875 }
3876
3877 void InvariantOuterEdgeCase::init (void)
3878 {
3879         checkTessellationSupport(m_context);
3880         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3881
3882         for (int windingI = 0; windingI < WINDING_LAST; windingI++)
3883         {
3884                 const Winding winding = (Winding)windingI;
3885
3886                 for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
3887                 {
3888                         const bool              usePointMode    = usePointModeI != 0;
3889                         const int               programNdx              = (int)m_programs.size();
3890                         const string    floatLit01              = de::floatToString(10.0f / (float)(programNdx + 10), 2);
3891
3892                         m_programs.push_back(Program(winding, usePointMode,
3893                                                                                  SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3894                                 << glu::VertexSource                                    ("#version 310 es\n"
3895                                                                                                                  "\n"
3896                                                                                                                  "in highp float in_v_attr;\n"
3897                                                                                                                  "out highp float in_tc_attr;\n"
3898                                                                                                                  "\n"
3899                                                                                                                  "void main (void)\n"
3900                                                                                                                  "{\n"
3901                                                                                                                  "      in_tc_attr = in_v_attr;\n"
3902                                                                                                                  "}\n")
3903
3904                                 << glu::TessellationControlSource               ("#version 310 es\n"
3905                                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
3906                                                                                                                  "\n"
3907                                                                                                                  "layout (vertices = " + de::toString(programNdx+1) + ") out;\n"
3908                                                                                                                  "\n"
3909                                                                                                                  "in highp float in_tc_attr[];\n"
3910                                                                                                                  "\n"
3911                                                                                                                  "void main (void)\n"
3912                                                                                                                  "{\n"
3913                                                                                                                  "      gl_TessLevelInner[0] = in_tc_attr[0];\n"
3914                                                                                                                  "      gl_TessLevelInner[1] = in_tc_attr[1];\n"
3915                                                                                                                  "\n"
3916                                                                                                                  "      gl_TessLevelOuter[0] = in_tc_attr[2];\n"
3917                                                                                                                  "      gl_TessLevelOuter[1] = in_tc_attr[3];\n"
3918                                                                                                                  "      gl_TessLevelOuter[2] = in_tc_attr[4];\n"
3919                                                                                                                  "      gl_TessLevelOuter[3] = in_tc_attr[5];\n"
3920                                                                                                                  "}\n")
3921
3922                                 << glu::TessellationEvaluationSource    ("#version 310 es\n"
3923                                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
3924                                                                                                                  "\n"
3925                                                                                                                  + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, winding, usePointMode) +
3926                                                                                                                  "\n"
3927                                                                                                                  "out highp vec4 in_f_color;\n"
3928                                                                                                                  "invariant out highp vec3 out_te_tessCoord;\n"
3929                                                                                                                  "\n"
3930                                                                                                                  "void main (void)\n"
3931                                                                                                                  "{\n"
3932                                                                                                                  "      gl_Position = vec4(gl_TessCoord.xy*" + floatLit01 + " - float(gl_PrimitiveID)*0.05, 0.0, 1.0);\n"
3933                                                                                                                  "      in_f_color = vec4(" + floatLit01 + ");\n"
3934                                                                                                                  "      out_te_tessCoord = gl_TessCoord;\n"
3935                                                                                                                  "}\n")
3936
3937                                 << glu::FragmentSource                                  ("#version 310 es\n"
3938                                                                                                                  "\n"
3939                                                                                                                  "layout (location = 0) out mediump vec4 o_color;\n"
3940                                                                                                                  "\n"
3941                                                                                                                  "in highp vec4 in_f_color;\n"
3942                                                                                                                  "\n"
3943                                                                                                                  "void main (void)\n"
3944                                                                                                                  "{\n"
3945                                                                                                                  "      o_color = in_f_color;\n"
3946                                                                                                                  "}\n")
3947
3948                                 << glu::TransformFeedbackVarying                ("out_te_tessCoord")
3949                                 << glu::TransformFeedbackMode                   (GL_INTERLEAVED_ATTRIBS)))));
3950
3951                         {
3952                                 const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program" + de::toString(programNdx), "Program " + de::toString(programNdx));
3953
3954                                 if (programNdx == 0 || !m_programs.back().program->isOk())
3955                                         m_testCtx.getLog() << *m_programs.back().program;
3956
3957                                 if (!m_programs.back().program->isOk())
3958                                         TCU_FAIL("Program compilation failed");
3959
3960                                 if (programNdx > 0)
3961                                         m_testCtx.getLog() << TestLog::Message << "Note: program " << programNdx << " is similar to above, except some constants are different, and: " << m_programs.back().description() << TestLog::EndMessage;
3962                         }
3963                 }
3964         }
3965 }
3966
3967 void InvariantOuterEdgeCase::deinit (void)
3968 {
3969         m_programs.clear();
3970 }
3971
3972 InvariantOuterEdgeCase::IterateResult InvariantOuterEdgeCase::iterate (void)
3973 {
3974         typedef TransformFeedbackHandler<Vec3> TFHandler;
3975
3976         TestLog&                                                        log                                                     = m_testCtx.getLog();
3977         const RenderContext&                            renderCtx                                       = m_context.getRenderContext();
3978         const RandomViewport                            viewport                                        (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3979         const glw::Functions&                           gl                                                      = renderCtx.getFunctions();
3980
3981         static const float                                      singleOuterEdgeLevels[]         = { 1.0f, 1.2f, 1.9f, 2.3f, 2.8f, 3.3f, 3.8f, 10.2f, 1.6f, 24.4f, 24.7f, 63.0f };
3982         const int                                                       numPatchesPerDrawCall           = 10;
3983         const vector<OuterEdgeDescription>      edgeDescriptions                        = outerEdgeDescriptions(m_primitiveType);
3984
3985         {
3986                 // Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
3987                 int maxNumVerticesInDrawCall = 0;
3988                 {
3989                         const vector<float> patchTessLevels = generatePatchTessLevels(numPatchesPerDrawCall, 0 /* outer-edge index doesn't affect vertex count */, arrayMax(singleOuterEdgeLevels));
3990
3991                         for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
3992                                 maxNumVerticesInDrawCall = de::max(maxNumVerticesInDrawCall,
3993                                                                                                    multiplePatchReferenceVertexCount(m_primitiveType, m_spacing, usePointModeI != 0, &patchTessLevels[0], numPatchesPerDrawCall));
3994                 }
3995
3996                 {
3997                         const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
3998
3999                         setViewport(gl, viewport);
4000                         gl.patchParameteri(GL_PATCH_VERTICES, 6);
4001
4002                         for (int outerEdgeIndex = 0; outerEdgeIndex < (int)edgeDescriptions.size(); outerEdgeIndex++)
4003                         {
4004                                 const OuterEdgeDescription& edgeDesc = edgeDescriptions[outerEdgeIndex];
4005
4006                                 for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(singleOuterEdgeLevels); outerEdgeLevelCaseNdx++)
4007                                 {
4008                                         typedef std::set<Vec3, VecLexLessThan<3> > Vec3Set;
4009
4010                                         const vector<float>                             patchTessLevels         = generatePatchTessLevels(numPatchesPerDrawCall, outerEdgeIndex, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4011                                         const glu::VertexArrayBinding   bindings[]                      = { glu::va::Float("in_v_attr", 1, (int)patchTessLevels.size(), 0, &patchTessLevels[0]) };
4012                                         Vec3Set                                                 firstOuterEdgeVertices; // Vertices of the outer edge of the first patch of the first program's draw call; used for comparison with other patches.
4013
4014                                         log << TestLog::Message << "Testing with outer tessellation level " << singleOuterEdgeLevels[outerEdgeLevelCaseNdx]
4015                                                                                         << " for the " << edgeDesc.description() << " edge, and with various levels for other edges, and with all programs" << TestLog::EndMessage;
4016
4017                                         for (int programNdx = 0; programNdx < (int)m_programs.size(); programNdx++)
4018                                         {
4019                                                 const Program& program          = m_programs[programNdx];
4020                                                 const deUint32 programGL        = program.program->getProgram();
4021
4022                                                 gl.useProgram(programGL);
4023
4024                                                 {
4025                                                         const TFHandler::Result         tfResult                        = tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, program.usePointMode),
4026                                                                                                                                                                                                                            DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)patchTessLevels.size());
4027                                                         const int                                       refNumVertices          = multiplePatchReferenceVertexCount(m_primitiveType, m_spacing, program.usePointMode, &patchTessLevels[0], numPatchesPerDrawCall);
4028                                                         int                                                     numVerticesRead         = 0;
4029
4030                                                         if ((int)tfResult.varying.size() != refNumVertices)
4031                                                         {
4032                                                                 log << TestLog::Message << "Failure: the number of vertices returned by transform feedback is "
4033                                                                                                                 << tfResult.varying.size() << ", expected " << refNumVertices << TestLog::EndMessage
4034                                                                         << TestLog::Message << "Note: rendered " << numPatchesPerDrawCall
4035                                                                                                                 << " patches in one draw call; tessellation levels for each patch are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
4036                                                                                                                 << containerStr(patchTessLevels, 6) << TestLog::EndMessage;
4037
4038                                                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4039                                                                 return STOP;
4040                                                         }
4041
4042                                                         // Check the vertices of each patch.
4043
4044                                                         for (int patchNdx = 0; patchNdx < numPatchesPerDrawCall; patchNdx++)
4045                                                         {
4046                                                                 const float* const      innerLevels                     = &patchTessLevels[6*patchNdx + 0];
4047                                                                 const float* const      outerLevels                     = &patchTessLevels[6*patchNdx + 2];
4048                                                                 const int                       patchNumVertices        = referenceVertexCount(m_primitiveType, m_spacing, program.usePointMode, innerLevels, outerLevels);
4049                                                                 Vec3Set                         outerEdgeVertices;
4050
4051                                                                 // We're interested in just the vertices on the current outer edge.
4052                                                                 for(int vtxNdx = numVerticesRead; vtxNdx < numVerticesRead + patchNumVertices; vtxNdx++)
4053                                                                 {
4054                                                                         const Vec3& vtx = tfResult.varying[vtxNdx];
4055                                                                         if (edgeDesc.contains(vtx))
4056                                                                                 outerEdgeVertices.insert(tfResult.varying[vtxNdx]);
4057                                                                 }
4058
4059                                                                 // Check that the outer edge contains an appropriate number of vertices.
4060                                                                 {
4061                                                                         const int refNumVerticesOnOuterEdge = 1 + getClampedRoundedTessLevel(m_spacing, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4062
4063                                                                         if ((int)outerEdgeVertices.size() != refNumVerticesOnOuterEdge)
4064                                                                         {
4065                                                                                 log << TestLog::Message << "Failure: the number of vertices on outer edge is " << outerEdgeVertices.size()
4066                                                                                                                                 << ", expected " << refNumVerticesOnOuterEdge << TestLog::EndMessage
4067                                                                                         << TestLog::Message << "Note: vertices on the outer edge are:\n" << containerStr(outerEdgeVertices, 5, 0) << TestLog::EndMessage
4068                                                                                         << TestLog::Message << "Note: the following parameters were used: " << program.description()
4069                                                                                                                                 << ", tessellation levels: " << tessellationLevelsString(innerLevels, outerLevels) << TestLog::EndMessage;
4070                                                                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4071                                                                                 return STOP;
4072                                                                         }
4073                                                                 }
4074
4075                                                                 // Compare the vertices to those of the first patch (unless this is the first patch).
4076
4077                                                                 if (programNdx == 0 && patchNdx == 0)
4078                                                                         firstOuterEdgeVertices = outerEdgeVertices;
4079                                                                 else
4080                                                                 {
4081                                                                         if (firstOuterEdgeVertices != outerEdgeVertices)
4082                                                                         {
4083                                                                                 log << TestLog::Message << "Failure: vertices generated for the edge differ between the following cases:\n"
4084                                                                                                                                 << "  - case A: " << m_programs[0].description() << ", tessellation levels: "
4085                                                                                                                                                                   << tessellationLevelsString(&patchTessLevels[0], &patchTessLevels[2]) << "\n"
4086                                                                                                                                 << "  - case B: " << program.description() << ", tessellation levels: "
4087                                                                                                                                                                   << tessellationLevelsString(innerLevels, outerLevels) << TestLog::EndMessage;
4088
4089                                                                                 log << TestLog::Message << "Note: resulting vertices for the edge for the cases were:\n"
4090                                                                                                                                 << "  - case A: " << containerStr(firstOuterEdgeVertices, 5, 14) << "\n"
4091                                                                                                                                 << "  - case B: " << containerStr(outerEdgeVertices, 5, 14) << TestLog::EndMessage;
4092
4093                                                                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4094                                                                                 return STOP;
4095                                                                         }
4096                                                                 }
4097
4098                                                                 numVerticesRead += patchNumVertices;
4099                                                         }
4100
4101                                                         DE_ASSERT(numVerticesRead == (int)tfResult.varying.size());
4102                                                 }
4103                                         }
4104                                 }
4105                         }
4106                 }
4107         }
4108
4109         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4110         return STOP;
4111 }
4112
4113 /*--------------------------------------------------------------------*//*!
4114  * \brief Test invariance rule #3
4115  *
4116  * Test that the vertices along an outer edge are placed symmetrically.
4117  *
4118  * Draw multiple patches with different tessellation levels and different
4119  * point_mode, winding etc. Before outputting tesscoords with TF, mirror
4120  * the vertices in the TES such that every vertex on an outer edge -
4121  * except the possible middle vertex - should be duplicated in the output.
4122  * Check that appropriate duplicates exist.
4123  *//*--------------------------------------------------------------------*/
4124 class SymmetricOuterEdgeCase : public TestCase
4125 {
4126 public:
4127         SymmetricOuterEdgeCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
4128                 : TestCase                      (context, name, description)
4129                 , m_primitiveType       (primType)
4130                 , m_spacing                     (spacing)
4131                 , m_winding                     (winding)
4132                 , m_usePointMode        (usePointMode)
4133         {
4134         }
4135
4136         void                                                                    init            (void);
4137         void                                                                    deinit          (void);
4138         IterateResult                                                   iterate         (void);
4139
4140 private:
4141         static vector<float>                                    generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel);
4142
4143         static const int                                                RENDER_SIZE = 16;
4144
4145         const TessPrimitiveType                                 m_primitiveType;
4146         const SpacingMode                                               m_spacing;
4147         const Winding                                                   m_winding;
4148         const bool                                                              m_usePointMode;
4149
4150         SharedPtr<const glu::ShaderProgram>             m_program;
4151 };
4152
4153 vector<float> SymmetricOuterEdgeCase::generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel)
4154 {
4155         de::Random rnd(123);
4156         return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
4157 }
4158
4159 void SymmetricOuterEdgeCase::init (void)
4160 {
4161         checkTessellationSupport(m_context);
4162         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
4163
4164         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
4165                 << glu::VertexSource                                    ("#version 310 es\n"
4166                                                                                                  "\n"
4167                                                                                                  "in highp float in_v_attr;\n"
4168                                                                                                  "out highp float in_tc_attr;\n"
4169                                                                                                  "\n"
4170                                                                                                  "void main (void)\n"
4171                                                                                                  "{\n"
4172                                                                                                  "      in_tc_attr = in_v_attr;\n"
4173                                                                                                  "}\n")
4174
4175                 << glu::TessellationControlSource               ("#version 310 es\n"
4176                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
4177                                                                                                  "\n"
4178                                                                                                  "layout (vertices = 1) out;\n"
4179                                                                                                  "\n"
4180                                                                                                  "in highp float in_tc_attr[];\n"
4181                                                                                                  "\n"
4182                                                                                                  "void main (void)\n"
4183                                                                                                  "{\n"
4184                                                                                                  "      gl_TessLevelInner[0] = in_tc_attr[0];\n"
4185                                                                                                  "      gl_TessLevelInner[1] = in_tc_attr[1];\n"
4186                                                                                                  "\n"
4187                                                                                                  "      gl_TessLevelOuter[0] = in_tc_attr[2];\n"
4188                                                                                                  "      gl_TessLevelOuter[1] = in_tc_attr[3];\n"
4189                                                                                                  "      gl_TessLevelOuter[2] = in_tc_attr[4];\n"
4190                                                                                                  "      gl_TessLevelOuter[3] = in_tc_attr[5];\n"
4191                                                                                                  "}\n")
4192
4193                 << glu::TessellationEvaluationSource    ("#version 310 es\n"
4194                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
4195                                                                                                  "\n"
4196                                                                                                  + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
4197                                                                                                  "\n"
4198                                                                                                  "out highp vec4 in_f_color;\n"
4199                                                                                                  "out highp vec4 out_te_tessCoord_isMirrored;\n"
4200                                                                                                  "\n"
4201                                                                                                  "void main (void)\n"
4202                                                                                                  "{\n"
4203                                                                                                  + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
4204                                                                                                         "       float x = gl_TessCoord.x;\n"
4205                                                                                                         "       float y = gl_TessCoord.y;\n"
4206                                                                                                         "       float z = gl_TessCoord.z;\n"
4207                                                                                                         "       // Mirror one half of each outer edge onto the other half, except the endpoints (because they belong to two edges)\n"
4208                                                                                                         "       out_te_tessCoord_isMirrored = z == 0.0 && x > 0.5 && x != 1.0 ? vec4(1.0-x,  1.0-y,    0.0, 1.0)\n"
4209                                                                                                         "                                   : y == 0.0 && z > 0.5 && z != 1.0 ? vec4(1.0-x,    0.0,  1.0-z, 1.0)\n"
4210                                                                                                         "                                   : x == 0.0 && y > 0.5 && y != 1.0 ? vec4(  0.0,  1.0-y,  1.0-z, 1.0)\n"
4211                                                                                                         "                                   : vec4(x, y, z, 0.0);\n"
4212                                                                                                   : m_primitiveType == TESSPRIMITIVETYPE_QUADS ?
4213                                                                                                         "       float x = gl_TessCoord.x;\n"
4214                                                                                                         "       float y = gl_TessCoord.y;\n"
4215                                                                                                         "       // Mirror one half of each outer edge onto the other half, except the endpoints (because they belong to two edges)\n"
4216                                                                                                         "       out_te_tessCoord_isMirrored = (x == 0.0 || x == 1.0) && y > 0.5 && y != 1.0 ? vec4(    x, 1.0-y, 0.0, 1.0)\n"
4217                                                                                                         "                                   : (y == 0.0 || y == 1.0) && x > 0.5 && x != 1.0 ? vec4(1.0-x,     y, 0.0, 1.0)\n"
4218                                                                                                         "                                   : vec4(x, y, 0.0, 0.0);\n"
4219                                                                                                   : m_primitiveType == TESSPRIMITIVETYPE_ISOLINES ?
4220                                                                                                         "       float x = gl_TessCoord.x;\n"
4221                                                                                                         "       float y = gl_TessCoord.y;\n"
4222                                                                                                         "       // Mirror one half of each outer edge onto the other half\n"
4223                                                                                                         "       out_te_tessCoord_isMirrored = (x == 0.0 || x == 1.0) && y > 0.5 ? vec4(x, 1.0-y, 0.0, 1.0)\n"
4224                                                                                                         "                                   : vec4(x, y, 0.0, 0.0f);\n"
4225                                                                                                   : DE_NULL) +
4226                                                                                                  "\n"
4227                                                                                                  "      gl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
4228                                                                                                  "      in_f_color = vec4(1.0);\n"
4229                                                                                                  "}\n")
4230
4231                 << glu::FragmentSource                                  ("#version 310 es\n"
4232                                                                                                  "\n"
4233                                                                                                  "layout (location = 0) out mediump vec4 o_color;\n"
4234                                                                                                  "\n"
4235                                                                                                  "in highp vec4 in_f_color;\n"
4236                                                                                                  "\n"
4237                                                                                                  "void main (void)\n"
4238                                                                                                  "{\n"
4239                                                                                                  "      o_color = in_f_color;\n"
4240                                                                                                  "}\n")
4241
4242                 << glu::TransformFeedbackVarying                ("out_te_tessCoord_isMirrored")
4243                 << glu::TransformFeedbackMode                   (GL_INTERLEAVED_ATTRIBS)));
4244
4245         m_testCtx.getLog() << *m_program;
4246         if (!m_program->isOk())
4247                 TCU_FAIL("Program compilation failed");
4248 }
4249
4250 void SymmetricOuterEdgeCase::deinit (void)
4251 {
4252         m_program.clear();
4253 }
4254
4255 SymmetricOuterEdgeCase::IterateResult SymmetricOuterEdgeCase::iterate (void)
4256 {
4257         typedef TransformFeedbackHandler<Vec4> TFHandler;
4258
4259         TestLog&                                                        log                                                     = m_testCtx.getLog();
4260         const RenderContext&                            renderCtx                                       = m_context.getRenderContext();
4261         const RandomViewport                            viewport                                        (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
4262         const glw::Functions&                           gl                                                      = renderCtx.getFunctions();
4263
4264         static const float                                      singleOuterEdgeLevels[]         = { 1.0f, 1.2f, 1.9f, 2.3f, 2.8f, 3.3f, 3.8f, 10.2f, 1.6f, 24.4f, 24.7f, 63.0f };
4265         const vector<OuterEdgeDescription>      edgeDescriptions                        = outerEdgeDescriptions(m_primitiveType);
4266
4267         {
4268                 // Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
4269                 int maxNumVerticesInDrawCall;
4270                 {
4271                         const vector<float> patchTessLevels = generatePatchTessLevels(1, 0 /* outer-edge index doesn't affect vertex count */, arrayMax(singleOuterEdgeLevels));
4272                         maxNumVerticesInDrawCall = referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4273                 }
4274
4275                 {
4276                         const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
4277
4278                         setViewport(gl, viewport);
4279                         gl.patchParameteri(GL_PATCH_VERTICES, 6);
4280
4281                         for (int outerEdgeIndex = 0; outerEdgeIndex < (int)edgeDescriptions.size(); outerEdgeIndex++)
4282                         {
4283                                 const OuterEdgeDescription& edgeDesc = edgeDescriptions[outerEdgeIndex];
4284
4285                                 for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(singleOuterEdgeLevels); outerEdgeLevelCaseNdx++)
4286                                 {
4287                                         typedef std::set<Vec3, VecLexLessThan<3> > Vec3Set;
4288
4289                                         const vector<float>                             patchTessLevels         = generatePatchTessLevels(1, outerEdgeIndex, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4290                                         const glu::VertexArrayBinding   bindings[]                      = { glu::va::Float("in_v_attr", 1, (int)patchTessLevels.size(), 0, &patchTessLevels[0]) };
4291
4292                                         log << TestLog::Message << "Testing with outer tessellation level " << singleOuterEdgeLevels[outerEdgeLevelCaseNdx]
4293                                                                                         << " for the " << edgeDesc.description() << " edge, and with various levels for other edges" << TestLog::EndMessage;
4294
4295                                         {
4296                                                 const deUint32 programGL = m_program->getProgram();
4297
4298                                                 gl.useProgram(programGL);
4299
4300                                                 {
4301                                                         const TFHandler::Result         tfResult                = tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
4302                                                                                                                                                                                                                    DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)patchTessLevels.size());
4303                                                         const int                                       refNumVertices  = referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4304
4305                                                         if ((int)tfResult.varying.size() != refNumVertices)
4306                                                         {
4307                                                                 log << TestLog::Message << "Failure: the number of vertices returned by transform feedback is "
4308                                                                                                                 << tfResult.varying.size() << ", expected " << refNumVertices << TestLog::EndMessage
4309                                                                         << TestLog::Message << "Note: rendered 1 patch, tessellation levels are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
4310                                                                                                                 << containerStr(patchTessLevels, 6) << TestLog::EndMessage;
4311
4312                                                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4313                                                                 return STOP;
4314                                                         }
4315
4316                                                         // Check the vertices.
4317
4318                                                         {
4319                                                                 Vec3Set nonMirroredEdgeVertices;
4320                                                                 Vec3Set mirroredEdgeVertices;
4321
4322                                                                 // We're interested in just the vertices on the current outer edge.
4323                                                                 for(int vtxNdx = 0; vtxNdx < refNumVertices; vtxNdx++)
4324                                                                 {
4325                                                                         const Vec3& vtx = tfResult.varying[vtxNdx].swizzle(0,1,2);
4326                                                                         if (edgeDesc.contains(vtx))
4327                                                                         {
4328                                                                                 // Ignore the middle vertex of the outer edge, as it's exactly at the mirroring point;
4329                                                                                 // for isolines, also ignore (0, 0) and (1, 0) because there's no mirrored counterpart for them.
4330                                                                                 if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES && vtx == tcu::select(Vec3(0.0f), Vec3(0.5f), singleTrueMask<3>(edgeDesc.constantCoordinateIndex)))
4331                                                                                         continue;
4332                                                                                 if (m_primitiveType == TESSPRIMITIVETYPE_QUADS && vtx.swizzle(0,1) == tcu::select(Vec2(edgeDesc.constantCoordinateValueChoices[0]),
4333                                                                                                                                                                                                                                                            Vec2(0.5f),
4334                                                                                                                                                                                                                                                            singleTrueMask<2>(edgeDesc.constantCoordinateIndex)))
4335                                                                                         continue;
4336                                                                                 if (m_primitiveType == TESSPRIMITIVETYPE_ISOLINES && (vtx == Vec3(0.0f, 0.5f, 0.0f) || vtx == Vec3(1.0f, 0.5f, 0.0f) ||
4337                                                                                                                                                                                           vtx == Vec3(0.0f, 0.0f, 0.0f) || vtx == Vec3(1.0f, 0.0f, 0.0f)))
4338                                                                                         continue;
4339
4340                                                                                 const bool isMirrored = tfResult.varying[vtxNdx].w() > 0.5f;
4341                                                                                 if (isMirrored)
4342                                                                                         mirroredEdgeVertices.insert(vtx);
4343                                                                                 else
4344                                                                                         nonMirroredEdgeVertices.insert(vtx);
4345                                                                         }
4346                                                                 }
4347
4348                                                                 if (m_primitiveType != TESSPRIMITIVETYPE_ISOLINES)
4349                                                                 {
4350                                                                         // Check that both endpoints are present. Note that endpoints aren't mirrored by the shader, since they belong to more than one edge.
4351
4352                                                                         Vec3 endpointA;
4353                                                                         Vec3 endpointB;
4354
4355                                                                         if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4356                                                                         {
4357                                                                                 endpointA = tcu::select(Vec3(1.0f), Vec3(0.0f), singleTrueMask<3>((edgeDesc.constantCoordinateIndex + 1) % 3));
4358                                                                                 endpointB = tcu::select(Vec3(1.0f), Vec3(0.0f), singleTrueMask<3>((edgeDesc.constantCoordinateIndex + 2) % 3));
4359                                                                         }
4360                                                                         else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4361                                                                         {
4362                                                                                 endpointA.xy() = tcu::select(Vec2(edgeDesc.constantCoordinateValueChoices[0]), Vec2(0.0f), singleTrueMask<2>(edgeDesc.constantCoordinateIndex));
4363                                                                                 endpointB.xy() = tcu::select(Vec2(edgeDesc.constantCoordinateValueChoices[0]), Vec2(1.0f), singleTrueMask<2>(edgeDesc.constantCoordinateIndex));
4364                                                                         }
4365                                                                         else
4366                                                                                 DE_ASSERT(false);
4367
4368                                                                         if (!contains(nonMirroredEdgeVertices, endpointA) ||
4369                                                                                 !contains(nonMirroredEdgeVertices, endpointB))
4370                                                                         {
4371                                                                                 log << TestLog::Message << "Failure: edge doesn't contain both endpoints, " << endpointA << " and " << endpointB << TestLog::EndMessage
4372                                                                                         << TestLog::Message << "Note: non-mirrored vertices:\n" << containerStr(nonMirroredEdgeVertices, 5)
4373                                                                                                                                 << "\nmirrored vertices:\n" << containerStr(mirroredEdgeVertices, 5) << TestLog::EndMessage;
4374                                                                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4375                                                                                 return STOP;
4376                                                                         }
4377                                                                         nonMirroredEdgeVertices.erase(endpointA);
4378                                                                         nonMirroredEdgeVertices.erase(endpointB);
4379                                                                 }
4380
4381                                                                 if (nonMirroredEdgeVertices != mirroredEdgeVertices)
4382                                                                 {
4383                                                                         log << TestLog::Message << "Failure: the set of mirrored edges isn't equal to the set of non-mirrored edges (ignoring endpoints and possible middle)" << TestLog::EndMessage
4384                                                                                 << TestLog::Message << "Note: non-mirrored vertices:\n" << containerStr(nonMirroredEdgeVertices, 5)
4385                                                                                                                                 << "\nmirrored vertices:\n" << containerStr(mirroredEdgeVertices, 5) << TestLog::EndMessage;
4386                                                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4387                                                                         return STOP;
4388                                                                 }
4389                                                         }
4390                                                 }
4391                                         }
4392                                 }
4393                         }
4394                 }
4395         }
4396
4397         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4398         return STOP;
4399 }
4400
4401 /*--------------------------------------------------------------------*//*!
4402  * \brief Test invariance rule #4
4403  *
4404  * Test that the vertices on an outer edge don't depend on which of the
4405  * edges it is, other than with respect to component order.
4406  *//*--------------------------------------------------------------------*/
4407 class OuterEdgeVertexSetIndexIndependenceCase : public TestCase
4408 {
4409 public:
4410         OuterEdgeVertexSetIndexIndependenceCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
4411                 : TestCase                      (context, name, description)
4412                 , m_primitiveType       (primType)
4413                 , m_spacing                     (spacing)
4414                 , m_winding                     (winding)
4415                 , m_usePointMode        (usePointMode)
4416         {
4417                 DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4418         }
4419
4420         void                                                                    init            (void);
4421         void                                                                    deinit          (void);
4422         IterateResult                                                   iterate         (void);
4423
4424 private:
4425         static vector<float>                                    generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel);
4426
4427         static const int                                                RENDER_SIZE = 16;
4428
4429         const TessPrimitiveType                                 m_primitiveType;
4430         const SpacingMode                                               m_spacing;
4431         const Winding                                                   m_winding;
4432         const bool                                                              m_usePointMode;
4433
4434         SharedPtr<const glu::ShaderProgram>             m_program;
4435 };
4436
4437 vector<float> OuterEdgeVertexSetIndexIndependenceCase::generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel)
4438 {
4439         de::Random rnd(123);
4440         return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
4441 }
4442
4443 void OuterEdgeVertexSetIndexIndependenceCase::init (void)
4444 {
4445         checkTessellationSupport(m_context);
4446         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
4447
4448         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
4449                 << glu::VertexSource                                    ("#version 310 es\n"
4450                                                                                                  "\n"
4451                                                                                                  "in highp float in_v_attr;\n"
4452                                                                                                  "out highp float in_tc_attr;\n"
4453                                                                                                  "\n"
4454                                                                                                  "void main (void)\n"
4455                                                                                                  "{\n"
4456                                                                                                  "      in_tc_attr = in_v_attr;\n"
4457                                                                                                  "}\n")
4458
4459                 << glu::TessellationControlSource               ("#version 310 es\n"
4460                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
4461                                                                                                  "\n"
4462                                                                                                  "layout (vertices = 1) out;\n"
4463                                                                                                  "\n"
4464                                                                                                  "in highp float in_tc_attr[];\n"
4465                                                                                                  "\n"
4466                                                                                                  "void main (void)\n"
4467                                                                                                  "{\n"
4468                                                                                                  "      gl_TessLevelInner[0] = in_tc_attr[0];\n"
4469                                                                                                  "      gl_TessLevelInner[1] = in_tc_attr[1];\n"
4470                                                                                                  "\n"
4471                                                                                                  "      gl_TessLevelOuter[0] = in_tc_attr[2];\n"
4472                                                                                                  "      gl_TessLevelOuter[1] = in_tc_attr[3];\n"
4473                                                                                                  "      gl_TessLevelOuter[2] = in_tc_attr[4];\n"
4474                                                                                                  "      gl_TessLevelOuter[3] = in_tc_attr[5];\n"
4475                                                                                                  "}\n")
4476
4477                 << glu::TessellationEvaluationSource    ("#version 310 es\n"
4478                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
4479                                                                                                  "\n"
4480                                                                                                  + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
4481                                                                                                  "\n"
4482                                                                                                  "out highp vec4 in_f_color;\n"
4483                                                                                                  "out highp vec3 out_te_tessCoord;\n"
4484                                                                                                  "\n"
4485                                                                                                  "void main (void)\n"
4486                                                                                                  "{\n"
4487                                                                                                  "      out_te_tessCoord = gl_TessCoord;"
4488                                                                                                  "      gl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
4489                                                                                                  "      in_f_color = vec4(1.0);\n"
4490                                                                                                  "}\n")
4491
4492                 << glu::FragmentSource                                  ("#version 310 es\n"
4493                                                                                                  "\n"
4494                                                                                                  "layout (location = 0) out mediump vec4 o_color;\n"
4495                                                                                                  "\n"
4496                                                                                                  "in highp vec4 in_f_color;\n"
4497                                                                                                  "\n"
4498                                                                                                  "void main (void)\n"
4499                                                                                                  "{\n"
4500                                                                                                  "      o_color = in_f_color;\n"
4501                                                                                                  "}\n")
4502
4503                 << glu::TransformFeedbackVarying                ("out_te_tessCoord")
4504                 << glu::TransformFeedbackMode                   (GL_INTERLEAVED_ATTRIBS)));
4505
4506         m_testCtx.getLog() << *m_program;
4507         if (!m_program->isOk())
4508                 TCU_FAIL("Program compilation failed");
4509 }
4510
4511 void OuterEdgeVertexSetIndexIndependenceCase::deinit (void)
4512 {
4513         m_program.clear();
4514 }
4515
4516 OuterEdgeVertexSetIndexIndependenceCase::IterateResult OuterEdgeVertexSetIndexIndependenceCase::iterate (void)
4517 {
4518         typedef TransformFeedbackHandler<Vec3> TFHandler;
4519
4520         TestLog&                                                        log                                                     = m_testCtx.getLog();
4521         const RenderContext&                            renderCtx                                       = m_context.getRenderContext();
4522         const RandomViewport                            viewport                                        (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
4523         const glw::Functions&                           gl                                                      = renderCtx.getFunctions();
4524         const deUint32                                          programGL                                       = m_program->getProgram();
4525
4526         static const float                                      singleOuterEdgeLevels[]         = { 1.0f, 1.2f, 1.9f, 2.3f, 2.8f, 3.3f, 3.8f, 10.2f, 1.6f, 24.4f, 24.7f, 63.0f };
4527         const vector<OuterEdgeDescription>      edgeDescriptions                        = outerEdgeDescriptions(m_primitiveType);
4528
4529         gl.useProgram(programGL);
4530         setViewport(gl, viewport);
4531         gl.patchParameteri(GL_PATCH_VERTICES, 6);
4532
4533         {
4534                 // Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
4535                 int maxNumVerticesInDrawCall = 0;
4536                 {
4537                         const vector<float> patchTessLevels = generatePatchTessLevels(1, 0 /* outer-edge index doesn't affect vertex count */, arrayMax(singleOuterEdgeLevels));
4538                         maxNumVerticesInDrawCall = referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4539                 }
4540
4541                 {
4542                         const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
4543
4544                         for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(singleOuterEdgeLevels); outerEdgeLevelCaseNdx++)
4545                         {
4546                                 typedef std::set<Vec3, VecLexLessThan<3> > Vec3Set;
4547
4548                                 Vec3Set firstEdgeVertices;
4549
4550                                 for (int outerEdgeIndex = 0; outerEdgeIndex < (int)edgeDescriptions.size(); outerEdgeIndex++)
4551                                 {
4552                                         const OuterEdgeDescription&             edgeDesc                        = edgeDescriptions[outerEdgeIndex];
4553                                         const vector<float>                             patchTessLevels         = generatePatchTessLevels(1, outerEdgeIndex, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4554                                         const glu::VertexArrayBinding   bindings[]                      = { glu::va::Float("in_v_attr", 1, (int)patchTessLevels.size(), 0, &patchTessLevels[0]) };
4555
4556                                         log << TestLog::Message << "Testing with outer tessellation level " << singleOuterEdgeLevels[outerEdgeLevelCaseNdx]
4557                                                                                         << " for the " << edgeDesc.description() << " edge, and with various levels for other edges" << TestLog::EndMessage;
4558
4559                                         {
4560                                                 const TFHandler::Result         tfResult                = tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
4561                                                                                                                                                                                                                 DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)patchTessLevels.size());
4562                                                 const int                                       refNumVertices  = referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4563
4564                                                 if ((int)tfResult.varying.size() != refNumVertices)
4565                                                 {
4566                                                         log << TestLog::Message << "Failure: the number of vertices returned by transform feedback is "
4567                                                                                                         << tfResult.varying.size() << ", expected " << refNumVertices << TestLog::EndMessage
4568                                                                 << TestLog::Message << "Note: rendered 1 patch, tessellation levels are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
4569                                                                                                         << containerStr(patchTessLevels, 6) << TestLog::EndMessage;
4570
4571                                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4572                                                         return STOP;
4573                                                 }
4574
4575                                                 {
4576                                                         Vec3Set currentEdgeVertices;
4577
4578                                                         // Get the vertices on the current outer edge.
4579                                                         for(int vtxNdx = 0; vtxNdx < refNumVertices; vtxNdx++)
4580                                                         {
4581                                                                 const Vec3& vtx = tfResult.varying[vtxNdx];
4582                                                                 if (edgeDesc.contains(vtx))
4583                                                                 {
4584                                                                         // Swizzle components to match the order of the first edge.
4585                                                                         if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4586                                                                         {
4587                                                                                 currentEdgeVertices.insert(outerEdgeIndex == 0 ? vtx
4588                                                                                                                                         : outerEdgeIndex == 1 ? vtx.swizzle(1, 0, 2)
4589                                                                                                                                         : outerEdgeIndex == 2 ? vtx.swizzle(2, 1, 0)
4590                                                                                                                                         : Vec3(-1.0f));
4591                                                                         }
4592                                                                         else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4593                                                                         {
4594                                                                                 currentEdgeVertices.insert(Vec3(outerEdgeIndex == 0 ? vtx.y()
4595                                                                                                                                                 : outerEdgeIndex == 1 ? vtx.x()
4596                                                                                                                                                 : outerEdgeIndex == 2 ? vtx.y()
4597                                                                                                                                                 : outerEdgeIndex == 3 ? vtx.x()
4598                                                                                                                                                 : -1.0f,
4599                                                                                                                                                 0.0f, 0.0f));
4600                                                                         }
4601                                                                         else
4602                                                                                 DE_ASSERT(false);
4603                                                                 }
4604                                                         }
4605
4606                                                         if (outerEdgeIndex == 0)
4607                                                                 firstEdgeVertices = currentEdgeVertices;
4608                                                         else
4609                                                         {
4610                                                                 // Compare vertices of this edge to those of the first edge.
4611
4612                                                                 if (currentEdgeVertices != firstEdgeVertices)
4613                                                                 {
4614                                                                         const char* const swizzleDesc = m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? (outerEdgeIndex == 1 ? "(y, x, z)"
4615                                                                                                                                                                                                                                         : outerEdgeIndex == 2 ? "(z, y, x)"
4616                                                                                                                                                                                                                                         : DE_NULL)
4617                                                                                                                                         : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? (outerEdgeIndex == 1 ? "(x, 0)"
4618                                                                                                                                                                                                                                 : outerEdgeIndex == 2 ? "(y, 0)"
4619                                                                                                                                                                                                                                 : outerEdgeIndex == 3 ? "(x, 0)"
4620                                                                                                                                                                                                                                 : DE_NULL)
4621                                                                                                                                         : DE_NULL;
4622
4623                                                                         log << TestLog::Message << "Failure: the set of vertices on the " << edgeDesc.description() << " edge"
4624                                                                                                                         << " doesn't match the set of vertices on the " << edgeDescriptions[0].description() << " edge" << TestLog::EndMessage
4625                                                                                 << TestLog::Message << "Note: set of vertices on " << edgeDesc.description() << " edge, components swizzled like " << swizzleDesc
4626                                                                                                                         << " to match component order on first edge:\n" << containerStr(currentEdgeVertices, 5)
4627                                                                                                                         << "\non " << edgeDescriptions[0].description() << " edge:\n" << containerStr(firstEdgeVertices, 5) << TestLog::EndMessage;
4628                                                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4629                                                                         return STOP;
4630                                                                 }
4631                                                         }
4632                                                 }
4633                                         }
4634                                 }
4635                         }
4636                 }
4637         }
4638
4639         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4640         return STOP;
4641 }
4642
4643 /*--------------------------------------------------------------------*//*!
4644  * \brief Test invariance rule #5
4645  *
4646  * Test that the set of triangles input to the TES only depends on the
4647  * tessellation levels, tessellation mode and spacing mode. Specifically,
4648  * winding doesn't change the set of triangles, though it can change the
4649  * order in which they are input to TES, and can (and will) change the
4650  * vertex order within a triangle.
4651  *//*--------------------------------------------------------------------*/
4652 class InvariantTriangleSetCase : public PrimitiveSetInvarianceCase
4653 {
4654 public:
4655         InvariantTriangleSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
4656                 : PrimitiveSetInvarianceCase(context, name, description, primType, spacing, false, WINDINGUSAGE_VARY)
4657         {
4658                 DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4659         }
4660
4661 protected:
4662         virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int) const
4663         {
4664                 return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog());
4665         }
4666 };
4667
4668 /*--------------------------------------------------------------------*//*!
4669  * \brief Test invariance rule #6
4670  *
4671  * Test that the set of inner triangles input to the TES only depends on
4672  * the inner tessellation levels, tessellation mode and spacing mode.
4673  *//*--------------------------------------------------------------------*/
4674 class InvariantInnerTriangleSetCase : public PrimitiveSetInvarianceCase
4675 {
4676 public:
4677         InvariantInnerTriangleSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
4678                 : PrimitiveSetInvarianceCase(context, name, description, primType, spacing, false, WINDINGUSAGE_VARY)
4679         {
4680                 DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4681         }
4682
4683 protected:
4684         virtual vector<LevelCase> genTessLevelCases (void) const
4685         {
4686                 const int                                       numSubCases             = 4;
4687                 const vector<LevelCase>         baseResults             = PrimitiveSetInvarianceCase::genTessLevelCases();
4688                 vector<LevelCase>                       result;
4689                 de::Random                                      rnd                             (123);
4690
4691                 // Generate variants with different values for irrelevant levels.
4692                 for (int baseNdx = 0; baseNdx < (int)baseResults.size(); baseNdx++)
4693                 {
4694                         const TessLevels&       base    = baseResults[baseNdx].levels[0];
4695                         TessLevels                      levels  = base;
4696                         LevelCase                       levelCase;
4697
4698                         for (int subNdx = 0; subNdx < numSubCases; subNdx++)
4699                         {
4700                                 levelCase.levels.push_back(levels);
4701
4702                                 for (int i = 0; i < DE_LENGTH_OF_ARRAY(levels.outer); i++)
4703                                         levels.outer[i] = rnd.getFloat(2.0f, 16.0f);
4704                                 if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4705                                         levels.inner[1] = rnd.getFloat(2.0f, 16.0f);
4706                         }
4707
4708                         result.push_back(levelCase);
4709                 }
4710
4711                 return result;
4712         }
4713
4714         struct IsInnerTriangleTriangle
4715         {
4716                 bool operator() (const Vec3* vertices) const
4717                 {
4718                         for (int v = 0; v < 3; v++)
4719                                 for (int c = 0; c < 3; c++)
4720                                         if (vertices[v][c] == 0.0f)
4721                                                 return false;
4722                         return true;
4723                 }
4724         };
4725
4726         struct IsInnerQuadTriangle
4727         {
4728                 bool operator() (const Vec3* vertices) const
4729                 {
4730                         for (int v = 0; v < 3; v++)
4731                                 for (int c = 0; c < 2; c++)
4732                                         if (vertices[v][c] == 0.0f || vertices[v][c] == 1.0f)
4733                                                 return false;
4734                         return true;
4735                 }
4736         };
4737
4738         virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int) const
4739         {
4740                 if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4741                         return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(), IsInnerTriangleTriangle(), "outer triangles");
4742                 else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4743                         return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(), IsInnerQuadTriangle(), "outer triangles");
4744                 else
4745                 {
4746                         DE_ASSERT(false);
4747                         return false;
4748                 }
4749         }
4750 };
4751
4752 /*--------------------------------------------------------------------*//*!
4753  * \brief Test invariance rule #7
4754  *
4755  * Test that the set of outer triangles input to the TES only depends on
4756  * tessellation mode, spacing mode and the inner and outer tessellation
4757  * levels corresponding to the inner and outer edges relevant to that
4758  * triangle.
4759  *//*--------------------------------------------------------------------*/
4760 class InvariantOuterTriangleSetCase : public PrimitiveSetInvarianceCase
4761 {
4762 public:
4763         InvariantOuterTriangleSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
4764                 : PrimitiveSetInvarianceCase(context, name, description, primType, spacing, false, WINDINGUSAGE_VARY)
4765         {
4766                 DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4767         }
4768
4769 protected:
4770         virtual vector<LevelCase> genTessLevelCases (void) const
4771         {
4772                 const int                                       numSubCasesPerEdge      = 4;
4773                 const int                                       numEdges                        = m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES        ? 3
4774                                                                                                                 : m_primitiveType == TESSPRIMITIVETYPE_QUADS            ? 4
4775                                                                                                                 : -1;
4776                 const vector<LevelCase>         baseResult                      = PrimitiveSetInvarianceCase::genTessLevelCases();
4777                 vector<LevelCase>                       result;
4778                 de::Random                                      rnd                                     (123);
4779
4780                 // Generate variants with different values for irrelevant levels.
4781                 for (int baseNdx = 0; baseNdx < (int)baseResult.size(); baseNdx++)
4782                 {
4783                         const TessLevels& base = baseResult[baseNdx].levels[0];
4784                         if (base.inner[0] == 1.0f || (m_primitiveType == TESSPRIMITIVETYPE_QUADS && base.inner[1] == 1.0f))
4785                                 continue;
4786
4787                         for (int edgeNdx = 0; edgeNdx < numEdges; edgeNdx++)
4788                         {
4789                                 TessLevels      levels = base;
4790                                 LevelCase       levelCase;
4791                                 levelCase.mem = edgeNdx;
4792
4793                                 for (int subCaseNdx = 0; subCaseNdx < numSubCasesPerEdge; subCaseNdx++)
4794                                 {
4795                                         levelCase.levels.push_back(levels);
4796
4797                                         for (int i = 0; i < DE_LENGTH_OF_ARRAY(levels.outer); i++)
4798                                         {
4799                                                 if (i != edgeNdx)
4800                                                         levels.outer[i] = rnd.getFloat(2.0f, 16.0f);
4801                                         }
4802
4803                                         if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4804                                                 levels.inner[1] = rnd.getFloat(2.0f, 16.0f);
4805                                 }
4806
4807                                 result.push_back(levelCase);
4808                         }
4809                 }
4810
4811                 return result;
4812         }
4813
4814         class IsTriangleTriangleOnOuterEdge
4815         {
4816         public:
4817                 IsTriangleTriangleOnOuterEdge (int edgeNdx) : m_edgeNdx(edgeNdx) {}
4818                 bool operator() (const Vec3* vertices) const
4819                 {
4820                         bool touchesAppropriateEdge = false;
4821                         for (int v = 0; v < 3; v++)
4822                                 if (vertices[v][m_edgeNdx] == 0.0f)
4823                                         touchesAppropriateEdge = true;
4824
4825                         if (touchesAppropriateEdge)
4826                         {
4827                                 const Vec3 avg = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
4828                                 return avg[m_edgeNdx] < avg[(m_edgeNdx+1)%3] &&
4829                                            avg[m_edgeNdx] < avg[(m_edgeNdx+2)%3];
4830                         }
4831                         return false;
4832                 }
4833
4834         private:
4835                 int m_edgeNdx;
4836         };
4837
4838         class IsQuadTriangleOnOuterEdge
4839         {
4840         public:
4841                 IsQuadTriangleOnOuterEdge (int edgeNdx) : m_edgeNdx(edgeNdx) {}
4842
4843                 bool onEdge (const Vec3& v) const
4844                 {
4845                         return v[m_edgeNdx%2] == (m_edgeNdx <= 1 ? 0.0f : 1.0f);
4846                 }
4847
4848                 static inline bool onAnyEdge (const Vec3& v)
4849                 {
4850                         return v[0] == 0.0f || v[0] == 1.0f || v[1] == 0.0f || v[1] == 1.0f;
4851                 }
4852
4853                 bool operator() (const Vec3* vertices) const
4854                 {
4855                         for (int v = 0; v < 3; v++)
4856                         {
4857                                 const Vec3& a = vertices[v];
4858                                 const Vec3& b = vertices[(v+1)%3];
4859                                 const Vec3& c = vertices[(v+2)%3];
4860                                 if (onEdge(a) && onEdge(b))
4861                                         return true;
4862                                 if (onEdge(c) && !onAnyEdge(a) && !onAnyEdge(b) && a[m_edgeNdx%2] == b[m_edgeNdx%2])
4863                                         return true;
4864                         }
4865
4866                         return false;
4867                 }
4868
4869         private:
4870                 int m_edgeNdx;
4871         };
4872
4873         virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int outerEdgeNdx) const
4874         {
4875                 if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4876                 {
4877                         return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(),
4878                                                                            IsTriangleTriangleOnOuterEdge(outerEdgeNdx),
4879                                                                            ("inner triangles, and outer triangles corresponding to other edge than edge "
4880                                                                                 + outerEdgeDescriptions(m_primitiveType)[outerEdgeNdx].description()).c_str());
4881                 }
4882                 else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4883                 {
4884                         return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(),
4885                                                                            IsQuadTriangleOnOuterEdge(outerEdgeNdx),
4886                                                                            ("inner triangles, and outer triangles corresponding to other edge than edge "
4887                                                                                 + outerEdgeDescriptions(m_primitiveType)[outerEdgeNdx].description()).c_str());
4888                 }
4889                 else
4890                         DE_ASSERT(false);
4891
4892                 return true;
4893         }
4894 };
4895
4896 /*--------------------------------------------------------------------*//*!
4897  * \brief Base class for testing individual components of tess coords
4898  *
4899  * Useful for testing parts of invariance rule #8.
4900  *//*--------------------------------------------------------------------*/
4901 class TessCoordComponentInvarianceCase : public TestCase
4902 {
4903 public:
4904         TessCoordComponentInvarianceCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
4905                 : TestCase                      (context, name, description)
4906                 , m_primitiveType       (primType)
4907                 , m_spacing                     (spacing)
4908                 , m_winding                     (winding)
4909                 , m_usePointMode        (usePointMode)
4910         {
4911         }
4912
4913         void                                                                    init            (void);
4914         void                                                                    deinit          (void);
4915         IterateResult                                                   iterate         (void);
4916
4917 protected:
4918         virtual string                                                  tessEvalOutputComponentStatements       (const char* tessCoordComponentName, const char* outputComponentName) const = 0;
4919         virtual bool                                                    checkTessCoordComponent                         (float component) const = 0;
4920
4921 private:
4922         static vector<float>                                    genTessLevelCases (int numCases);
4923
4924         static const int                                                RENDER_SIZE = 16;
4925
4926         const TessPrimitiveType                                 m_primitiveType;
4927         const SpacingMode                                               m_spacing;
4928         const Winding                                                   m_winding;
4929         const bool                                                              m_usePointMode;
4930
4931         SharedPtr<const glu::ShaderProgram>             m_program;
4932 };
4933
4934 void TessCoordComponentInvarianceCase::init (void)
4935 {
4936         checkTessellationSupport(m_context);
4937         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
4938
4939         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
4940                 << glu::VertexSource                                    ("#version 310 es\n"
4941                                                                                                  "\n"
4942                                                                                                  "in highp float in_v_attr;\n"
4943                                                                                                  "out highp float in_tc_attr;\n"
4944                                                                                                  "\n"
4945                                                                                                  "void main (void)\n"
4946                                                                                                  "{\n"
4947                                                                                                  "      in_tc_attr = in_v_attr;\n"
4948                                                                                                  "}\n")
4949
4950                 << glu::TessellationControlSource               ("#version 310 es\n"
4951                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
4952                                                                                                  "\n"
4953                                                                                                  "layout (vertices = 1) out;\n"
4954                                                                                                  "\n"
4955                                                                                                  "in highp float in_tc_attr[];\n"
4956                                                                                                  "\n"
4957                                                                                                  "void main (void)\n"
4958                                                                                                  "{\n"
4959                                                                                                  "      gl_TessLevelInner[0] = in_tc_attr[0];\n"
4960                                                                                                  "      gl_TessLevelInner[1] = in_tc_attr[1];\n"
4961                                                                                                  "\n"
4962                                                                                                  "      gl_TessLevelOuter[0] = in_tc_attr[2];\n"
4963                                                                                                  "      gl_TessLevelOuter[1] = in_tc_attr[3];\n"
4964                                                                                                  "      gl_TessLevelOuter[2] = in_tc_attr[4];\n"
4965                                                                                                  "      gl_TessLevelOuter[3] = in_tc_attr[5];\n"
4966                                                                                                  "}\n")
4967
4968                 << glu::TessellationEvaluationSource    ("#version 310 es\n"
4969                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
4970                                                                                                  "\n"
4971                                                                                                  + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
4972                                                                                                  "\n"
4973                                                                                                  "out highp vec4 in_f_color;\n"
4974                                                                                                  "out highp vec3 out_te_output;\n"
4975                                                                                                  "\n"
4976                                                                                                  "void main (void)\n"
4977                                                                                                  "{\n"
4978                                                                                                  + tessEvalOutputComponentStatements("gl_TessCoord.x", "out_te_output.x")
4979                                                                                                  + tessEvalOutputComponentStatements("gl_TessCoord.y", "out_te_output.y")
4980
4981                                                                                                  + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
4982                                                                                                         tessEvalOutputComponentStatements("gl_TessCoord.z", "out_te_output.z") :
4983                                                                                                         "       out_te_output.z = 0.0f;\n") +
4984                                                                                                  "      gl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
4985                                                                                                  "      in_f_color = vec4(1.0);\n"
4986                                                                                                  "}\n")
4987
4988                 << glu::FragmentSource                                  ("#version 310 es\n"
4989                                                                                                  "\n"
4990                                                                                                  "layout (location = 0) out mediump vec4 o_color;\n"
4991                                                                                                  "\n"
4992                                                                                                  "in highp vec4 in_f_color;\n"
4993                                                                                                  "\n"
4994                                                                                                  "void main (void)\n"
4995                                                                                                  "{\n"
4996                                                                                                  "      o_color = in_f_color;\n"
4997                                                                                                  "}\n")
4998
4999                 << glu::TransformFeedbackVarying                ("out_te_output")
5000                 << glu::TransformFeedbackMode                   (GL_INTERLEAVED_ATTRIBS)));
5001
5002         m_testCtx.getLog() << *m_program;
5003         if (!m_program->isOk())
5004                 TCU_FAIL("Program compilation failed");
5005 }
5006
5007 void TessCoordComponentInvarianceCase::deinit (void)
5008 {
5009         m_program.clear();
5010 }
5011
5012 vector<float> TessCoordComponentInvarianceCase::genTessLevelCases (int numCases)
5013 {
5014         de::Random              rnd(123);
5015         vector<float>   result;
5016
5017         for (int i = 0; i < numCases; i++)
5018                 for (int j = 0; j < 6; j++)
5019                         result.push_back(rnd.getFloat(1.0f, 63.0f));
5020
5021         return result;
5022 }
5023
5024 TessCoordComponentInvarianceCase::IterateResult TessCoordComponentInvarianceCase::iterate (void)
5025 {
5026         typedef TransformFeedbackHandler<Vec3> TFHandler;
5027
5028         TestLog&                                log                                     = m_testCtx.getLog();
5029         const RenderContext&    renderCtx                       = m_context.getRenderContext();
5030         const RandomViewport    viewport                        (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
5031         const glw::Functions&   gl                                      = renderCtx.getFunctions();
5032         const int                               numTessLevelCases       = 32;
5033         const vector<float>             tessLevels                      = genTessLevelCases(numTessLevelCases);
5034         const deUint32                  programGL                       = m_program->getProgram();
5035
5036         gl.useProgram(programGL);
5037         setViewport(gl, viewport);
5038         gl.patchParameteri(GL_PATCH_VERTICES, 6);
5039
5040         {
5041                 // Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
5042                 int maxNumVerticesInDrawCall = 0;
5043                 for (int i = 0; i < numTessLevelCases; i++)
5044                         maxNumVerticesInDrawCall = de::max(maxNumVerticesInDrawCall, referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &tessLevels[6*i+0], &tessLevels[6*i+2]));
5045
5046                 {
5047                         const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
5048
5049                         for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < numTessLevelCases; tessLevelCaseNdx++)
5050                         {
5051                                 log << TestLog::Message << "Testing with tessellation levels: " << tessellationLevelsString(&tessLevels[6*tessLevelCaseNdx+0], &tessLevels[6*tessLevelCaseNdx+2]) << TestLog::EndMessage;
5052
5053                                 const glu::VertexArrayBinding bindings[] = { glu::va::Float("in_v_attr", 1, (int)6, 0, &tessLevels[6*tessLevelCaseNdx]) };
5054                                 const TFHandler::Result tfResult = tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
5055                                                                                                                                                                         DE_LENGTH_OF_ARRAY(bindings), &bindings[0], 6);
5056
5057                                 for (int vtxNdx = 0; vtxNdx < (int)tfResult.varying.size(); vtxNdx++)
5058                                 {
5059                                         const Vec3&             vec                     = tfResult.varying[vtxNdx];
5060                                         const int               numComps        = m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2;
5061
5062                                         for (int compNdx = 0; compNdx < numComps; compNdx++)
5063                                         {
5064                                                 if (!checkTessCoordComponent(vec[compNdx]))
5065                                                 {
5066                                                         log << TestLog::Message << "Note: output value at index " << vtxNdx << " is "
5067                                                                                                         << (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? de::toString(vec) : de::toString(vec.swizzle(0,1)))
5068                                                                                                         << TestLog::EndMessage;
5069                                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid tessellation coordinate component");
5070                                                         return STOP;
5071                                                 }
5072                                         }
5073                                 }
5074                         }
5075                 }
5076         }
5077
5078         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5079         return STOP;
5080 }
5081
5082 /*--------------------------------------------------------------------*//*!
5083  * \brief Test first part of invariance rule #8
5084  *
5085  * Test that all (relevant) components of tess coord are in [0,1].
5086  *//*--------------------------------------------------------------------*/
5087 class TessCoordComponentRangeCase : public TessCoordComponentInvarianceCase
5088 {
5089 public:
5090         TessCoordComponentRangeCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
5091                 : TessCoordComponentInvarianceCase(context, name, description, primType, spacing, winding, usePointMode)
5092         {
5093         }
5094
5095 protected:
5096         virtual string tessEvalOutputComponentStatements (const char* tessCoordComponentName, const char* outputComponentName) const
5097         {
5098                 return string() + "\t" + outputComponentName + " = " + tessCoordComponentName + ";\n";
5099         }
5100
5101         virtual bool checkTessCoordComponent (float component) const
5102         {
5103                 if (!de::inRange(component, 0.0f, 1.0f))
5104                 {
5105                         m_testCtx.getLog() << TestLog::Message << "Failure: tess coord component isn't in range [0,1]" << TestLog::EndMessage;
5106                         return false;
5107                 }
5108                 return true;
5109         }
5110 };
5111
5112 /*--------------------------------------------------------------------*//*!
5113  * \brief Test second part of invariance rule #8
5114  *
5115  * Test that all (relevant) components of tess coord are in [0,1] and
5116  * 1.0-c is exact for every such component c.
5117  *//*--------------------------------------------------------------------*/
5118 class OneMinusTessCoordComponentCase : public TessCoordComponentInvarianceCase
5119 {
5120 public:
5121         OneMinusTessCoordComponentCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
5122                 : TessCoordComponentInvarianceCase(context, name, description, primType, spacing, winding, usePointMode)
5123         {
5124         }
5125
5126 protected:
5127         virtual string tessEvalOutputComponentStatements (const char* tessCoordComponentName, const char* outputComponentName) const
5128         {
5129                 return string() + "     {\n"
5130                                                   "             float oneMinusComp = 1.0 - " + tessCoordComponentName + ";\n"
5131                                                   "             " + outputComponentName + " = " + tessCoordComponentName + " + oneMinusComp;\n"
5132                                                   "     }\n";
5133         }
5134
5135         virtual bool checkTessCoordComponent (float component) const
5136         {
5137                 if (component != 1.0f)
5138                 {
5139                         m_testCtx.getLog() << TestLog::Message << "Failure: comp + (1.0-comp) doesn't equal 1.0 for some component of tessellation coordinate" << TestLog::EndMessage;
5140                         return false;
5141                 }
5142                 return true;
5143         }
5144 };
5145
5146 /*--------------------------------------------------------------------*//*!
5147  * \brief Test that patch is discarded if relevant outer level <= 0.0
5148  *
5149  * Draws patches with different combinations of tessellation levels,
5150  * varying which levels are negative. Verifies by checking that colored
5151  * pixels exist inside the area of valid primitives, and only black pixels
5152  * exist inside the area of discarded primitives. An additional sanity
5153  * test is done, checking that the number of primitives written by TF is
5154  * correct.
5155  *//*--------------------------------------------------------------------*/
5156 class PrimitiveDiscardCase : public TestCase
5157 {
5158 public:
5159         PrimitiveDiscardCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
5160                 : TestCase                      (context, name, description)
5161                 , m_primitiveType       (primType)
5162                 , m_spacing                     (spacing)
5163                 , m_winding                     (winding)
5164                 , m_usePointMode        (usePointMode)
5165         {
5166         }
5167
5168         void                                                                    init            (void);
5169         void                                                                    deinit          (void);
5170         IterateResult                                                   iterate         (void);
5171
5172 private:
5173         static vector<float>                                    genAttributes (void);
5174
5175         static const int                                                RENDER_SIZE = 256;
5176
5177         const TessPrimitiveType                                 m_primitiveType;
5178         const SpacingMode                                               m_spacing;
5179         const Winding                                                   m_winding;
5180         const bool                                                              m_usePointMode;
5181
5182         SharedPtr<const glu::ShaderProgram>             m_program;
5183 };
5184
5185 void PrimitiveDiscardCase::init (void)
5186 {
5187         checkTessellationSupport(m_context);
5188         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
5189
5190         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
5191                 << glu::VertexSource                                    ("#version 310 es\n"
5192                                                                                                  "\n"
5193                                                                                                  "in highp float in_v_attr;\n"
5194                                                                                                  "out highp float in_tc_attr;\n"
5195                                                                                                  "\n"
5196                                                                                                  "void main (void)\n"
5197                                                                                                  "{\n"
5198                                                                                                  "      in_tc_attr = in_v_attr;\n"
5199                                                                                                  "}\n")
5200
5201                 << glu::TessellationControlSource               ("#version 310 es\n"
5202                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
5203                                                                                                  "\n"
5204                                                                                                  "layout (vertices = 1) out;\n"
5205                                                                                                  "\n"
5206                                                                                                  "in highp float in_tc_attr[];\n"
5207                                                                                                  "\n"
5208                                                                                                  "patch out highp vec2 in_te_positionScale;\n"
5209                                                                                                  "patch out highp vec2 in_te_positionOffset;\n"
5210                                                                                                  "\n"
5211                                                                                                  "void main (void)\n"
5212                                                                                                  "{\n"
5213                                                                                                  "      in_te_positionScale  = vec2(in_tc_attr[6], in_tc_attr[7]);\n"
5214                                                                                                  "      in_te_positionOffset = vec2(in_tc_attr[8], in_tc_attr[9]);\n"
5215                                                                                                  "\n"
5216                                                                                                  "      gl_TessLevelInner[0] = in_tc_attr[0];\n"
5217                                                                                                  "      gl_TessLevelInner[1] = in_tc_attr[1];\n"
5218                                                                                                  "\n"
5219                                                                                                  "      gl_TessLevelOuter[0] = in_tc_attr[2];\n"
5220                                                                                                  "      gl_TessLevelOuter[1] = in_tc_attr[3];\n"
5221                                                                                                  "      gl_TessLevelOuter[2] = in_tc_attr[4];\n"
5222                                                                                                  "      gl_TessLevelOuter[3] = in_tc_attr[5];\n"
5223                                                                                                  "}\n")
5224
5225                 << glu::TessellationEvaluationSource    ("#version 310 es\n"
5226                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
5227                                                                                                  "\n"
5228                                                                                                  + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
5229                                                                                                  "\n"
5230                                                                                                  "patch in highp vec2 in_te_positionScale;\n"
5231                                                                                                  "patch in highp vec2 in_te_positionOffset;\n"
5232                                                                                                  "\n"
5233                                                                                                  "out highp vec3 out_te_tessCoord;\n"
5234                                                                                                  "\n"
5235                                                                                                  "void main (void)\n"
5236                                                                                                  "{\n"
5237                                                                                                  "      out_te_tessCoord = gl_TessCoord;\n"
5238                                                                                                  "      gl_Position = vec4(gl_TessCoord.xy*in_te_positionScale + in_te_positionOffset, 0.0, 1.0);\n"
5239                                                                                                  "}\n")
5240
5241                 << glu::FragmentSource                                  ("#version 310 es\n"
5242                                                                                                  "\n"
5243                                                                                                  "layout (location = 0) out mediump vec4 o_color;\n"
5244                                                                                                  "\n"
5245                                                                                                  "void main (void)\n"
5246                                                                                                  "{\n"
5247                                                                                                  "      o_color = vec4(1.0);\n"
5248                                                                                                  "}\n")
5249
5250                 << glu::TransformFeedbackVarying                ("out_te_tessCoord")
5251                 << glu::TransformFeedbackMode                   (GL_INTERLEAVED_ATTRIBS)));
5252
5253         m_testCtx.getLog() << *m_program;
5254         if (!m_program->isOk())
5255                 TCU_FAIL("Program compilation failed");
5256 }
5257
5258 void PrimitiveDiscardCase::deinit (void)
5259 {
5260         m_program.clear();
5261 }
5262
5263 vector<float> PrimitiveDiscardCase::genAttributes (void)
5264 {
5265         // Generate input attributes (tessellation levels, and position scale and
5266         // offset) for a number of primitives. Each primitive has a different
5267         // combination of tessellatio levels; each level is either a valid
5268         // value or an "invalid" value (negative or zero, chosen from
5269         // invalidTessLevelChoices).
5270
5271         // \note The attributes are generated in such an order that all of the
5272         //               valid attribute tuples come before the first invalid one both
5273         //               in the result vector, and when scanning the resulting 2d grid
5274         //               of primitives is scanned in y-major order. This makes
5275         //               verification somewhat simpler.
5276
5277         static const float      baseTessLevels[6]                       = { 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };
5278         static const float      invalidTessLevelChoices[]       = { -0.42f, 0.0f };
5279         const int                       numChoices                                      = 1 + DE_LENGTH_OF_ARRAY(invalidTessLevelChoices);
5280         float                           choices[6][numChoices];
5281         vector<float>           result;
5282
5283         for (int levelNdx = 0; levelNdx < 6; levelNdx++)
5284                 for (int choiceNdx = 0; choiceNdx < numChoices; choiceNdx++)
5285                         choices[levelNdx][choiceNdx] = choiceNdx == 0 ? baseTessLevels[levelNdx] : invalidTessLevelChoices[choiceNdx-1];
5286
5287         {
5288                 const int       numCols                 = intPow(numChoices, 6/2); // sqrt(numChoices**6) == sqrt(number of primitives)
5289                 const int       numRows                 = numCols;
5290                 int                     index                   = 0;
5291                 int                     i[6];
5292                 // We could do this with some generic combination-generation function, but meh, it's not that bad.
5293                 for (i[2] = 0; i[2] < numChoices; i[2]++) // First  outer
5294                 for (i[3] = 0; i[3] < numChoices; i[3]++) // Second outer
5295                 for (i[4] = 0; i[4] < numChoices; i[4]++) // Third  outer
5296                 for (i[5] = 0; i[5] < numChoices; i[5]++) // Fourth outer
5297                 for (i[0] = 0; i[0] < numChoices; i[0]++) // First  inner
5298                 for (i[1] = 0; i[1] < numChoices; i[1]++) // Second inner
5299                 {
5300                         for (int j = 0; j < 6; j++)
5301                                 result.push_back(choices[j][i[j]]);
5302
5303                         {
5304                                 const int col = index % numCols;
5305                                 const int row = index / numCols;
5306                                 // Position scale.
5307                                 result.push_back((float)2.0f / (float)numCols);
5308                                 result.push_back((float)2.0f / (float)numRows);
5309                                 // Position offset.
5310                                 result.push_back((float)col / (float)numCols * 2.0f - 1.0f);
5311                                 result.push_back((float)row / (float)numRows * 2.0f - 1.0f);
5312                         }
5313
5314                         index++;
5315                 }
5316         }
5317
5318         return result;
5319 }
5320
5321 PrimitiveDiscardCase::IterateResult PrimitiveDiscardCase::iterate (void)
5322 {
5323         typedef TransformFeedbackHandler<Vec3> TFHandler;
5324
5325         TestLog&                                log                                             = m_testCtx.getLog();
5326         const RenderContext&    renderCtx                               = m_context.getRenderContext();
5327         const RandomViewport    viewport                                (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
5328         const glw::Functions&   gl                                              = renderCtx.getFunctions();
5329         const vector<float>             attributes                              = genAttributes();
5330         const int                               numAttribsPerPrimitive  = 6+2+2; // Tess levels, scale, offset.
5331         const int                               numPrimitives                   = (int)attributes.size() / numAttribsPerPrimitive;
5332         const deUint32                  programGL                               = m_program->getProgram();
5333
5334         gl.useProgram(programGL);
5335         setViewport(gl, viewport);
5336         gl.patchParameteri(GL_PATCH_VERTICES, numAttribsPerPrimitive);
5337
5338         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
5339         gl.clear(GL_COLOR_BUFFER_BIT);
5340
5341         // Check the convenience assertion that all discarded patches come after the last non-discarded patch.
5342         {
5343                 bool discardedPatchEncountered = false;
5344                 for (int patchNdx = 0; patchNdx < numPrimitives; patchNdx++)
5345                 {
5346                         const bool discard = isPatchDiscarded(m_primitiveType, &attributes[numAttribsPerPrimitive*patchNdx + 2]);
5347                         DE_ASSERT(discard || !discardedPatchEncountered);
5348                         discardedPatchEncountered = discard;
5349                 }
5350                 DE_UNREF(discardedPatchEncountered);
5351         }
5352
5353         {
5354                 int numVerticesInDrawCall = 0;
5355                 for (int patchNdx = 0; patchNdx < numPrimitives; patchNdx++)
5356                         numVerticesInDrawCall += referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &attributes[numAttribsPerPrimitive*patchNdx+0], &attributes[numAttribsPerPrimitive*patchNdx+2]);
5357
5358                 log << TestLog::Message << "Note: rendering " << numPrimitives << " patches; first patches have valid relevant outer levels, "
5359                                                                 << "but later patches have one or more invalid (i.e. less than or equal to 0.0) relevant outer levels" << TestLog::EndMessage;
5360
5361                 {
5362                         const TFHandler                                 tfHandler       (m_context.getRenderContext(), numVerticesInDrawCall);
5363                         const glu::VertexArrayBinding   bindings[]      = { glu::va::Float("in_v_attr", 1, (int)attributes.size(), 0, &attributes[0]) };
5364                         const TFHandler::Result                 tfResult        = tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
5365                                                                                                                                                                                    DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)attributes.size());
5366                         const tcu::Surface                              pixels          = getPixels(renderCtx, viewport);
5367
5368                         log << TestLog::Image("RenderedImage", "Rendered image", pixels);
5369
5370                         if ((int)tfResult.varying.size() != numVerticesInDrawCall)
5371                         {
5372                                 log << TestLog::Message << "Failure: expected " << numVerticesInDrawCall << " vertices from transform feedback, got " << tfResult.varying.size() << TestLog::EndMessage;
5373                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Wrong number of tessellation coordinates");
5374                                 return STOP;
5375                         }
5376
5377                         // Check that white pixels are found around every non-discarded
5378                         // patch, and that only black pixels are found after the last
5379                         // non-discarded patch.
5380                         {
5381                                 int lastWhitePixelRow                                                                   = 0;
5382                                 int secondToLastWhitePixelRow                                                   = 0;
5383                                 int     lastWhitePixelColumnOnSecondToLastWhitePixelRow         = 0;
5384
5385                                 for (int patchNdx = 0; patchNdx < numPrimitives; patchNdx++)
5386                                 {
5387                                         const float* const      attr                    = &attributes[numAttribsPerPrimitive*patchNdx];
5388                                         const bool                      validLevels             = !isPatchDiscarded(m_primitiveType, &attr[2]);
5389
5390                                         if (validLevels)
5391                                         {
5392                                                 // Not a discarded patch; check that at least one white pixel is found in its area.
5393
5394                                                 const float* const      scale           = &attr[6];
5395                                                 const float* const      offset          = &attr[8];
5396                                                 const int                       x0                      = (int)((                       offset[0] + 1.0f)*0.5f*(float)pixels.getWidth()) - 1;
5397                                                 const int                       x1                      = (int)((scale[0] + offset[0] + 1.0f)*0.5f*(float)pixels.getWidth()) + 1;
5398                                                 const int                       y0                      = (int)((                       offset[1] + 1.0f)*0.5f*(float)pixels.getHeight()) - 1;
5399                                                 const int                       y1                      = (int)((scale[1] + offset[1] + 1.0f)*0.5f*(float)pixels.getHeight()) + 1;
5400                                                 const bool                      isMSAA          = renderCtx.getRenderTarget().getNumSamples() > 1;
5401                                                 bool                            pixelOk         = false;
5402
5403                                                 if (y1 > lastWhitePixelRow)
5404                                                 {
5405                                                         secondToLastWhitePixelRow       = lastWhitePixelRow;
5406                                                         lastWhitePixelRow                       = y1;
5407                                                 }
5408                                                 lastWhitePixelColumnOnSecondToLastWhitePixelRow = x1;
5409
5410                                                 for (int y = y0; y <= y1 && !pixelOk; y++)
5411                                                 for (int x = x0; x <= x1 && !pixelOk; x++)
5412                                                 {
5413                                                         if (!de::inBounds(x, 0, pixels.getWidth()) || !de::inBounds(y, 0, pixels.getHeight()))
5414                                                                 continue;
5415
5416                                                         if (isMSAA)
5417                                                         {
5418                                                                 if (pixels.getPixel(x, y) != tcu::RGBA::black())
5419                                                                         pixelOk = true;
5420                                                         }
5421                                                         else
5422                                                         {
5423                                                                 if (pixels.getPixel(x, y) == tcu::RGBA::white())
5424                                                                         pixelOk = true;
5425                                                         }
5426                                                 }
5427
5428                                                 if (!pixelOk)
5429                                                 {
5430                                                         log << TestLog::Message << "Failure: expected at least one " << (isMSAA ? "non-black" : "white") << " pixel in the rectangle "
5431                                                                                                         << "[x0=" << x0 << ", y0=" << y0 << ", x1=" << x1 << ", y1=" << y1 << "]" << TestLog::EndMessage
5432                                                                 << TestLog::Message << "Note: the rectangle approximately corresponds to the patch with these tessellation levels: "
5433                                                                                                         << tessellationLevelsString(&attr[0], &attr[1]) << TestLog::EndMessage;
5434                                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
5435                                                         return STOP;
5436                                                 }
5437                                         }
5438                                         else
5439                                         {
5440                                                 // First discarded primitive patch; the remaining are guaranteed to be discarded ones as well.
5441
5442                                                 for (int y = 0; y < pixels.getHeight(); y++)
5443                                                 for (int x = 0; x < pixels.getWidth(); x++)
5444                                                 {
5445                                                         if (y > lastWhitePixelRow || (y > secondToLastWhitePixelRow && x > lastWhitePixelColumnOnSecondToLastWhitePixelRow))
5446                                                         {
5447                                                                 if (pixels.getPixel(x, y) != tcu::RGBA::black())
5448                                                                 {
5449                                                                         log << TestLog::Message << "Failure: expected all pixels to be black in the area "
5450                                                                                                                         << (lastWhitePixelColumnOnSecondToLastWhitePixelRow < pixels.getWidth()-1
5451                                                                                                                                         ? string() + "y > " + de::toString(lastWhitePixelRow) + " || (y > " + de::toString(secondToLastWhitePixelRow)
5452                                                                                                                                                            + " && x > " + de::toString(lastWhitePixelColumnOnSecondToLastWhitePixelRow) + ")"
5453                                                                                                                                         : string() + "y > " + de::toString(lastWhitePixelRow))
5454                                                                                                                         << " (they all correspond to patches that should be discarded)" << TestLog::EndMessage
5455                                                                                 << TestLog::Message << "Note: pixel " << tcu::IVec2(x, y) << " isn't black" << TestLog::EndMessage;
5456                                                                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
5457                                                                         return STOP;
5458                                                                 }
5459                                                         }
5460                                                 }
5461
5462                                                 break;
5463                                         }
5464                                 }
5465                         }
5466                 }
5467         }
5468
5469         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5470         return STOP;
5471 }
5472
5473 /*--------------------------------------------------------------------*//*!
5474  * \brief Case testing user-defined IO between TCS and TES
5475  *
5476  * TCS outputs various values to TES, including aggregates. The outputs
5477  * can be per-patch or per-vertex, and if per-vertex, they can also be in
5478  * an IO block. Per-vertex input array size can be left implicit (i.e.
5479  * inputArray[]) or explicit either by gl_MaxPatchVertices or an integer
5480  * literal whose value is queried from GL.
5481  *
5482  * The values output are generated in TCS and verified in TES against
5483  * similarly generated values. In case a verification of a value fails, the
5484  * index of the invalid value is output with TF.
5485  * As a sanity check, also the rendering result is verified (against pre-
5486  * rendered reference).
5487  *//*--------------------------------------------------------------------*/
5488 class UserDefinedIOCase : public TestCase
5489 {
5490 public:
5491         enum IOType
5492         {
5493                 IO_TYPE_PER_PATCH = 0,
5494                 IO_TYPE_PER_PATCH_ARRAY,
5495                 IO_TYPE_PER_PATCH_BLOCK,
5496                 IO_TYPE_PER_PATCH_BLOCK_ARRAY,
5497                 IO_TYPE_PER_VERTEX,
5498                 IO_TYPE_PER_VERTEX_BLOCK,
5499
5500                 IO_TYPE_LAST
5501         };
5502
5503         enum VertexIOArraySize
5504         {
5505                 VERTEX_IO_ARRAY_SIZE_IMPLICIT = 0,
5506                 VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN,           //!< Use gl_MaxPatchVertices as size for per-vertex input array.
5507                 VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY,                            //!< Query GL_MAX_PATCH_VERTICES, and use that as size for per-vertex input array.
5508
5509                 VERTEX_IO_ARRAY_SIZE_LAST
5510         };
5511
5512         enum TessControlOutArraySize
5513         {
5514                 TESS_CONTROL_OUT_ARRAY_SIZE_IMPLICIT = 0,
5515                 TESS_CONTROL_OUT_ARRAY_SIZE_LAYOUT,
5516                 TESS_CONTROL_OUT_ARRAY_SIZE_QUERY,
5517                 TESS_CONTROL_OUT_ARRAY_SIZE_SHADER_BUILTIN
5518         };
5519
5520         UserDefinedIOCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, IOType ioType, VertexIOArraySize vertexIOArraySize, TessControlOutArraySize tessControlOutArraySize, const char* referenceImagePath)
5521                 : TestCase                                      (context, name, description)
5522                 , m_primitiveType                       (primType)
5523                 , m_ioType                                      (ioType)
5524                 , m_vertexIOArraySize           (vertexIOArraySize)
5525                 , m_tessControlOutArraySize     (tessControlOutArraySize)
5526                 , m_referenceImagePath          (referenceImagePath)
5527         {
5528         }
5529
5530         void                                                                    init            (void);
5531         void                                                                    deinit          (void);
5532         IterateResult                                                   iterate         (void);
5533
5534 private:
5535         typedef string (*BasicTypeVisitFunc)(const string& name, glu::DataType type, int indentationDepth); //!< See glslTraverseBasicTypes below.
5536
5537         class TopLevelObject
5538         {
5539         public:
5540                 virtual                 ~TopLevelObject                                 (void) {}
5541
5542                 virtual string  name                                                    (void) const = 0;
5543                 virtual string  declare                                                 (void) const = 0;
5544                 virtual string  declareArray                                    (const string& arraySizeExpr) const = 0;
5545                 virtual string  glslTraverseBasicTypeArray              (int numArrayElements, //!< If negative, traverse just array[gl_InvocationID], not all indices.
5546                                                                                                                  int indentationDepth,
5547                                                                                                                  BasicTypeVisitFunc) const = 0;
5548                 virtual string  glslTraverseBasicType                   (int indentationDepth,
5549                                                                                                                  BasicTypeVisitFunc) const = 0;
5550                 virtual int             numBasicSubobjectsInElementType (void) const = 0;
5551                 virtual string  basicSubobjectAtIndex                   (int index, int arraySize) const = 0;
5552         };
5553
5554         class Variable : public TopLevelObject
5555         {
5556         public:
5557                 Variable (const string& name_, const glu::VarType& type, bool isArray)
5558                         : m_name                (name_)
5559                         , m_type                (type)
5560                         , m_isArray             (isArray)
5561                 {
5562                         DE_ASSERT(!type.isArrayType());
5563                 }
5564
5565                 string  name                                                            (void) const { return m_name; }
5566                 string  declare                                                         (void) const;
5567                 string  declareArray                                            (const string& arraySizeExpr) const;
5568                 string  glslTraverseBasicTypeArray                      (int numArrayElements, int indentationDepth, BasicTypeVisitFunc) const;
5569                 string  glslTraverseBasicType                           (int indentationDepth, BasicTypeVisitFunc) const;
5570                 int             numBasicSubobjectsInElementType         (void) const;
5571                 string  basicSubobjectAtIndex                           (int index, int arraySize) const;
5572
5573         private:
5574                 string                  m_name;
5575                 glu::VarType    m_type; //!< If this Variable is an array element, m_type is the element type; otherwise just the variable type.
5576                 const bool              m_isArray;
5577         };
5578
5579         class IOBlock : public TopLevelObject
5580         {
5581         public:
5582                 struct Member
5583                 {
5584                         string                  name;
5585                         glu::VarType    type;
5586                         Member (const string& n, const glu::VarType& t) : name(n), type(t) {}
5587                 };
5588
5589                 IOBlock (const string& blockName, const string& interfaceName, const vector<Member>& members)
5590                         : m_blockName           (blockName)
5591                         , m_interfaceName       (interfaceName)
5592                         , m_members                     (members)
5593                 {
5594                 }
5595
5596                 string  name                                                            (void) const { return m_interfaceName; }
5597                 string  declare                                                         (void) const;
5598                 string  declareArray                                            (const string& arraySizeExpr) const;
5599                 string  glslTraverseBasicTypeArray                      (int numArrayElements, int indentationDepth, BasicTypeVisitFunc) const;
5600                 string  glslTraverseBasicType                           (int indentationDepth, BasicTypeVisitFunc) const;
5601                 int             numBasicSubobjectsInElementType         (void) const;
5602                 string  basicSubobjectAtIndex                           (int index, int arraySize) const;
5603
5604         private:
5605                 string                  m_blockName;
5606                 string                  m_interfaceName;
5607                 vector<Member>  m_members;
5608         };
5609
5610         static string                                                   glslTraverseBasicTypes                          (const string&                  rootName,
5611                                                                                                                                                                  const glu::VarType&    rootType,
5612                                                                                                                                                                  int                                    arrayNestingDepth,
5613                                                                                                                                                                  int                                    indentationDepth,
5614                                                                                                                                                                  BasicTypeVisitFunc             visit);
5615
5616         static string                                                   glslAssignBasicTypeObject                       (const string& name, glu::DataType, int indentationDepth);
5617         static string                                                   glslCheckBasicTypeObject                        (const string& name, glu::DataType, int indentationDepth);
5618         static int                                                              numBasicSubobjectsInElementType         (const vector<SharedPtr<TopLevelObject> >&);
5619         static string                                                   basicSubobjectAtIndex                           (int index, const vector<SharedPtr<TopLevelObject> >&, int topLevelArraySizes);
5620
5621         enum
5622         {
5623                 RENDER_SIZE = 256
5624         };
5625         enum
5626         {
5627                 NUM_OUTPUT_VERTICES = 5
5628         };
5629         enum
5630         {
5631                 NUM_PER_PATCH_ARRAY_ELEMS = 3
5632         };
5633         enum
5634         {
5635                 NUM_PER_PATCH_BLOCKS = 2
5636         };
5637
5638         const TessPrimitiveType                                 m_primitiveType;
5639         const IOType                                                    m_ioType;
5640         const VertexIOArraySize                                 m_vertexIOArraySize;
5641         const TessControlOutArraySize                   m_tessControlOutArraySize;
5642         const string                                                    m_referenceImagePath;
5643
5644         vector<glu::StructType>                                 m_structTypes;
5645         vector<SharedPtr<TopLevelObject> >              m_tcsOutputs;
5646         vector<SharedPtr<TopLevelObject> >              m_tesInputs;
5647
5648         SharedPtr<const glu::ShaderProgram>             m_program;
5649 };
5650
5651 /*--------------------------------------------------------------------*//*!
5652  * \brief Generate GLSL code to traverse (possibly aggregate) object
5653  *
5654  * Generates a string that represents GLSL code that traverses the
5655  * basic-type subobjects in a rootType-typed object named rootName. Arrays
5656  * are traversed with loops and struct members are each traversed
5657  * separately. The code for each basic-type subobject is generated with
5658  * the function given as the 'visit' argument.
5659  *//*--------------------------------------------------------------------*/
5660 string UserDefinedIOCase::glslTraverseBasicTypes (const string&                 rootName,
5661                                                                                                   const glu::VarType&   rootType,
5662                                                                                                   int                                   arrayNestingDepth,
5663                                                                                                   int                                   indentationDepth,
5664                                                                                                   BasicTypeVisitFunc    visit)
5665 {
5666         if (rootType.isBasicType())
5667                 return visit(rootName, rootType.getBasicType(), indentationDepth);
5668         else if (rootType.isArrayType())
5669         {
5670                 const string indentation        = string(indentationDepth, '\t');
5671                 const string loopIndexName      = "i" + de::toString(arrayNestingDepth);
5672                 const string arrayLength        = de::toString(rootType.getArraySize());
5673                 return indentation + "for (int " + loopIndexName + " = 0; " + loopIndexName + " < " + de::toString(rootType.getArraySize()) + "; " + loopIndexName + "++)\n" +
5674                            indentation + "{\n" +
5675                            glslTraverseBasicTypes(rootName + "[" + loopIndexName + "]", rootType.getElementType(), arrayNestingDepth+1, indentationDepth+1, visit) +
5676                            indentation + "}\n";
5677         }
5678         else if (rootType.isStructType())
5679         {
5680                 const glu::StructType&  structType = *rootType.getStructPtr();
5681                 const int                               numMembers = structType.getNumMembers();
5682                 string                                  result;
5683
5684                 for (int membNdx = 0; membNdx < numMembers; membNdx++)
5685                 {
5686                         const glu::StructMember& member = structType.getMember(membNdx);
5687                         result += glslTraverseBasicTypes(rootName + "." + member.getName(), member.getType(), arrayNestingDepth, indentationDepth, visit);
5688                 }
5689
5690                 return result;
5691         }
5692         else
5693         {
5694                 DE_ASSERT(false);
5695                 return DE_NULL;
5696         }
5697 }
5698
5699 string UserDefinedIOCase::Variable::declare (void) const
5700 {
5701         DE_ASSERT(!m_isArray);
5702         return de::toString(glu::declare(m_type, m_name)) + ";\n";
5703 }
5704
5705 string UserDefinedIOCase::Variable::declareArray (const string& sizeExpr) const
5706 {
5707         DE_ASSERT(m_isArray);
5708         return de::toString(glu::declare(m_type, m_name)) + "[" + sizeExpr + "];\n";
5709 }
5710
5711 string UserDefinedIOCase::IOBlock::declare (void) const
5712 {
5713         std::ostringstream buf;
5714
5715         buf << m_blockName << "\n"
5716                 << "{\n";
5717
5718         for (int i = 0; i < (int)m_members.size(); i++)
5719                 buf << "\t" << glu::declare(m_members[i].type, m_members[i].name) << ";\n";
5720
5721         buf << "} " << m_interfaceName << ";\n";
5722         return buf.str();
5723 }
5724
5725 string UserDefinedIOCase::IOBlock::declareArray (const string& sizeExpr) const
5726 {
5727         std::ostringstream buf;
5728
5729         buf << m_blockName << "\n"
5730                 << "{\n";
5731
5732         for (int i = 0; i < (int)m_members.size(); i++)
5733                 buf << "\t" << glu::declare(m_members[i].type, m_members[i].name) << ";\n";
5734
5735         buf << "} " << m_interfaceName << "[" << sizeExpr << "];\n";
5736         return buf.str();
5737 }
5738
5739 string UserDefinedIOCase::Variable::glslTraverseBasicTypeArray (int numArrayElements, int indentationDepth, BasicTypeVisitFunc visit) const
5740 {
5741         DE_ASSERT(m_isArray);
5742
5743         const bool                              traverseAsArray         = numArrayElements >= 0;
5744         const string                    traversedName           = m_name + (!traverseAsArray ? "[gl_InvocationID]" : "");
5745         const glu::VarType              type                            = traverseAsArray ? glu::VarType(m_type, numArrayElements) : m_type;
5746
5747         return UserDefinedIOCase::glslTraverseBasicTypes(traversedName, type, 0, indentationDepth, visit);
5748 }
5749
5750 string UserDefinedIOCase::Variable::glslTraverseBasicType (int indentationDepth, BasicTypeVisitFunc visit) const
5751 {
5752         DE_ASSERT(!m_isArray);
5753
5754         return UserDefinedIOCase::glslTraverseBasicTypes(m_name, m_type, 0, indentationDepth, visit);
5755 }
5756
5757 string UserDefinedIOCase::IOBlock::glslTraverseBasicTypeArray (int numArrayElements, int indentationDepth, BasicTypeVisitFunc visit) const
5758 {
5759         if (numArrayElements >= 0)
5760         {
5761                 const string    indentation                     = string(indentationDepth, '\t');
5762                 string                  result                          = indentation + "for (int i0 = 0; i0 < " + de::toString(numArrayElements) + "; i0++)\n" +
5763                                                                                           indentation + "{\n";
5764                 for (int i = 0; i < (int)m_members.size(); i++)
5765                         result += UserDefinedIOCase::glslTraverseBasicTypes(m_interfaceName + "[i0]." + m_members[i].name, m_members[i].type, 1, indentationDepth+1, visit);
5766                 result += indentation + "}\n";
5767                 return result;
5768         }
5769         else
5770         {
5771                 string result;
5772                 for (int i = 0; i < (int)m_members.size(); i++)
5773                         result += UserDefinedIOCase::glslTraverseBasicTypes(m_interfaceName + "[gl_InvocationID]." + m_members[i].name, m_members[i].type, 0, indentationDepth, visit);
5774                 return result;
5775         }
5776 }
5777
5778
5779 string UserDefinedIOCase::IOBlock::glslTraverseBasicType (int indentationDepth, BasicTypeVisitFunc visit) const
5780 {
5781         string result;
5782         for (int i = 0; i < (int)m_members.size(); i++)
5783                 result += UserDefinedIOCase::glslTraverseBasicTypes(m_interfaceName + "." + m_members[i].name, m_members[i].type, 0, indentationDepth, visit);
5784         return result;
5785 }
5786
5787 int UserDefinedIOCase::Variable::numBasicSubobjectsInElementType (void) const
5788 {
5789         return numBasicSubobjects(m_type);
5790 }
5791
5792 int UserDefinedIOCase::IOBlock::numBasicSubobjectsInElementType (void) const
5793 {
5794         int result = 0;
5795         for (int i = 0; i < (int)m_members.size(); i++)
5796                 result += numBasicSubobjects(m_members[i].type);
5797         return result;
5798 }
5799
5800 string UserDefinedIOCase::Variable::basicSubobjectAtIndex (int subobjectIndex, int arraySize) const
5801 {
5802         const glu::VarType      type                    = m_isArray ? glu::VarType(m_type, arraySize) : m_type;
5803         int                                     currentIndex    = 0;
5804
5805         for (glu::BasicTypeIterator basicIt = glu::BasicTypeIterator::begin(&type);
5806                  basicIt != glu::BasicTypeIterator::end(&type);
5807                  ++basicIt)
5808         {
5809                 if (currentIndex == subobjectIndex)
5810                         return m_name + de::toString(glu::TypeAccessFormat(type, basicIt.getPath()));
5811                 currentIndex++;
5812         }
5813         DE_ASSERT(false);
5814         return DE_NULL;
5815 }
5816
5817 string UserDefinedIOCase::IOBlock::basicSubobjectAtIndex (int subobjectIndex, int arraySize) const
5818 {
5819         int currentIndex = 0;
5820         for (int arrayNdx = 0; arrayNdx < arraySize; arrayNdx++)
5821         {
5822                 for (int memberNdx = 0; memberNdx < (int)m_members.size(); memberNdx++)
5823                 {
5824                         const glu::VarType& membType = m_members[memberNdx].type;
5825                         for (glu::BasicTypeIterator basicIt = glu::BasicTypeIterator::begin(&membType);
5826                                  basicIt != glu::BasicTypeIterator::end(&membType);
5827                                  ++basicIt)
5828                         {
5829                                 if (currentIndex == subobjectIndex)
5830                                         return m_interfaceName + "[" + de::toString(arrayNdx) + "]." + m_members[memberNdx].name + de::toString(glu::TypeAccessFormat(membType, basicIt.getPath()));
5831                                 currentIndex++;
5832                         }
5833                 }
5834         }
5835         DE_ASSERT(false);
5836         return DE_NULL;
5837 }
5838
5839 // Used as the 'visit' argument for glslTraverseBasicTypes.
5840 string UserDefinedIOCase::glslAssignBasicTypeObject (const string& name, glu::DataType type, int indentationDepth)
5841 {
5842         const int               scalarSize              = glu::getDataTypeScalarSize(type);
5843         const string    indentation             = string(indentationDepth, '\t');
5844         string                  result;
5845
5846         result += indentation + name + " = ";
5847
5848         if (type != glu::TYPE_FLOAT)
5849                 result += string() + glu::getDataTypeName(type) + "(";
5850         for (int i = 0; i < scalarSize; i++)
5851                 result += (i > 0 ? ", v+" + de::floatToString(0.8f*(float)i, 1)
5852                                                  : "v");
5853         if (type != glu::TYPE_FLOAT)
5854                 result += ")";
5855         result += ";\n" +
5856                           indentation + "v += 0.4;\n";
5857         return result;
5858 }
5859
5860 // Used as the 'visit' argument for glslTraverseBasicTypes.
5861 string UserDefinedIOCase::glslCheckBasicTypeObject (const string& name, glu::DataType type, int indentationDepth)
5862 {
5863         const int               scalarSize              = glu::getDataTypeScalarSize(type);
5864         const string    indentation             = string(indentationDepth, '\t');
5865         string                  result;
5866
5867         result += indentation + "allOk = allOk && compare_" + glu::getDataTypeName(type) + "(" + name + ", ";
5868
5869         if (type != glu::TYPE_FLOAT)
5870                 result += string() + glu::getDataTypeName(type) + "(";
5871         for (int i = 0; i < scalarSize; i++)
5872                 result += (i > 0 ? ", v+" + de::floatToString(0.8f*(float)i, 1)
5873                                                  : "v");
5874         if (type != glu::TYPE_FLOAT)
5875                 result += ")";
5876         result += ");\n" +
5877                           indentation + "v += 0.4;\n" +
5878                           indentation + "if (allOk) firstFailedInputIndex++;\n";
5879
5880         return result;
5881 }
5882
5883 int UserDefinedIOCase::numBasicSubobjectsInElementType (const vector<SharedPtr<TopLevelObject> >& objects)
5884 {
5885         int result = 0;
5886         for (int i = 0; i < (int)objects.size(); i++)
5887                 result += objects[i]->numBasicSubobjectsInElementType();
5888         return result;
5889 }
5890
5891 string UserDefinedIOCase::basicSubobjectAtIndex (int subobjectIndex, const vector<SharedPtr<TopLevelObject> >& objects, int topLevelArraySize)
5892 {
5893         int currentIndex        = 0;
5894         int objectIndex         = 0;
5895         for (; currentIndex < subobjectIndex; objectIndex++)
5896                 currentIndex += objects[objectIndex]->numBasicSubobjectsInElementType() * topLevelArraySize;
5897         if (currentIndex > subobjectIndex)
5898         {
5899                 objectIndex--;
5900                 currentIndex -= objects[objectIndex]->numBasicSubobjectsInElementType() * topLevelArraySize;
5901         }
5902
5903         return objects[objectIndex]->basicSubobjectAtIndex(subobjectIndex - currentIndex, topLevelArraySize);
5904 }
5905
5906 void UserDefinedIOCase::init (void)
5907 {
5908         checkTessellationSupport(m_context);
5909         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
5910
5911         const bool                      isPerPatchIO                            = m_ioType == IO_TYPE_PER_PATCH                         ||
5912                                                                                                           m_ioType == IO_TYPE_PER_PATCH_ARRAY           ||
5913                                                                                                           m_ioType == IO_TYPE_PER_PATCH_BLOCK           ||
5914                                                                                                           m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY;
5915
5916         const bool                      isExplicitVertexArraySize       = m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN ||
5917                                                                                                           m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY;
5918
5919         const string            vertexAttrArrayInputSize        = m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_IMPLICIT                                  ? ""
5920                                                                                                         : m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN   ? "gl_MaxPatchVertices"
5921                                                                                                         : m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY                    ? de::toString(m_context.getContextInfo().getInt(GL_MAX_PATCH_VERTICES))
5922                                                                                                         : DE_NULL;
5923
5924         const char* const       maybePatch                                      = isPerPatchIO ? "patch " : "";
5925         const string            outMaybePatch                           = string() + maybePatch + "out ";
5926         const string            inMaybePatch                            = string() + maybePatch + "in ";
5927         const bool                      useBlock                                        = m_ioType == IO_TYPE_PER_VERTEX_BLOCK          ||
5928                                                                                                           m_ioType == IO_TYPE_PER_PATCH_BLOCK           ||
5929                                                                                                           m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY;
5930
5931         string                          tcsDeclarations;
5932         string                          tcsStatements;
5933
5934         string                          tesDeclarations;
5935         string                          tesStatements;
5936
5937         {
5938                 m_structTypes.push_back(glu::StructType("S"));
5939
5940                 const glu::VarType      highpFloat              (glu::TYPE_FLOAT, glu::PRECISION_HIGHP);
5941                 glu::StructType&        structType              = m_structTypes.back();
5942                 const glu::VarType      structVarType   (&structType);
5943                 bool                            usedStruct              = false;
5944
5945                 structType.addMember("x", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP));
5946                 structType.addMember("y", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
5947
5948                 if (useBlock)
5949                 {
5950                         // It is illegal to have a structure containing an array as an output variable
5951                         structType.addMember("z", glu::VarType(highpFloat, 2));
5952                 }
5953
5954                 if (useBlock)
5955                 {
5956                         const bool                              useLightweightBlock = (m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY); // use leaner block to make sure it is not larger than allowed (per-patch storage is very limited)
5957                         vector<IOBlock::Member> blockMembers;
5958
5959                         if (!useLightweightBlock)
5960                                 blockMembers.push_back(IOBlock::Member("blockS",        structVarType));
5961
5962                         blockMembers.push_back(IOBlock::Member("blockFa",       glu::VarType(highpFloat, 3)));
5963                         blockMembers.push_back(IOBlock::Member("blockSa",       glu::VarType(structVarType, 2)));
5964                         blockMembers.push_back(IOBlock::Member("blockF",        highpFloat));
5965
5966                         m_tcsOutputs.push_back  (SharedPtr<TopLevelObject>(new IOBlock("TheBlock", "tcBlock", blockMembers)));
5967                         m_tesInputs.push_back   (SharedPtr<TopLevelObject>(new IOBlock("TheBlock", "teBlock", blockMembers)));
5968
5969                         usedStruct = true;
5970                 }
5971                 else
5972                 {
5973                         const Variable var0("in_te_s", structVarType,   m_ioType != IO_TYPE_PER_PATCH);
5974                         const Variable var1("in_te_f", highpFloat,              m_ioType != IO_TYPE_PER_PATCH);
5975
5976                         if (m_ioType != IO_TYPE_PER_PATCH_ARRAY)
5977                         {
5978                                 // Arrays of structures are disallowed, add struct cases only if not arrayed variable
5979                                 m_tcsOutputs.push_back  (SharedPtr<TopLevelObject>(new Variable(var0)));
5980                                 m_tesInputs.push_back   (SharedPtr<TopLevelObject>(new Variable(var0)));
5981
5982                                 usedStruct = true;
5983                         }
5984
5985                         m_tcsOutputs.push_back  (SharedPtr<TopLevelObject>(new Variable(var1)));
5986                         m_tesInputs.push_back   (SharedPtr<TopLevelObject>(new Variable(var1)));
5987                 }
5988
5989                 tcsDeclarations += "in " + Variable("in_tc_attr", highpFloat, true).declareArray(vertexAttrArrayInputSize);
5990
5991                 if (usedStruct)
5992                         tcsDeclarations += de::toString(glu::declare(structType)) + ";\n";
5993
5994                 tcsStatements += "\t{\n"
5995                                                  "\t\thighp float v = 1.3;\n";
5996
5997                 for (int tcsOutputNdx = 0; tcsOutputNdx < (int)m_tcsOutputs.size(); tcsOutputNdx++)
5998                 {
5999                         const TopLevelObject&   output          = *m_tcsOutputs[tcsOutputNdx];
6000                         const int                               numElements     = !isPerPatchIO                                                         ? -1    //!< \note -1 means indexing with gl_InstanceID
6001                                                                                                 : m_ioType == IO_TYPE_PER_PATCH                         ? 1
6002                                                                                                 : m_ioType == IO_TYPE_PER_PATCH_ARRAY           ? NUM_PER_PATCH_ARRAY_ELEMS
6003                                                                                                 : m_ioType == IO_TYPE_PER_PATCH_BLOCK           ? 1
6004                                                                                                 : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY     ? NUM_PER_PATCH_BLOCKS
6005                                                                                                 : -2;
6006                         const bool                              isArray         = (numElements != 1);
6007
6008                         DE_ASSERT(numElements != -2);
6009
6010                         if (isArray)
6011                         {
6012                                 tcsDeclarations += outMaybePatch + output.declareArray(m_ioType == IO_TYPE_PER_PATCH_ARRAY                                                                                      ? de::toString(int(NUM_PER_PATCH_ARRAY_ELEMS))
6013                                                                                                                                            : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY                                                                  ? de::toString(int(NUM_PER_PATCH_BLOCKS))
6014                                                                                                                                            : m_tessControlOutArraySize == TESS_CONTROL_OUT_ARRAY_SIZE_LAYOUT                    ? de::toString(int(NUM_OUTPUT_VERTICES))
6015                                                                                                                                            : m_tessControlOutArraySize == TESS_CONTROL_OUT_ARRAY_SIZE_QUERY                             ? de::toString(m_context.getContextInfo().getInt(GL_MAX_PATCH_VERTICES))
6016                                                                                                                                            : m_tessControlOutArraySize == TESS_CONTROL_OUT_ARRAY_SIZE_SHADER_BUILTIN    ? "gl_MaxPatchVertices"
6017                                                                                                                                            : "");
6018                         }
6019                         else
6020                                 tcsDeclarations += outMaybePatch + output.declare();
6021
6022                         if (!isPerPatchIO)
6023                                 tcsStatements += "\t\tv += float(gl_InvocationID)*" + de::floatToString(0.4f * (float)output.numBasicSubobjectsInElementType(), 1) + ";\n";
6024
6025                         tcsStatements += "\n\t\t// Assign values to output " + output.name() + "\n";
6026                         if (isArray)
6027                                 tcsStatements += output.glslTraverseBasicTypeArray(numElements, 2, glslAssignBasicTypeObject);
6028                         else
6029                                 tcsStatements += output.glslTraverseBasicType(2, glslAssignBasicTypeObject);
6030
6031                         if (!isPerPatchIO)
6032                                 tcsStatements += "\t\tv += float(" + de::toString(int(NUM_OUTPUT_VERTICES)) + "-gl_InvocationID-1)*" + de::floatToString(0.4f * (float)output.numBasicSubobjectsInElementType(), 1) + ";\n";
6033                 }
6034                 tcsStatements += "\t}\n";
6035
6036                 if (usedStruct)
6037                         tesDeclarations += de::toString(glu::declare(structType)) + ";\n";
6038
6039                 tesStatements += "\tbool allOk = true;\n"
6040                                                  "\thighp uint firstFailedInputIndex = 0u;\n"
6041                                                  "\t{\n"
6042                                                  "\t\thighp float v = 1.3;\n";
6043                 for (int tesInputNdx = 0; tesInputNdx < (int)m_tesInputs.size(); tesInputNdx++)
6044                 {
6045                         const TopLevelObject&   input           = *m_tesInputs[tesInputNdx];
6046                         const int                               numElements     = !isPerPatchIO                                                         ? (int)NUM_OUTPUT_VERTICES
6047                                                                                                 : m_ioType == IO_TYPE_PER_PATCH                         ? 1
6048                                                                                                 : m_ioType == IO_TYPE_PER_PATCH_BLOCK           ? 1
6049                                                                                                 : m_ioType == IO_TYPE_PER_PATCH_ARRAY           ? NUM_PER_PATCH_ARRAY_ELEMS
6050                                                                                                 : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY     ? NUM_PER_PATCH_BLOCKS
6051                                                                                                 : -2;
6052                         const bool                              isArray         = (numElements != 1);
6053
6054                         DE_ASSERT(numElements != -2);
6055
6056                         if (isArray)
6057                                 tesDeclarations += inMaybePatch + input.declareArray(m_ioType == IO_TYPE_PER_PATCH_ARRAY                        ? de::toString(int(NUM_PER_PATCH_ARRAY_ELEMS))
6058                                                                                                                                          : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY    ? de::toString(int(NUM_PER_PATCH_BLOCKS))
6059                                                                                                                                          : isExplicitVertexArraySize                                    ? de::toString(vertexAttrArrayInputSize)
6060                                                                                                                                          : "");
6061                         else
6062                                 tesDeclarations += inMaybePatch + input.declare();
6063
6064                         tesStatements += "\n\t\t// Check values in input " + input.name() + "\n";
6065                         if (isArray)
6066                                 tesStatements += input.glslTraverseBasicTypeArray(numElements, 2, glslCheckBasicTypeObject);
6067                         else
6068                                 tesStatements += input.glslTraverseBasicType(2, glslCheckBasicTypeObject);
6069                 }
6070                 tesStatements += "\t}\n";
6071         }
6072
6073         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
6074                 << glu::VertexSource                                    ("#version 310 es\n"
6075                                                                                                  "\n"
6076                                                                                                  "in highp float in_v_attr;\n"
6077                                                                                                  "out highp float in_tc_attr;\n"
6078                                                                                                  "\n"
6079                                                                                                  "void main (void)\n"
6080                                                                                                  "{\n"
6081                                                                                                  "      in_tc_attr = in_v_attr;\n"
6082                                                                                                  "}\n")
6083
6084                 << glu::TessellationControlSource               ("#version 310 es\n"
6085                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
6086                                                                                                  "\n"
6087                                                                                                  "layout (vertices = " + de::toString(int(NUM_OUTPUT_VERTICES)) + ") out;\n"
6088                                                                                                  "\n"
6089                                                                                                  + tcsDeclarations +
6090                                                                                                  "\n"
6091                                                                                                  "patch out highp vec2 in_te_positionScale;\n"
6092                                                                                                  "patch out highp vec2 in_te_positionOffset;\n"
6093                                                                                                  "\n"
6094                                                                                                  "void main (void)\n"
6095                                                                                                  "{\n"
6096                                                                                                  + tcsStatements +
6097                                                                                                  "\n"
6098                                                                                                  "      in_te_positionScale  = vec2(in_tc_attr[6], in_tc_attr[7]);\n"
6099                                                                                                  "      in_te_positionOffset = vec2(in_tc_attr[8], in_tc_attr[9]);\n"
6100                                                                                                  "\n"
6101                                                                                                  "      gl_TessLevelInner[0] = in_tc_attr[0];\n"
6102                                                                                                  "      gl_TessLevelInner[1] = in_tc_attr[1];\n"
6103                                                                                                  "\n"
6104                                                                                                  "      gl_TessLevelOuter[0] = in_tc_attr[2];\n"
6105                                                                                                  "      gl_TessLevelOuter[1] = in_tc_attr[3];\n"
6106                                                                                                  "      gl_TessLevelOuter[2] = in_tc_attr[4];\n"
6107                                                                                                  "      gl_TessLevelOuter[3] = in_tc_attr[5];\n"
6108                                                                                                  "}\n")
6109
6110                 << glu::TessellationEvaluationSource    ("#version 310 es\n"
6111                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
6112                                                                                                  "\n"
6113                                                                                                  + getTessellationEvaluationInLayoutString(m_primitiveType) +
6114                                                                                                  "\n"
6115                                                                                                  + tesDeclarations +
6116                                                                                                  "\n"
6117                                                                                                  "patch in highp vec2 in_te_positionScale;\n"
6118                                                                                                  "patch in highp vec2 in_te_positionOffset;\n"
6119                                                                                                  "\n"
6120                                                                                                  "out highp vec4 in_f_color;\n"
6121                                                                                                  "// Will contain the index of the first incorrect input,\n"
6122                                                                                                  "// or the number of inputs if all are correct\n"
6123                                                                                                  "flat out highp uint out_te_firstFailedInputIndex;\n"
6124                                                                                                  "\n"
6125                                                                                                  "bool compare_int   (int   a, int   b) { return a == b; }\n"
6126                                                                                                  "bool compare_float (float a, float b) { return abs(a - b) < 0.01f; }\n"
6127                                                                                                  "bool compare_vec4  (vec4  a, vec4  b) { return all(lessThan(abs(a - b), vec4(0.01f))); }\n"
6128                                                                                                  "\n"
6129                                                                                                  "void main (void)\n"
6130                                                                                                  "{\n"
6131                                                                                                  + tesStatements +
6132                                                                                                  "\n"
6133                                                                                                  "      gl_Position = vec4(gl_TessCoord.xy*in_te_positionScale + in_te_positionOffset, 0.0, 1.0);\n"
6134                                                                                                  "      in_f_color = allOk ? vec4(0.0, 1.0, 0.0, 1.0)\n"
6135                                                                                                  "                         : vec4(1.0, 0.0, 0.0, 1.0);\n"
6136                                                                                                  "      out_te_firstFailedInputIndex = firstFailedInputIndex;\n"
6137                                                                                                  "}\n")
6138
6139                 << glu::FragmentSource                                  ("#version 310 es\n"
6140                                                                                                  "\n"
6141                                                                                                  "layout (location = 0) out mediump vec4 o_color;\n"
6142                                                                                                  "\n"
6143                                                                                                  "in highp vec4 in_f_color;\n"
6144                                                                                                  "\n"
6145                                                                                                  "void main (void)\n"
6146                                                                                                  "{\n"
6147                                                                                                  "      o_color = in_f_color;\n"
6148                                                                                                  "}\n")
6149
6150                 << glu::TransformFeedbackVarying                ("out_te_firstFailedInputIndex")
6151                 << glu::TransformFeedbackMode                   (GL_INTERLEAVED_ATTRIBS)));
6152
6153         m_testCtx.getLog() << *m_program;
6154         if (!m_program->isOk())
6155                 TCU_FAIL("Program compilation failed");
6156 }
6157
6158 void UserDefinedIOCase::deinit (void)
6159 {
6160         m_program.clear();
6161 }
6162
6163 UserDefinedIOCase::IterateResult UserDefinedIOCase::iterate (void)
6164 {
6165         typedef TransformFeedbackHandler<deUint32> TFHandler;
6166
6167         TestLog&                                log                                             = m_testCtx.getLog();
6168         const RenderContext&    renderCtx                               = m_context.getRenderContext();
6169         const RandomViewport    viewport                                (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
6170         const glw::Functions&   gl                                              = renderCtx.getFunctions();
6171         static const float              attributes[6+2+2]               = { /* inner */ 3.0f, 4.0f, /* outer */ 5.0f, 6.0f, 7.0f, 8.0f, /* pos. scale */ 1.2f, 1.3f, /* pos. offset */ -0.3f, -0.4f };
6172         const deUint32                  programGL                               = m_program->getProgram();
6173         const int                               numVertices                             = referenceVertexCount(m_primitiveType, SPACINGMODE_EQUAL, false, &attributes[0], &attributes[2]);
6174         const TFHandler                 tfHandler                               (renderCtx, numVertices);
6175         tcu::ResultCollector    result;
6176
6177         gl.useProgram(programGL);
6178         setViewport(gl, viewport);
6179         gl.patchParameteri(GL_PATCH_VERTICES, DE_LENGTH_OF_ARRAY(attributes));
6180
6181         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
6182         gl.clear(GL_COLOR_BUFFER_BIT);
6183
6184         {
6185                 const glu::VertexArrayBinding   bindings[]      = { glu::va::Float("in_v_attr", 1, DE_LENGTH_OF_ARRAY(attributes), 0, &attributes[0]) };
6186                 const TFHandler::Result                 tfResult        = tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, false),
6187                                                                                                                                                                            DE_LENGTH_OF_ARRAY(bindings), &bindings[0], DE_LENGTH_OF_ARRAY(attributes));
6188
6189                 {
6190                         const tcu::Surface                      pixels          = getPixels(renderCtx, viewport);
6191                         const tcu::TextureLevel         reference       = getPNG(m_testCtx.getArchive(), m_referenceImagePath.c_str());
6192                         const bool                                      success         = tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), pixels.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
6193
6194                         if (!success)
6195                                 result.fail("Image comparison failed");
6196                 }
6197
6198                 if ((int)tfResult.varying.size() != numVertices)
6199                 {
6200                         log << TestLog::Message << "Failure: transform feedback returned " << tfResult.varying.size() << " vertices; expected " << numVertices << TestLog::EndMessage;
6201                         result.fail("Wrong number of vertices");
6202                 }
6203                 else
6204                 {
6205                         const int topLevelArraySize             = (m_ioType == IO_TYPE_PER_PATCH                                ? 1
6206                                                                                          : m_ioType == IO_TYPE_PER_PATCH_ARRAY                  ? NUM_PER_PATCH_ARRAY_ELEMS
6207                                                                                          : m_ioType == IO_TYPE_PER_PATCH_BLOCK                  ? 1
6208                                                                                          : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY    ? NUM_PER_PATCH_BLOCKS
6209                                                                                          : (int)NUM_OUTPUT_VERTICES);
6210                         const int numTEInputs                   = numBasicSubobjectsInElementType(m_tesInputs) * topLevelArraySize;
6211
6212                         for (int vertexNdx = 0; vertexNdx < (int)numVertices; vertexNdx++)
6213                         {
6214                                 if (tfResult.varying[vertexNdx] > (deUint32)numTEInputs)
6215                                 {
6216                                         log << TestLog::Message << "Failure: out_te_firstFailedInputIndex has value " << tfResult.varying[vertexNdx]
6217                                                                                         << ", should be in range [0, " << numTEInputs << "]" << TestLog::EndMessage;
6218                                         result.fail("Invalid transform feedback output");
6219                                 }
6220                                 else if (tfResult.varying[vertexNdx] != (deUint32)numTEInputs)
6221                                 {
6222                                         log << TestLog::Message << "Failure: in tessellation evaluation shader, check for input "
6223                                                                                         << basicSubobjectAtIndex(tfResult.varying[vertexNdx], m_tesInputs, topLevelArraySize) << " failed" << TestLog::EndMessage;
6224                                         result.fail("Invalid input value in tessellation evaluation shader");
6225                                 }
6226                         }
6227                 }
6228         }
6229
6230         result.setTestContextResult(m_testCtx);
6231         return STOP;
6232 }
6233
6234 /*--------------------------------------------------------------------*//*!
6235  * \brief Pass gl_Position between VS and TCS, or between TCS and TES.
6236  *
6237  * In TCS gl_Position is in the gl_out[] block and in TES in the gl_in[]
6238  * block, and has no special semantics in those. Arbitrary vec4 data can
6239  * thus be passed there.
6240  *//*--------------------------------------------------------------------*/
6241 class GLPositionCase : public TestCase
6242 {
6243 public:
6244         enum CaseType
6245         {
6246                 CASETYPE_VS_TO_TCS = 0,
6247                 CASETYPE_TCS_TO_TES,
6248                 CASETYPE_VS_TO_TCS_TO_TES,
6249
6250                 CASETYPE_LAST
6251         };
6252
6253         GLPositionCase (Context& context, const char* name, const char* description, CaseType caseType, const char* referenceImagePath)
6254                 : TestCase                              (context, name, description)
6255                 , m_caseType                    (caseType)
6256                 , m_referenceImagePath  (referenceImagePath)
6257         {
6258         }
6259
6260         void                                                                    init                            (void);
6261         void                                                                    deinit                          (void);
6262         IterateResult                                                   iterate                         (void);
6263
6264         static const char*                                              getCaseTypeName         (CaseType type);
6265
6266 private:
6267         static const int                                                RENDER_SIZE = 256;
6268
6269         const CaseType                                                  m_caseType;
6270         const string                                                    m_referenceImagePath;
6271
6272         SharedPtr<const glu::ShaderProgram>             m_program;
6273 };
6274
6275 const char* GLPositionCase::getCaseTypeName (CaseType type)
6276 {
6277         switch (type)
6278         {
6279                 case CASETYPE_VS_TO_TCS:                        return "gl_position_vs_to_tcs";
6280                 case CASETYPE_TCS_TO_TES:                       return "gl_position_tcs_to_tes";
6281                 case CASETYPE_VS_TO_TCS_TO_TES:         return "gl_position_vs_to_tcs_to_tes";
6282                 default:
6283                         DE_ASSERT(false); return DE_NULL;
6284         }
6285 }
6286
6287 void GLPositionCase::init (void)
6288 {
6289         checkTessellationSupport(m_context);
6290         checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
6291
6292         const bool              vsToTCS         = m_caseType == CASETYPE_VS_TO_TCS              || m_caseType == CASETYPE_VS_TO_TCS_TO_TES;
6293         const bool              tcsToTES        = m_caseType == CASETYPE_TCS_TO_TES             || m_caseType == CASETYPE_VS_TO_TCS_TO_TES;
6294
6295         const string    tesIn0          = tcsToTES ? "gl_in[0].gl_Position" : "in_te_attr[0]";
6296         const string    tesIn1          = tcsToTES ? "gl_in[1].gl_Position" : "in_te_attr[1]";
6297         const string    tesIn2          = tcsToTES ? "gl_in[2].gl_Position" : "in_te_attr[2]";
6298
6299         m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
6300                 << glu::VertexSource                                    ("#version 310 es\n"
6301                                                                                                  "\n"
6302                                                                                                  "in highp vec4 in_v_attr;\n"
6303                                                                                                  + string(!vsToTCS ? "out highp vec4 in_tc_attr;\n" : "") +
6304                                                                                                  "\n"
6305                                                                                                  "void main (void)\n"
6306                                                                                                  "{\n"
6307                                                                                                  "      " + (vsToTCS ? "gl_Position" : "in_tc_attr") + " = in_v_attr;\n"
6308                                                                                                  "}\n")
6309
6310                 << glu::TessellationControlSource               ("#version 310 es\n"
6311                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
6312                                                                                                  "\n"
6313                                                                                                  "layout (vertices = 3) out;\n"
6314                                                                                                  "\n"
6315                                                                                                  + string(!vsToTCS ? "in highp vec4 in_tc_attr[];\n" : "") +
6316                                                                                                  "\n"
6317                                                                                                  + (!tcsToTES ? "out highp vec4 in_te_attr[];\n" : "") +
6318                                                                                                  "\n"
6319                                                                                                  "void main (void)\n"
6320                                                                                                  "{\n"
6321                                                                                                  "      " + (tcsToTES ? "gl_out[gl_InvocationID].gl_Position" : "in_te_attr[gl_InvocationID]") + " = "
6322                                                                                                           + (vsToTCS ? "gl_in[gl_InvocationID].gl_Position" : "in_tc_attr[gl_InvocationID]") + ";\n"
6323                                                                                                  "\n"
6324                                                                                                  "      gl_TessLevelInner[0] = 2.0;\n"
6325                                                                                                  "      gl_TessLevelInner[1] = 3.0;\n"
6326                                                                                                  "\n"
6327                                                                                                  "      gl_TessLevelOuter[0] = 4.0;\n"
6328                                                                                                  "      gl_TessLevelOuter[1] = 5.0;\n"
6329                                                                                                  "      gl_TessLevelOuter[2] = 6.0;\n"
6330                                                                                                  "      gl_TessLevelOuter[3] = 7.0;\n"
6331                                                                                                  "}\n")
6332
6333                 << glu::TessellationEvaluationSource    ("#version 310 es\n"
6334                                                                                                  "#extension GL_EXT_tessellation_shader : require\n"
6335                                                                                                  "\n"
6336                                                                                                  + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_TRIANGLES) +
6337                                                                                                  "\n"
6338                                                                                                  + (!tcsToTES ? "in highp vec4 in_te_attr[];\n" : "") +
6339                                                                                                  "\n"
6340                                                                                                  "out highp vec4 in_f_color;\n"
6341                                                                                                  "\n"
6342                                                                                                  "void main (void)\n"
6343                                                                                                  "{\n"
6344                                                                                                  "      highp vec2 xy = gl_TessCoord.x * " + tesIn0 + ".xy\n"
6345                                                                                                  "                    + gl_TessCoord.y * " + tesIn1 + ".xy\n"
6346                                                                                                  "                    + gl_TessCoord.z * " + tesIn2 + ".xy;\n"
6347                                                                                                  "      gl_Position = vec4(xy, 0.0, 1.0);\n"
6348                                                                                                  "      in_f_color = vec4(" + tesIn0 + ".z + " + tesIn1 + ".w,\n"
6349                                                                                                  "                        " + tesIn2 + ".z + " + tesIn0 + ".w,\n"
6350                                                                                                  "                        " + tesIn1 + ".z + " + tesIn2 + ".w,\n"
6351                                                                                                  "                        1.0);\n"
6352                                                                                                  "}\n")
6353
6354                 << glu::FragmentSource                                  ("#version 310 es\n"
6355                                                                                                  "\n"
6356                                                                                                  "layout (location = 0) out mediump vec4 o_color;\n"
6357                                                                                                  "\n"
6358                                                                                                  "in highp vec4 in_f_color;\n"
6359                                                                                                  "\n"
6360                                                                                                  "void main (void)\n"
6361                                                                                                  "{\n"
6362                                                                                                  "      o_color = in_f_color;\n"
6363                                                                                                  "}\n")));
6364
6365         m_testCtx.getLog() << *m_program;
6366         if (!m_program->isOk())
6367                 TCU_FAIL("Program compilation failed");
6368 }
6369
6370 void GLPositionCase::deinit (void)
6371 {
6372         m_program.clear();
6373 }
6374
6375 GLPositionCase::IterateResult GLPositionCase::iterate (void)
6376 {
6377         TestLog&                                log                                             = m_testCtx.getLog();
6378         const RenderContext&    renderCtx                               = m_context.getRenderContext();
6379         const RandomViewport    viewport                                (renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
6380         const glw::Functions&   gl                                              = renderCtx.getFunctions();
6381         const deUint32                  programGL                               = m_program->getProgram();
6382
6383         static const float attributes[3*4] =
6384         {
6385                 -0.8f, -0.7f, 0.1f, 0.7f,
6386                 -0.5f,  0.4f, 0.2f, 0.5f,
6387                  0.3f,  0.2f, 0.3f, 0.45f
6388         };
6389
6390         gl.useProgram(programGL);
6391         setViewport(gl, viewport);
6392         gl.patchParameteri(GL_PATCH_VERTICES, 3);
6393
6394         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
6395         gl.clear(GL_COLOR_BUFFER_BIT);
6396
6397         log << TestLog::Message << "Note: input data for in_v_attr:\n" << arrayStr(attributes, 4) << TestLog::EndMessage;
6398
6399         {
6400                 const glu::VertexArrayBinding bindings[] = { glu::va::Float("in_v_attr", 4, 3, 0, &attributes[0]) };
6401                 glu::draw(renderCtx, programGL, DE_LENGTH_OF_ARRAY(bindings), &bindings[0], glu::pr::Patches(3));
6402
6403                 {
6404                         const tcu::Surface                      pixels          = getPixels(renderCtx, viewport);
6405                         const tcu::TextureLevel         reference       = getPNG(m_testCtx.getArchive(), m_referenceImagePath.c_str());
6406                         const bool                                      success         = tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), pixels.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
6407
6408                         if (!success)
6409                         {
6410                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
6411                                 return STOP;
6412                         }
6413                 }
6414         }
6415
6416         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
6417         return STOP;
6418 }
6419
6420 class LimitQueryCase : public TestCase
6421 {
6422 public:
6423                                                 LimitQueryCase  (Context& context, const char* name, const char* desc, glw::GLenum target, int minValue);
6424 private:
6425         IterateResult           iterate                 (void);
6426
6427         const glw::GLenum       m_target;
6428         const int                       m_minValue;
6429 };
6430
6431 LimitQueryCase::LimitQueryCase (Context& context, const char* name, const char* desc, glw::GLenum target, int minValue)
6432         : TestCase                      (context, name, desc)
6433         , m_target                      (target)
6434         , m_minValue            (minValue)
6435 {
6436 }
6437
6438 LimitQueryCase::IterateResult LimitQueryCase::iterate (void)
6439 {
6440         checkTessellationSupport(m_context);
6441
6442         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6443         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
6444
6445         gl.enableLogging(true);
6446         verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER);
6447
6448         {
6449                 const tcu::ScopedLogSection     section(m_testCtx.getLog(), "Types", "Alternative queries");
6450                 verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_BOOLEAN);
6451                 verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER64);
6452                 verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_FLOAT);
6453         }
6454
6455         result.setTestContextResult(m_testCtx);
6456         return STOP;
6457 }
6458
6459 class CombinedUniformLimitCase : public TestCase
6460 {
6461 public:
6462                                                 CombinedUniformLimitCase        (Context& context, const char* name, const char* desc, glw::GLenum combined, glw::GLenum numBlocks, glw::GLenum defaultComponents);
6463 private:
6464         IterateResult           iterate                                         (void);
6465
6466         const glw::GLenum       m_combined;
6467         const glw::GLenum       m_numBlocks;
6468         const glw::GLenum       m_defaultComponents;
6469 };
6470
6471 CombinedUniformLimitCase::CombinedUniformLimitCase (Context& context, const char* name, const char* desc, glw::GLenum combined, glw::GLenum numBlocks, glw::GLenum defaultComponents)
6472         : TestCase                              (context, name, desc)
6473         , m_combined                    (combined)
6474         , m_numBlocks                   (numBlocks)
6475         , m_defaultComponents   (defaultComponents)
6476 {
6477 }
6478
6479 CombinedUniformLimitCase::IterateResult CombinedUniformLimitCase::iterate (void)
6480 {
6481         checkTessellationSupport(m_context);
6482
6483         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6484         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
6485
6486         gl.enableLogging(true);
6487
6488         m_testCtx.getLog()      << tcu::TestLog::Message
6489                                                 << "The minimum value of " << glu::getGettableStateStr(m_combined)
6490                                                 << " is " << glu::getGettableStateStr(m_numBlocks)
6491                                                 << " x MAX_UNIFORM_BLOCK_SIZE / 4 + "
6492                                                 << glu::getGettableStateStr(m_defaultComponents)
6493                                                 << tcu::TestLog::EndMessage;
6494
6495         StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlocks;
6496         gl.glGetIntegerv(m_numBlocks, &maxUniformBlocks);
6497         GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
6498
6499         StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlockSize;
6500         gl.glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
6501         GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
6502
6503         StateQueryMemoryWriteGuard<glw::GLint> maxUniformComponents;
6504         gl.glGetIntegerv(m_defaultComponents, &maxUniformComponents);
6505         GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
6506
6507         if (maxUniformBlocks.verifyValidity(result) && maxUniformBlockSize.verifyValidity(result) && maxUniformComponents.verifyValidity(result))
6508         {
6509                 const int limit = ((int)maxUniformBlocks) * ((int)maxUniformBlockSize) / 4 + (int)maxUniformComponents;
6510                 verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_INTEGER);
6511
6512                 {
6513                         const tcu::ScopedLogSection     section(m_testCtx.getLog(), "Types", "Alternative queries");
6514                         verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_BOOLEAN);
6515                         verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_INTEGER64);
6516                         verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_FLOAT);
6517                 }
6518         }
6519
6520         result.setTestContextResult(m_testCtx);
6521         return STOP;
6522 }
6523
6524 class PatchVerticesStateCase : public TestCase
6525 {
6526 public:
6527                                                 PatchVerticesStateCase  (Context& context, const char* name, const char* desc);
6528 private:
6529         IterateResult           iterate                                 (void);
6530 };
6531
6532 PatchVerticesStateCase::PatchVerticesStateCase (Context& context, const char* name, const char* desc)
6533         : TestCase(context, name, desc)
6534 {
6535 }
6536
6537 PatchVerticesStateCase::IterateResult PatchVerticesStateCase::iterate (void)
6538 {
6539         checkTessellationSupport(m_context);
6540
6541         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6542         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
6543
6544         gl.enableLogging(true);
6545
6546         // initial
6547         {
6548                 const tcu::ScopedLogSection section(m_testCtx.getLog(), "initial", "Initial value");
6549
6550                 verifyStateInteger(result, gl, GL_PATCH_VERTICES, 3, QUERY_INTEGER);
6551         }
6552
6553         // bind
6554         {
6555                 const tcu::ScopedLogSection section(m_testCtx.getLog(), "set", "After set");
6556
6557                 gl.glPatchParameteri(GL_PATCH_VERTICES, 22);
6558                 GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glPatchParameteri");
6559
6560                 verifyStateInteger(result, gl, GL_PATCH_VERTICES, 22, QUERY_INTEGER);
6561                 {
6562                         const tcu::ScopedLogSection     subsection(m_testCtx.getLog(), "Types", "Alternative queries");
6563                         verifyStateIntegerMin(result, gl, GL_PATCH_VERTICES, 22, QUERY_BOOLEAN);
6564                         verifyStateIntegerMin(result, gl, GL_PATCH_VERTICES, 22, QUERY_INTEGER64);
6565                         verifyStateIntegerMin(result, gl, GL_PATCH_VERTICES, 22, QUERY_FLOAT);
6566                 }
6567         }
6568
6569         result.setTestContextResult(m_testCtx);
6570         return STOP;
6571 }
6572
6573 class PrimitiveRestartForPatchesSupportedCase : public TestCase
6574 {
6575 public:
6576                                                 PrimitiveRestartForPatchesSupportedCase (Context& context, const char* name, const char* desc);
6577 private:
6578         IterateResult           iterate                                                                 (void);
6579 };
6580
6581 PrimitiveRestartForPatchesSupportedCase::PrimitiveRestartForPatchesSupportedCase (Context& context, const char* name, const char* desc)
6582         : TestCase(context, name, desc)
6583 {
6584 }
6585
6586 PrimitiveRestartForPatchesSupportedCase::IterateResult PrimitiveRestartForPatchesSupportedCase::iterate (void)
6587 {
6588         checkTessellationSupport(m_context);
6589
6590         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6591         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
6592         QueriedState                    state;
6593
6594         gl.enableLogging(true);
6595
6596         queryState(result, gl, QUERY_BOOLEAN, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state);
6597
6598         if (!state.isUndefined())
6599         {
6600                 const tcu::ScopedLogSection     subsection(m_testCtx.getLog(), "Types", "Alternative types");
6601                 verifyStateBoolean(result, gl, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state.getBoolAccess(), QUERY_INTEGER);
6602                 verifyStateBoolean(result, gl, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state.getBoolAccess(), QUERY_INTEGER64);
6603                 verifyStateBoolean(result, gl, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state.getBoolAccess(), QUERY_FLOAT);
6604         }
6605
6606         result.setTestContextResult(m_testCtx);
6607         return STOP;
6608 }
6609
6610 class TessProgramQueryCase : public TestCase
6611 {
6612 public:
6613                                                 TessProgramQueryCase    (Context& context, const char* name, const char* desc);
6614
6615         std::string                     getVertexSource                 (void) const;
6616         std::string                     getFragmentSource               (void) const;
6617         std::string                     getTessCtrlSource               (const char* globalLayouts) const;
6618         std::string                     getTessEvalSource               (const char* globalLayouts) const;
6619 };
6620
6621 TessProgramQueryCase::TessProgramQueryCase (Context& context, const char* name, const char* desc)
6622         : TestCase(context, name, desc)
6623 {
6624 }
6625
6626 std::string TessProgramQueryCase::getVertexSource (void) const
6627 {
6628         return  "#version 310 es\n"
6629                         "void main (void)\n"
6630                         "{\n"
6631                         "       gl_Position = vec4(float(gl_VertexID), float(gl_VertexID / 2), 0.0, 1.0);\n"
6632                         "}\n";
6633 }
6634
6635 std::string TessProgramQueryCase::getFragmentSource (void) const
6636 {
6637         return  "#version 310 es\n"
6638                         "layout (location = 0) out mediump vec4 o_color;\n"
6639                         "void main (void)\n"
6640                         "{\n"
6641                         "       o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
6642                         "}\n";
6643 }
6644
6645 std::string TessProgramQueryCase::getTessCtrlSource (const char* globalLayouts) const
6646 {
6647         return  "#version 310 es\n"
6648                         "#extension GL_EXT_tessellation_shader : require\n"
6649                         + std::string(globalLayouts) + ";\n"
6650                         "void main (void)\n"
6651                         "{\n"
6652                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
6653                         "       gl_TessLevelInner[0] = 2.8;\n"
6654                         "       gl_TessLevelInner[1] = 2.8;\n"
6655                         "       gl_TessLevelOuter[0] = 2.8;\n"
6656                         "       gl_TessLevelOuter[1] = 2.8;\n"
6657                         "       gl_TessLevelOuter[2] = 2.8;\n"
6658                         "       gl_TessLevelOuter[3] = 2.8;\n"
6659                         "}\n";
6660 }
6661
6662 std::string TessProgramQueryCase::getTessEvalSource (const char* globalLayouts) const
6663 {
6664         return  "#version 310 es\n"
6665                         "#extension GL_EXT_tessellation_shader : require\n"
6666                         + std::string(globalLayouts) + ";\n"
6667                         "void main (void)\n"
6668                         "{\n"
6669                         "       gl_Position = gl_TessCoord.x * gl_in[0].gl_Position\n"
6670                         "                   + gl_TessCoord.y * gl_in[1].gl_Position\n"
6671                         "                   + gl_TessCoord.y * gl_in[2].gl_Position\n"
6672                         "                   + gl_TessCoord.z * gl_in[3].gl_Position;\n"
6673                         "}\n";
6674 }
6675
6676 class TessControlOutputVerticesCase : public TessProgramQueryCase
6677 {
6678 public:
6679                                                 TessControlOutputVerticesCase   (Context& context, const char* name, const char* desc);
6680 private:
6681         IterateResult           iterate                                                 (void);
6682 };
6683
6684 TessControlOutputVerticesCase::TessControlOutputVerticesCase (Context& context, const char* name, const char* desc)
6685         : TessProgramQueryCase(context, name, desc)
6686 {
6687 }
6688
6689 TessControlOutputVerticesCase::IterateResult TessControlOutputVerticesCase::iterate (void)
6690 {
6691         checkTessellationSupport(m_context);
6692
6693         glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6694                                                                                                                                 << glu::VertexSource(getVertexSource())
6695                                                                                                                                 << glu::FragmentSource(getFragmentSource())
6696                                                                                                                                 << glu::TessellationControlSource(getTessCtrlSource("layout(vertices=4) out"))
6697                                                                                                                                 << glu::TessellationEvaluationSource(getTessEvalSource("layout(triangles) in")));
6698
6699         m_testCtx.getLog() << program;
6700         if (!program.isOk())
6701                 throw tcu::TestError("failed to build program");
6702
6703         {
6704                 glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6705                 tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
6706
6707                 gl.enableLogging(true);
6708                 verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_CONTROL_OUTPUT_VERTICES, 4, QUERY_PROGRAM_INTEGER);
6709
6710                 result.setTestContextResult(m_testCtx);
6711         }
6712         return STOP;
6713 }
6714
6715 class TessGenModeQueryCase : public TessProgramQueryCase
6716 {
6717 public:
6718                                                 TessGenModeQueryCase    (Context& context, const char* name, const char* desc);
6719 private:
6720         IterateResult           iterate                                 (void);
6721 };
6722
6723 TessGenModeQueryCase::TessGenModeQueryCase (Context& context, const char* name, const char* desc)
6724         : TessProgramQueryCase(context, name, desc)
6725 {
6726 }
6727
6728 TessGenModeQueryCase::IterateResult TessGenModeQueryCase::iterate (void)
6729 {
6730         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
6731         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6732
6733         static const struct
6734         {
6735                 const char* description;
6736                 const char* layout;
6737                 glw::GLenum mode;
6738         } s_modes[] =
6739         {
6740                 { "Triangles",  "layout(triangles) in", GL_TRIANGLES    },
6741                 { "Isolines",   "layout(isolines) in",  GL_ISOLINES             },
6742                 { "Quads",              "layout(quads) in",             GL_QUADS                },
6743         };
6744
6745         checkTessellationSupport(m_context);
6746         gl.enableLogging(true);
6747
6748         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
6749         {
6750                 const tcu::ScopedLogSection     section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
6751
6752                 glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6753                                                                                                                                         << glu::VertexSource(getVertexSource())
6754                                                                                                                                         << glu::FragmentSource(getFragmentSource())
6755                                                                                                                                         << glu::TessellationControlSource(getTessCtrlSource("layout(vertices=6) out"))
6756                                                                                                                                         << glu::TessellationEvaluationSource(getTessEvalSource(s_modes[ndx].layout)));
6757
6758                 m_testCtx.getLog() << program;
6759                 if (!program.isOk())
6760                         result.fail("failed to build program");
6761                 else
6762                         verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_MODE, s_modes[ndx].mode, QUERY_PROGRAM_INTEGER);
6763         }
6764
6765         result.setTestContextResult(m_testCtx);
6766         return STOP;
6767 }
6768
6769 class TessGenSpacingQueryCase : public TessProgramQueryCase
6770 {
6771 public:
6772                                                 TessGenSpacingQueryCase (Context& context, const char* name, const char* desc);
6773 private:
6774         IterateResult           iterate                                 (void);
6775 };
6776
6777 TessGenSpacingQueryCase::TessGenSpacingQueryCase (Context& context, const char* name, const char* desc)
6778         : TessProgramQueryCase(context, name, desc)
6779 {
6780 }
6781
6782 TessGenSpacingQueryCase::IterateResult TessGenSpacingQueryCase::iterate (void)
6783 {
6784         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
6785         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6786
6787         static const struct
6788         {
6789                 const char* description;
6790                 const char* layout;
6791                 glw::GLenum spacing;
6792         } s_modes[] =
6793         {
6794                 { "Default spacing",                    "layout(triangles) in",                                                         GL_EQUAL                        },
6795                 { "Equal spacing",                              "layout(triangles, equal_spacing) in",                          GL_EQUAL                        },
6796                 { "Fractional even spacing",    "layout(triangles, fractional_even_spacing) in",        GL_FRACTIONAL_EVEN      },
6797                 { "Fractional odd spacing",             "layout(triangles, fractional_odd_spacing) in",         GL_FRACTIONAL_ODD       },
6798         };
6799
6800         checkTessellationSupport(m_context);
6801         gl.enableLogging(true);
6802
6803         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
6804         {
6805                 const tcu::ScopedLogSection     section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
6806
6807                 glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6808                                                                                                                                         << glu::VertexSource(getVertexSource())
6809                                                                                                                                         << glu::FragmentSource(getFragmentSource())
6810                                                                                                                                         << glu::TessellationControlSource(getTessCtrlSource("layout(vertices=6) out"))
6811                                                                                                                                         << glu::TessellationEvaluationSource(getTessEvalSource(s_modes[ndx].layout)));
6812
6813                 m_testCtx.getLog() << program;
6814                 if (!program.isOk())
6815                         result.fail("failed to build program");
6816                 else
6817                         verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_SPACING, s_modes[ndx].spacing, QUERY_PROGRAM_INTEGER);
6818         }
6819
6820         result.setTestContextResult(m_testCtx);
6821         return STOP;
6822 }
6823
6824 class TessGenVertexOrderQueryCase : public TessProgramQueryCase
6825 {
6826 public:
6827                                                 TessGenVertexOrderQueryCase     (Context& context, const char* name, const char* desc);
6828 private:
6829         IterateResult           iterate                                         (void);
6830 };
6831
6832 TessGenVertexOrderQueryCase::TessGenVertexOrderQueryCase (Context& context, const char* name, const char* desc)
6833         : TessProgramQueryCase(context, name, desc)
6834 {
6835 }
6836
6837 TessGenVertexOrderQueryCase::IterateResult TessGenVertexOrderQueryCase::iterate (void)
6838 {
6839         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
6840         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6841
6842         static const struct
6843         {
6844                 const char* description;
6845                 const char* layout;
6846                 glw::GLenum order;
6847         } s_modes[] =
6848         {
6849                 { "Default order",      "layout(triangles) in",                 GL_CCW  },
6850                 { "CW order",           "layout(triangles, cw) in",             GL_CW   },
6851                 { "CCW order",          "layout(triangles, ccw) in",    GL_CCW  },
6852         };
6853
6854         checkTessellationSupport(m_context);
6855         gl.enableLogging(true);
6856
6857         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
6858         {
6859                 const tcu::ScopedLogSection     section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
6860
6861                 glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6862                                                                                                                                         << glu::VertexSource(getVertexSource())
6863                                                                                                                                         << glu::FragmentSource(getFragmentSource())
6864                                                                                                                                         << glu::TessellationControlSource(getTessCtrlSource("layout(vertices=6) out"))
6865                                                                                                                                         << glu::TessellationEvaluationSource(getTessEvalSource(s_modes[ndx].layout)));
6866
6867                 m_testCtx.getLog() << program;
6868                 if (!program.isOk())
6869                         result.fail("failed to build program");
6870                 else
6871                         verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_VERTEX_ORDER, s_modes[ndx].order, QUERY_PROGRAM_INTEGER);
6872         }
6873
6874         result.setTestContextResult(m_testCtx);
6875         return STOP;
6876 }
6877
6878 class TessGenPointModeQueryCase : public TessProgramQueryCase
6879 {
6880 public:
6881                                                 TessGenPointModeQueryCase       (Context& context, const char* name, const char* desc);
6882 private:
6883         IterateResult           iterate                                         (void);
6884 };
6885
6886 TessGenPointModeQueryCase::TessGenPointModeQueryCase (Context& context, const char* name, const char* desc)
6887         : TessProgramQueryCase(context, name, desc)
6888 {
6889 }
6890
6891 TessGenPointModeQueryCase::IterateResult TessGenPointModeQueryCase::iterate (void)
6892 {
6893         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
6894         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6895
6896         static const struct
6897         {
6898                 const char* description;
6899                 const char* layout;
6900                 glw::GLenum mode;
6901         } s_modes[] =
6902         {
6903                 { "Default mode",       "layout(triangles) in",                 GL_FALSE        },
6904                 { "Point mode",         "layout(triangles, point_mode) in",             GL_TRUE         },
6905         };
6906
6907         checkTessellationSupport(m_context);
6908         gl.enableLogging(true);
6909
6910         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
6911         {
6912                 const tcu::ScopedLogSection     section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
6913
6914                 glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6915                                                                                                                                         << glu::VertexSource(getVertexSource())
6916                                                                                                                                         << glu::FragmentSource(getFragmentSource())
6917                                                                                                                                         << glu::TessellationControlSource(getTessCtrlSource("layout(vertices=6) out"))
6918                                                                                                                                         << glu::TessellationEvaluationSource(getTessEvalSource(s_modes[ndx].layout)));
6919
6920                 m_testCtx.getLog() << program;
6921                 if (!program.isOk())
6922                         result.fail("failed to build program");
6923                 else
6924                         verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_POINT_MODE, s_modes[ndx].mode, QUERY_PROGRAM_INTEGER);
6925         }
6926
6927         result.setTestContextResult(m_testCtx);
6928         return STOP;
6929 }
6930
6931 class ReferencedByTessellationQueryCase : public TestCase
6932 {
6933 public:
6934                                         ReferencedByTessellationQueryCase       (Context& context, const char* name, const char* desc, bool isCtrlCase);
6935 private:
6936         void                    init                                                            (void);
6937         IterateResult   iterate                                                         (void);
6938
6939         std::string             getVertexSource                                         (void) const;
6940         std::string             getFragmentSource                                       (void) const;
6941         std::string             getTessCtrlSource                                       (void) const;
6942         std::string             getTessEvalSource                                       (void) const;
6943
6944         const bool              m_isCtrlCase;
6945 };
6946
6947 ReferencedByTessellationQueryCase::ReferencedByTessellationQueryCase (Context& context, const char* name, const char* desc, bool isCtrlCase)
6948         : TestCase              (context, name, desc)
6949         , m_isCtrlCase  (isCtrlCase)
6950 {
6951 }
6952
6953 void ReferencedByTessellationQueryCase::init (void)
6954 {
6955         checkTessellationSupport(m_context);
6956 }
6957
6958 ReferencedByTessellationQueryCase::IterateResult ReferencedByTessellationQueryCase::iterate (void)
6959 {
6960         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
6961         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6962         glu::ShaderProgram              program (m_context.getRenderContext(), glu::ProgramSources()
6963                                                                                                                                         << glu::VertexSource(getVertexSource())
6964                                                                                                                                         << glu::FragmentSource(getFragmentSource())
6965                                                                                                                                         << glu::TessellationControlSource(getTessCtrlSource())
6966                                                                                                                                         << glu::TessellationEvaluationSource(getTessEvalSource()));
6967
6968         gl.enableLogging(true);
6969
6970         m_testCtx.getLog() << program;
6971         if (!program.isOk())
6972                 result.fail("failed to build program");
6973         else
6974         {
6975                 const deUint32 props[1] = { (deUint32)((m_isCtrlCase) ? (GL_REFERENCED_BY_TESS_CONTROL_SHADER) : (GL_REFERENCED_BY_TESS_EVALUATION_SHADER)) };
6976
6977                 {
6978                         const tcu::ScopedLogSection section             (m_testCtx.getLog(), "UnreferencedUniform", "Unreferenced uniform u_unreferenced");
6979                         deUint32                                        resourcePos;
6980                         glw::GLsizei                            length          = 0;
6981                         glw::GLint                                      referenced      = 0;
6982
6983                         resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_unreferenced");
6984                         m_testCtx.getLog() << tcu::TestLog::Message << "u_unreferenced resource index: " << resourcePos << tcu::TestLog::EndMessage;
6985
6986                         if (resourcePos == GL_INVALID_INDEX)
6987                                 result.fail("resourcePos was GL_INVALID_INDEX");
6988                         else
6989                         {
6990                                 gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
6991                                 m_testCtx.getLog()
6992                                         << tcu::TestLog::Message
6993                                         << "Query " << glu::getProgramResourcePropertyStr(props[0])
6994                                         << ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
6995                                         << tcu::TestLog::EndMessage;
6996
6997                                 GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "query resource");
6998
6999                                 if (length == 0 || referenced != GL_FALSE)
7000                                         result.fail("expected GL_FALSE");
7001                         }
7002                 }
7003
7004                 {
7005                         const tcu::ScopedLogSection section             (m_testCtx.getLog(), "ReferencedUniform", "Referenced uniform u_referenced");
7006                         deUint32                                        resourcePos;
7007                         glw::GLsizei                            length          = 0;
7008                         glw::GLint                                      referenced      = 0;
7009
7010                         resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_referenced");
7011                         m_testCtx.getLog() << tcu::TestLog::Message << "u_referenced resource index: " << resourcePos << tcu::TestLog::EndMessage;
7012
7013                         if (resourcePos == GL_INVALID_INDEX)
7014                                 result.fail("resourcePos was GL_INVALID_INDEX");
7015                         else
7016                         {
7017                                 gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
7018                                 m_testCtx.getLog()
7019                                         << tcu::TestLog::Message
7020                                         << "Query " << glu::getProgramResourcePropertyStr(props[0])
7021                                         << ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7022                                         << tcu::TestLog::EndMessage;
7023
7024                                 GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
7025
7026                                 if (length == 0 || referenced != GL_TRUE)
7027                                         result.fail("expected GL_TRUE");
7028                         }
7029                 }
7030         }
7031
7032         result.setTestContextResult(m_testCtx);
7033         return STOP;
7034 }
7035
7036 std::string ReferencedByTessellationQueryCase::getVertexSource (void) const
7037 {
7038         return  "#version 310 es\n"
7039                         "void main (void)\n"
7040                         "{\n"
7041                         "       gl_Position = vec4(float(gl_VertexID), float(gl_VertexID / 2), 0.0, 1.0);\n"
7042                         "}\n";
7043 }
7044
7045 std::string ReferencedByTessellationQueryCase::getFragmentSource (void) const
7046 {
7047         return  "#version 310 es\n"
7048                         "layout (location = 0) out mediump vec4 o_color;\n"
7049                         "void main (void)\n"
7050                         "{\n"
7051                         "       o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
7052                         "}\n";
7053 }
7054
7055 std::string ReferencedByTessellationQueryCase::getTessCtrlSource (void) const
7056 {
7057         std::ostringstream buf;
7058         buf <<  "#version 310 es\n"
7059                         "#extension GL_EXT_tessellation_shader : require\n"
7060                         "layout(vertices = 3) out;\n"
7061                         "uniform highp vec4 " << ((m_isCtrlCase) ? ("u_referenced") : ("u_unreferenced")) << ";\n"
7062                         "void main (void)\n"
7063                         "{\n"
7064                         "       vec4 offset = " << ((m_isCtrlCase) ? ("u_referenced") : ("u_unreferenced")) << ";\n"
7065                         "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position + offset;\n"
7066                         "       gl_TessLevelInner[0] = 2.8;\n"
7067                         "       gl_TessLevelInner[1] = 2.8;\n"
7068                         "       gl_TessLevelOuter[0] = 2.8;\n"
7069                         "       gl_TessLevelOuter[1] = 2.8;\n"
7070                         "       gl_TessLevelOuter[2] = 2.8;\n"
7071                         "       gl_TessLevelOuter[3] = 2.8;\n"
7072                         "}\n";
7073         return buf.str();
7074 }
7075
7076 std::string ReferencedByTessellationQueryCase::getTessEvalSource (void) const
7077 {
7078         std::ostringstream buf;
7079         buf <<  "#version 310 es\n"
7080                         "#extension GL_EXT_tessellation_shader : require\n"
7081                         "layout(triangles) in;\n"
7082                         "uniform highp vec4 " << ((m_isCtrlCase) ? ("u_unreferenced") : ("u_referenced")) << ";\n"
7083                         "void main (void)\n"
7084                         "{\n"
7085                         "       vec4 offset = " << ((m_isCtrlCase) ? ("u_unreferenced") : ("u_referenced")) << ";\n"
7086                         "       gl_Position = gl_TessCoord.x * gl_in[0].gl_Position\n"
7087                         "                   + gl_TessCoord.y * gl_in[1].gl_Position\n"
7088                         "                   + gl_TessCoord.z * gl_in[2].gl_Position\n"
7089                         "                   + offset;\n"
7090                         "}\n";
7091
7092         return buf.str();
7093 }
7094
7095 class IsPerPatchQueryCase : public TestCase
7096 {
7097 public:
7098                                         IsPerPatchQueryCase             (Context& context, const char* name, const char* desc);
7099 private:
7100         void                    init                                    (void);
7101         IterateResult   iterate                                 (void);
7102 };
7103
7104 IsPerPatchQueryCase::IsPerPatchQueryCase (Context& context, const char* name, const char* desc)
7105         : TestCase(context, name, desc)
7106 {
7107 }
7108
7109 void IsPerPatchQueryCase::init (void)
7110 {
7111         checkTessellationSupport(m_context);
7112 }
7113
7114 IsPerPatchQueryCase::IterateResult IsPerPatchQueryCase::iterate (void)
7115 {
7116         static const char* const s_controlSource =      "#version 310 es\n"
7117                                                                                                 "#extension GL_EXT_tessellation_shader : require\n"
7118                                                                                                 "layout(vertices = 3) out;\n"
7119                                                                                                 "patch out highp vec4 v_perPatch;\n"
7120                                                                                                 "out highp vec4 v_perVertex[];\n"
7121                                                                                                 "void main (void)\n"
7122                                                                                                 "{\n"
7123                                                                                                 "       gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
7124                                                                                                 "       v_perPatch = gl_in[0].gl_Position;\n"
7125                                                                                                 "       v_perVertex[gl_InvocationID] = -gl_in[gl_InvocationID].gl_Position;\n"
7126                                                                                                 "       gl_TessLevelInner[0] = 2.8;\n"
7127                                                                                                 "       gl_TessLevelInner[1] = 2.8;\n"
7128                                                                                                 "       gl_TessLevelOuter[0] = 2.8;\n"
7129                                                                                                 "       gl_TessLevelOuter[1] = 2.8;\n"
7130                                                                                                 "       gl_TessLevelOuter[2] = 2.8;\n"
7131                                                                                                 "       gl_TessLevelOuter[3] = 2.8;\n"
7132                                                                                                 "}\n";
7133         tcu::ResultCollector    result  (m_testCtx.getLog(), " // ERROR: ");
7134         glu::CallLogWrapper             gl              (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
7135         glu::ShaderProgram              program (m_context.getRenderContext(), glu::ProgramSources()
7136                                                                                                                                         << glu::TessellationControlSource(s_controlSource)
7137                                                                                                                                         << glu::ProgramSeparable(true));
7138
7139         gl.enableLogging(true);
7140
7141         m_testCtx.getLog() << program;
7142         if (!program.isOk())
7143                 result.fail("failed to build program");
7144         else
7145         {
7146                 const deUint32 props[1] = { GL_IS_PER_PATCH };
7147
7148                 {
7149                         const tcu::ScopedLogSection section             (m_testCtx.getLog(), "PerPatchOutput", "Per patch v_perPatch");
7150                         deUint32                                        resourcePos;
7151                         glw::GLsizei                            length          = 0;
7152                         glw::GLint                                      referenced      = 0;
7153
7154                         resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_PROGRAM_OUTPUT, "v_perPatch");
7155                         m_testCtx.getLog() << tcu::TestLog::Message << "v_perPatch resource index: " << resourcePos << tcu::TestLog::EndMessage;
7156
7157                         if (resourcePos == GL_INVALID_INDEX)
7158                                 result.fail("resourcePos was GL_INVALID_INDEX");
7159                         else
7160                         {
7161                                 gl.glGetProgramResourceiv(program.getProgram(), GL_PROGRAM_OUTPUT, resourcePos, 1, props, 1, &length, &referenced);
7162                                 m_testCtx.getLog()
7163                                         << tcu::TestLog::Message
7164                                         << "Query " << glu::getProgramResourcePropertyStr(props[0])
7165                                         << ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7166                                         << tcu::TestLog::EndMessage;
7167
7168                                 GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "query resource");
7169
7170                                 if (length == 0 || referenced != GL_TRUE)
7171                                         result.fail("expected GL_TRUE");
7172                         }
7173                 }
7174
7175                 {
7176                         const tcu::ScopedLogSection section             (m_testCtx.getLog(), "PerVertexhOutput", "Per vertex v_perVertex");
7177                         deUint32                                        resourcePos;
7178                         glw::GLsizei                            length          = 0;
7179                         glw::GLint                                      referenced      = 0;
7180
7181                         resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_PROGRAM_OUTPUT, "v_perVertex");
7182                         m_testCtx.getLog() << tcu::TestLog::Message << "v_perVertex resource index: " << resourcePos << tcu::TestLog::EndMessage;
7183
7184                         if (resourcePos == GL_INVALID_INDEX)
7185                                 result.fail("resourcePos was GL_INVALID_INDEX");
7186                         else
7187                         {
7188                                 gl.glGetProgramResourceiv(program.getProgram(), GL_PROGRAM_OUTPUT, resourcePos, 1, props, 1, &length, &referenced);
7189                                 m_testCtx.getLog()
7190                                         << tcu::TestLog::Message
7191                                         << "Query " << glu::getProgramResourcePropertyStr(props[0])
7192                                         << ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7193                                         << tcu::TestLog::EndMessage;
7194
7195                                 GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
7196
7197                                 if (length == 0 || referenced != GL_FALSE)
7198                                         result.fail("expected GL_FALSE");
7199                         }
7200                 }
7201         }
7202
7203         result.setTestContextResult(m_testCtx);
7204         return STOP;
7205 }
7206
7207 } // anonymous
7208
7209 TessellationTests::TessellationTests (Context& context)
7210         : TestCaseGroup(context, "tessellation", "Tessellation Tests")
7211 {
7212 }
7213
7214 TessellationTests::~TessellationTests (void)
7215 {
7216 }
7217
7218 void TessellationTests::init (void)
7219 {
7220         {
7221                 tcu::TestCaseGroup* const queryGroup = new tcu::TestCaseGroup(m_testCtx, "state_query", "Query tests");
7222                 addChild(queryGroup);
7223
7224                 // new limits
7225                 queryGroup->addChild(new LimitQueryCase(m_context, "max_patch_vertices",                                                                "Test MAX_PATCH_VERTICES",                                                              GL_MAX_PATCH_VERTICES,                                                  32));
7226                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_gen_level",                                                                "Test MAX_TESS_GEN_LEVEL",                                                              GL_MAX_TESS_GEN_LEVEL,                                                  64));
7227                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_uniform_components",                               "Test MAX_TESS_CONTROL_UNIFORM_COMPONENTS",                             GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS,                 1024));
7228                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_uniform_components",                    "Test MAX_TESS_EVALUATION_UNIFORM_COMPONENTS",                  GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS,              1024));
7229                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_texture_image_units",                              "Test MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS",                    GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,                16));
7230                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_texture_image_units",                   "Test MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS",                 GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,             16));
7231                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_output_components",                                "Test MAX_TESS_CONTROL_OUTPUT_COMPONENTS",                              GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS,                  64));
7232                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_patch_components",                                                 "Test MAX_TESS_PATCH_COMPONENTS",                                               GL_MAX_TESS_PATCH_COMPONENTS,                                   120));
7233                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_total_output_components",                  "Test MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS",                GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS,    2048));
7234                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_output_components",                             "Test MAX_TESS_EVALUATION_OUTPUT_COMPONENTS",                   GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS,               64));
7235                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_uniform_blocks",                                   "Test MAX_TESS_CONTROL_UNIFORM_BLOCKS",                                 GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,                             12));
7236                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_uniform_blocks",                                "Test MAX_TESS_EVALUATION_UNIFORM_BLOCKS",                              GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,                  12));
7237                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_input_components",                                 "Test MAX_TESS_CONTROL_INPUT_COMPONENTS",                               GL_MAX_TESS_CONTROL_INPUT_COMPONENTS,                   64));
7238                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_input_components",                              "Test MAX_TESS_EVALUATION_INPUT_COMPONENTS",                    GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS,                64));
7239                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_atomic_counter_buffers",                   "Test MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS",                 GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS,             0));
7240                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_atomic_counter_buffers",                "Test MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS",              GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS,  0));
7241                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_atomic_counters",                                  "Test MAX_TESS_CONTROL_ATOMIC_COUNTERS",                                GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS,                    0));
7242                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_atomic_counters",                               "Test MAX_TESS_EVALUATION_ATOMIC_COUNTERS",                             GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS,                 0));
7243                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_image_uniforms",                                   "Test MAX_TESS_CONTROL_IMAGE_UNIFORMS",                                 GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS,                             0));
7244                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_image_uniforms",                                "Test MAX_TESS_EVALUATION_IMAGE_UNIFORMS",                              GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS,                  0));
7245                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_shader_storage_blocks",                    "Test MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS",                  GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,              0));
7246                 queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_shader_storage_blocks",                 "Test MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS",               GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,   0));
7247
7248                 // modified limits
7249                 queryGroup->addChild(new LimitQueryCase(m_context, "max_uniform_buffer_bindings",                                               "Test MAX_UNIFORM_BUFFER_BINDINGS",                                             GL_MAX_UNIFORM_BUFFER_BINDINGS,                                 72));
7250                 queryGroup->addChild(new LimitQueryCase(m_context, "max_combined_uniform_blocks",                                               "Test MAX_COMBINED_UNIFORM_BLOCKS",                                             GL_MAX_COMBINED_UNIFORM_BLOCKS,                                 60));
7251                 queryGroup->addChild(new LimitQueryCase(m_context, "max_combined_texture_image_units",                                  "Test MAX_COMBINED_TEXTURE_IMAGE_UNITS",                                GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,                    96));
7252
7253                 // combined limits
7254                 queryGroup->addChild(new CombinedUniformLimitCase(m_context, "max_combined_tess_control_uniform_components",            "Test MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS",    GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS,                GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,             GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS));
7255                 queryGroup->addChild(new CombinedUniformLimitCase(m_context, "max_combined_tess_evaluation_uniform_components",         "Test MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS", GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS,             GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,  GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS));
7256
7257                 // features
7258                 queryGroup->addChild(new PrimitiveRestartForPatchesSupportedCase(m_context, "primitive_restart_for_patches_supported", "Test PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED"));
7259
7260                 // states
7261                 queryGroup->addChild(new PatchVerticesStateCase(m_context, "patch_vertices", "Test PATCH_VERTICES"));
7262
7263                 // program states
7264                 queryGroup->addChild(new TessControlOutputVerticesCase  (m_context, "tess_control_output_vertices",     "Test TESS_CONTROL_OUTPUT_VERTICES"));
7265                 queryGroup->addChild(new TessGenModeQueryCase                   (m_context, "tess_gen_mode",                            "Test TESS_GEN_MODE"));
7266                 queryGroup->addChild(new TessGenSpacingQueryCase                (m_context, "tess_gen_spacing",                         "Test TESS_GEN_SPACING"));
7267                 queryGroup->addChild(new TessGenVertexOrderQueryCase    (m_context, "tess_gen_vertex_order",            "Test TESS_GEN_VERTEX_ORDER"));
7268                 queryGroup->addChild(new TessGenPointModeQueryCase              (m_context, "tess_gen_point_mode",                      "Test TESS_GEN_POINT_MODE"));
7269
7270                 // resource queries
7271                 queryGroup->addChild(new ReferencedByTessellationQueryCase      (m_context, "referenced_by_tess_control_shader",        "Test REFERENCED_BY_TESS_CONTROL_SHADER",               true));
7272                 queryGroup->addChild(new ReferencedByTessellationQueryCase      (m_context, "referenced_by_tess_evaluation_shader",     "Test REFERENCED_BY_TESS_EVALUATION_SHADER",    false));
7273                 queryGroup->addChild(new IsPerPatchQueryCase                            (m_context, "is_per_patch",                                                     "Test IS_PER_PATCH"));
7274         }
7275
7276         {
7277                 TestCaseGroup* const tessCoordGroup = new TestCaseGroup(m_context, "tesscoord", "Get tessellation coordinates with transform feedback and validate them");
7278                 addChild(tessCoordGroup);
7279
7280                 for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7281                 {
7282                         const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7283
7284                         for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7285                                 tessCoordGroup->addChild(new TessCoordCase(m_context,
7286                                                                                                                    (string() + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName((SpacingMode)spacingI)).c_str(), "",
7287                                                                                                                    primitiveType, (SpacingMode)spacingI));
7288                 }
7289         }
7290
7291         {
7292                 TestCaseGroup* const windingGroup = new TestCaseGroup(m_context, "winding", "Test the cw and ccw input layout qualifiers");
7293                 addChild(windingGroup);
7294
7295                 for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7296                 {
7297                         const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7298                         if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7299                                 continue;
7300
7301                         for (int windingI = 0; windingI < WINDING_LAST; windingI++)
7302                         {
7303                                 const Winding winding = (Winding)windingI;
7304                                 windingGroup->addChild(new WindingCase(m_context, (string() + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getWindingShaderName(winding)).c_str(), "", primitiveType, winding));
7305                         }
7306                 }
7307         }
7308
7309         {
7310                 TestCaseGroup* const shaderInputOutputGroup = new TestCaseGroup(m_context, "shader_input_output", "Test tessellation control and evaluation shader inputs and outputs");
7311                 addChild(shaderInputOutputGroup);
7312
7313                 {
7314                         static const struct
7315                         {
7316                                 int inPatchSize;
7317                                 int outPatchSize;
7318                         } patchVertexCountCases[] =
7319                         {
7320                                 {  5, 10 },
7321                                 { 10,  5 }
7322                         };
7323
7324                         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(patchVertexCountCases); caseNdx++)
7325                         {
7326                                 const int inSize        = patchVertexCountCases[caseNdx].inPatchSize;
7327                                 const int outSize       = patchVertexCountCases[caseNdx].outPatchSize;
7328
7329                                 const string caseName = "patch_vertices_" + de::toString(inSize) + "_in_" + de::toString(outSize) + "_out";
7330
7331                                 shaderInputOutputGroup->addChild(new PatchVertexCountCase(m_context, caseName.c_str(), "Test input and output patch vertex counts", inSize, outSize,
7332                                                                                                                                                   ("data/tessellation/" + caseName + "_ref.png").c_str()));
7333                         }
7334                 }
7335
7336                 for (int caseTypeI = 0; caseTypeI < PerPatchDataCase::CASETYPE_LAST; caseTypeI++)
7337                 {
7338                         const PerPatchDataCase::CaseType        caseType        = (PerPatchDataCase::CaseType)caseTypeI;
7339                         const char* const                                       caseName        = PerPatchDataCase::getCaseTypeName(caseType);
7340
7341                         shaderInputOutputGroup->addChild(new PerPatchDataCase(m_context, caseName, PerPatchDataCase::getCaseTypeDescription(caseType), caseType,
7342                                                                                                                                   PerPatchDataCase::caseTypeUsesRefImageFromFile(caseType) ? (string() + "data/tessellation/" + caseName + "_ref.png").c_str() : DE_NULL));
7343                 }
7344
7345                 for (int caseTypeI = 0; caseTypeI < GLPositionCase::CASETYPE_LAST; caseTypeI++)
7346                 {
7347                         const GLPositionCase::CaseType  caseType        = (GLPositionCase::CaseType)caseTypeI;
7348                         const char* const                               caseName        = GLPositionCase::getCaseTypeName(caseType);
7349
7350                         shaderInputOutputGroup->addChild(new GLPositionCase(m_context, caseName, "", caseType, "data/tessellation/gl_position_ref.png"));
7351                 }
7352
7353                 shaderInputOutputGroup->addChild(new BarrierCase(m_context, "barrier", "Basic barrier usage", "data/tessellation/barrier_ref.png"));
7354         }
7355
7356         {
7357                 TestCaseGroup* const miscDrawGroup = new TestCaseGroup(m_context, "misc_draw", "Miscellaneous draw-result-verifying cases");
7358                 addChild(miscDrawGroup);
7359
7360                 for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7361                 {
7362                         const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7363                         if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7364                                 continue;
7365
7366                         const char* const primTypeName = getTessPrimitiveTypeShaderName(primitiveType);
7367
7368                         for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7369                         {
7370                                 const string caseName = string() + "fill_cover_" + primTypeName + "_" + getSpacingModeShaderName((SpacingMode)spacingI);
7371
7372                                 miscDrawGroup->addChild(new BasicTriangleFillCoverCase(m_context,
7373                                                                                                                                            caseName.c_str(), "Check that there are no obvious gaps in the triangle-filled area of a tessellated shape",
7374                                                                                                                                            primitiveType, (SpacingMode)spacingI,
7375                                                                                                                                            ("data/tessellation/" + caseName + "_ref").c_str()));
7376                         }
7377                 }
7378
7379                 for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7380                 {
7381                         const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7382                         if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7383                                 continue;
7384
7385                         const char* const primTypeName = getTessPrimitiveTypeShaderName(primitiveType);
7386
7387                         for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7388                         {
7389                                 const string caseName = string() + "fill_overlap_" + primTypeName + "_" + getSpacingModeShaderName((SpacingMode)spacingI);
7390
7391                                 miscDrawGroup->addChild(new BasicTriangleFillNonOverlapCase(m_context,
7392                                                                                                                                                         caseName.c_str(), "Check that there are no obvious triangle overlaps in the triangle-filled area of a tessellated shape",
7393                                                                                                                                                         primitiveType, (SpacingMode)spacingI,
7394                                                                                                                                                         ("data/tessellation/" + caseName + "_ref").c_str()));
7395                         }
7396                 }
7397
7398                 for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7399                 {
7400                         const string caseName = string() + "isolines_" + getSpacingModeShaderName((SpacingMode)spacingI);
7401
7402                         miscDrawGroup->addChild(new IsolinesRenderCase(m_context,
7403                                                                                                                    caseName.c_str(), "Basic isolines render test",
7404                                                                                                                    (SpacingMode)spacingI,
7405                                                                                                                    ("data/tessellation/" + caseName + "_ref").c_str()));
7406                 }
7407         }
7408
7409         {
7410                 TestCaseGroup* const commonEdgeGroup = new TestCaseGroup(m_context, "common_edge", "Draw multiple adjacent shapes and check that no cracks appear between them");
7411                 addChild(commonEdgeGroup);
7412
7413                 for (int caseTypeI = 0; caseTypeI < CommonEdgeCase::CASETYPE_LAST; caseTypeI++)
7414                 {
7415                         for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7416                         {
7417                                 const CommonEdgeCase::CaseType  caseType                = (CommonEdgeCase::CaseType)caseTypeI;
7418                                 const TessPrimitiveType                 primitiveType   = (TessPrimitiveType)primitiveTypeI;
7419                                 if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7420                                                 continue;
7421
7422                                 for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7423                                 {
7424                                         const SpacingMode       spacing         = (SpacingMode)spacingI;
7425                                         const string            caseName        = (string() + getTessPrimitiveTypeShaderName(primitiveType)
7426                                                                                                                                 + "_" + getSpacingModeShaderName(spacing)
7427                                                                                                                                 + (caseType == CommonEdgeCase::CASETYPE_BASIC           ? ""
7428                                                                                                                                  : caseType == CommonEdgeCase::CASETYPE_PRECISE         ? "_precise"
7429                                                                                                                                  : DE_NULL));
7430
7431                                         commonEdgeGroup->addChild(new CommonEdgeCase(m_context, caseName.c_str(), "", primitiveType, spacing, caseType));
7432                                 }
7433                         }
7434                 }
7435         }
7436
7437         {
7438                 TestCaseGroup* const fractionalSpacingModeGroup = new TestCaseGroup(m_context, "fractional_spacing", "Test fractional spacing modes");
7439                 addChild(fractionalSpacingModeGroup);
7440
7441                 fractionalSpacingModeGroup->addChild(new FractionalSpacingModeCase(m_context, "odd",    "", SPACINGMODE_FRACTIONAL_ODD));
7442                 fractionalSpacingModeGroup->addChild(new FractionalSpacingModeCase(m_context, "even",   "", SPACINGMODE_FRACTIONAL_EVEN));
7443         }
7444
7445         {
7446                 TestCaseGroup* const primitiveDiscardGroup = new TestCaseGroup(m_context, "primitive_discard", "Test primitive discard with relevant outer tessellation level <= 0.0");
7447                 addChild(primitiveDiscardGroup);
7448
7449                 for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7450                 {
7451                         for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7452                         {
7453                                 for (int windingI = 0; windingI < WINDING_LAST; windingI++)
7454                                 {
7455                                         for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
7456                                         {
7457                                                 const TessPrimitiveType         primitiveType   = (TessPrimitiveType)primitiveTypeI;
7458                                                 const SpacingMode                       spacing                 = (SpacingMode)spacingI;
7459                                                 const Winding                           winding                 = (Winding)windingI;
7460                                                 const bool                                      usePointMode    = usePointModeI != 0;
7461
7462                                                 primitiveDiscardGroup->addChild(new PrimitiveDiscardCase(m_context, (string() + getTessPrimitiveTypeShaderName(primitiveType)
7463                                                                                                                                                                                                           + "_" + getSpacingModeShaderName(spacing)
7464                                                                                                                                                                                                           + "_" + getWindingShaderName(winding)
7465                                                                                                                                                                                                           + (usePointMode ? "_point_mode" : "")).c_str(), "",
7466                                                                                                                                                                  primitiveType, spacing, winding, usePointMode));
7467                                         }
7468                                 }
7469                         }
7470                 }
7471         }
7472
7473         {
7474                 TestCaseGroup* const invarianceGroup                                                    = new TestCaseGroup(m_context, "invariance",                                            "Test tessellation invariance rules");
7475
7476                 TestCaseGroup* const invariantPrimitiveSetGroup                                 = new TestCaseGroup(m_context, "primitive_set",                                         "Test invariance rule #1");
7477                 TestCaseGroup* const invariantOuterEdgeGroup                                    = new TestCaseGroup(m_context, "outer_edge_division",                           "Test invariance rule #2");
7478                 TestCaseGroup* const symmetricOuterEdgeGroup                                    = new TestCaseGroup(m_context, "outer_edge_symmetry",                           "Test invariance rule #3");
7479                 TestCaseGroup* const outerEdgeVertexSetIndexIndependenceGroup   = new TestCaseGroup(m_context, "outer_edge_index_independence",         "Test invariance rule #4");
7480                 TestCaseGroup* const invariantTriangleSetGroup                                  = new TestCaseGroup(m_context, "triangle_set",                                          "Test invariance rule #5");
7481                 TestCaseGroup* const invariantInnerTriangleSetGroup                             = new TestCaseGroup(m_context, "inner_triangle_set",                            "Test invariance rule #6");
7482                 TestCaseGroup* const invariantOuterTriangleSetGroup                             = new TestCaseGroup(m_context, "outer_triangle_set",                            "Test invariance rule #7");
7483                 TestCaseGroup* const tessCoordComponentRangeGroup                               = new TestCaseGroup(m_context, "tess_coord_component_range",            "Test invariance rule #8, first part");
7484                 TestCaseGroup* const oneMinusTessCoordComponentGroup                    = new TestCaseGroup(m_context, "one_minus_tess_coord_component",        "Test invariance rule #8, second part");
7485
7486                 addChild(invarianceGroup);
7487                 invarianceGroup->addChild(invariantPrimitiveSetGroup);
7488                 invarianceGroup->addChild(invariantOuterEdgeGroup);
7489                 invarianceGroup->addChild(symmetricOuterEdgeGroup);
7490                 invarianceGroup->addChild(outerEdgeVertexSetIndexIndependenceGroup);
7491                 invarianceGroup->addChild(invariantTriangleSetGroup);
7492                 invarianceGroup->addChild(invariantInnerTriangleSetGroup);
7493                 invarianceGroup->addChild(invariantOuterTriangleSetGroup);
7494                 invarianceGroup->addChild(tessCoordComponentRangeGroup);
7495                 invarianceGroup->addChild(oneMinusTessCoordComponentGroup);
7496
7497                 for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7498                 {
7499                         const TessPrimitiveType         primitiveType   = (TessPrimitiveType)primitiveTypeI;
7500                         const string                            primName                = getTessPrimitiveTypeShaderName(primitiveType);
7501                         const bool                                      triOrQuad               = primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS;
7502
7503                         for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7504                         {
7505                                 const SpacingMode       spacing                 = (SpacingMode)spacingI;
7506                                 const string            primSpacName    = primName + "_" + getSpacingModeShaderName(spacing);
7507
7508                                 if (triOrQuad)
7509                                 {
7510                                         invariantOuterEdgeGroup->addChild               (new InvariantOuterEdgeCase                     (m_context, primSpacName.c_str(), "", primitiveType, spacing));
7511                                         invariantTriangleSetGroup->addChild             (new InvariantTriangleSetCase           (m_context, primSpacName.c_str(), "", primitiveType, spacing));
7512                                         invariantInnerTriangleSetGroup->addChild(new InvariantInnerTriangleSetCase      (m_context, primSpacName.c_str(), "", primitiveType, spacing));
7513                                         invariantOuterTriangleSetGroup->addChild(new InvariantOuterTriangleSetCase      (m_context, primSpacName.c_str(), "", primitiveType, spacing));
7514                                 }
7515
7516                                 for (int windingI = 0; windingI < WINDING_LAST; windingI++)
7517                                 {
7518                                         const Winding   winding                         = (Winding)windingI;
7519                                         const string    primSpacWindName        = primSpacName + "_" + getWindingShaderName(winding);
7520
7521                                         for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
7522                                         {
7523                                                 const bool              usePointMode                    = usePointModeI != 0;
7524                                                 const string    primSpacWindPointName   = primSpacWindName + (usePointMode ? "_point_mode" : "");
7525
7526                                                 invariantPrimitiveSetGroup->addChild            (new InvariantPrimitiveSetCase                  (m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7527                                                 symmetricOuterEdgeGroup->addChild                       (new SymmetricOuterEdgeCase                             (m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7528                                                 tessCoordComponentRangeGroup->addChild          (new TessCoordComponentRangeCase                (m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7529                                                 oneMinusTessCoordComponentGroup->addChild       (new OneMinusTessCoordComponentCase             (m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7530
7531                                                 if (triOrQuad)
7532                                                         outerEdgeVertexSetIndexIndependenceGroup->addChild(new OuterEdgeVertexSetIndexIndependenceCase(m_context, primSpacWindPointName.c_str(), "",
7533                                                                                                                                                                                                                                                    primitiveType, spacing, winding, usePointMode));
7534                                         }
7535                                 }
7536                         }
7537                 }
7538         }
7539
7540         {
7541                 static const struct
7542                 {
7543                         const char*                                     name;
7544                         const char*                                     description;
7545                         UserDefinedIOCase::IOType       ioType;
7546                 } ioCases[] =
7547                 {
7548                         { "per_patch",                                  "Per-patch TCS outputs",                                        UserDefinedIOCase::IO_TYPE_PER_PATCH                            },
7549                         { "per_patch_array",                    "Per-patch array TCS outputs",                          UserDefinedIOCase::IO_TYPE_PER_PATCH_ARRAY                      },
7550                         { "per_patch_block",                    "Per-patch TCS outputs in IO block",            UserDefinedIOCase::IO_TYPE_PER_PATCH_BLOCK                      },
7551                         { "per_patch_block_array",              "Per-patch TCS outputs in IO block array",      UserDefinedIOCase::IO_TYPE_PER_PATCH_BLOCK_ARRAY        },
7552                         { "per_vertex",                                 "Per-vertex TCS outputs",                                       UserDefinedIOCase::IO_TYPE_PER_VERTEX                           },
7553                         { "per_vertex_block",                   "Per-vertex TCS outputs in IO block",           UserDefinedIOCase::IO_TYPE_PER_VERTEX_BLOCK                     },
7554                 };
7555
7556                 TestCaseGroup* const userDefinedIOGroup = new TestCaseGroup(m_context, "user_defined_io", "Test non-built-in per-patch and per-vertex inputs and outputs");
7557                 addChild(userDefinedIOGroup);
7558
7559                 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(ioCases); ++ndx)
7560                 {
7561                         TestCaseGroup* const ioTypeGroup = new TestCaseGroup(m_context, ioCases[ndx].name, ioCases[ndx].description);
7562                         userDefinedIOGroup->addChild(ioTypeGroup);
7563
7564                         for (int vertexArraySizeI = 0; vertexArraySizeI < UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_LAST; vertexArraySizeI++)
7565                         {
7566                                 const UserDefinedIOCase::VertexIOArraySize      vertexArraySize                 = (UserDefinedIOCase::VertexIOArraySize)vertexArraySizeI;
7567                                 TestCaseGroup* const                                            vertexArraySizeGroup    = new TestCaseGroup(m_context,
7568                                                                                                                                                                                                                 vertexArraySizeI == UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_IMPLICIT
7569                                                                                                                                                                                                                         ? "vertex_io_array_size_implicit"
7570                                                                                                                                                                                                           : vertexArraySizeI == UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN
7571                                                                                                                                                                                                                         ? "vertex_io_array_size_shader_builtin"
7572                                                                                                                                                                                                           : vertexArraySizeI == UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY
7573                                                                                                                                                                                                                         ? "vertex_io_array_size_query"
7574                                                                                                                                                                                                           : DE_NULL,
7575                                                                                                                                                                                                             "");
7576                                 ioTypeGroup->addChild(vertexArraySizeGroup);
7577
7578                                 for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7579                                 {
7580                                         const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7581                                         vertexArraySizeGroup->addChild(new UserDefinedIOCase(m_context, getTessPrimitiveTypeShaderName(primitiveType), "", primitiveType, ioCases[ndx].ioType, vertexArraySize, UserDefinedIOCase::TESS_CONTROL_OUT_ARRAY_SIZE_IMPLICIT,
7582                                                                                                                                                  (string() + "data/tessellation/user_defined_io_" + getTessPrimitiveTypeShaderName(primitiveType) + "_ref.png").c_str()));
7583                                 }
7584
7585                                 if (ioCases[ndx].ioType == UserDefinedIOCase::IO_TYPE_PER_VERTEX
7586                                         || ioCases[ndx].ioType == UserDefinedIOCase::IO_TYPE_PER_VERTEX_BLOCK)
7587                                 {
7588                                         for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7589                                         {
7590                                                 const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7591                                                 vertexArraySizeGroup->addChild(new UserDefinedIOCase(m_context, (string(getTessPrimitiveTypeShaderName(primitiveType)) + "_explicit_tcs_out_size").c_str(), "", primitiveType, ioCases[ndx].ioType, vertexArraySize, UserDefinedIOCase::TESS_CONTROL_OUT_ARRAY_SIZE_LAYOUT,
7592                                                                                                                                                          (string() + "data/tessellation/user_defined_io_" + getTessPrimitiveTypeShaderName(primitiveType) + "_ref.png").c_str()));
7593                                         }
7594                                 }
7595                         }
7596                 }
7597
7598                 {
7599                         TestCaseGroup* const                            negativeGroup   = new TestCaseGroup(m_context, "negative", "Negative cases");
7600                         gls::ShaderLibrary                                      shaderLibrary   (m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
7601                         const std::vector<tcu::TestNode*>       children                = shaderLibrary.loadShaderFile("shaders/tessellation_negative_user_defined_io.test");
7602
7603                         userDefinedIOGroup->addChild(negativeGroup);
7604
7605                         for (int i = 0; i < (int)children.size(); i++)
7606                                 negativeGroup->addChild(children[i]);
7607                 }
7608         }
7609 }
7610
7611 } // Functional
7612 } // gles31
7613 } // deqp