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