Fix missing dependency on sparse binds
[platform/upstream/VK-GL-CTS.git] / modules / glshared / glsDrawTest.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) 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 Draw tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "glsDrawTest.hpp"
25
26 #include "deRandom.h"
27 #include "deRandom.hpp"
28 #include "deMath.h"
29 #include "deStringUtil.hpp"
30 #include "deFloat16.h"
31 #include "deUniquePtr.hpp"
32 #include "deArrayUtil.hpp"
33
34 #include "tcuTestLog.hpp"
35 #include "tcuPixelFormat.hpp"
36 #include "tcuRGBA.hpp"
37 #include "tcuSurface.hpp"
38 #include "tcuVector.hpp"
39 #include "tcuTestLog.hpp"
40 #include "tcuRenderTarget.hpp"
41 #include "tcuStringTemplate.hpp"
42 #include "tcuImageCompare.hpp"
43 #include "tcuFloat.hpp"
44 #include "tcuTextureUtil.hpp"
45
46 #include "gluContextInfo.hpp"
47 #include "gluPixelTransfer.hpp"
48 #include "gluCallLogWrapper.hpp"
49
50 #include "sglrContext.hpp"
51 #include "sglrReferenceContext.hpp"
52 #include "sglrGLContext.hpp"
53
54 #include "rrGenericVector.hpp"
55
56 #include <cstring>
57 #include <cmath>
58 #include <vector>
59 #include <sstream>
60 #include <limits>
61 #include <cstdint>
62
63 #include "glwDefs.hpp"
64 #include "glwEnums.hpp"
65
66 namespace deqp
67 {
68 namespace gls
69 {
70 namespace
71 {
72
73 using tcu::TestLog;
74 using namespace glw; // GL types
75
76 const int MAX_RENDER_TARGET_SIZE = 512;
77
78 // Utils
79
80 static GLenum targetToGL (DrawTestSpec::Target target)
81 {
82         static const GLenum targets[] =
83         {
84                 GL_ELEMENT_ARRAY_BUFFER,        // TARGET_ELEMENT_ARRAY = 0,
85                 GL_ARRAY_BUFFER                         // TARGET_ARRAY,
86         };
87
88         return de::getSizedArrayElement<DrawTestSpec::TARGET_LAST>(targets, (int)target);
89 }
90
91 static GLenum usageToGL (DrawTestSpec::Usage usage)
92 {
93         static const GLenum usages[] =
94         {
95                 GL_DYNAMIC_DRAW,        // USAGE_DYNAMIC_DRAW = 0,
96                 GL_STATIC_DRAW,         // USAGE_STATIC_DRAW,
97                 GL_STREAM_DRAW,         // USAGE_STREAM_DRAW,
98
99                 GL_STREAM_READ,         // USAGE_STREAM_READ,
100                 GL_STREAM_COPY,         // USAGE_STREAM_COPY,
101
102                 GL_STATIC_READ,         // USAGE_STATIC_READ,
103                 GL_STATIC_COPY,         // USAGE_STATIC_COPY,
104
105                 GL_DYNAMIC_READ,        // USAGE_DYNAMIC_READ,
106                 GL_DYNAMIC_COPY         // USAGE_DYNAMIC_COPY,
107         };
108
109         return de::getSizedArrayElement<DrawTestSpec::USAGE_LAST>(usages, (int)usage);
110 }
111
112 static GLenum inputTypeToGL (DrawTestSpec::InputType type)
113 {
114         static const GLenum types[] =
115         {
116                 GL_FLOAT,                               // INPUTTYPE_FLOAT = 0,
117                 GL_FIXED,                               // INPUTTYPE_FIXED,
118                 GL_DOUBLE,                              // INPUTTYPE_DOUBLE
119                 GL_BYTE,                                // INPUTTYPE_BYTE,
120                 GL_SHORT,                               // INPUTTYPE_SHORT,
121                 GL_UNSIGNED_BYTE,               // INPUTTYPE_UNSIGNED_BYTE,
122                 GL_UNSIGNED_SHORT,              // INPUTTYPE_UNSIGNED_SHORT,
123
124                 GL_INT,                                 // INPUTTYPE_INT,
125                 GL_UNSIGNED_INT,                // INPUTTYPE_UNSIGNED_INT,
126                 GL_HALF_FLOAT,                  // INPUTTYPE_HALF,
127                 GL_UNSIGNED_INT_2_10_10_10_REV, // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
128                 GL_INT_2_10_10_10_REV                   // INPUTTYPE_INT_2_10_10_10,
129         };
130
131         return de::getSizedArrayElement<DrawTestSpec::INPUTTYPE_LAST>(types, (int)type);
132 }
133
134 static std::string outputTypeToGLType (DrawTestSpec::OutputType type)
135 {
136         static const char* types[] =
137         {
138                 "float",                // OUTPUTTYPE_FLOAT = 0,
139                 "vec2",                 // OUTPUTTYPE_VEC2,
140                 "vec3",                 // OUTPUTTYPE_VEC3,
141                 "vec4",                 // OUTPUTTYPE_VEC4,
142
143                 "int",                  // OUTPUTTYPE_INT,
144                 "uint",                 // OUTPUTTYPE_UINT,
145
146                 "ivec2",                // OUTPUTTYPE_IVEC2,
147                 "ivec3",                // OUTPUTTYPE_IVEC3,
148                 "ivec4",                // OUTPUTTYPE_IVEC4,
149
150                 "uvec2",                // OUTPUTTYPE_UVEC2,
151                 "uvec3",                // OUTPUTTYPE_UVEC3,
152                 "uvec4",                // OUTPUTTYPE_UVEC4,
153         };
154
155         return de::getSizedArrayElement<DrawTestSpec::OUTPUTTYPE_LAST>(types, (int)type);
156 }
157
158 static GLenum primitiveToGL (DrawTestSpec::Primitive primitive)
159 {
160         static const GLenum primitives[] =
161         {
162                 GL_POINTS,                                              // PRIMITIVE_POINTS = 0,
163                 GL_TRIANGLES,                                   // PRIMITIVE_TRIANGLES,
164                 GL_TRIANGLE_FAN,                                // PRIMITIVE_TRIANGLE_FAN,
165                 GL_TRIANGLE_STRIP,                              // PRIMITIVE_TRIANGLE_STRIP,
166                 GL_LINES,                                               // PRIMITIVE_LINES
167                 GL_LINE_STRIP,                                  // PRIMITIVE_LINE_STRIP
168                 GL_LINE_LOOP,                                   // PRIMITIVE_LINE_LOOP
169                 GL_LINES_ADJACENCY,                             // PRIMITIVE_LINES_ADJACENCY
170                 GL_LINE_STRIP_ADJACENCY,                // PRIMITIVE_LINE_STRIP_ADJACENCY
171                 GL_TRIANGLES_ADJACENCY,                 // PRIMITIVE_TRIANGLES_ADJACENCY
172                 GL_TRIANGLE_STRIP_ADJACENCY,    // PRIMITIVE_TRIANGLE_STRIP_ADJACENCY
173         };
174
175         return de::getSizedArrayElement<DrawTestSpec::PRIMITIVE_LAST>(primitives, (int)primitive);
176 }
177
178 static deUint32 indexTypeToGL (DrawTestSpec::IndexType indexType)
179 {
180         static const GLenum indexTypes[] =
181         {
182                 GL_UNSIGNED_BYTE,       // INDEXTYPE_BYTE = 0,
183                 GL_UNSIGNED_SHORT,      // INDEXTYPE_SHORT,
184                 GL_UNSIGNED_INT,        // INDEXTYPE_INT,
185         };
186
187         return de::getSizedArrayElement<DrawTestSpec::INDEXTYPE_LAST>(indexTypes, (int)indexType);
188 }
189
190 static bool inputTypeIsFloatType (DrawTestSpec::InputType type)
191 {
192         if (type == DrawTestSpec::INPUTTYPE_FLOAT)
193                 return true;
194         if (type == DrawTestSpec::INPUTTYPE_FIXED)
195                 return true;
196         if (type == DrawTestSpec::INPUTTYPE_HALF)
197                 return true;
198         if (type == DrawTestSpec::INPUTTYPE_DOUBLE)
199                 return true;
200         return false;
201 }
202
203 static bool outputTypeIsFloatType (DrawTestSpec::OutputType type)
204 {
205         if (type == DrawTestSpec::OUTPUTTYPE_FLOAT
206                 || type == DrawTestSpec::OUTPUTTYPE_VEC2
207                 || type == DrawTestSpec::OUTPUTTYPE_VEC3
208                 || type == DrawTestSpec::OUTPUTTYPE_VEC4)
209                 return true;
210
211         return false;
212 }
213
214 static bool outputTypeIsIntType (DrawTestSpec::OutputType type)
215 {
216         if (type == DrawTestSpec::OUTPUTTYPE_INT
217                 || type == DrawTestSpec::OUTPUTTYPE_IVEC2
218                 || type == DrawTestSpec::OUTPUTTYPE_IVEC3
219                 || type == DrawTestSpec::OUTPUTTYPE_IVEC4)
220                 return true;
221
222         return false;
223 }
224
225 static bool outputTypeIsUintType (DrawTestSpec::OutputType type)
226 {
227         if (type == DrawTestSpec::OUTPUTTYPE_UINT
228                 || type == DrawTestSpec::OUTPUTTYPE_UVEC2
229                 || type == DrawTestSpec::OUTPUTTYPE_UVEC3
230                 || type == DrawTestSpec::OUTPUTTYPE_UVEC4)
231                 return true;
232
233         return false;
234 }
235
236 static size_t getElementCount (DrawTestSpec::Primitive primitive, size_t primitiveCount)
237 {
238         switch (primitive)
239         {
240                 case DrawTestSpec::PRIMITIVE_POINTS:                                            return primitiveCount;
241                 case DrawTestSpec::PRIMITIVE_TRIANGLES:                                         return primitiveCount * 3;
242                 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:                                      return primitiveCount + 2;
243                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:                            return primitiveCount + 2;
244                 case DrawTestSpec::PRIMITIVE_LINES:                                                     return primitiveCount * 2;
245                 case DrawTestSpec::PRIMITIVE_LINE_STRIP:                                        return primitiveCount + 1;
246                 case DrawTestSpec::PRIMITIVE_LINE_LOOP:                                         return (primitiveCount==1) ? (2) : (primitiveCount);
247                 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:                           return primitiveCount * 4;
248                 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:                      return primitiveCount + 3;
249                 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:                       return primitiveCount * 6;
250                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:          return primitiveCount * 2 + 4;
251                 default:
252                         DE_ASSERT(false);
253                         return 0;
254         }
255 }
256
257 struct MethodInfo
258 {
259         bool indexed;
260         bool instanced;
261         bool ranged;
262         bool first;
263         bool baseVertex;
264         bool indirect;
265 };
266
267 static MethodInfo getMethodInfo (gls::DrawTestSpec::DrawMethod method)
268 {
269         static const MethodInfo infos[] =
270         {
271                 //      indexed         instanced       ranged          first           baseVertex      indirect
272                 {       false,          false,          false,          true,           false,          false   }, //!< DRAWMETHOD_DRAWARRAYS,
273                 {       false,          true,           false,          true,           false,          false   }, //!< DRAWMETHOD_DRAWARRAYS_INSTANCED,
274                 {       false,          true,           false,          true,           false,          true    }, //!< DRAWMETHOD_DRAWARRAYS_INDIRECT,
275                 {       true,           false,          false,          false,          false,          false   }, //!< DRAWMETHOD_DRAWELEMENTS,
276                 {       true,           false,          true,           false,          false,          false   }, //!< DRAWMETHOD_DRAWELEMENTS_RANGED,
277                 {       true,           true,           false,          false,          false,          false   }, //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED,
278                 {       true,           true,           false,          false,          true,           true    }, //!< DRAWMETHOD_DRAWELEMENTS_INDIRECT,
279                 {       true,           false,          false,          false,          true,           false   }, //!< DRAWMETHOD_DRAWELEMENTS_BASEVERTEX,
280                 {       true,           true,           false,          false,          true,           false   }, //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX,
281                 {       true,           false,          true,           false,          true,           false   }, //!< DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX,
282         };
283
284         return de::getSizedArrayElement<DrawTestSpec::DRAWMETHOD_LAST>(infos, (int)method);
285 }
286
287 template<class T>
288 inline static void alignmentSafeAssignment (char* dst, T val)
289 {
290         std::memcpy(dst, &val, sizeof(T));
291 }
292
293 static bool checkSpecsShaderCompatible (const DrawTestSpec& a, const DrawTestSpec& b)
294 {
295         // Only the attributes matter
296         if (a.attribs.size() != b.attribs.size())
297                 return false;
298
299         for (size_t ndx = 0; ndx < a.attribs.size(); ++ndx)
300         {
301                 // Only the output type (== shader input type) matters and the usage in the shader.
302
303                 if (a.attribs[ndx].additionalPositionAttribute != b.attribs[ndx].additionalPositionAttribute)
304                         return false;
305
306                 // component counts need not to match
307                 if (outputTypeIsFloatType(a.attribs[ndx].outputType) && outputTypeIsFloatType(b.attribs[ndx].outputType))
308                         continue;
309                 if (outputTypeIsIntType(a.attribs[ndx].outputType) && outputTypeIsIntType(b.attribs[ndx].outputType))
310                         continue;
311                 if (outputTypeIsUintType(a.attribs[ndx].outputType) && outputTypeIsUintType(b.attribs[ndx].outputType))
312                         continue;
313
314                 return false;
315         }
316
317         return true;
318 }
319
320 // generate random vectors in a way that does not depend on argument evaluation order
321
322 tcu::Vec4 generateRandomVec4 (de::Random& random)
323 {
324         tcu::Vec4 retVal;
325
326         for (int i = 0; i < 4; ++i)
327                 retVal[i] = random.getFloat();
328
329         return retVal;
330 }
331
332 tcu::IVec4 generateRandomIVec4 (de::Random& random)
333 {
334         tcu::IVec4 retVal;
335
336         for (int i = 0; i < 4; ++i)
337                 retVal[i] = random.getUint32();
338
339         return retVal;
340 }
341
342 tcu::UVec4 generateRandomUVec4 (de::Random& random)
343 {
344         tcu::UVec4 retVal;
345
346         for (int i = 0; i < 4; ++i)
347                 retVal[i] = random.getUint32();
348
349         return retVal;
350 }
351
352 // IterationLogSectionEmitter
353
354 class IterationLogSectionEmitter
355 {
356 public:
357                                                                 IterationLogSectionEmitter              (tcu::TestLog& log, size_t testIteration, size_t testIterations, const std::string& description, bool enabled);
358                                                                 ~IterationLogSectionEmitter             (void);
359 private:
360                                                                 IterationLogSectionEmitter              (const IterationLogSectionEmitter&); // delete
361         IterationLogSectionEmitter&     operator=                                               (const IterationLogSectionEmitter&); // delete
362
363         tcu::TestLog&                           m_log;
364         bool                                            m_enabled;
365 };
366
367 IterationLogSectionEmitter::IterationLogSectionEmitter (tcu::TestLog& log, size_t testIteration, size_t testIterations, const std::string& description, bool enabled)
368         : m_log         (log)
369         , m_enabled     (enabled)
370 {
371         if (m_enabled)
372         {
373                 std::ostringstream buf;
374                 buf << "Iteration " << (testIteration+1) << "/" << testIterations;
375
376                 if (!description.empty())
377                         buf << " - " << description;
378
379                 m_log << tcu::TestLog::Section(buf.str(), buf.str());
380         }
381 }
382
383 IterationLogSectionEmitter::~IterationLogSectionEmitter (void)
384 {
385         if (m_enabled)
386                 m_log << tcu::TestLog::EndSection;
387 }
388
389 // GLValue
390
391 class GLValue
392 {
393 public:
394
395         template<class Type>
396         class WrappedType
397         {
398         public:
399                 static WrappedType<Type>        create                  (Type value)                                                    { WrappedType<Type> v; v.m_value = value; return v; }
400                 inline Type                                     getValue                (void) const                                                    { return m_value; }
401
402                 inline WrappedType<Type>        operator+               (const WrappedType<Type>& other) const  { return WrappedType<Type>::create((Type)(m_value + other.getValue())); }
403                 inline WrappedType<Type>        operator*               (const WrappedType<Type>& other) const  { return WrappedType<Type>::create((Type)(m_value * other.getValue())); }
404                 inline WrappedType<Type>        operator/               (const WrappedType<Type>& other) const  { return WrappedType<Type>::create((Type)(m_value / other.getValue())); }
405                 inline WrappedType<Type>        operator-               (const WrappedType<Type>& other) const  { return WrappedType<Type>::create((Type)(m_value - other.getValue())); }
406
407                 inline WrappedType<Type>&       operator+=              (const WrappedType<Type>& other)                { m_value += other.getValue(); return *this; }
408                 inline WrappedType<Type>&       operator*=              (const WrappedType<Type>& other)                { m_value *= other.getValue(); return *this; }
409                 inline WrappedType<Type>&       operator/=              (const WrappedType<Type>& other)                { m_value /= other.getValue(); return *this; }
410                 inline WrappedType<Type>&       operator-=              (const WrappedType<Type>& other)                { m_value -= other.getValue(); return *this; }
411
412                 inline bool                                     operator==              (const WrappedType<Type>& other) const  { return m_value == other.m_value; }
413                 inline bool                                     operator!=              (const WrappedType<Type>& other) const  { return m_value != other.m_value; }
414                 inline bool                                     operator<               (const WrappedType<Type>& other) const  { return m_value < other.m_value; }
415                 inline bool                                     operator>               (const WrappedType<Type>& other) const  { return m_value > other.m_value; }
416                 inline bool                                     operator<=              (const WrappedType<Type>& other) const  { return m_value <= other.m_value; }
417                 inline bool                                     operator>=              (const WrappedType<Type>& other) const  { return m_value >= other.m_value; }
418
419                 inline                                          operator Type   (void) const                                                    { return m_value; }
420                 template<class T>
421                 inline T                                        to                              (void) const                                                    { return (T)m_value; }
422         private:
423                 Type    m_value;
424         };
425
426         typedef WrappedType<deInt16>    Short;
427         typedef WrappedType<deUint16>   Ushort;
428
429         typedef WrappedType<deInt8>             Byte;
430         typedef WrappedType<deUint8>    Ubyte;
431
432         typedef WrappedType<float>              Float;
433         typedef WrappedType<double>             Double;
434
435         typedef WrappedType<deUint32>   Uint;
436
437         // All operations are calculated using 64bit values to avoid signed integer overflow which is undefined.
438         class Int
439         {
440         public:
441                 static Int              create                          (deInt32 value)                         { Int v; v.m_value = value; return v; }
442                 inline deInt32  getValue                        (void) const                            { return m_value; }
443
444                 inline Int              operator+                       (const Int& other) const        { return Int::create((deInt32)((deInt64)m_value + (deInt64)other.getValue())); }
445                 inline Int              operator*                       (const Int& other) const        { return Int::create((deInt32)((deInt64)m_value * (deInt64)other.getValue())); }
446                 inline Int              operator/                       (const Int& other) const        { return Int::create((deInt32)((deInt64)m_value / (deInt64)other.getValue())); }
447                 inline Int              operator-                       (const Int& other) const        { return Int::create((deInt32)((deInt64)m_value - (deInt64)other.getValue())); }
448
449                 inline Int&             operator+=                      (const Int& other)                      { m_value = (deInt32)((deInt64)m_value + (deInt64)other.getValue()); return *this; }
450                 inline Int&             operator*=                      (const Int& other)                      { m_value = (deInt32)((deInt64)m_value * (deInt64)other.getValue()); return *this; }
451                 inline Int&             operator/=                      (const Int& other)                      { m_value = (deInt32)((deInt64)m_value / (deInt64)other.getValue()); return *this; }
452                 inline Int&             operator-=                      (const Int& other)                      { m_value = (deInt32)((deInt64)m_value - (deInt64)other.getValue()); return *this; }
453
454                 inline bool             operator==                      (const Int& other) const        { return m_value == other.m_value; }
455                 inline bool             operator!=                      (const Int& other) const        { return m_value != other.m_value; }
456                 inline bool             operator<                       (const Int& other) const        { return m_value < other.m_value; }
457                 inline bool             operator>                       (const Int& other) const        { return m_value > other.m_value; }
458                 inline bool             operator<=                      (const Int& other) const        { return m_value <= other.m_value; }
459                 inline bool             operator>=                      (const Int& other) const        { return m_value >= other.m_value; }
460
461                 inline                  operator deInt32        (void) const                            { return m_value; }
462                 template<class T>
463                 inline T                to                                      (void) const                            { return (T)m_value; }
464         private:
465                 deInt32 m_value;
466         };
467
468         class Half
469         {
470         public:
471                 static Half                     create                  (float value)                           { Half h; h.m_value = floatToHalf(value); return h; }
472                 inline deFloat16        getValue                (void) const                            { return m_value; }
473
474                 inline Half                     operator+               (const Half& other) const       { return create(halfToFloat(m_value) + halfToFloat(other.getValue())); }
475                 inline Half                     operator*               (const Half& other) const       { return create(halfToFloat(m_value) * halfToFloat(other.getValue())); }
476                 inline Half                     operator/               (const Half& other) const       { return create(halfToFloat(m_value) / halfToFloat(other.getValue())); }
477                 inline Half                     operator-               (const Half& other) const       { return create(halfToFloat(m_value) - halfToFloat(other.getValue())); }
478
479                 inline Half&            operator+=              (const Half& other)                     { m_value = floatToHalf(halfToFloat(other.getValue()) + halfToFloat(m_value)); return *this; }
480                 inline Half&            operator*=              (const Half& other)                     { m_value = floatToHalf(halfToFloat(other.getValue()) * halfToFloat(m_value)); return *this; }
481                 inline Half&            operator/=              (const Half& other)                     { m_value = floatToHalf(halfToFloat(other.getValue()) / halfToFloat(m_value)); return *this; }
482                 inline Half&            operator-=              (const Half& other)                     { m_value = floatToHalf(halfToFloat(other.getValue()) - halfToFloat(m_value)); return *this; }
483
484                 inline bool                     operator==              (const Half& other) const       { return m_value == other.m_value; }
485                 inline bool                     operator!=              (const Half& other) const       { return m_value != other.m_value; }
486                 inline bool                     operator<               (const Half& other) const       { return halfToFloat(m_value) < halfToFloat(other.m_value); }
487                 inline bool                     operator>               (const Half& other) const       { return halfToFloat(m_value) > halfToFloat(other.m_value); }
488                 inline bool                     operator<=              (const Half& other) const       { return halfToFloat(m_value) <= halfToFloat(other.m_value); }
489                 inline bool                     operator>=              (const Half& other) const       { return halfToFloat(m_value) >= halfToFloat(other.m_value); }
490
491                 template<class T>
492                 inline T                        to                              (void) const                            { return (T)halfToFloat(m_value); }
493
494                 inline static deFloat16 floatToHalf             (float f);
495                 inline static float             halfToFloat             (deFloat16 h);
496         private:
497                 deFloat16 m_value;
498         };
499
500         class Fixed
501         {
502         public:
503                 static Fixed            create                  (deInt32 value)                         { Fixed v; v.m_value = value; return v; }
504                 inline deInt32          getValue                (void) const                            { return m_value; }
505
506                 inline Fixed            operator+               (const Fixed& other) const      { return create(m_value + other.getValue()); }
507                 inline Fixed            operator*               (const Fixed& other) const      { return create(m_value * other.getValue()); }
508                 inline Fixed            operator/               (const Fixed& other) const      { return create(m_value / other.getValue()); }
509                 inline Fixed            operator-               (const Fixed& other) const      { return create(m_value - other.getValue()); }
510
511                 inline Fixed&           operator+=              (const Fixed& other)            { m_value += other.getValue(); return *this; }
512                 inline Fixed&           operator*=              (const Fixed& other)            { m_value *= other.getValue(); return *this; }
513                 inline Fixed&           operator/=              (const Fixed& other)            { m_value /= other.getValue(); return *this; }
514                 inline Fixed&           operator-=              (const Fixed& other)            { m_value -= other.getValue(); return *this; }
515
516                 inline bool                     operator==              (const Fixed& other) const      { return m_value == other.m_value; }
517                 inline bool                     operator!=              (const Fixed& other) const      { return m_value != other.m_value; }
518                 inline bool                     operator<               (const Fixed& other) const      { return m_value < other.m_value; }
519                 inline bool                     operator>               (const Fixed& other) const      { return m_value > other.m_value; }
520                 inline bool                     operator<=              (const Fixed& other) const      { return m_value <= other.m_value; }
521                 inline bool                     operator>=              (const Fixed& other) const      { return m_value >= other.m_value; }
522
523                 inline                          operator deInt32 (void) const                           { return m_value; }
524                 template<class T>
525                 inline T                        to                              (void) const                            { return (T)m_value; }
526         private:
527                 deInt32                         m_value;
528         };
529
530         // \todo [mika] This is pretty messy
531                                                 GLValue                 (void)                  : type(DrawTestSpec::INPUTTYPE_LAST) {}
532         explicit                        GLValue                 (Float value)   : type(DrawTestSpec::INPUTTYPE_FLOAT),                          fl(value)       {}
533         explicit                        GLValue                 (Fixed value)   : type(DrawTestSpec::INPUTTYPE_FIXED),                          fi(value)       {}
534         explicit                        GLValue                 (Byte value)    : type(DrawTestSpec::INPUTTYPE_BYTE),                           b(value)        {}
535         explicit                        GLValue                 (Ubyte value)   : type(DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE),          ub(value)       {}
536         explicit                        GLValue                 (Short value)   : type(DrawTestSpec::INPUTTYPE_SHORT),                          s(value)        {}
537         explicit                        GLValue                 (Ushort value)  : type(DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT),         us(value)       {}
538         explicit                        GLValue                 (Int value)             : type(DrawTestSpec::INPUTTYPE_INT),                            i(value)        {}
539         explicit                        GLValue                 (Uint value)    : type(DrawTestSpec::INPUTTYPE_UNSIGNED_INT),           ui(value)       {}
540         explicit                        GLValue                 (Half value)    : type(DrawTestSpec::INPUTTYPE_HALF),                           h(value)        {}
541         explicit                        GLValue                 (Double value)  : type(DrawTestSpec::INPUTTYPE_DOUBLE),                         d(value)        {}
542
543         float                           toFloat                 (void) const;
544
545         static GLValue          getMaxValue             (DrawTestSpec::InputType type);
546         static GLValue          getMinValue             (DrawTestSpec::InputType type);
547
548         DrawTestSpec::InputType type;
549
550         union
551         {
552                 Float           fl;
553                 Fixed           fi;
554                 Double          d;
555                 Byte            b;
556                 Ubyte           ub;
557                 Short           s;
558                 Ushort          us;
559                 Int                     i;
560                 Uint            ui;
561                 Half            h;
562         };
563 };
564
565 inline deFloat16 GLValue::Half::floatToHalf (float f)
566 {
567         // No denorm support.
568         tcu::Float<deUint16, 5, 10, 15, tcu::FLOAT_HAS_SIGN> v(f);
569         DE_ASSERT(!v.isNaN() && !v.isInf());
570         return v.bits();
571 }
572
573 inline float GLValue::Half::halfToFloat (deFloat16 h)
574 {
575         return tcu::Float16((deUint16)h).asFloat();
576 }
577
578 float GLValue::toFloat (void) const
579 {
580         switch (type)
581         {
582                 case DrawTestSpec::INPUTTYPE_FLOAT:
583                         return fl.getValue();
584
585                 case DrawTestSpec::INPUTTYPE_BYTE:
586                         return b.getValue();
587
588                 case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE:
589                         return ub.getValue();
590
591                 case DrawTestSpec::INPUTTYPE_SHORT:
592                         return s.getValue();
593
594                 case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT:
595                         return us.getValue();
596
597                 case DrawTestSpec::INPUTTYPE_FIXED:
598                 {
599                         int maxValue = 65536;
600                         return (float)(double(2 * fi.getValue() + 1) / (maxValue - 1));
601                 }
602
603                 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
604                         return (float)ui.getValue();
605
606                 case DrawTestSpec::INPUTTYPE_INT:
607                         return (float)i.getValue();
608
609                 case DrawTestSpec::INPUTTYPE_HALF:
610                         return h.to<float>();
611
612                 case DrawTestSpec::INPUTTYPE_DOUBLE:
613                         return d.to<float>();
614
615                 default:
616                         DE_ASSERT(false);
617                         return 0.0f;
618         }
619 }
620
621 GLValue GLValue::getMaxValue (DrawTestSpec::InputType type)
622 {
623         GLValue rangesHi[(int)DrawTestSpec::INPUTTYPE_LAST];
624
625         rangesHi[(int)DrawTestSpec::INPUTTYPE_FLOAT]                    = GLValue(Float::create(127.0f));
626         rangesHi[(int)DrawTestSpec::INPUTTYPE_DOUBLE]                   = GLValue(Double::create(127.0f));
627         rangesHi[(int)DrawTestSpec::INPUTTYPE_BYTE]                             = GLValue(Byte::create(127));
628         rangesHi[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE]    = GLValue(Ubyte::create(255));
629         rangesHi[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT]   = GLValue(Ushort::create(65530));
630         rangesHi[(int)DrawTestSpec::INPUTTYPE_SHORT]                    = GLValue(Short::create(32760));
631         rangesHi[(int)DrawTestSpec::INPUTTYPE_FIXED]                    = GLValue(Fixed::create(32760));
632         rangesHi[(int)DrawTestSpec::INPUTTYPE_INT]                              = GLValue(Int::create(2147483647));
633         rangesHi[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_INT]             = GLValue(Uint::create(4294967295u));
634         rangesHi[(int)DrawTestSpec::INPUTTYPE_HALF]                             = GLValue(Half::create(256.0f));
635
636         return rangesHi[(int)type];
637 }
638
639 GLValue GLValue::getMinValue (DrawTestSpec::InputType type)
640 {
641         GLValue rangesLo[(int)DrawTestSpec::INPUTTYPE_LAST];
642
643         rangesLo[(int)DrawTestSpec::INPUTTYPE_FLOAT]                    = GLValue(Float::create(-127.0f));
644         rangesLo[(int)DrawTestSpec::INPUTTYPE_DOUBLE]                   = GLValue(Double::create(-127.0f));
645         rangesLo[(int)DrawTestSpec::INPUTTYPE_BYTE]                             = GLValue(Byte::create(-127));
646         rangesLo[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE]    = GLValue(Ubyte::create(0));
647         rangesLo[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT]   = GLValue(Ushort::create(0));
648         rangesLo[(int)DrawTestSpec::INPUTTYPE_SHORT]                    = GLValue(Short::create(-32760));
649         rangesLo[(int)DrawTestSpec::INPUTTYPE_FIXED]                    = GLValue(Fixed::create(-32760));
650         rangesLo[(int)DrawTestSpec::INPUTTYPE_INT]                              = GLValue(Int::create(-2147483647));
651         rangesLo[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_INT]             = GLValue(Uint::create(0));
652         rangesLo[(int)DrawTestSpec::INPUTTYPE_HALF]                             = GLValue(Half::create(-256.0f));
653
654         return rangesLo[(int)type];
655 }
656
657 template<typename T>
658 struct GLValueTypeTraits;
659
660 template<> struct GLValueTypeTraits<GLValue::Float>      { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_FLOAT;                   };
661 template<> struct GLValueTypeTraits<GLValue::Double> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_DOUBLE;                      };
662 template<> struct GLValueTypeTraits<GLValue::Byte>       { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_BYTE;                    };
663 template<> struct GLValueTypeTraits<GLValue::Ubyte>      { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE;   };
664 template<> struct GLValueTypeTraits<GLValue::Ushort> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT;      };
665 template<> struct GLValueTypeTraits<GLValue::Short>      { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_SHORT;                   };
666 template<> struct GLValueTypeTraits<GLValue::Fixed>      { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_FIXED;                   };
667 template<> struct GLValueTypeTraits<GLValue::Int>        { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_INT;                     };
668 template<> struct GLValueTypeTraits<GLValue::Uint>       { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_UNSIGNED_INT;    };
669 template<> struct GLValueTypeTraits<GLValue::Half>       { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_HALF;                    };
670
671 template<typename T>
672 inline T extractGLValue (const GLValue& v);
673
674 template<> GLValue::Float       inline extractGLValue<GLValue::Float>           (const GLValue& v) { return v.fl; }
675 template<> GLValue::Double      inline extractGLValue<GLValue::Double>          (const GLValue& v) { return v.d; }
676 template<> GLValue::Byte        inline extractGLValue<GLValue::Byte>            (const GLValue& v) { return v.b; }
677 template<> GLValue::Ubyte       inline extractGLValue<GLValue::Ubyte>           (const GLValue& v) { return v.ub; }
678 template<> GLValue::Ushort      inline extractGLValue<GLValue::Ushort>          (const GLValue& v) { return v.us; }
679 template<> GLValue::Short       inline extractGLValue<GLValue::Short>           (const GLValue& v) { return v.s; }
680 template<> GLValue::Fixed       inline extractGLValue<GLValue::Fixed>           (const GLValue& v) { return v.fi; }
681 template<> GLValue::Int         inline extractGLValue<GLValue::Int>                     (const GLValue& v) { return v.i; }
682 template<> GLValue::Uint        inline extractGLValue<GLValue::Uint>            (const GLValue& v) { return v.ui; }
683 template<> GLValue::Half        inline extractGLValue<GLValue::Half>            (const GLValue& v) { return v.h; }
684
685 template<class T>
686 inline T getRandom (deRandom& rnd, T min, T max);
687
688 template<>
689 inline GLValue::Float getRandom (deRandom& rnd, GLValue::Float min, GLValue::Float max)
690 {
691         if (max < min)
692                 return min;
693
694         return GLValue::Float::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>()));
695 }
696
697 template<>
698 inline GLValue::Double getRandom (deRandom& rnd, GLValue::Double min, GLValue::Double max)
699 {
700         if (max < min)
701                 return min;
702
703         return GLValue::Double::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>()));
704 }
705
706 template<>
707 inline GLValue::Short getRandom (deRandom& rnd, GLValue::Short min, GLValue::Short max)
708 {
709         if (max < min)
710                 return min;
711
712         return GLValue::Short::create((min == max ? min : (deInt16)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
713 }
714
715 template<>
716 inline GLValue::Ushort getRandom (deRandom& rnd, GLValue::Ushort min, GLValue::Ushort max)
717 {
718         if (max < min)
719                 return min;
720
721         return GLValue::Ushort::create((min == max ? min : (deUint16)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
722 }
723
724 template<>
725 inline GLValue::Byte getRandom (deRandom& rnd, GLValue::Byte min, GLValue::Byte max)
726 {
727         if (max < min)
728                 return min;
729
730         return GLValue::Byte::create((min == max ? min : (deInt8)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
731 }
732
733 template<>
734 inline GLValue::Ubyte getRandom (deRandom& rnd, GLValue::Ubyte min, GLValue::Ubyte max)
735 {
736         if (max < min)
737                 return min;
738
739         return GLValue::Ubyte::create((min == max ? min : (deUint8)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
740 }
741
742 template<>
743 inline GLValue::Fixed getRandom (deRandom& rnd, GLValue::Fixed min, GLValue::Fixed max)
744 {
745         if (max < min)
746                 return min;
747
748         return GLValue::Fixed::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
749 }
750
751 template<>
752 inline GLValue::Half getRandom (deRandom& rnd, GLValue::Half min, GLValue::Half max)
753 {
754         if (max < min)
755                 return min;
756
757         float fMax = max.to<float>();
758         float fMin = min.to<float>();
759         GLValue::Half h = GLValue::Half::create(fMin + deRandom_getFloat(&rnd) * (fMax - fMin));
760         return h;
761 }
762
763 template<>
764 inline GLValue::Int getRandom (deRandom& rnd, GLValue::Int min, GLValue::Int max)
765 {
766         if (max < min)
767                 return min;
768
769         return GLValue::Int::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
770 }
771
772 template<>
773 inline GLValue::Uint getRandom (deRandom& rnd, GLValue::Uint min, GLValue::Uint max)
774 {
775         if (max < min)
776                 return min;
777
778         return GLValue::Uint::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
779 }
780
781 // Minimum difference required between coordinates
782 template<class T>
783 inline T minValue (void);
784
785 template<>
786 inline GLValue::Float minValue (void)
787 {
788         return GLValue::Float::create(4 * 1.0f);
789 }
790
791 template<>
792 inline GLValue::Double minValue (void)
793 {
794         return GLValue::Double::create(4 * 1.0f);
795 }
796
797 template<>
798 inline GLValue::Short minValue (void)
799 {
800         return GLValue::Short::create(4 * 256);
801 }
802
803 template<>
804 inline GLValue::Ushort minValue (void)
805 {
806         return GLValue::Ushort::create(4 * 256);
807 }
808
809 template<>
810 inline GLValue::Byte minValue (void)
811 {
812         return GLValue::Byte::create(4 * 1);
813 }
814
815 template<>
816 inline GLValue::Ubyte minValue (void)
817 {
818         return GLValue::Ubyte::create(4 * 2);
819 }
820
821 template<>
822 inline GLValue::Fixed minValue (void)
823 {
824         return GLValue::Fixed::create(4 * 1);
825 }
826
827 template<>
828 inline GLValue::Int minValue (void)
829 {
830         return GLValue::Int::create(4 * 16777216);
831 }
832
833 template<>
834 inline GLValue::Uint minValue (void)
835 {
836         return GLValue::Uint::create(4 * 16777216);
837 }
838
839 template<>
840 inline GLValue::Half minValue (void)
841 {
842         return GLValue::Half::create(4 * 1.0f);
843 }
844
845 template<class T>
846 inline T abs (T val);
847
848 template<>
849 inline GLValue::Fixed abs (GLValue::Fixed val)
850 {
851         return GLValue::Fixed::create(0x7FFFu & val.getValue());
852 }
853
854 template<>
855 inline GLValue::Ubyte abs (GLValue::Ubyte val)
856 {
857         return val;
858 }
859
860 template<>
861 inline GLValue::Byte abs (GLValue::Byte val)
862 {
863         return GLValue::Byte::create(0x7Fu & val.getValue());
864 }
865
866 template<>
867 inline GLValue::Ushort abs (GLValue::Ushort val)
868 {
869         return val;
870 }
871
872 template<>
873 inline GLValue::Short abs (GLValue::Short val)
874 {
875         return GLValue::Short::create(0x7FFFu & val.getValue());
876 }
877
878 template<>
879 inline GLValue::Float abs (GLValue::Float val)
880 {
881         return GLValue::Float::create(std::fabs(val.to<float>()));
882 }
883
884 template<>
885 inline GLValue::Double abs (GLValue::Double val)
886 {
887         return GLValue::Double::create(std::fabs(val.to<float>()));
888 }
889
890 template<>
891 inline GLValue::Uint abs (GLValue::Uint val)
892 {
893         return val;
894 }
895
896 template<>
897 inline GLValue::Int abs (GLValue::Int val)
898 {
899         return GLValue::Int::create(0x7FFFFFFFu & val.getValue());
900 }
901
902 template<>
903 inline GLValue::Half abs (GLValue::Half val)
904 {
905         return GLValue::Half::create(std::fabs(val.to<float>()));
906 }
907
908 // AttributeArray
909
910 class AttributeArray
911 {
912 public:
913                                                                 AttributeArray          (DrawTestSpec::Storage storage, sglr::Context& context);
914                                                                 ~AttributeArray         (void);
915
916         void                                            data                            (DrawTestSpec::Target target, size_t size, const char* data, DrawTestSpec::Usage usage);
917         void                                            setupArray                      (bool bound, int offset, int size, DrawTestSpec::InputType inType, DrawTestSpec::OutputType outType, bool normalized, int stride, int instanceDivisor, const rr::GenericVec4& defaultAttrib, bool isPositionAttr, bool bgraComponentOrder);
918         void                                            bindAttribute           (deUint32 loc);
919         void                                            bindIndexArray          (DrawTestSpec::Target storage);
920
921         int                                                     getComponentCount       (void) const { return m_componentCount; }
922         DrawTestSpec::Target            getTarget                       (void) const { return m_target; }
923         DrawTestSpec::InputType         getInputType            (void) const { return m_inputType; }
924         DrawTestSpec::OutputType        getOutputType           (void) const { return m_outputType; }
925         DrawTestSpec::Storage           getStorageType          (void) const { return m_storage; }
926         bool                                            getNormalized           (void) const { return m_normalize; }
927         int                                                     getStride                       (void) const { return m_stride; }
928         bool                                            isBound                         (void) const { return m_bound; }
929         bool                                            isPositionAttribute     (void) const { return m_isPositionAttr; }
930
931 private:
932         DrawTestSpec::Storage           m_storage;
933         sglr::Context&                          m_ctx;
934         deUint32                                        m_glBuffer;
935
936         int                                                     m_size;
937         char*                                           m_data;
938         int                                                     m_componentCount;
939         bool                                            m_bound;
940         DrawTestSpec::Target            m_target;
941         DrawTestSpec::InputType         m_inputType;
942         DrawTestSpec::OutputType        m_outputType;
943         bool                                            m_normalize;
944         int                                                     m_stride;
945         int                                                     m_offset;
946         rr::GenericVec4                         m_defaultAttrib;
947         int                                                     m_instanceDivisor;
948         bool                                            m_isPositionAttr;
949         bool                                            m_bgraOrder;
950 };
951
952 AttributeArray::AttributeArray (DrawTestSpec::Storage storage, sglr::Context& context)
953         : m_storage                     (storage)
954         , m_ctx                         (context)
955         , m_glBuffer            (0)
956         , m_size                        (0)
957         , m_data                        (DE_NULL)
958         , m_componentCount      (1)
959         , m_bound                       (false)
960         , m_target                      (DrawTestSpec::TARGET_ARRAY)
961         , m_inputType           (DrawTestSpec::INPUTTYPE_FLOAT)
962         , m_outputType          (DrawTestSpec::OUTPUTTYPE_VEC4)
963         , m_normalize           (false)
964         , m_stride                      (0)
965         , m_offset                      (0)
966         , m_instanceDivisor     (0)
967         , m_isPositionAttr      (false)
968         , m_bgraOrder           (false)
969 {
970         if (m_storage == DrawTestSpec::STORAGE_BUFFER)
971         {
972                 m_ctx.genBuffers(1, &m_glBuffer);
973                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glGenBuffers()");
974         }
975 }
976
977 AttributeArray::~AttributeArray (void)
978 {
979         if (m_storage == DrawTestSpec::STORAGE_BUFFER)
980         {
981                 m_ctx.deleteBuffers(1, &m_glBuffer);
982                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDeleteBuffers()");
983         }
984         else if (m_storage == DrawTestSpec::STORAGE_USER)
985                 delete[] m_data;
986         else
987                 DE_ASSERT(false);
988 }
989
990 void AttributeArray::data (DrawTestSpec::Target target, size_t size, const char* ptr, DrawTestSpec::Usage usage)
991 {
992         m_size = (int)size;
993         m_target = target;
994
995         if (m_storage == DrawTestSpec::STORAGE_BUFFER)
996         {
997                 m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
998                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
999
1000                 m_ctx.bufferData(targetToGL(target), size, ptr, usageToGL(usage));
1001                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferData()");
1002         }
1003         else if (m_storage == DrawTestSpec::STORAGE_USER)
1004         {
1005                 if (m_data)
1006                         delete[] m_data;
1007
1008                 m_data = new char[size];
1009                 std::memcpy(m_data, ptr, size);
1010         }
1011         else
1012                 DE_ASSERT(false);
1013 }
1014
1015 void AttributeArray::setupArray (bool bound, int offset, int size, DrawTestSpec::InputType inputType, DrawTestSpec::OutputType outType, bool normalized, int stride, int instanceDivisor, const rr::GenericVec4& defaultAttrib, bool isPositionAttr, bool bgraComponentOrder)
1016 {
1017         m_componentCount        = size;
1018         m_bound                         = bound;
1019         m_inputType                     = inputType;
1020         m_outputType            = outType;
1021         m_normalize                     = normalized;
1022         m_stride                        = stride;
1023         m_offset                        = offset;
1024         m_defaultAttrib         = defaultAttrib;
1025         m_instanceDivisor       = instanceDivisor;
1026         m_isPositionAttr        = isPositionAttr;
1027         m_bgraOrder                     = bgraComponentOrder;
1028 }
1029
1030 void AttributeArray::bindAttribute (deUint32 loc)
1031 {
1032         if (!isBound())
1033         {
1034                 switch (m_inputType)
1035                 {
1036                         case DrawTestSpec::INPUTTYPE_FLOAT:
1037                         {
1038                                 tcu::Vec4 attr = m_defaultAttrib.get<float>();
1039
1040                                 switch (m_componentCount)
1041                                 {
1042                                         case 1: m_ctx.vertexAttrib1f(loc, attr.x()); break;
1043                                         case 2: m_ctx.vertexAttrib2f(loc, attr.x(), attr.y()); break;
1044                                         case 3: m_ctx.vertexAttrib3f(loc, attr.x(), attr.y(), attr.z()); break;
1045                                         case 4: m_ctx.vertexAttrib4f(loc, attr.x(), attr.y(), attr.z(), attr.w()); break;
1046                                         default: DE_ASSERT(DE_FALSE); break;
1047                                 }
1048                                 break;
1049                         }
1050                         case DrawTestSpec::INPUTTYPE_INT:
1051                         {
1052                                 tcu::IVec4 attr = m_defaultAttrib.get<deInt32>();
1053                                 m_ctx.vertexAttribI4i(loc, attr.x(), attr.y(), attr.z(), attr.w());
1054                                 break;
1055                         }
1056                         case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
1057                         {
1058                                 tcu::UVec4 attr = m_defaultAttrib.get<deUint32>();
1059                                 m_ctx.vertexAttribI4ui(loc, attr.x(), attr.y(), attr.z(), attr.w());
1060                                 break;
1061                         }
1062                         default:
1063                                 DE_ASSERT(DE_FALSE);
1064                                 break;
1065                 }
1066         }
1067         else
1068         {
1069                 const deUint8* basePtr = DE_NULL;
1070
1071                 if (m_storage == DrawTestSpec::STORAGE_BUFFER)
1072                 {
1073                         m_ctx.bindBuffer(targetToGL(m_target), m_glBuffer);
1074                         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
1075
1076                         basePtr = DE_NULL;
1077                 }
1078                 else if (m_storage == DrawTestSpec::STORAGE_USER)
1079                 {
1080                         m_ctx.bindBuffer(targetToGL(m_target), 0);
1081                         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
1082
1083                         basePtr = (const deUint8*)m_data;
1084                 }
1085                 else
1086                         DE_ASSERT(DE_FALSE);
1087
1088                 if (!inputTypeIsFloatType(m_inputType))
1089                 {
1090                         // Input is not float type
1091
1092                         if (outputTypeIsFloatType(m_outputType))
1093                         {
1094                                 const int size = (m_bgraOrder) ? (GL_BGRA) : (m_componentCount);
1095
1096                                 DE_ASSERT(!(m_bgraOrder && m_componentCount != 4));
1097
1098                                 // Output type is float type
1099                                 m_ctx.vertexAttribPointer(loc, size, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset);
1100                                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
1101                         }
1102                         else
1103                         {
1104                                 // Output type is int type
1105                                 m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, basePtr + m_offset);
1106                                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
1107                         }
1108                 }
1109                 else
1110                 {
1111                         // Input type is float type
1112
1113                         // Output type must be float type
1114                         DE_ASSERT(outputTypeIsFloatType(m_outputType));
1115
1116                         m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset);
1117                         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
1118                 }
1119
1120                 if (m_instanceDivisor)
1121                         m_ctx.vertexAttribDivisor(loc, m_instanceDivisor);
1122         }
1123 }
1124
1125 void AttributeArray::bindIndexArray (DrawTestSpec::Target target)
1126 {
1127         if (m_storage == DrawTestSpec::STORAGE_USER)
1128         {
1129         }
1130         else if (m_storage == DrawTestSpec::STORAGE_BUFFER)
1131         {
1132                 m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
1133         }
1134 }
1135
1136 // DrawTestShaderProgram
1137
1138 class DrawTestShaderProgram : public sglr::ShaderProgram
1139 {
1140 public:
1141                                                                                                 DrawTestShaderProgram           (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
1142
1143         void                                                                            shadeVertices                           (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
1144         void                                                                            shadeFragments                          (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
1145
1146 private:
1147         static std::string                                                      genVertexSource                         (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
1148         static std::string                                                      genFragmentSource                       (const glu::RenderContext& ctx);
1149         static void                                                                     generateShaderParams            (std::map<std::string, std::string>& params, glu::ContextType type);
1150         static rr::GenericVecType                                       mapOutputType                           (const DrawTestSpec::OutputType& type);
1151         static int                                                                      getComponentCount                       (const DrawTestSpec::OutputType& type);
1152
1153         static sglr::pdec::ShaderProgramDeclaration createProgramDeclaration    (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
1154
1155         std::vector<int>                                                        m_componentCount;
1156         std::vector<bool>                                                       m_isCoord;
1157         std::vector<rr::GenericVecType>                         m_attrType;
1158 };
1159
1160 DrawTestShaderProgram::DrawTestShaderProgram (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
1161         : sglr::ShaderProgram   (createProgramDeclaration(ctx, arrays))
1162         , m_componentCount              (arrays.size())
1163         , m_isCoord                             (arrays.size())
1164         , m_attrType                    (arrays.size())
1165 {
1166         for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1167         {
1168                 m_componentCount[arrayNdx]      = getComponentCount(arrays[arrayNdx]->getOutputType());
1169                 m_isCoord[arrayNdx]                     = arrays[arrayNdx]->isPositionAttribute();
1170                 m_attrType[arrayNdx]            = mapOutputType(arrays[arrayNdx]->getOutputType());
1171         }
1172 }
1173
1174 template <typename T>
1175 void calcShaderColorCoord (tcu::Vec2& coord, tcu::Vec3& color, const tcu::Vector<T, 4>& attribValue, bool isCoordinate, int numComponents)
1176 {
1177         if (isCoordinate)
1178                 switch (numComponents)
1179                 {
1180                         case 1: coord += tcu::Vec2((float)attribValue.x(),                                                      (float)attribValue.x());                                                        break;
1181                         case 2: coord += tcu::Vec2((float)attribValue.x(),                                                      (float)attribValue.y());                                                        break;
1182                         case 3: coord += tcu::Vec2((float)attribValue.x() + (float)attribValue.z(),     (float)attribValue.y());                                                        break;
1183                         case 4: coord += tcu::Vec2((float)attribValue.x() + (float)attribValue.z(),     (float)attribValue.y() + (float)attribValue.w());       break;
1184
1185                         default:
1186                                 DE_ASSERT(false);
1187                 }
1188         else
1189         {
1190                 switch (numComponents)
1191                 {
1192                         case 1:
1193                                 color = color * (float)attribValue.x();
1194                                 break;
1195
1196                         case 2:
1197                                 color.x() = color.x() * (float)attribValue.x();
1198                                 color.y() = color.y() * (float)attribValue.y();
1199                                 break;
1200
1201                         case 3:
1202                                 color.x() = color.x() * (float)attribValue.x();
1203                                 color.y() = color.y() * (float)attribValue.y();
1204                                 color.z() = color.z() * (float)attribValue.z();
1205                                 break;
1206
1207                         case 4:
1208                                 color.x() = color.x() * (float)attribValue.x() * (float)attribValue.w();
1209                                 color.y() = color.y() * (float)attribValue.y() * (float)attribValue.w();
1210                                 color.z() = color.z() * (float)attribValue.z() * (float)attribValue.w();
1211                                 break;
1212
1213                         default:
1214                                 DE_ASSERT(false);
1215                 }
1216         }
1217 }
1218
1219 void DrawTestShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
1220 {
1221         const float     u_coordScale = getUniformByName("u_coordScale").value.f;
1222         const float u_colorScale = getUniformByName("u_colorScale").value.f;
1223
1224         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1225         {
1226                 const size_t varyingLocColor = 0;
1227
1228                 rr::VertexPacket& packet = *packets[packetNdx];
1229
1230                 // Calc output color
1231                 tcu::Vec2 coord = tcu::Vec2(0.0, 0.0);
1232                 tcu::Vec3 color = tcu::Vec3(1.0, 1.0, 1.0);
1233
1234                 for (int attribNdx = 0; attribNdx < (int)m_attrType.size(); attribNdx++)
1235                 {
1236                         const int       numComponents   = m_componentCount[attribNdx];
1237                         const bool      isCoord                 = m_isCoord[attribNdx];
1238
1239                         switch (m_attrType[attribNdx])
1240                         {
1241                                 case rr::GENERICVECTYPE_FLOAT:  calcShaderColorCoord(coord, color, rr::readVertexAttribFloat(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents); break;
1242                                 case rr::GENERICVECTYPE_INT32:  calcShaderColorCoord(coord, color, rr::readVertexAttribInt      (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents);     break;
1243                                 case rr::GENERICVECTYPE_UINT32: calcShaderColorCoord(coord, color, rr::readVertexAttribUint     (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents);     break;
1244                                 default:
1245                                         DE_ASSERT(false);
1246                         }
1247                 }
1248
1249                 // Transform position
1250                 {
1251                         packet.position = tcu::Vec4(u_coordScale * coord.x(), u_coordScale * coord.y(), 1.0f, 1.0f);
1252                         packet.pointSize = 1.0f;
1253                 }
1254
1255                 // Pass color to FS
1256                 {
1257                         packet.outputs[varyingLocColor] = tcu::Vec4(u_colorScale * color.x(), u_colorScale * color.y(), u_colorScale * color.z(), 1.0f) * 0.5f + tcu::Vec4(0.5f, 0.5f, 0.5f, 0.5f);
1258                 }
1259         }
1260 }
1261
1262 void DrawTestShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
1263 {
1264         const size_t varyingLocColor = 0;
1265
1266         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1267         {
1268                 rr::FragmentPacket& packet = packets[packetNdx];
1269
1270                 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1271                         rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, varyingLocColor, fragNdx));
1272         }
1273 }
1274
1275 std::string DrawTestShaderProgram::genVertexSource (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
1276 {
1277         std::map<std::string, std::string>      params;
1278         std::stringstream                                       vertexShaderTmpl;
1279
1280         generateShaderParams(params, ctx.getType());
1281
1282         vertexShaderTmpl << "${VTX_HDR}";
1283
1284         for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1285         {
1286                 vertexShaderTmpl
1287                         << "${VTX_IN} highp " << outputTypeToGLType(arrays[arrayNdx]->getOutputType()) << " a_" << arrayNdx << ";\n";
1288         }
1289
1290         vertexShaderTmpl <<
1291                 "uniform highp float u_coordScale;\n"
1292                 "uniform highp float u_colorScale;\n"
1293                 "${VTX_OUT} ${COL_PRECISION} vec4 v_color;\n"
1294                 "void main(void)\n"
1295                 "{\n"
1296                 "\tgl_PointSize = 1.0;\n"
1297                 "\thighp vec2 coord = vec2(0.0, 0.0);\n"
1298                 "\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n";
1299
1300         for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1301         {
1302                 const bool isPositionAttr = arrays[arrayNdx]->isPositionAttribute();
1303
1304                 if (isPositionAttr)
1305                 {
1306                         switch (arrays[arrayNdx]->getOutputType())
1307                         {
1308                                 case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1309                                 case (DrawTestSpec::OUTPUTTYPE_INT):
1310                                 case (DrawTestSpec::OUTPUTTYPE_UINT):
1311                                         vertexShaderTmpl <<
1312                                                 "\tcoord += vec2(float(a_" << arrayNdx << "), float(a_" << arrayNdx << "));\n";
1313                                         break;
1314
1315                                 case (DrawTestSpec::OUTPUTTYPE_VEC2):
1316                                 case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1317                                 case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1318                                         vertexShaderTmpl <<
1319                                                 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n";
1320                                         break;
1321
1322                                 case (DrawTestSpec::OUTPUTTYPE_VEC3):
1323                                 case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1324                                 case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1325                                         vertexShaderTmpl <<
1326                                                 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n"
1327                                                 "\tcoord.x += float(a_" << arrayNdx << ".z);\n";
1328                                         break;
1329
1330                                 case (DrawTestSpec::OUTPUTTYPE_VEC4):
1331                                 case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1332                                 case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1333                                         vertexShaderTmpl <<
1334                                                 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n"
1335                                                 "\tcoord += vec2(a_" << arrayNdx << ".zw);\n";
1336                                         break;
1337
1338                                 default:
1339                                         DE_ASSERT(false);
1340                                         break;
1341                         }
1342                 }
1343                 else
1344                 {
1345                         switch (arrays[arrayNdx]->getOutputType())
1346                         {
1347                                 case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1348                                 case (DrawTestSpec::OUTPUTTYPE_INT):
1349                                 case (DrawTestSpec::OUTPUTTYPE_UINT):
1350                                         vertexShaderTmpl <<
1351                                                 "\tcolor = color * float(a_" << arrayNdx << ");\n";
1352                                         break;
1353
1354                                 case (DrawTestSpec::OUTPUTTYPE_VEC2):
1355                                 case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1356                                 case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1357                                         vertexShaderTmpl <<
1358                                                 "\tcolor.rg = color.rg * vec2(a_" << arrayNdx << ".xy);\n";
1359                                         break;
1360
1361                                 case (DrawTestSpec::OUTPUTTYPE_VEC3):
1362                                 case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1363                                 case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1364                                         vertexShaderTmpl <<
1365                                                 "\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz);\n";
1366                                         break;
1367
1368                                 case (DrawTestSpec::OUTPUTTYPE_VEC4):
1369                                 case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1370                                 case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1371                                         vertexShaderTmpl <<
1372                                                 "\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz) * float(a_" << arrayNdx << ".w);\n";
1373                                         break;
1374
1375                                 default:
1376                                         DE_ASSERT(false);
1377                                         break;
1378                         }
1379                 }
1380         }
1381
1382         vertexShaderTmpl <<
1383                 "\tv_color = vec4(u_colorScale * color, 1.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);\n"
1384                 "\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n"
1385                 "}\n";
1386
1387         return tcu::StringTemplate(vertexShaderTmpl.str().c_str()).specialize(params);
1388 }
1389
1390 std::string DrawTestShaderProgram::genFragmentSource (const glu::RenderContext& ctx)
1391 {
1392         std::map<std::string, std::string> params;
1393
1394         generateShaderParams(params, ctx.getType());
1395
1396         static const char* fragmentShaderTmpl =
1397                 "${FRAG_HDR}"
1398                 "${FRAG_IN} ${COL_PRECISION} vec4 v_color;\n"
1399                 "void main(void)\n"
1400                 "{\n"
1401                 "\t${FRAG_COLOR} = v_color;\n"
1402                 "}\n";
1403
1404         return tcu::StringTemplate(fragmentShaderTmpl).specialize(params);
1405 }
1406
1407 void DrawTestShaderProgram::generateShaderParams (std::map<std::string, std::string>& params, glu::ContextType type)
1408 {
1409         if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_300_ES))
1410         {
1411                 params["VTX_IN"]                = "in";
1412                 params["VTX_OUT"]               = "out";
1413                 params["FRAG_IN"]               = "in";
1414                 params["FRAG_COLOR"]    = "dEQP_FragColor";
1415                 params["VTX_HDR"]               = "#version 300 es\n";
1416                 params["FRAG_HDR"]              = "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1417                 params["COL_PRECISION"] = "mediump";
1418         }
1419         else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_100_ES))
1420         {
1421                 params["VTX_IN"]                = "attribute";
1422                 params["VTX_OUT"]               = "varying";
1423                 params["FRAG_IN"]               = "varying";
1424                 params["FRAG_COLOR"]    = "gl_FragColor";
1425                 params["VTX_HDR"]               = "";
1426                 params["FRAG_HDR"]              = "";
1427                 params["COL_PRECISION"] = "mediump";
1428         }
1429         else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_430))
1430         {
1431                 params["VTX_IN"]                = "in";
1432                 params["VTX_OUT"]               = "out";
1433                 params["FRAG_IN"]               = "in";
1434                 params["FRAG_COLOR"]    = "dEQP_FragColor";
1435                 params["VTX_HDR"]               = "#version 430\n";
1436                 params["FRAG_HDR"]              = "#version 430\nlayout(location = 0) out highp vec4 dEQP_FragColor;\n";
1437                 params["COL_PRECISION"] = "highp";
1438         }
1439         else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_330))
1440         {
1441                 params["VTX_IN"]                = "in";
1442                 params["VTX_OUT"]               = "out";
1443                 params["FRAG_IN"]               = "in";
1444                 params["FRAG_COLOR"]    = "dEQP_FragColor";
1445                 params["VTX_HDR"]               = "#version 330\n";
1446                 params["FRAG_HDR"]              = "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1447                 params["COL_PRECISION"] = "mediump";
1448         }
1449         else
1450                 DE_ASSERT(DE_FALSE);
1451 }
1452
1453 rr::GenericVecType DrawTestShaderProgram::mapOutputType (const DrawTestSpec::OutputType& type)
1454 {
1455         switch (type)
1456         {
1457                 case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1458                 case (DrawTestSpec::OUTPUTTYPE_VEC2):
1459                 case (DrawTestSpec::OUTPUTTYPE_VEC3):
1460                 case (DrawTestSpec::OUTPUTTYPE_VEC4):
1461                         return rr::GENERICVECTYPE_FLOAT;
1462
1463                 case (DrawTestSpec::OUTPUTTYPE_INT):
1464                 case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1465                 case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1466                 case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1467                         return rr::GENERICVECTYPE_INT32;
1468
1469                 case (DrawTestSpec::OUTPUTTYPE_UINT):
1470                 case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1471                 case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1472                 case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1473                         return rr::GENERICVECTYPE_UINT32;
1474
1475                 default:
1476                         DE_ASSERT(false);
1477                         return rr::GENERICVECTYPE_LAST;
1478         }
1479 }
1480
1481 int DrawTestShaderProgram::getComponentCount (const DrawTestSpec::OutputType& type)
1482 {
1483         switch (type)
1484         {
1485                 case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1486                 case (DrawTestSpec::OUTPUTTYPE_INT):
1487                 case (DrawTestSpec::OUTPUTTYPE_UINT):
1488                         return 1;
1489
1490                 case (DrawTestSpec::OUTPUTTYPE_VEC2):
1491                 case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1492                 case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1493                         return 2;
1494
1495                 case (DrawTestSpec::OUTPUTTYPE_VEC3):
1496                 case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1497                 case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1498                         return 3;
1499
1500                 case (DrawTestSpec::OUTPUTTYPE_VEC4):
1501                 case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1502                 case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1503                         return 4;
1504
1505                 default:
1506                         DE_ASSERT(false);
1507                         return 0;
1508         }
1509 }
1510
1511 sglr::pdec::ShaderProgramDeclaration DrawTestShaderProgram::createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
1512 {
1513         sglr::pdec::ShaderProgramDeclaration decl;
1514
1515         for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1516                 decl << sglr::pdec::VertexAttribute(std::string("a_") + de::toString(arrayNdx), mapOutputType(arrays[arrayNdx]->getOutputType()));
1517
1518         decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
1519         decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT);
1520
1521         decl << sglr::pdec::VertexSource(genVertexSource(ctx, arrays));
1522         decl << sglr::pdec::FragmentSource(genFragmentSource(ctx));
1523
1524         decl << sglr::pdec::Uniform("u_coordScale", glu::TYPE_FLOAT);
1525         decl << sglr::pdec::Uniform("u_colorScale", glu::TYPE_FLOAT);
1526
1527         return decl;
1528 }
1529
1530 class RandomArrayGenerator
1531 {
1532 public:
1533         static char*                    generateArray                   (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type);
1534         static char*                    generateIndices                 (int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase);
1535         static rr::GenericVec4  generateAttributeValue  (int seed, DrawTestSpec::InputType type);
1536
1537 private:
1538         template<typename T>
1539         static char*                    createIndices                   (int seed, int elementCount, int offset, int min, int max, int indexBase);
1540
1541         static char*                    generateBasicArray              (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type);
1542         template<typename T, typename GLType>
1543         static char*                    createBasicArray                (int seed, int elementCount, int componentCount, int offset, int stride);
1544         static char*                    generatePackedArray             (int seed, int elementCount, int componentCount, int offset, int stride);
1545 };
1546
1547 char* RandomArrayGenerator::generateArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type)
1548 {
1549         if (type == DrawTestSpec::INPUTTYPE_INT_2_10_10_10 || type == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
1550                 return generatePackedArray(seed, elementCount, componentCount, offset, stride);
1551         else
1552                 return generateBasicArray(seed, elementCount, componentCount, offset, stride, type);
1553 }
1554
1555 char* RandomArrayGenerator::generateBasicArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type)
1556 {
1557         switch (type)
1558         {
1559                 case DrawTestSpec::INPUTTYPE_FLOAT:                             return createBasicArray<float,          GLValue::Float> (seed, elementCount, componentCount, offset, stride);
1560                 case DrawTestSpec::INPUTTYPE_DOUBLE:                    return createBasicArray<double,         GLValue::Double>(seed, elementCount, componentCount, offset, stride);
1561                 case DrawTestSpec::INPUTTYPE_SHORT:                             return createBasicArray<deInt16,        GLValue::Short> (seed, elementCount, componentCount, offset, stride);
1562                 case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT:    return createBasicArray<deUint16,       GLValue::Ushort>(seed, elementCount, componentCount, offset, stride);
1563                 case DrawTestSpec::INPUTTYPE_BYTE:                              return createBasicArray<deInt8,         GLValue::Byte>  (seed, elementCount, componentCount, offset, stride);
1564                 case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE:             return createBasicArray<deUint8,        GLValue::Ubyte> (seed, elementCount, componentCount, offset, stride);
1565                 case DrawTestSpec::INPUTTYPE_FIXED:                             return createBasicArray<deInt32,        GLValue::Fixed> (seed, elementCount, componentCount, offset, stride);
1566                 case DrawTestSpec::INPUTTYPE_INT:                               return createBasicArray<deInt32,        GLValue::Int>   (seed, elementCount, componentCount, offset, stride);
1567                 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:              return createBasicArray<deUint32,       GLValue::Uint>  (seed, elementCount, componentCount, offset, stride);
1568                 case DrawTestSpec::INPUTTYPE_HALF:                              return createBasicArray<deFloat16,      GLValue::Half>  (seed, elementCount, componentCount, offset, stride);
1569                 default:
1570                         DE_ASSERT(false);
1571                         break;
1572         }
1573         return DE_NULL;
1574 }
1575
1576 #if (DE_COMPILER == DE_COMPILER_GCC) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)
1577         // GCC 4.8/4.9 incorrectly emits array-bounds warning from createBasicArray()
1578 #       define GCC_ARRAY_BOUNDS_FALSE_NEGATIVE 1
1579 #endif
1580
1581 #if defined(GCC_ARRAY_BOUNDS_FALSE_NEGATIVE)
1582 #       pragma GCC diagnostic push
1583 #       pragma GCC diagnostic ignored "-Warray-bounds"
1584 #endif
1585
1586 template<typename T, typename GLType>
1587 char* RandomArrayGenerator::createBasicArray (int seed, int elementCount, int componentCount, int offset, int stride)
1588 {
1589         DE_ASSERT(componentCount >= 1 && componentCount <= 4);
1590
1591         const GLType min = extractGLValue<GLType>(GLValue::getMinValue(GLValueTypeTraits<GLType>::Type));
1592         const GLType max = extractGLValue<GLType>(GLValue::getMaxValue(GLValueTypeTraits<GLType>::Type));
1593
1594         const size_t componentSize      = sizeof(T);
1595         const size_t elementSize        = componentSize * componentCount;
1596         const size_t bufferSize         = offset + (elementCount - 1) * stride + elementSize;
1597
1598         char* data = new char[bufferSize];
1599         char* writePtr = data + offset;
1600
1601         GLType previousComponents[4];
1602
1603         deRandom rnd;
1604         deRandom_init(&rnd, seed);
1605
1606         for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++)
1607         {
1608                 GLType components[4];
1609
1610                 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1611                 {
1612                         components[componentNdx] = getRandom<GLType>(rnd, min, max);
1613
1614                         // Try to not create vertex near previous
1615                         if (vertexNdx != 0 && abs(components[componentNdx] - previousComponents[componentNdx]) < minValue<GLType>())
1616                         {
1617                                 // Too close, try again (but only once)
1618                                 components[componentNdx] = getRandom<GLType>(rnd, min, max);
1619                         }
1620                 }
1621
1622                 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1623                         previousComponents[componentNdx] = components[componentNdx];
1624
1625                 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1626                         alignmentSafeAssignment(writePtr + componentNdx*componentSize, components[componentNdx].getValue());
1627
1628                 writePtr += stride;
1629         }
1630
1631         return data;
1632 }
1633
1634 #if defined(GCC_ARRAY_BOUNDS_FALSE_NEGATIVE)
1635 #       pragma GCC diagnostic pop
1636 #endif
1637
1638 char* RandomArrayGenerator::generatePackedArray (int seed, int elementCount, int componentCount, int offset, int stride)
1639 {
1640         DE_ASSERT(componentCount == 4);
1641         DE_UNREF(componentCount);
1642
1643         const deUint32 limit10          = (1 << 10);
1644         const deUint32 limit2           = (1 << 2);
1645         const size_t elementSize        = 4;
1646         const size_t bufferSize         = offset + (elementCount - 1) * stride + elementSize;
1647
1648         char* data = new char[bufferSize];
1649         char* writePtr = data + offset;
1650
1651         deRandom rnd;
1652         deRandom_init(&rnd, seed);
1653
1654         for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++)
1655         {
1656                 const deUint32 x                        = deRandom_getUint32(&rnd) % limit10;
1657                 const deUint32 y                        = deRandom_getUint32(&rnd) % limit10;
1658                 const deUint32 z                        = deRandom_getUint32(&rnd) % limit10;
1659                 const deUint32 w                        = deRandom_getUint32(&rnd) % limit2;
1660                 const deUint32 packedValue      = (w << 30) | (z << 20) | (y << 10) | (x);
1661
1662                 alignmentSafeAssignment(writePtr, packedValue);
1663                 writePtr += stride;
1664         }
1665
1666         return data;
1667 }
1668
1669 char* RandomArrayGenerator::generateIndices (int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase)
1670 {
1671         char* data = DE_NULL;
1672
1673         switch (type)
1674         {
1675                 case DrawTestSpec::INDEXTYPE_BYTE:
1676                         data = createIndices<deUint8>(seed, elementCount, offset, min, max, indexBase);
1677                         break;
1678
1679                 case DrawTestSpec::INDEXTYPE_SHORT:
1680                         data = createIndices<deUint16>(seed, elementCount, offset, min, max, indexBase);
1681                         break;
1682
1683                 case DrawTestSpec::INDEXTYPE_INT:
1684                         data = createIndices<deUint32>(seed, elementCount, offset, min, max, indexBase);
1685                         break;
1686
1687                 default:
1688                         DE_ASSERT(false);
1689                         break;
1690         }
1691
1692         return data;
1693 }
1694
1695 template<typename T>
1696 char* RandomArrayGenerator::createIndices (int seed, int elementCount, int offset, int min, int max, int indexBase)
1697 {
1698         const size_t elementSize        = sizeof(T);
1699         const size_t bufferSize         = offset + elementCount * elementSize;
1700
1701         char* data = new char[bufferSize];
1702         char* writePtr = data + offset;
1703
1704         deUint32 oldNdx1 = deUint32(-1);
1705         deUint32 oldNdx2 = deUint32(-1);
1706
1707         deRandom rnd;
1708         deRandom_init(&rnd, seed);
1709
1710         DE_ASSERT(indexBase >= 0); // watch for underflows
1711
1712         if (min < 0 || (size_t)min > std::numeric_limits<T>::max() ||
1713                 max < 0 || (size_t)max > std::numeric_limits<T>::max() ||
1714                 min > max)
1715                 DE_FATAL("Invalid range");
1716
1717         for (int elementNdx = 0; elementNdx < elementCount; ++elementNdx)
1718         {
1719                 deUint32 ndx = getRandom(rnd, GLValue::Uint::create(min), GLValue::Uint::create(max)).getValue();
1720
1721                 // Try not to generate same index as any of previous two. This prevents
1722                 // generation of degenerate triangles and lines. If [min, max] is too
1723                 // small this cannot be guaranteed.
1724
1725                 if (ndx == oldNdx1)                     ++ndx;
1726                 if (ndx > (deUint32)max)        ndx = min;
1727                 if (ndx == oldNdx2)                     ++ndx;
1728                 if (ndx > (deUint32)max)        ndx = min;
1729                 if (ndx == oldNdx1)                     ++ndx;
1730                 if (ndx > (deUint32)max)        ndx = min;
1731
1732                 oldNdx2 = oldNdx1;
1733                 oldNdx1 = ndx;
1734
1735                 ndx += indexBase;
1736
1737                 alignmentSafeAssignment<T>(writePtr + elementSize * elementNdx, T(ndx));
1738         }
1739
1740         return data;
1741 }
1742
1743 rr::GenericVec4 RandomArrayGenerator::generateAttributeValue (int seed, DrawTestSpec::InputType type)
1744 {
1745         de::Random random(seed);
1746
1747         switch (type)
1748         {
1749                 case DrawTestSpec::INPUTTYPE_FLOAT:
1750                         return rr::GenericVec4(generateRandomVec4(random));
1751
1752                 case DrawTestSpec::INPUTTYPE_INT:
1753                         return rr::GenericVec4(generateRandomIVec4(random));
1754
1755                 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
1756                         return rr::GenericVec4(generateRandomUVec4(random));
1757
1758                 default:
1759                         DE_ASSERT(false);
1760                         return rr::GenericVec4(tcu::Vec4(1, 1, 1, 1));
1761         }
1762 }
1763
1764 } // anonymous
1765
1766 // AttributePack
1767
1768 class AttributePack
1769 {
1770 public:
1771
1772                                                                 AttributePack           (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled);
1773                                                                 ~AttributePack          (void);
1774
1775         AttributeArray*                         getArray                        (int i);
1776         int                                                     getArrayCount           (void);
1777
1778         void                                            newArray                        (DrawTestSpec::Storage storage);
1779         void                                            clearArrays                     (void);
1780         void                                            updateProgram           (void);
1781
1782         void                                            render                          (DrawTestSpec::Primitive primitive, DrawTestSpec::DrawMethod drawMethod, int firstVertex, int vertexCount, DrawTestSpec::IndexType indexType, const void* indexOffset, int rangeStart, int rangeEnd, int instanceCount, int indirectOffset, int baseVertex, float coordScale, float colorScale, AttributeArray* indexArray);
1783
1784         const tcu::Surface&                     getSurface                      (void) const { return m_screen; }
1785 private:
1786         tcu::TestContext&                       m_testCtx;
1787         glu::RenderContext&                     m_renderCtx;
1788         sglr::Context&                          m_ctx;
1789
1790         std::vector<AttributeArray*>m_arrays;
1791         sglr::ShaderProgram*            m_program;
1792         tcu::Surface                            m_screen;
1793         const bool                                      m_useVao;
1794         const bool                                      m_logEnabled;
1795         deUint32                                        m_programID;
1796         deUint32                                        m_vaoID;
1797 };
1798
1799 AttributePack::AttributePack (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled)
1800         : m_testCtx             (testCtx)
1801         , m_renderCtx   (renderCtx)
1802         , m_ctx                 (drawContext)
1803         , m_program             (DE_NULL)
1804         , m_screen              (screenSize.x(), screenSize.y())
1805         , m_useVao              (useVao)
1806         , m_logEnabled  (logEnabled)
1807         , m_programID   (0)
1808         , m_vaoID               (0)
1809 {
1810         if (m_useVao)
1811                 m_ctx.genVertexArrays(1, &m_vaoID);
1812 }
1813
1814 AttributePack::~AttributePack (void)
1815 {
1816         clearArrays();
1817
1818         if (m_programID)
1819                 m_ctx.deleteProgram(m_programID);
1820
1821         if (m_program)
1822                 delete m_program;
1823
1824         if (m_useVao)
1825                 m_ctx.deleteVertexArrays(1, &m_vaoID);
1826 }
1827
1828 AttributeArray* AttributePack::getArray (int i)
1829 {
1830         return m_arrays.at(i);
1831 }
1832
1833 int AttributePack::getArrayCount (void)
1834 {
1835         return (int)m_arrays.size();
1836 }
1837
1838 void AttributePack::newArray (DrawTestSpec::Storage storage)
1839 {
1840         m_arrays.push_back(new AttributeArray(storage, m_ctx));
1841 }
1842
1843 void AttributePack::clearArrays (void)
1844 {
1845         for (std::vector<AttributeArray*>::iterator itr = m_arrays.begin(); itr != m_arrays.end(); itr++)
1846                 delete *itr;
1847         m_arrays.clear();
1848 }
1849
1850 void AttributePack::updateProgram (void)
1851 {
1852         if (m_programID)
1853                 m_ctx.deleteProgram(m_programID);
1854         if (m_program)
1855                 delete m_program;
1856
1857         m_program = new DrawTestShaderProgram(m_renderCtx, m_arrays);
1858         m_programID = m_ctx.createProgram(m_program);
1859 }
1860
1861 void AttributePack::render (DrawTestSpec::Primitive primitive, DrawTestSpec::DrawMethod drawMethod, int firstVertex, int vertexCount, DrawTestSpec::IndexType indexType, const void* indexOffset, int rangeStart, int rangeEnd, int instanceCount, int indirectOffset, int baseVertex, float coordScale, float colorScale, AttributeArray* indexArray)
1862 {
1863         DE_ASSERT(m_program != DE_NULL);
1864         DE_ASSERT(m_programID != 0);
1865
1866         m_ctx.viewport(0, 0, m_screen.getWidth(), m_screen.getHeight());
1867         m_ctx.clearColor(0.0, 0.0, 0.0, 1.0);
1868         m_ctx.clear(GL_COLOR_BUFFER_BIT);
1869
1870         m_ctx.useProgram(m_programID);
1871         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glUseProgram()");
1872
1873         m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_coordScale"), coordScale);
1874         m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_colorScale"), colorScale);
1875
1876         if (m_useVao)
1877                 m_ctx.bindVertexArray(m_vaoID);
1878
1879         if (indexArray)
1880                 indexArray->bindIndexArray(DrawTestSpec::TARGET_ELEMENT_ARRAY);
1881
1882         for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
1883         {
1884                 std::stringstream attribName;
1885                 attribName << "a_" << arrayNdx;
1886
1887                 deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str());
1888
1889                 if (m_arrays[arrayNdx]->isBound())
1890                 {
1891                         m_ctx.enableVertexAttribArray(loc);
1892                         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glEnableVertexAttribArray()");
1893                 }
1894
1895                 m_arrays[arrayNdx]->bindAttribute(loc);
1896         }
1897
1898         if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS)
1899         {
1900                 m_ctx.drawArrays(primitiveToGL(primitive), firstVertex, vertexCount);
1901                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArrays()");
1902         }
1903         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED)
1904         {
1905                 m_ctx.drawArraysInstanced(primitiveToGL(primitive), firstVertex, vertexCount, instanceCount);
1906                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysInstanced()");
1907         }
1908         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS)
1909         {
1910                 m_ctx.drawElements(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset);
1911                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElements()");
1912         }
1913         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED)
1914         {
1915                 m_ctx.drawRangeElements(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset);
1916                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElements()");
1917         }
1918         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED)
1919         {
1920                 m_ctx.drawElementsInstanced(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount);
1921                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstanced()");
1922         }
1923         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT)
1924         {
1925                 struct DrawCommand
1926                 {
1927                         GLuint count;
1928                         GLuint primCount;
1929                         GLuint first;
1930                         GLuint reservedMustBeZero;
1931                 };
1932                 deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset];
1933
1934                 {
1935                         DrawCommand command;
1936
1937                         command.count                           = vertexCount;
1938                         command.primCount                       = instanceCount;
1939                         command.first                           = firstVertex;
1940                         command.reservedMustBeZero      = 0;
1941
1942                         memcpy(buffer + indirectOffset, &command, sizeof(command));
1943
1944                         if (m_logEnabled)
1945                                 m_testCtx.getLog()
1946                                         << tcu::TestLog::Message
1947                                         << "DrawArraysIndirectCommand:\n"
1948                                         << "\tcount: " << command.count << "\n"
1949                                         << "\tprimCount: " << command.primCount << "\n"
1950                                         << "\tfirst: " << command.first << "\n"
1951                                         << "\treservedMustBeZero: " << command.reservedMustBeZero << "\n"
1952                                         << tcu::TestLog::EndMessage;
1953                 }
1954
1955                 GLuint indirectBuf = 0;
1956                 m_ctx.genBuffers(1, &indirectBuf);
1957                 m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf);
1958                 m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW);
1959                 delete [] buffer;
1960
1961                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer");
1962
1963                 m_ctx.drawArraysIndirect(primitiveToGL(primitive), glu::BufferOffsetAsPointer(indirectOffset));
1964                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()");
1965
1966                 m_ctx.deleteBuffers(1, &indirectBuf);
1967         }
1968         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT)
1969         {
1970                 struct DrawCommand
1971                 {
1972                         GLuint count;
1973                         GLuint primCount;
1974                         GLuint firstIndex;
1975                         GLint  baseVertex;
1976                         GLuint reservedMustBeZero;
1977                 };
1978                 deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset];
1979
1980                 {
1981                         DrawCommand command;
1982
1983                         // index offset must be converted to firstIndex by dividing with the index element size
1984                         const auto offsetAsInteger = reinterpret_cast<uintptr_t>(indexOffset);
1985                         DE_ASSERT(offsetAsInteger % gls::DrawTestSpec::indexTypeSize(indexType) == 0); // \note This is checked in spec validation
1986
1987                         command.count                           = vertexCount;
1988                         command.primCount                       = instanceCount;
1989                         command.firstIndex                      = (glw::GLuint)(offsetAsInteger / gls::DrawTestSpec::indexTypeSize(indexType));
1990                         command.baseVertex                      = baseVertex;
1991                         command.reservedMustBeZero      = 0;
1992
1993                         memcpy(buffer + indirectOffset, &command, sizeof(command));
1994
1995                         if (m_logEnabled)
1996                                 m_testCtx.getLog()
1997                                         << tcu::TestLog::Message
1998                                         << "DrawElementsIndirectCommand:\n"
1999                                         << "\tcount: " << command.count << "\n"
2000                                         << "\tprimCount: " << command.primCount << "\n"
2001                                         << "\tfirstIndex: " << command.firstIndex << "\n"
2002                                         << "\tbaseVertex: " << command.baseVertex << "\n"
2003                                         << "\treservedMustBeZero: " << command.reservedMustBeZero << "\n"
2004                                         << tcu::TestLog::EndMessage;
2005                 }
2006
2007                 GLuint indirectBuf = 0;
2008                 m_ctx.genBuffers(1, &indirectBuf);
2009                 m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf);
2010                 m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW);
2011                 delete [] buffer;
2012
2013                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer");
2014
2015                 m_ctx.drawElementsIndirect(primitiveToGL(primitive), indexTypeToGL(indexType), glu::BufferOffsetAsPointer(indirectOffset));
2016                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()");
2017
2018                 m_ctx.deleteBuffers(1, &indirectBuf);
2019         }
2020         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX)
2021         {
2022                 m_ctx.drawElementsBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex);
2023                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsBaseVertex()");
2024         }
2025         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX)
2026         {
2027                 m_ctx.drawElementsInstancedBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount, baseVertex);
2028                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstancedBaseVertex()");
2029         }
2030         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
2031         {
2032                 m_ctx.drawRangeElementsBaseVertex(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex);
2033                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElementsBaseVertex()");
2034         }
2035         else
2036                 DE_ASSERT(DE_FALSE);
2037
2038         for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
2039         {
2040                 if (m_arrays[arrayNdx]->isBound())
2041                 {
2042                         std::stringstream attribName;
2043                         attribName << "a_" << arrayNdx;
2044
2045                         deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str());
2046
2047                         m_ctx.disableVertexAttribArray(loc);
2048                         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDisableVertexAttribArray()");
2049                 }
2050         }
2051
2052         if (m_useVao)
2053                 m_ctx.bindVertexArray(0);
2054
2055         m_ctx.useProgram(0);
2056         m_ctx.readPixels(m_screen, 0, 0, m_screen.getWidth(), m_screen.getHeight());
2057 }
2058
2059 // DrawTestSpec
2060
2061 DrawTestSpec::AttributeSpec     DrawTestSpec::AttributeSpec::createAttributeArray (InputType inputType, OutputType outputType, Storage storage, Usage usage, int componentCount, int offset, int stride, bool normalize, int instanceDivisor)
2062 {
2063         DrawTestSpec::AttributeSpec spec;
2064
2065         spec.inputType                  = inputType;
2066         spec.outputType                 = outputType;
2067         spec.storage                    = storage;
2068         spec.usage                              = usage;
2069         spec.componentCount             = componentCount;
2070         spec.offset                             = offset;
2071         spec.stride                             = stride;
2072         spec.normalize                  = normalize;
2073         spec.instanceDivisor    = instanceDivisor;
2074
2075         spec.useDefaultAttribute= false;
2076
2077         return spec;
2078 }
2079
2080 DrawTestSpec::AttributeSpec     DrawTestSpec::AttributeSpec::createDefaultAttribute (InputType inputType, OutputType outputType, int componentCount)
2081 {
2082         DE_ASSERT(inputType == INPUTTYPE_INT || inputType == INPUTTYPE_UNSIGNED_INT || inputType == INPUTTYPE_FLOAT);
2083         DE_ASSERT(inputType == INPUTTYPE_FLOAT || componentCount == 4);
2084
2085         DrawTestSpec::AttributeSpec spec;
2086
2087         spec.inputType                          = inputType;
2088         spec.outputType                         = outputType;
2089         spec.storage                            = DrawTestSpec::STORAGE_LAST;
2090         spec.usage                                      = DrawTestSpec::USAGE_LAST;
2091         spec.componentCount                     = componentCount;
2092         spec.offset                                     = 0;
2093         spec.stride                                     = 0;
2094         spec.normalize                          = 0;
2095         spec.instanceDivisor            = 0;
2096
2097         spec.useDefaultAttribute        = true;
2098
2099         return spec;
2100 }
2101
2102 DrawTestSpec::AttributeSpec::AttributeSpec (void)
2103 {
2104         inputType                                       = DrawTestSpec::INPUTTYPE_LAST;
2105         outputType                                      = DrawTestSpec::OUTPUTTYPE_LAST;
2106         storage                                         = DrawTestSpec::STORAGE_LAST;
2107         usage                                           = DrawTestSpec::USAGE_LAST;
2108         componentCount                          = 0;
2109         offset                                          = 0;
2110         stride                                          = 0;
2111         normalize                                       = false;
2112         instanceDivisor                         = 0;
2113         useDefaultAttribute                     = false;
2114         additionalPositionAttribute = false;
2115         bgraComponentOrder                      = false;
2116 }
2117
2118 int DrawTestSpec::AttributeSpec::hash (void) const
2119 {
2120         if (useDefaultAttribute)
2121         {
2122                 return 1 * int(inputType) + 7 * int(outputType) + 13 * componentCount;
2123         }
2124         else
2125         {
2126                 return 1 * int(inputType) + 2 * int(outputType) + 3 * int(storage) + 5 * int(usage) + 7 * componentCount + 11 * offset + 13 * stride + 17 * (normalize ? 0 : 1) + 19 * instanceDivisor;
2127         }
2128 }
2129
2130 bool DrawTestSpec::AttributeSpec::valid (glu::ApiType ctxType) const
2131 {
2132         const bool inputTypeFloat                               = inputType == DrawTestSpec::INPUTTYPE_FLOAT || inputType  == DrawTestSpec::INPUTTYPE_FIXED || inputType == DrawTestSpec::INPUTTYPE_HALF;
2133         const bool inputTypeUnsignedInteger             = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE || inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT || inputType  == DrawTestSpec::INPUTTYPE_UNSIGNED_INT || inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10;
2134         const bool inputTypeSignedInteger               = inputType == DrawTestSpec::INPUTTYPE_BYTE  || inputType == DrawTestSpec::INPUTTYPE_SHORT || inputType == DrawTestSpec::INPUTTYPE_INT || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2135         const bool inputTypePacked                              = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2136
2137         const bool outputTypeFloat                              = outputType == DrawTestSpec::OUTPUTTYPE_FLOAT || outputType == DrawTestSpec::OUTPUTTYPE_VEC2  || outputType == DrawTestSpec::OUTPUTTYPE_VEC3  || outputType == DrawTestSpec::OUTPUTTYPE_VEC4;
2138         const bool outputTypeSignedInteger              = outputType == DrawTestSpec::OUTPUTTYPE_INT   || outputType == DrawTestSpec::OUTPUTTYPE_IVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC4;
2139         const bool outputTypeUnsignedInteger    = outputType == DrawTestSpec::OUTPUTTYPE_UINT  || outputType == DrawTestSpec::OUTPUTTYPE_UVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC4;
2140
2141         if (useDefaultAttribute)
2142         {
2143                 if (inputType != DrawTestSpec::INPUTTYPE_INT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT && inputType != DrawTestSpec::INPUTTYPE_FLOAT)
2144                         return false;
2145
2146                 if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && componentCount != 4)
2147                         return false;
2148
2149                 // no casting allowed (undefined results)
2150                 if (inputType == DrawTestSpec::INPUTTYPE_INT && !outputTypeSignedInteger)
2151                         return false;
2152                 if (inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT && !outputTypeUnsignedInteger)
2153                         return false;
2154         }
2155
2156         if (inputTypePacked && componentCount != 4)
2157                 return false;
2158
2159         // Invalid conversions:
2160
2161         // float -> [u]int
2162         if (inputTypeFloat && !outputTypeFloat)
2163                 return false;
2164
2165         // uint -> int          (undefined results)
2166         if (inputTypeUnsignedInteger && outputTypeSignedInteger)
2167                 return false;
2168
2169         // int -> uint          (undefined results)
2170         if (inputTypeSignedInteger && outputTypeUnsignedInteger)
2171                 return false;
2172
2173         // packed -> non-float (packed formats are converted to floats)
2174         if (inputTypePacked && !outputTypeFloat)
2175                 return false;
2176
2177         // Invalid normalize. Normalize is only valid if output type is float
2178         if (normalize && !outputTypeFloat)
2179                 return false;
2180
2181         // Allow reverse order (GL_BGRA) only for packed and 4-component ubyte
2182         if (bgraComponentOrder && componentCount != 4)
2183                 return false;
2184         if (bgraComponentOrder && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE)
2185                 return false;
2186         if (bgraComponentOrder && normalize != true)
2187                 return false;
2188
2189         // GLES2 limits
2190         if (ctxType == glu::ApiType::es(2,0))
2191         {
2192                 if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && inputType != DrawTestSpec::INPUTTYPE_FIXED &&
2193                         inputType != DrawTestSpec::INPUTTYPE_BYTE  && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE &&
2194                         inputType != DrawTestSpec::INPUTTYPE_SHORT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT)
2195                         return false;
2196
2197                 if (!outputTypeFloat)
2198                         return false;
2199
2200                 if (bgraComponentOrder)
2201                         return false;
2202         }
2203
2204         // GLES3 limits
2205         if (ctxType.getProfile() == glu::PROFILE_ES && ctxType.getMajorVersion() == 3)
2206         {
2207                 if (bgraComponentOrder)
2208                         return false;
2209         }
2210
2211         // No user pointers in GL core
2212         if (ctxType.getProfile() == glu::PROFILE_CORE)
2213         {
2214                 if (!useDefaultAttribute && storage == DrawTestSpec::STORAGE_USER)
2215                         return false;
2216         }
2217
2218         return true;
2219 }
2220
2221 bool DrawTestSpec::AttributeSpec::isBufferAligned (void) const
2222 {
2223         const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2224
2225         // Buffer alignment, offset is a multiple of underlying data type size?
2226         if (storage == STORAGE_BUFFER)
2227         {
2228                 int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType);
2229                 if (inputTypePacked)
2230                         dataTypeSize = 4;
2231
2232                 if (offset % dataTypeSize != 0)
2233                         return false;
2234         }
2235
2236         return true;
2237 }
2238
2239 bool DrawTestSpec::AttributeSpec::isBufferStrideAligned (void) const
2240 {
2241         const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2242
2243         // Buffer alignment, offset is a multiple of underlying data type size?
2244         if (storage == STORAGE_BUFFER)
2245         {
2246                 int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType);
2247                 if (inputTypePacked)
2248                         dataTypeSize = 4;
2249
2250                 if (stride % dataTypeSize != 0)
2251                         return false;
2252         }
2253
2254         return true;
2255 }
2256
2257 std::string DrawTestSpec::targetToString(Target target)
2258 {
2259         static const char* targets[] =
2260         {
2261                 "element_array",        // TARGET_ELEMENT_ARRAY = 0,
2262                 "array"                         // TARGET_ARRAY,
2263         };
2264
2265         return de::getSizedArrayElement<DrawTestSpec::TARGET_LAST>(targets, (int)target);
2266 }
2267
2268 std::string DrawTestSpec::inputTypeToString(InputType type)
2269 {
2270         static const char* types[] =
2271         {
2272                 "float",                        // INPUTTYPE_FLOAT = 0,
2273                 "fixed",                        // INPUTTYPE_FIXED,
2274                 "double",                       // INPUTTYPE_DOUBLE
2275
2276                 "byte",                         // INPUTTYPE_BYTE,
2277                 "short",                        // INPUTTYPE_SHORT,
2278
2279                 "unsigned_byte",        // INPUTTYPE_UNSIGNED_BYTE,
2280                 "unsigned_short",       // INPUTTYPE_UNSIGNED_SHORT,
2281
2282                 "int",                                          // INPUTTYPE_INT,
2283                 "unsigned_int",                         // INPUTTYPE_UNSIGNED_INT,
2284                 "half",                                         // INPUTTYPE_HALF,
2285                 "unsigned_int2_10_10_10",       // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
2286                 "int2_10_10_10"                         // INPUTTYPE_INT_2_10_10_10,
2287         };
2288
2289         return de::getSizedArrayElement<DrawTestSpec::INPUTTYPE_LAST>(types, (int)type);
2290 }
2291
2292 std::string DrawTestSpec::outputTypeToString(OutputType type)
2293 {
2294         static const char* types[] =
2295         {
2296                 "float",                // OUTPUTTYPE_FLOAT = 0,
2297                 "vec2",                 // OUTPUTTYPE_VEC2,
2298                 "vec3",                 // OUTPUTTYPE_VEC3,
2299                 "vec4",                 // OUTPUTTYPE_VEC4,
2300
2301                 "int",                  // OUTPUTTYPE_INT,
2302                 "uint",                 // OUTPUTTYPE_UINT,
2303
2304                 "ivec2",                // OUTPUTTYPE_IVEC2,
2305                 "ivec3",                // OUTPUTTYPE_IVEC3,
2306                 "ivec4",                // OUTPUTTYPE_IVEC4,
2307
2308                 "uvec2",                // OUTPUTTYPE_UVEC2,
2309                 "uvec3",                // OUTPUTTYPE_UVEC3,
2310                 "uvec4",                // OUTPUTTYPE_UVEC4,
2311         };
2312
2313         return de::getSizedArrayElement<DrawTestSpec::OUTPUTTYPE_LAST>(types, (int)type);
2314 }
2315
2316 std::string DrawTestSpec::usageTypeToString(Usage usage)
2317 {
2318         static const char* usages[] =
2319         {
2320                 "dynamic_draw", // USAGE_DYNAMIC_DRAW = 0,
2321                 "static_draw",  // USAGE_STATIC_DRAW,
2322                 "stream_draw",  // USAGE_STREAM_DRAW,
2323
2324                 "stream_read",  // USAGE_STREAM_READ,
2325                 "stream_copy",  // USAGE_STREAM_COPY,
2326
2327                 "static_read",  // USAGE_STATIC_READ,
2328                 "static_copy",  // USAGE_STATIC_COPY,
2329
2330                 "dynamic_read", // USAGE_DYNAMIC_READ,
2331                 "dynamic_copy", // USAGE_DYNAMIC_COPY,
2332         };
2333
2334         return de::getSizedArrayElement<DrawTestSpec::USAGE_LAST>(usages, (int)usage);
2335 }
2336
2337 std::string     DrawTestSpec::storageToString (Storage storage)
2338 {
2339         static const char* storages[] =
2340         {
2341                 "user_ptr",     // STORAGE_USER = 0,
2342                 "buffer"        // STORAGE_BUFFER,
2343         };
2344
2345         return de::getSizedArrayElement<DrawTestSpec::STORAGE_LAST>(storages, (int)storage);
2346 }
2347
2348 std::string DrawTestSpec::primitiveToString (Primitive primitive)
2349 {
2350         static const char* primitives[] =
2351         {
2352                 "points",                                       // PRIMITIVE_POINTS ,
2353                 "triangles",                            // PRIMITIVE_TRIANGLES,
2354                 "triangle_fan",                         // PRIMITIVE_TRIANGLE_FAN,
2355                 "triangle_strip",                       // PRIMITIVE_TRIANGLE_STRIP,
2356                 "lines",                                        // PRIMITIVE_LINES
2357                 "line_strip",                           // PRIMITIVE_LINE_STRIP
2358                 "line_loop",                            // PRIMITIVE_LINE_LOOP
2359                 "lines_adjacency",                      // PRIMITIVE_LINES_ADJACENCY
2360                 "line_strip_adjacency",         // PRIMITIVE_LINE_STRIP_ADJACENCY
2361                 "triangles_adjacency",          // PRIMITIVE_TRIANGLES_ADJACENCY
2362                 "triangle_strip_adjacency",     // PRIMITIVE_TRIANGLE_STRIP_ADJACENCY
2363         };
2364
2365         return de::getSizedArrayElement<DrawTestSpec::PRIMITIVE_LAST>(primitives, (int)primitive);
2366 }
2367
2368 std::string DrawTestSpec::indexTypeToString (IndexType type)
2369 {
2370         static const char* indexTypes[] =
2371         {
2372                 "byte",         // INDEXTYPE_BYTE = 0,
2373                 "short",        // INDEXTYPE_SHORT,
2374                 "int",          // INDEXTYPE_INT,
2375         };
2376
2377         return de::getSizedArrayElement<DrawTestSpec::INDEXTYPE_LAST>(indexTypes, (int)type);
2378 }
2379
2380 std::string DrawTestSpec::drawMethodToString (DrawTestSpec::DrawMethod method)
2381 {
2382         static const char* methods[] =
2383         {
2384                 "draw_arrays",                                                  //!< DRAWMETHOD_DRAWARRAYS
2385                 "draw_arrays_instanced",                                //!< DRAWMETHOD_DRAWARRAYS_INSTANCED
2386                 "draw_arrays_indirect",                                 //!< DRAWMETHOD_DRAWARRAYS_INDIRECT
2387                 "draw_elements",                                                //!< DRAWMETHOD_DRAWELEMENTS
2388                 "draw_range_elements",                                  //!< DRAWMETHOD_DRAWELEMENTS_RANGED
2389                 "draw_elements_instanced",                              //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED
2390                 "draw_elements_indirect",                               //!< DRAWMETHOD_DRAWELEMENTS_INDIRECT
2391                 "draw_elements_base_vertex",                    //!< DRAWMETHOD_DRAWELEMENTS_BASEVERTEX,
2392                 "draw_elements_instanced_base_vertex",  //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX,
2393                 "draw_range_elements_base_vertex",              //!< DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX,
2394         };
2395
2396         return de::getSizedArrayElement<DrawTestSpec::DRAWMETHOD_LAST>(methods, (int)method);
2397 }
2398
2399 int DrawTestSpec::inputTypeSize (InputType type)
2400 {
2401         static const int size[] =
2402         {
2403                 (int)sizeof(float),                     // INPUTTYPE_FLOAT = 0,
2404                 (int)sizeof(deInt32),           // INPUTTYPE_FIXED,
2405                 (int)sizeof(double),            // INPUTTYPE_DOUBLE
2406
2407                 (int)sizeof(deInt8),            // INPUTTYPE_BYTE,
2408                 (int)sizeof(deInt16),           // INPUTTYPE_SHORT,
2409
2410                 (int)sizeof(deUint8),           // INPUTTYPE_UNSIGNED_BYTE,
2411                 (int)sizeof(deUint16),          // INPUTTYPE_UNSIGNED_SHORT,
2412
2413                 (int)sizeof(deInt32),           // INPUTTYPE_INT,
2414                 (int)sizeof(deUint32),          // INPUTTYPE_UNSIGNED_INT,
2415                 (int)sizeof(deFloat16),         // INPUTTYPE_HALF,
2416                 (int)sizeof(deUint32) / 4,      // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
2417                 (int)sizeof(deUint32) / 4       // INPUTTYPE_INT_2_10_10_10,
2418         };
2419
2420         return de::getSizedArrayElement<DrawTestSpec::INPUTTYPE_LAST>(size, (int)type);
2421 }
2422
2423 int DrawTestSpec::indexTypeSize (IndexType type)
2424 {
2425         static const int size[] =
2426         {
2427                 sizeof(deUint8),        // INDEXTYPE_BYTE,
2428                 sizeof(deUint16),       // INDEXTYPE_SHORT,
2429                 sizeof(deUint32),       // INDEXTYPE_INT,
2430         };
2431
2432         return de::getSizedArrayElement<DrawTestSpec::INDEXTYPE_LAST>(size, (int)type);
2433 }
2434
2435 std::string DrawTestSpec::getName (void) const
2436 {
2437         const MethodInfo        methodInfo      = getMethodInfo(drawMethod);
2438         const bool                      hasFirst        = methodInfo.first;
2439         const bool                      instanced       = methodInfo.instanced;
2440         const bool                      ranged          = methodInfo.ranged;
2441         const bool                      indexed         = methodInfo.indexed;
2442
2443         std::stringstream name;
2444
2445         for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
2446         {
2447                 const AttributeSpec& attrib = attribs[ndx];
2448
2449                 if (attribs.size() > 1)
2450                         name << "attrib" << ndx << "_";
2451
2452                 if (ndx == 0|| attrib.additionalPositionAttribute)
2453                         name << "pos_";
2454                 else
2455                         name << "col_";
2456
2457                 if (attrib.useDefaultAttribute)
2458                 {
2459                         name
2460                                 << "non_array_"
2461                                 << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "_"
2462                                 << attrib.componentCount << "_"
2463                                 << DrawTestSpec::outputTypeToString(attrib.outputType) << "_";
2464                 }
2465                 else
2466                 {
2467                         name
2468                                 << DrawTestSpec::storageToString(attrib.storage) << "_"
2469                                 << attrib.offset << "_"
2470                                 << attrib.stride << "_"
2471                                 << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType);
2472                         if (attrib.inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && attrib.inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
2473                                 name << attrib.componentCount;
2474                         name
2475                                 << "_"
2476                                 << (attrib.normalize ? "normalized_" : "")
2477                                 << DrawTestSpec::outputTypeToString(attrib.outputType) << "_"
2478                                 << DrawTestSpec::usageTypeToString(attrib.usage) << "_"
2479                                 << attrib.instanceDivisor << "_";
2480                 }
2481         }
2482
2483         if (indexed)
2484                 name
2485                         << "index_" << DrawTestSpec::indexTypeToString(indexType) << "_"
2486                         << DrawTestSpec::storageToString(indexStorage) << "_"
2487                         << "offset" << indexPointerOffset << "_";
2488         if (hasFirst)
2489                 name << "first" << first << "_";
2490         if (ranged)
2491                 name << "ranged_" << indexMin << "_" << indexMax << "_";
2492         if (instanced)
2493                 name << "instances" << instanceCount << "_";
2494
2495         switch (primitive)
2496         {
2497                 case DrawTestSpec::PRIMITIVE_POINTS:
2498                         name << "points_";
2499                         break;
2500                 case DrawTestSpec::PRIMITIVE_TRIANGLES:
2501                         name << "triangles_";
2502                         break;
2503                 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
2504                         name << "triangle_fan_";
2505                         break;
2506                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
2507                         name << "triangle_strip_";
2508                         break;
2509                 case DrawTestSpec::PRIMITIVE_LINES:
2510                         name << "lines_";
2511                         break;
2512                 case DrawTestSpec::PRIMITIVE_LINE_STRIP:
2513                         name << "line_strip_";
2514                         break;
2515                 case DrawTestSpec::PRIMITIVE_LINE_LOOP:
2516                         name << "line_loop_";
2517                         break;
2518                 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
2519                         name << "line_adjancency";
2520                         break;
2521                 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
2522                         name << "line_strip_adjancency";
2523                         break;
2524                 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
2525                         name << "triangles_adjancency";
2526                         break;
2527                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
2528                         name << "triangle_strip_adjancency";
2529                         break;
2530                 default:
2531                         DE_ASSERT(false);
2532                         break;
2533         }
2534
2535         name << primitiveCount;
2536
2537         return name.str();
2538 }
2539
2540 std::string DrawTestSpec::getDesc (void) const
2541 {
2542         std::stringstream desc;
2543
2544         for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
2545         {
2546                 const AttributeSpec& attrib = attribs[ndx];
2547
2548                 if (attrib.useDefaultAttribute)
2549                 {
2550                         desc
2551                                 << "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,"))
2552                                 << "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", "
2553                                 << "input component count " << attrib.componentCount << ", "
2554                                 << "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", ";
2555                 }
2556                 else
2557                 {
2558                         desc
2559                                 << "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,"))
2560                                 << "Storage in " << DrawTestSpec::storageToString(attrib.storage) << ", "
2561                                 << "stride " << attrib.stride << ", "
2562                                 << "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", "
2563                                 << "input component count " << attrib.componentCount << ", "
2564                                 << (attrib.normalize ? "normalized, " : "")
2565                                 << "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", "
2566                                 << "instance divisor " << attrib.instanceDivisor << ", ";
2567                 }
2568         }
2569
2570         if (drawMethod == DRAWMETHOD_DRAWARRAYS)
2571         {
2572                 desc
2573                         << "drawArrays(), "
2574                         << "first " << first << ", ";
2575         }
2576         else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED)
2577         {
2578                 desc
2579                         << "drawArraysInstanced(), "
2580                         << "first " << first << ", "
2581                         << "instance count " << instanceCount << ", ";
2582         }
2583         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS)
2584         {
2585                 desc
2586                         << "drawElements(), "
2587                         << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2588                         << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2589                         << "index offset " << indexPointerOffset << ", ";
2590         }
2591         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED)
2592         {
2593                 desc
2594                         << "drawElementsRanged(), "
2595                         << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2596                         << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2597                         << "index offset " << indexPointerOffset << ", "
2598                         << "range start " << indexMin << ", "
2599                         << "range end " << indexMax << ", ";
2600         }
2601         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED)
2602         {
2603                 desc
2604                         << "drawElementsInstanced(), "
2605                         << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2606                         << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2607                         << "index offset " << indexPointerOffset << ", "
2608                         << "instance count " << instanceCount << ", ";
2609         }
2610         else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT)
2611         {
2612                 desc
2613                         << "drawArraysIndirect(), "
2614                         << "first " << first << ", "
2615                         << "instance count " << instanceCount << ", "
2616                         << "indirect offset " << indirectOffset << ", ";
2617         }
2618         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2619         {
2620                 desc
2621                         << "drawElementsIndirect(), "
2622                         << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2623                         << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2624                         << "index offset " << indexPointerOffset << ", "
2625                         << "instance count " << instanceCount << ", "
2626                         << "indirect offset " << indirectOffset << ", "
2627                         << "base vertex " << baseVertex << ", ";
2628         }
2629         else
2630                 DE_ASSERT(DE_FALSE);
2631
2632         desc << primitiveCount;
2633
2634         switch (primitive)
2635         {
2636                 case DrawTestSpec::PRIMITIVE_POINTS:
2637                         desc << "points";
2638                         break;
2639                 case DrawTestSpec::PRIMITIVE_TRIANGLES:
2640                         desc << "triangles";
2641                         break;
2642                 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
2643                         desc << "triangles (fan)";
2644                         break;
2645                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
2646                         desc << "triangles (strip)";
2647                         break;
2648                 case DrawTestSpec::PRIMITIVE_LINES:
2649                         desc << "lines";
2650                         break;
2651                 case DrawTestSpec::PRIMITIVE_LINE_STRIP:
2652                         desc << "lines (strip)";
2653                         break;
2654                 case DrawTestSpec::PRIMITIVE_LINE_LOOP:
2655                         desc << "lines (loop)";
2656                         break;
2657                 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
2658                         desc << "lines (adjancency)";
2659                         break;
2660                 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
2661                         desc << "lines (strip, adjancency)";
2662                         break;
2663                 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
2664                         desc << "triangles (adjancency)";
2665                         break;
2666                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
2667                         desc << "triangles (strip, adjancency)";
2668                         break;
2669                 default:
2670                         DE_ASSERT(false);
2671                         break;
2672         }
2673
2674         return desc.str();
2675 }
2676
2677 std::string DrawTestSpec::getMultilineDesc (void) const
2678 {
2679         std::stringstream desc;
2680
2681         for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
2682         {
2683                 const AttributeSpec& attrib = attribs[ndx];
2684
2685                 if (attrib.useDefaultAttribute)
2686                 {
2687                         desc
2688                                 << "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n"))
2689                                 << "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n"
2690                                 << "\tinput component count " << attrib.componentCount << "\n"
2691                                 << "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n";
2692                 }
2693                 else
2694                 {
2695                         desc
2696                                 << "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n"))
2697                                 << "\tStorage in " << DrawTestSpec::storageToString(attrib.storage) << "\n"
2698                                 << "\tstride " << attrib.stride << "\n"
2699                                 << "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n"
2700                                 << "\tinput component count " << attrib.componentCount << "\n"
2701                                 << (attrib.normalize ? "\tnormalized\n" : "")
2702                                 << "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n"
2703                                 << "\tinstance divisor " << attrib.instanceDivisor << "\n";
2704                 }
2705         }
2706
2707         if (drawMethod == DRAWMETHOD_DRAWARRAYS)
2708         {
2709                 desc
2710                         << "drawArrays()\n"
2711                         << "\tfirst " << first << "\n";
2712         }
2713         else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED)
2714         {
2715                 desc
2716                         << "drawArraysInstanced()\n"
2717                         << "\tfirst " << first << "\n"
2718                         << "\tinstance count " << instanceCount << "\n";
2719         }
2720         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS)
2721         {
2722                 desc
2723                         << "drawElements()\n"
2724                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2725                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2726                         << "\tindex offset " << indexPointerOffset << "\n";
2727         }
2728         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED)
2729         {
2730                 desc
2731                         << "drawElementsRanged()\n"
2732                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2733                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2734                         << "\tindex offset " << indexPointerOffset << "\n"
2735                         << "\trange start " << indexMin << "\n"
2736                         << "\trange end " << indexMax << "\n";
2737         }
2738         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED)
2739         {
2740                 desc
2741                         << "drawElementsInstanced()\n"
2742                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2743                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2744                         << "\tindex offset " << indexPointerOffset << "\n"
2745                         << "\tinstance count " << instanceCount << "\n";
2746         }
2747         else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT)
2748         {
2749                 desc
2750                         << "drawArraysIndirect()\n"
2751                         << "\tfirst " << first << "\n"
2752                         << "\tinstance count " << instanceCount << "\n"
2753                         << "\tindirect offset " << indirectOffset << "\n";
2754         }
2755         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2756         {
2757                 desc
2758                         << "drawElementsIndirect()\n"
2759                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2760                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2761                         << "\tindex offset " << indexPointerOffset << "\n"
2762                         << "\tinstance count " << instanceCount << "\n"
2763                         << "\tindirect offset " << indirectOffset << "\n"
2764                         << "\tbase vertex " << baseVertex << "\n";
2765         }
2766         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_BASEVERTEX)
2767         {
2768                 desc
2769                         << "drawElementsBaseVertex()\n"
2770                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2771                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2772                         << "\tindex offset " << indexPointerOffset << "\n"
2773                         << "\tbase vertex " << baseVertex << "\n";
2774         }
2775         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX)
2776         {
2777                 desc
2778                         << "drawElementsInstancedBaseVertex()\n"
2779                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2780                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2781                         << "\tindex offset " << indexPointerOffset << "\n"
2782                         << "\tinstance count " << instanceCount << "\n"
2783                         << "\tbase vertex " << baseVertex << "\n";
2784         }
2785         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
2786         {
2787                 desc
2788                         << "drawRangeElementsBaseVertex()\n"
2789                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2790                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2791                         << "\tindex offset " << indexPointerOffset << "\n"
2792                         << "\tbase vertex " << baseVertex << "\n"
2793                         << "\trange start " << indexMin << "\n"
2794                         << "\trange end " << indexMax << "\n";
2795         }
2796         else
2797                 DE_ASSERT(DE_FALSE);
2798
2799         desc << "\t" << primitiveCount << " ";
2800
2801         switch (primitive)
2802         {
2803                 case DrawTestSpec::PRIMITIVE_POINTS:
2804                         desc << "points";
2805                         break;
2806                 case DrawTestSpec::PRIMITIVE_TRIANGLES:
2807                         desc << "triangles";
2808                         break;
2809                 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
2810                         desc << "triangles (fan)";
2811                         break;
2812                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
2813                         desc << "triangles (strip)";
2814                         break;
2815                 case DrawTestSpec::PRIMITIVE_LINES:
2816                         desc << "lines";
2817                         break;
2818                 case DrawTestSpec::PRIMITIVE_LINE_STRIP:
2819                         desc << "lines (strip)";
2820                         break;
2821                 case DrawTestSpec::PRIMITIVE_LINE_LOOP:
2822                         desc << "lines (loop)";
2823                         break;
2824                 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
2825                         desc << "lines (adjancency)";
2826                         break;
2827                 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
2828                         desc << "lines (strip, adjancency)";
2829                         break;
2830                 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
2831                         desc << "triangles (adjancency)";
2832                         break;
2833                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
2834                         desc << "triangles (strip, adjancency)";
2835                         break;
2836                 default:
2837                         DE_ASSERT(false);
2838                         break;
2839         }
2840
2841         desc << "\n";
2842
2843         return desc.str();
2844 }
2845
2846 DrawTestSpec::DrawTestSpec (void)
2847 {
2848         primitive                       = PRIMITIVE_LAST;
2849         primitiveCount          = 0;
2850         drawMethod                      = DRAWMETHOD_LAST;
2851         indexType                       = INDEXTYPE_LAST;
2852         indexPointerOffset      = 0;
2853         indexStorage            = STORAGE_LAST;
2854         first                           = 0;
2855         indexMin                        = 0;
2856         indexMax                        = 0;
2857         instanceCount           = 0;
2858         indirectOffset          = 0;
2859         baseVertex                      = 0;
2860 }
2861
2862 int DrawTestSpec::hash (void) const
2863 {
2864         // Use only drawmode-relevant values in "hashing" as the unrelevant values might not be set (causing non-deterministic behavior).
2865         const MethodInfo        methodInfo              = getMethodInfo(drawMethod);
2866         const bool                      arrayed                 = methodInfo.first;
2867         const bool                      instanced               = methodInfo.instanced;
2868         const bool                      ranged                  = methodInfo.ranged;
2869         const bool                      indexed                 = methodInfo.indexed;
2870         const bool                      indirect                = methodInfo.indirect;
2871         const bool                      hasBaseVtx              = methodInfo.baseVertex;
2872
2873         const int                       indexHash               = (!indexed)    ? (0) : (int(indexType) + 10 * indexPointerOffset + 100 * int(indexStorage));
2874         const int                       arrayHash               = (!arrayed)    ? (0) : (first);
2875         const int                       indexRangeHash  = (!ranged)             ? (0) : (indexMin + 10 * indexMax);
2876         const int                       instanceHash    = (!instanced)  ? (0) : (instanceCount);
2877         const int                       indirectHash    = (!indirect)   ? (0) : (indirectOffset);
2878         const int                       baseVtxHash             = (!hasBaseVtx) ? (0) : (baseVertex);
2879         const int                       basicHash               = int(primitive) + 10 * primitiveCount + 100 * int(drawMethod);
2880
2881         return indexHash + 3 * arrayHash + 5 * indexRangeHash + 7 * instanceHash + 13 * basicHash + 17 * (int)attribs.size() + 19 * primitiveCount + 23 * indirectHash + 27 * baseVtxHash;
2882 }
2883
2884 bool DrawTestSpec::valid (void) const
2885 {
2886         DE_ASSERT(apiType.getProfile() != glu::PROFILE_LAST);
2887         DE_ASSERT(primitive != PRIMITIVE_LAST);
2888         DE_ASSERT(drawMethod != DRAWMETHOD_LAST);
2889
2890         const MethodInfo methodInfo = getMethodInfo(drawMethod);
2891
2892         for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
2893                 if (!attribs[ndx].valid(apiType))
2894                         return false;
2895
2896         if (methodInfo.ranged)
2897         {
2898                 deUint32 maxIndexValue = 0;
2899                 if (indexType == INDEXTYPE_BYTE)
2900                         maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_BYTE).ub.getValue();
2901                 else if (indexType == INDEXTYPE_SHORT)
2902                         maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_SHORT).us.getValue();
2903                 else if (indexType == INDEXTYPE_INT)
2904                         maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_INT).ui.getValue();
2905                 else
2906                         DE_ASSERT(DE_FALSE);
2907
2908                 if (indexMin > indexMax)
2909                         return false;
2910                 if (indexMin < 0 || indexMax < 0)
2911                         return false;
2912                 if ((deUint32)indexMin > maxIndexValue || (deUint32)indexMax > maxIndexValue)
2913                         return false;
2914         }
2915
2916         if (methodInfo.first && first < 0)
2917                 return false;
2918
2919         // GLES2 limits
2920         if (apiType == glu::ApiType::es(2,0))
2921         {
2922                 if (drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS && drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS)
2923                         return false;
2924                 if (drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS && (indexType != INDEXTYPE_BYTE && indexType != INDEXTYPE_SHORT))
2925                         return false;
2926         }
2927
2928         // Indirect limitations
2929         if (methodInfo.indirect)
2930         {
2931                 // Indirect offset alignment
2932                 if (indirectOffset % 4 != 0)
2933                         return false;
2934
2935                 // All attribute arrays must be stored in a buffer
2936                 for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
2937                         if (!attribs[ndx].useDefaultAttribute && attribs[ndx].storage == gls::DrawTestSpec::STORAGE_USER)
2938                                 return false;
2939         }
2940         if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2941         {
2942                 // index offset must be convertable to firstIndex
2943                 if (indexPointerOffset % gls::DrawTestSpec::indexTypeSize(indexType) != 0)
2944                         return false;
2945
2946                 // Indices must be in a buffer
2947                 if (indexStorage != STORAGE_BUFFER)
2948                         return false;
2949         }
2950
2951         // Do not allow user pointer in GL core
2952         if (apiType.getProfile() == glu::PROFILE_CORE)
2953         {
2954                 if (methodInfo.indexed && indexStorage == DrawTestSpec::STORAGE_USER)
2955                         return false;
2956         }
2957
2958         return true;
2959 }
2960
2961 DrawTestSpec::CompatibilityTestType DrawTestSpec::isCompatibilityTest (void) const
2962 {
2963         const MethodInfo methodInfo = getMethodInfo(drawMethod);
2964
2965         bool bufferAlignmentBad = false;
2966         bool strideAlignmentBad = false;
2967
2968         // Attribute buffer alignment
2969         for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
2970                 if (!attribs[ndx].isBufferAligned())
2971                         bufferAlignmentBad = true;
2972
2973         // Attribute stride alignment
2974         for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
2975                 if (!attribs[ndx].isBufferStrideAligned())
2976                         strideAlignmentBad = true;
2977
2978         // Index buffer alignment
2979         if (methodInfo.indexed)
2980         {
2981                 if (indexStorage == STORAGE_BUFFER)
2982                 {
2983                         int indexSize = 0;
2984                         if (indexType == INDEXTYPE_BYTE)
2985                                 indexSize = 1;
2986                         else if (indexType == INDEXTYPE_SHORT)
2987                                 indexSize = 2;
2988                         else if (indexType == INDEXTYPE_INT)
2989                                 indexSize = 4;
2990                         else
2991                                 DE_ASSERT(DE_FALSE);
2992
2993                         if (indexPointerOffset % indexSize != 0)
2994                                 bufferAlignmentBad = true;
2995                 }
2996         }
2997
2998         // \note combination bad alignment & stride is treated as bad offset
2999         if (bufferAlignmentBad)
3000                 return COMPATIBILITY_UNALIGNED_OFFSET;
3001         else if (strideAlignmentBad)
3002                 return COMPATIBILITY_UNALIGNED_STRIDE;
3003         else
3004                 return COMPATIBILITY_NONE;
3005 }
3006
3007 enum PrimitiveClass
3008 {
3009         PRIMITIVECLASS_POINT = 0,
3010         PRIMITIVECLASS_LINE,
3011         PRIMITIVECLASS_TRIANGLE,
3012
3013         PRIMITIVECLASS_LAST
3014 };
3015
3016 static PrimitiveClass getDrawPrimitiveClass (gls::DrawTestSpec::Primitive primitiveType)
3017 {
3018         switch (primitiveType)
3019         {
3020                 case gls::DrawTestSpec::PRIMITIVE_POINTS:
3021                         return PRIMITIVECLASS_POINT;
3022
3023                 case gls::DrawTestSpec::PRIMITIVE_LINES:
3024                 case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP:
3025                 case gls::DrawTestSpec::PRIMITIVE_LINE_LOOP:
3026                 case gls::DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
3027                 case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
3028                         return PRIMITIVECLASS_LINE;
3029
3030                 case gls::DrawTestSpec::PRIMITIVE_TRIANGLES:
3031                 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
3032                 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
3033                 case gls::DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
3034                 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
3035                         return PRIMITIVECLASS_TRIANGLE;
3036
3037                 default:
3038                         DE_ASSERT(false);
3039                         return PRIMITIVECLASS_LAST;
3040         }
3041 }
3042
3043 static bool containsLineCases (const std::vector<DrawTestSpec>& m_specs)
3044 {
3045         for (int ndx = 0; ndx < (int)m_specs.size(); ++ndx)
3046         {
3047                 if (getDrawPrimitiveClass(m_specs[ndx].primitive) == PRIMITIVECLASS_LINE)
3048                         return true;
3049         }
3050         return false;
3051 }
3052
3053 // DrawTest
3054
3055 DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const DrawTestSpec& spec, const char* name, const char* desc)
3056         : TestCase                      (testCtx, name, desc)
3057         , m_renderCtx           (renderCtx)
3058         , m_contextInfo         (DE_NULL)
3059         , m_refBuffers          (DE_NULL)
3060         , m_refContext          (DE_NULL)
3061         , m_glesContext         (DE_NULL)
3062         , m_glArrayPack         (DE_NULL)
3063         , m_rrArrayPack         (DE_NULL)
3064         , m_maxDiffRed          (-1)
3065         , m_maxDiffGreen        (-1)
3066         , m_maxDiffBlue         (-1)
3067         , m_iteration           (0)
3068         , m_result                      ()      // \note no per-iteration result logging (only one iteration)
3069 {
3070         addIteration(spec);
3071 }
3072
3073 DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc)
3074         : TestCase                      (testCtx, name, desc)
3075         , m_renderCtx           (renderCtx)
3076         , m_contextInfo         (DE_NULL)
3077         , m_refBuffers          (DE_NULL)
3078         , m_refContext          (DE_NULL)
3079         , m_glesContext         (DE_NULL)
3080         , m_glArrayPack         (DE_NULL)
3081         , m_rrArrayPack         (DE_NULL)
3082         , m_maxDiffRed          (-1)
3083         , m_maxDiffGreen        (-1)
3084         , m_maxDiffBlue         (-1)
3085         , m_iteration           (0)
3086         , m_result                      (testCtx.getLog(), "Iteration result: ")
3087 {
3088 }
3089
3090 DrawTest::~DrawTest     (void)
3091 {
3092         deinit();
3093 }
3094
3095 void DrawTest::addIteration (const DrawTestSpec& spec, const char* description)
3096 {
3097         // Validate spec
3098         const bool validSpec = spec.valid();
3099         DE_ASSERT(validSpec);
3100
3101         if (!validSpec)
3102                 return;
3103
3104         // Check the context type is the same with other iterations
3105         if (!m_specs.empty())
3106         {
3107                 const bool validContext = m_specs[0].apiType == spec.apiType;
3108                 DE_ASSERT(validContext);
3109
3110                 if (!validContext)
3111                         return;
3112         }
3113
3114         m_specs.push_back(spec);
3115
3116         if (description)
3117                 m_iteration_descriptions.push_back(std::string(description));
3118         else
3119                 m_iteration_descriptions.push_back(std::string());
3120 }
3121
3122 void DrawTest::init (void)
3123 {
3124         DE_ASSERT(!m_specs.empty());
3125         DE_ASSERT(contextSupports(m_renderCtx.getType(), m_specs[0].apiType));
3126
3127         const int                                               renderTargetWidth       = de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getWidth());
3128         const int                                               renderTargetHeight      = de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getHeight());
3129
3130         // lines have significantly different rasterization in MSAA mode
3131         const bool                                              isLineCase                      = containsLineCases(m_specs);
3132         const bool                                              isMSAACase                      = m_renderCtx.getRenderTarget().getNumSamples() > 1;
3133         const int                                               renderTargetSamples     = (isMSAACase && isLineCase) ? (4) : (1);
3134
3135         sglr::ReferenceContextLimits    limits                          (m_renderCtx);
3136         bool                                                    useVao                          = false;
3137
3138         m_glesContext = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
3139
3140         if (m_renderCtx.getType().getAPI() == glu::ApiType::es(2,0) || m_renderCtx.getType().getAPI() == glu::ApiType::es(3,0))
3141                 useVao = false;
3142         else if (contextSupports(m_renderCtx.getType(), glu::ApiType::es(3,1)) || glu::isContextTypeGLCore(m_renderCtx.getType()))
3143                 useVao = true;
3144         else
3145                 DE_FATAL("Unknown context type");
3146
3147         m_refBuffers    = new sglr::ReferenceContextBuffers(m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, renderTargetWidth, renderTargetHeight, renderTargetSamples);
3148         m_refContext    = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
3149
3150         m_glArrayPack   = new AttributePack(m_testCtx, m_renderCtx, *m_glesContext, tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, true);
3151         m_rrArrayPack   = new AttributePack(m_testCtx, m_renderCtx, *m_refContext,  tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, false);
3152
3153         m_maxDiffRed    = deCeilFloatToInt32(256.0f * (6.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().redBits)));
3154         m_maxDiffGreen  = deCeilFloatToInt32(256.0f * (6.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().greenBits)));
3155         m_maxDiffBlue   = deCeilFloatToInt32(256.0f * (6.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().blueBits)));
3156         m_contextInfo   = glu::ContextInfo::create(m_renderCtx);
3157 }
3158
3159 void DrawTest::deinit (void)
3160 {
3161         delete m_glArrayPack;
3162         delete m_rrArrayPack;
3163         delete m_refBuffers;
3164         delete m_refContext;
3165         delete m_glesContext;
3166         delete m_contextInfo;
3167
3168         m_glArrayPack   = DE_NULL;
3169         m_rrArrayPack   = DE_NULL;
3170         m_refBuffers    = DE_NULL;
3171         m_refContext    = DE_NULL;
3172         m_glesContext   = DE_NULL;
3173         m_contextInfo   = DE_NULL;
3174 }
3175
3176 DrawTest::IterateResult DrawTest::iterate (void)
3177 {
3178         const int                                       specNdx                 = (m_iteration / 2);
3179         const DrawTestSpec&                     spec                    = m_specs[specNdx];
3180
3181         if (spec.drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX ||
3182                 spec.drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX ||
3183                 spec.drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
3184         {
3185                 const bool supportsES32orGL45 = contextSupports(m_renderCtx.getType(), glu::ApiType::es(3, 2)) ||
3186                                                                                 contextSupports(m_renderCtx.getType(), glu::ApiType::core(4, 5));
3187                 TCU_CHECK_AND_THROW(NotSupportedError, supportsES32orGL45 || m_contextInfo->isExtensionSupported("GL_EXT_draw_elements_base_vertex"), "GL_EXT_draw_elements_base_vertex is not supported.");
3188         }
3189
3190         const bool                                      drawStep                = (m_iteration % 2) == 0;
3191         const bool                                      compareStep             = (m_iteration % 2) == 1;
3192         const IterateResult                     iterateResult   = ((size_t)m_iteration + 1 == m_specs.size()*2) ? (STOP) : (CONTINUE);
3193         const bool                                      updateProgram   = (m_iteration == 0) || (drawStep && !checkSpecsShaderCompatible(m_specs[specNdx], m_specs[specNdx-1])); // try to use the same shader in all iterations
3194         IterationLogSectionEmitter      sectionEmitter  (m_testCtx.getLog(), specNdx, m_specs.size(), m_iteration_descriptions[specNdx], drawStep && m_specs.size()!=1);
3195
3196         if (drawStep)
3197         {
3198                 const MethodInfo        methodInfo                              = getMethodInfo(spec.drawMethod);
3199                 const bool                      indexed                                 = methodInfo.indexed;
3200                 const bool                      instanced                               = methodInfo.instanced;
3201                 const bool                      ranged                                  = methodInfo.ranged;
3202                 const bool                      hasFirst                                = methodInfo.first;
3203                 const bool                      hasBaseVtx                              = methodInfo.baseVertex;
3204
3205                 const size_t            primitiveElementCount   = getElementCount(spec.primitive, spec.primitiveCount);                                         // !< elements to be drawn
3206                 const int                       indexMin                                = (ranged) ? (spec.indexMin) : (0);
3207                 const int                       firstAddition                   = (hasFirst) ? (spec.first) : (0);
3208                 const int                       baseVertexAddition              = (hasBaseVtx && spec.baseVertex > 0) ? ( spec.baseVertex) : (0);                       // spec.baseVertex > 0 => Create bigger attribute buffer
3209                 const int                       indexBase                               = (hasBaseVtx && spec.baseVertex < 0) ? (-spec.baseVertex) : (0);                       // spec.baseVertex < 0 => Create bigger indices
3210                 const size_t            elementCount                    = primitiveElementCount + indexMin + firstAddition + baseVertexAddition;        // !< elements in buffer (buffer should have at least primitiveElementCount ACCESSIBLE (index range, first) elements)
3211                 const int                       maxElementIndex                 = (int)primitiveElementCount + indexMin + firstAddition - 1;
3212                 const int                       indexMax                                = de::max(0, (ranged) ? (de::clamp<int>(spec.indexMax, 0, maxElementIndex)) : (maxElementIndex));
3213                 float                           coordScale                              = getCoordScale(spec);
3214                 float                           colorScale                              = getColorScale(spec);
3215
3216                 rr::GenericVec4         nullAttribValue;
3217
3218                 // Log info
3219                 m_testCtx.getLog() << TestLog::Message << spec.getMultilineDesc() << TestLog::EndMessage;
3220                 m_testCtx.getLog() << TestLog::Message << TestLog::EndMessage; // extra line for clarity
3221
3222                 // Data
3223
3224                 m_glArrayPack->clearArrays();
3225                 m_rrArrayPack->clearArrays();
3226
3227                 for (int attribNdx = 0; attribNdx < (int)spec.attribs.size(); attribNdx++)
3228                 {
3229                         DrawTestSpec::AttributeSpec attribSpec          = spec.attribs[attribNdx];
3230                         const bool                                      isPositionAttr  = (attribNdx == 0) || (attribSpec.additionalPositionAttribute);
3231
3232                         if (attribSpec.useDefaultAttribute)
3233                         {
3234                                 const int               seed            = 10 * attribSpec.hash() + 100 * spec.hash() + attribNdx;
3235                                 rr::GenericVec4 attribValue = RandomArrayGenerator::generateAttributeValue(seed, attribSpec.inputType);
3236
3237                                 m_glArrayPack->newArray(DrawTestSpec::STORAGE_USER);
3238                                 m_rrArrayPack->newArray(DrawTestSpec::STORAGE_USER);
3239
3240                                 m_glArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false);
3241                                 m_rrArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false);
3242                         }
3243                         else
3244                         {
3245                                 const int                                       seed                                    = attribSpec.hash() + 100 * spec.hash() + attribNdx;
3246                                 const size_t                            elementSize                             = attribSpec.componentCount * DrawTestSpec::inputTypeSize(attribSpec.inputType);
3247                                 const size_t                            stride                                  = (attribSpec.stride == 0) ? (elementSize) : (attribSpec.stride);
3248                                 const size_t                            evaluatedElementCount   = (instanced && attribSpec.instanceDivisor > 0) ? (spec.instanceCount / attribSpec.instanceDivisor + 1) : (elementCount);
3249                                 const size_t                            referencedElementCount  = (ranged) ? (de::max<size_t>(evaluatedElementCount, spec.indexMax + 1)) : (evaluatedElementCount);
3250                                 const size_t                            bufferSize                              = attribSpec.offset + stride * (referencedElementCount - 1) + elementSize;
3251                                 const char*                                     data                                    = RandomArrayGenerator::generateArray(seed, (int)referencedElementCount, attribSpec.componentCount, attribSpec.offset, (int)stride, attribSpec.inputType);
3252
3253                                 try
3254                                 {
3255                                         m_glArrayPack->newArray(attribSpec.storage);
3256                                         m_rrArrayPack->newArray(attribSpec.storage);
3257
3258                                         m_glArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage);
3259                                         m_rrArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage);
3260
3261                                         m_glArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder);
3262                                         m_rrArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder);
3263
3264                                         delete [] data;
3265                                         data = NULL;
3266                                 }
3267                                 catch (...)
3268                                 {
3269                                         delete [] data;
3270                                         throw;
3271                                 }
3272                         }
3273                 }
3274
3275                 // Shader program
3276                 if (updateProgram)
3277                 {
3278                         m_glArrayPack->updateProgram();
3279                         m_rrArrayPack->updateProgram();
3280                 }
3281
3282                 // Draw
3283                 try
3284                 {
3285                         // indices
3286                         if (indexed)
3287                         {
3288                                 const int               seed                            = spec.hash();
3289                                 const size_t    indexElementSize        = DrawTestSpec::indexTypeSize(spec.indexType);
3290                                 const size_t    indexArraySize          = spec.indexPointerOffset + indexElementSize * elementCount;
3291                                 const char*             indexArray                      = RandomArrayGenerator::generateIndices(seed, (int)elementCount, spec.indexType, spec.indexPointerOffset, indexMin, indexMax, indexBase);
3292                                 const char*             indexPointerBase        = (spec.indexStorage == DrawTestSpec::STORAGE_USER) ? (indexArray) : ((char*)DE_NULL);
3293                                 const char*             indexPointer            = indexPointerBase + spec.indexPointerOffset;
3294
3295                                 de::UniquePtr<AttributeArray> glArray   (new AttributeArray(spec.indexStorage, *m_glesContext));
3296                                 de::UniquePtr<AttributeArray> rrArray   (new AttributeArray(spec.indexStorage, *m_refContext));
3297
3298                                 try
3299                                 {
3300                                         glArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW);
3301                                         rrArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW);
3302
3303                                         m_glArrayPack->render(spec.primitive, spec.drawMethod, 0, (int)primitiveElementCount, spec.indexType, indexPointer, spec.indexMin, spec.indexMax, spec.instanceCount, spec.indirectOffset, spec.baseVertex, coordScale, colorScale, glArray.get());
3304                                         m_rrArrayPack->render(spec.primitive, spec.drawMethod, 0, (int)primitiveElementCount, spec.indexType, indexPointer, spec.indexMin, spec.indexMax, spec.instanceCount, spec.indirectOffset, spec.baseVertex, coordScale, colorScale, rrArray.get());
3305
3306                                         delete [] indexArray;
3307                                         indexArray = NULL;
3308                                 }
3309                                 catch (...)
3310                                 {
3311                                         delete [] indexArray;
3312                                         throw;
3313                                 }
3314                         }
3315                         else
3316                         {
3317                                 m_glArrayPack->render(spec.primitive, spec.drawMethod, spec.first, (int)primitiveElementCount, DrawTestSpec::INDEXTYPE_LAST, DE_NULL, 0, 0, spec.instanceCount, spec.indirectOffset, 0, coordScale, colorScale, DE_NULL);
3318                                 m_testCtx.touchWatchdog();
3319                                 m_rrArrayPack->render(spec.primitive, spec.drawMethod, spec.first, (int)primitiveElementCount, DrawTestSpec::INDEXTYPE_LAST, DE_NULL, 0, 0, spec.instanceCount, spec.indirectOffset, 0, coordScale, colorScale, DE_NULL);
3320                         }
3321                 }
3322                 catch (glu::Error& err)
3323                 {
3324                         // GL Errors are ok if the mode is not properly aligned
3325
3326                         const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest();
3327
3328                         m_testCtx.getLog() << TestLog::Message << "Got error: " << err.what() << TestLog::EndMessage;
3329
3330                         if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET)
3331                                 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
3332                         else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
3333                                 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
3334                         else
3335                                 throw;
3336                 }
3337         }
3338         else if (compareStep)
3339         {
3340                 if (!compare(spec.primitive))
3341                 {
3342                         const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest();
3343
3344                         if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET)
3345                                 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
3346                         else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
3347                                 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
3348                         else
3349                                 m_result.addResult(QP_TEST_RESULT_FAIL, "Image comparison failed.");
3350                 }
3351         }
3352         else
3353         {
3354                 DE_ASSERT(false);
3355                 return STOP;
3356         }
3357
3358         m_result.setTestContextResult(m_testCtx);
3359
3360         m_iteration++;
3361         return iterateResult;
3362 }
3363
3364 static bool isBlack (const tcu::RGBA& c)
3365 {
3366         // ignore alpha channel
3367         return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0;
3368 }
3369
3370 static bool isEdgeTripletComponent (int c1, int c2, int c3, int renderTargetDifference)
3371 {
3372         const int       roundingDifference      = 2 * renderTargetDifference; // src and dst pixels rounded to different directions
3373         const int       d1                                      = c2 - c1;
3374         const int       d2                                      = c3 - c2;
3375         const int       rampDiff                        = de::abs(d2 - d1);
3376
3377         return rampDiff > roundingDifference;
3378 }
3379
3380 static bool isEdgeTriplet (const tcu::RGBA& c1, const tcu::RGBA& c2, const tcu::RGBA& c3, const tcu::IVec3& renderTargetThreshold)
3381 {
3382         // black (background color) and non-black is always an edge
3383         {
3384                 const bool b1 = isBlack(c1);
3385                 const bool b2 = isBlack(c2);
3386                 const bool b3 = isBlack(c3);
3387
3388                 // both pixels with coverage and pixels without coverage
3389                 if ((b1 && b2 && b3) == false && (b1 || b2 || b3) == true)
3390                         return true;
3391                 // all black
3392                 if (b1 && b2 && b3)
3393                         return false;
3394                 // all with coverage
3395                 DE_ASSERT(!b1 && !b2 && !b3);
3396         }
3397
3398         // Color is always linearly interpolated => component values change nearly linearly
3399         // in any constant direction on triangle hull. (df/dx ~= C).
3400
3401         // Edge detection (this function) is run against the reference image
3402         // => no dithering to worry about
3403
3404         return  isEdgeTripletComponent(c1.getRed(),             c2.getRed(),    c3.getRed(),    renderTargetThreshold.x())      ||
3405                         isEdgeTripletComponent(c1.getGreen(),   c2.getGreen(),  c3.getGreen(),  renderTargetThreshold.y())      ||
3406                         isEdgeTripletComponent(c1.getBlue(),    c2.getBlue(),   c3.getBlue(),   renderTargetThreshold.z());
3407 }
3408
3409 static bool pixelNearEdge (int x, int y, const tcu::Surface& ref, const tcu::IVec3& renderTargetThreshold)
3410 {
3411         // should not be called for edge pixels
3412         DE_ASSERT(x >= 1 && x <= ref.getWidth()-2);
3413         DE_ASSERT(y >= 1 && y <= ref.getHeight()-2);
3414
3415         // horizontal
3416
3417         for (int dy = -1; dy < 2; ++dy)
3418         {
3419                 const tcu::RGBA c1 = ref.getPixel(x-1, y+dy);
3420                 const tcu::RGBA c2 = ref.getPixel(x,   y+dy);
3421                 const tcu::RGBA c3 = ref.getPixel(x+1, y+dy);
3422                 if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold))
3423                         return true;
3424         }
3425
3426         // vertical
3427
3428         for (int dx = -1; dx < 2; ++dx)
3429         {
3430                 const tcu::RGBA c1 = ref.getPixel(x+dx, y-1);
3431                 const tcu::RGBA c2 = ref.getPixel(x+dx, y);
3432                 const tcu::RGBA c3 = ref.getPixel(x+dx, y+1);
3433                 if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold))
3434                         return true;
3435         }
3436
3437         return false;
3438 }
3439
3440 static deUint32 getVisualizationGrayscaleColor (const tcu::RGBA& c)
3441 {
3442         // make triangle coverage and error pixels obvious by converting coverage to grayscale
3443         if (isBlack(c))
3444                 return 0;
3445         else
3446                 return 50u + (deUint32)(c.getRed() + c.getBlue() + c.getGreen()) / 8u;
3447 }
3448
3449 static bool pixelNearLineIntersection (int x, int y, const tcu::Surface& target)
3450 {
3451         // should not be called for edge pixels
3452         DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
3453         DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
3454
3455         int coveredPixels = 0;
3456
3457         for (int dy = -1; dy < 2; dy++)
3458         for (int dx = -1; dx < 2; dx++)
3459         {
3460                 const bool targetCoverage = !isBlack(target.getPixel(x+dx, y+dy));
3461                 if (targetCoverage)
3462                 {
3463                         ++coveredPixels;
3464
3465                         // A single thin line cannot have more than 3 covered pixels in a 3x3 area
3466                         if (coveredPixels >= 4)
3467                                 return true;
3468                 }
3469         }
3470
3471         return false;
3472 }
3473
3474 static inline bool colorsEqual (const tcu::RGBA& colorA, const tcu::RGBA& colorB, const tcu::IVec3& compareThreshold)
3475 {
3476         enum
3477         {
3478                 TCU_RGBA_RGB_MASK = tcu::RGBA::RED_MASK | tcu::RGBA::GREEN_MASK | tcu::RGBA::BLUE_MASK
3479         };
3480
3481         return tcu::compareThresholdMasked(colorA, colorB, tcu::RGBA(compareThreshold.x(), compareThreshold.y(), compareThreshold.z(), 0), TCU_RGBA_RGB_MASK);
3482 }
3483
3484 // search 3x3 are for matching color
3485 static bool pixelNeighborhoodContainsColor (const tcu::Surface& target, int x, int y, const tcu::RGBA& color, const tcu::IVec3& compareThreshold)
3486 {
3487         // should not be called for edge pixels
3488         DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
3489         DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
3490
3491         for (int dy = -1; dy < 2; dy++)
3492         for (int dx = -1; dx < 2; dx++)
3493         {
3494                 const tcu::RGBA targetCmpPixel = target.getPixel(x+dx, y+dy);
3495                 if (colorsEqual(color, targetCmpPixel, compareThreshold))
3496                         return true;
3497         }
3498
3499         return false;
3500 }
3501
3502 // search 3x3 are for matching coverage (coverage == (color != background color))
3503 static bool pixelNeighborhoodContainsCoverage (const tcu::Surface& target, int x, int y, bool coverage)
3504 {
3505         // should not be called for edge pixels
3506         DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
3507         DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
3508
3509         for (int dy = -1; dy < 2; dy++)
3510         for (int dx = -1; dx < 2; dx++)
3511         {
3512                 const bool targetCmpCoverage = !isBlack(target.getPixel(x+dx, y+dy));
3513                 if (targetCmpCoverage == coverage)
3514                         return true;
3515         }
3516
3517         return false;
3518 }
3519
3520 static bool edgeRelaxedImageCompare (tcu::TestLog& log, const char* imageSetName, const char* imageSetDesc, const tcu::Surface& reference, const tcu::Surface& result, const tcu::IVec3& compareThreshold, const tcu::IVec3& renderTargetThreshold, int maxAllowedInvalidPixels)
3521 {
3522         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3523
3524         const tcu::IVec4                                green                                           (0, 255, 0, 255);
3525         const tcu::IVec4                                red                                                     (255, 0, 0, 255);
3526         const int                                               width                                           = reference.getWidth();
3527         const int                                               height                                          = reference.getHeight();
3528         tcu::TextureLevel                               errorMask                                       (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height);
3529         const tcu::PixelBufferAccess    errorAccess                                     = errorMask.getAccess();
3530         int                                                             numFailingPixels                        = 0;
3531
3532         // clear errormask edges which would otherwise be transparent
3533
3534         tcu::clear(tcu::getSubregion(errorAccess, 0,                    0,                      width,  1),                     green);
3535         tcu::clear(tcu::getSubregion(errorAccess, 0,                    height-1,       width,  1),                     green);
3536         tcu::clear(tcu::getSubregion(errorAccess, 0,                    0,                      1,              height),        green);
3537         tcu::clear(tcu::getSubregion(errorAccess, width-1,              0,                      1,              height),        green);
3538
3539         // skip edge pixels since coverage on edge cannot be verified
3540
3541         for (int y = 1; y < height - 1; ++y)
3542         for (int x = 1; x < width - 1; ++x)
3543         {
3544                 const tcu::RGBA refPixel                        = reference.getPixel(x, y);
3545                 const tcu::RGBA screenPixel                     = result.getPixel(x, y);
3546                 const bool              directMatch                     = colorsEqual(refPixel, screenPixel, compareThreshold);
3547                 const bool              isOkReferencePixel      = directMatch || pixelNeighborhoodContainsColor(result, x, y, refPixel, compareThreshold);                      // screen image has a matching pixel nearby (~= If something is drawn on reference, it must be drawn to screen too.)
3548                 const bool              isOkScreenPixel         = directMatch || pixelNeighborhoodContainsColor(reference, x, y, screenPixel, compareThreshold);        // reference image has a matching pixel nearby (~= If something is drawn on screen, it must be drawn to reference too.)
3549
3550                 if (isOkScreenPixel && isOkReferencePixel)
3551                 {
3552                         // pixel valid, write greenish pixels to make the result image easier to read
3553                         const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3554                         errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3555                 }
3556                 else if (!pixelNearEdge(x, y, reference, renderTargetThreshold))
3557                 {
3558                         // non-edge pixel values must be within threshold of the reference values
3559                         errorAccess.setPixel(red, x, y);
3560                         ++numFailingPixels;
3561                 }
3562                 else
3563                 {
3564                         // we are on/near an edge, verify only coverage (coverage == not background colored)
3565                         const bool      referenceCoverage               = !isBlack(refPixel);
3566                         const bool      screenCoverage                  = !isBlack(screenPixel);
3567                         const bool      isOkReferenceCoverage   = pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage);   // Check reference pixel against screen pixel
3568                         const bool      isOkScreenCoverage              = pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage);   // Check screen pixels against reference pixel
3569
3570                         if (isOkScreenCoverage && isOkReferenceCoverage)
3571                         {
3572                                 // pixel valid, write greenish pixels to make the result image easier to read
3573                                 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3574                                 errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3575                         }
3576                         else
3577                         {
3578                                 // coverage does not match
3579                                 errorAccess.setPixel(red, x, y);
3580                                 ++numFailingPixels;
3581                         }
3582                 }
3583         }
3584
3585         log     << TestLog::Message
3586                 << "Comparing images:\n"
3587                 << "\tallowed deviation in pixel positions = 1\n"
3588                 << "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n"
3589                 << "\tnumber of invalid pixels = " << numFailingPixels
3590                 << TestLog::EndMessage;
3591
3592         if (numFailingPixels > maxAllowedInvalidPixels)
3593         {
3594                 log << TestLog::Message
3595                         << "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")"
3596                         << TestLog::EndMessage
3597                         << TestLog::ImageSet(imageSetName, imageSetDesc)
3598                         << TestLog::Image("Result",             "Result",               result)
3599                         << TestLog::Image("Reference",  "Reference",    reference)
3600                         << TestLog::Image("ErrorMask",  "Error mask",   errorMask)
3601                         << TestLog::EndImageSet;
3602
3603                 return false;
3604         }
3605         else
3606         {
3607                 log << TestLog::ImageSet(imageSetName, imageSetDesc)
3608                         << TestLog::Image("Result", "Result", result)
3609                         << TestLog::EndImageSet;
3610
3611                 return true;
3612         }
3613 }
3614
3615 static bool intersectionRelaxedLineImageCompare (tcu::TestLog& log, const char* imageSetName, const char* imageSetDesc, const tcu::Surface& reference, const tcu::Surface& result, const tcu::IVec3& compareThreshold, int maxAllowedInvalidPixels)
3616 {
3617         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3618
3619         const tcu::IVec4                                green                                           (0, 255, 0, 255);
3620         const tcu::IVec4                                red                                                     (255, 0, 0, 255);
3621         const int                                               width                                           = reference.getWidth();
3622         const int                                               height                                          = reference.getHeight();
3623         tcu::TextureLevel                               errorMask                                       (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height);
3624         const tcu::PixelBufferAccess    errorAccess                                     = errorMask.getAccess();
3625         int                                                             numFailingPixels                        = 0;
3626
3627         // clear errormask edges which would otherwise be transparent
3628
3629         tcu::clear(tcu::getSubregion(errorAccess, 0,                    0,                      width,  1),                     green);
3630         tcu::clear(tcu::getSubregion(errorAccess, 0,                    height-1,       width,  1),                     green);
3631         tcu::clear(tcu::getSubregion(errorAccess, 0,                    0,                      1,              height),        green);
3632         tcu::clear(tcu::getSubregion(errorAccess, width-1,              0,                      1,              height),        green);
3633
3634         // skip edge pixels since coverage on edge cannot be verified
3635
3636         for (int y = 1; y < height - 1; ++y)
3637         for (int x = 1; x < width - 1; ++x)
3638         {
3639                 const tcu::RGBA refPixel                        = reference.getPixel(x, y);
3640                 const tcu::RGBA screenPixel                     = result.getPixel(x, y);
3641                 const bool              directMatch                     = colorsEqual(refPixel, screenPixel, compareThreshold);
3642                 const bool              isOkScreenPixel         = directMatch || pixelNeighborhoodContainsColor(reference, x, y, screenPixel, compareThreshold);        // reference image has a matching pixel nearby (~= If something is drawn on screen, it must be drawn to reference too.)
3643                 const bool              isOkReferencePixel      = directMatch || pixelNeighborhoodContainsColor(result, x, y, refPixel, compareThreshold);                      // screen image has a matching pixel nearby (~= If something is drawn on reference, it must be drawn to screen too.)
3644
3645                 if (isOkScreenPixel && isOkReferencePixel)
3646                 {
3647                         // pixel valid, write greenish pixels to make the result image easier to read
3648                         const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3649                         errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3650                 }
3651                 else if (!pixelNearLineIntersection(x, y, reference) &&
3652                                  !pixelNearLineIntersection(x, y, result))
3653                 {
3654                         // non-intersection pixel values must be within threshold of the reference values
3655                         errorAccess.setPixel(red, x, y);
3656                         ++numFailingPixels;
3657                 }
3658                 else
3659                 {
3660                         // pixel is near a line intersection
3661                         // we are on/near an edge, verify only coverage (coverage == not background colored)
3662                         const bool      referenceCoverage               = !isBlack(refPixel);
3663                         const bool      screenCoverage                  = !isBlack(screenPixel);
3664                         const bool      isOkScreenCoverage              = pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage);   // Check screen pixels against reference pixel
3665                         const bool      isOkReferenceCoverage   = pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage);   // Check reference pixel against screen pixel
3666
3667                         if (isOkScreenCoverage && isOkReferenceCoverage)
3668                         {
3669                                 // pixel valid, write greenish pixels to make the result image easier to read
3670                                 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3671                                 errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3672                         }
3673                         else
3674                         {
3675                                 // coverage does not match
3676                                 errorAccess.setPixel(red, x, y);
3677                                 ++numFailingPixels;
3678                         }
3679                 }
3680         }
3681
3682         log     << TestLog::Message
3683                 << "Comparing images:\n"
3684                 << "\tallowed deviation in pixel positions = 1\n"
3685                 << "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n"
3686                 << "\tnumber of invalid pixels = " << numFailingPixels
3687                 << TestLog::EndMessage;
3688
3689         if (numFailingPixels > maxAllowedInvalidPixels)
3690         {
3691                 log << TestLog::Message
3692                         << "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")"
3693                         << TestLog::EndMessage
3694                         << TestLog::ImageSet(imageSetName, imageSetDesc)
3695                         << TestLog::Image("Result",             "Result",               result)
3696                         << TestLog::Image("Reference",  "Reference",    reference)
3697                         << TestLog::Image("ErrorMask",  "Error mask",   errorMask)
3698                         << TestLog::EndImageSet;
3699
3700                 return false;
3701         }
3702         else
3703         {
3704                 log << TestLog::ImageSet(imageSetName, imageSetDesc)
3705                         << TestLog::Image("Result", "Result", result)
3706                         << TestLog::EndImageSet;
3707
3708                 return true;
3709         }
3710 }
3711
3712 bool DrawTest::compare (gls::DrawTestSpec::Primitive primitiveType)
3713 {
3714         const tcu::Surface&     ref             = m_rrArrayPack->getSurface();
3715         const tcu::Surface&     screen  = m_glArrayPack->getSurface();
3716
3717         if (m_renderCtx.getRenderTarget().getNumSamples() > 1)
3718         {
3719                 // \todo [mika] Improve compare when using multisampling
3720                 m_testCtx.getLog() << tcu::TestLog::Message << "Warning: Comparision of result from multisample render targets are not as stricts as without multisampling. Might produce false positives!" << tcu::TestLog::EndMessage;
3721                 return tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", ref.getAccess(), screen.getAccess(), 0.3f, tcu::COMPARE_LOG_RESULT);
3722         }
3723         else
3724         {
3725                 const PrimitiveClass    primitiveClass                                                  = getDrawPrimitiveClass(primitiveType);
3726                 const int                               maxAllowedInvalidPixelsWithPoints               = 0;    //!< points are unlikely to have overlapping fragments
3727                 const int                               maxAllowedInvalidPixelsWithLines                = 5;    //!< line are allowed to have a few bad pixels
3728                 const int                               maxAllowedInvalidPixelsWithTriangles    = 10;
3729
3730                 switch (primitiveClass)
3731                 {
3732                         case PRIMITIVECLASS_POINT:
3733                         {
3734                                 // Point are extremely unlikely to have overlapping regions, don't allow any no extra / missing pixels
3735                                 return tcu::intThresholdPositionDeviationErrorThresholdCompare(m_testCtx.getLog(),
3736                                                                                                                                                            "CompareResult",
3737                                                                                                                                                            "Result of rendering",
3738                                                                                                                                                            ref.getAccess(),
3739                                                                                                                                                            screen.getAccess(),
3740                                                                                                                                                            tcu::UVec4(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue, 256),
3741                                                                                                                                                            tcu::IVec3(1, 1, 0),                                 //!< 3x3 search kernel
3742                                                                                                                                                            true,                                                                //!< relax comparison on the image boundary
3743                                                                                                                                                            maxAllowedInvalidPixelsWithPoints,   //!< error threshold
3744                                                                                                                                                            tcu::COMPARE_LOG_RESULT);
3745                         }
3746
3747                         case PRIMITIVECLASS_LINE:
3748                         {
3749                                 // Lines can potentially have a large number of overlapping pixels. Pixel comparison may potentially produce
3750                                 // false negatives in such pixels if for example the pixel in question is overdrawn by another line in the
3751                                 // reference image but not in the resultin image. Relax comparison near line intersection points (areas) and
3752                                 // compare only coverage, not color, in such pixels
3753                                 return intersectionRelaxedLineImageCompare(m_testCtx.getLog(),
3754                                                                                                                    "CompareResult",
3755                                                                                                                    "Result of rendering",
3756                                                                                                                    ref,
3757                                                                                                                    screen,
3758                                                                                                                    tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue),
3759                                                                                                                    maxAllowedInvalidPixelsWithLines);
3760                         }
3761
3762                         case PRIMITIVECLASS_TRIANGLE:
3763                         {
3764                                 // Triangles are likely to partially or fully overlap. Pixel difference comparison is fragile in pixels
3765                                 // where there could be potential overlapping since the  pixels might be covered by one triangle in the
3766                                 // reference image and by the other in the result image. Relax comparsion near primitive edges and
3767                                 // compare only coverage, not color, in such pixels.
3768                                 const tcu::IVec3        renderTargetThreshold                                   = m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold().toIVec().xyz();
3769
3770                                 return edgeRelaxedImageCompare(m_testCtx.getLog(),
3771                                                                                            "CompareResult",
3772                                                                                            "Result of rendering",
3773                                                                                            ref,
3774                                                                                            screen,
3775                                                                                            tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue),
3776                                                                                            renderTargetThreshold,
3777                                                                                            maxAllowedInvalidPixelsWithTriangles);
3778                         }
3779
3780                         default:
3781                                 DE_ASSERT(false);
3782                                 return false;
3783                 }
3784         }
3785 }
3786
3787 float DrawTest::getCoordScale (const DrawTestSpec& spec) const
3788 {
3789         float maxValue = 1.0f;
3790
3791         for (int arrayNdx = 0; arrayNdx < (int)spec.attribs.size(); arrayNdx++)
3792         {
3793                 DrawTestSpec::AttributeSpec attribSpec          = spec.attribs[arrayNdx];
3794                 const bool                                      isPositionAttr  = (arrayNdx == 0) || (attribSpec.additionalPositionAttribute);
3795                 float                                           attrMaxValue    = 0;
3796
3797                 if (!isPositionAttr)
3798                         continue;
3799
3800                 if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
3801                 {
3802                         if (attribSpec.normalize)
3803                                 attrMaxValue += 1.0f;
3804                         else
3805                                 attrMaxValue += 1024.0f;
3806                 }
3807                 else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
3808                 {
3809                         if (attribSpec.normalize)
3810                                 attrMaxValue += 1.0f;
3811                         else
3812                                 attrMaxValue += 512.0f;
3813                 }
3814                 else
3815                 {
3816                         const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat();
3817
3818                         attrMaxValue += (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType)) ? (1.0f) : (max * 1.1f);
3819                 }
3820
3821                 if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4
3822                         || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4
3823                         || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4)
3824                                 attrMaxValue *= 2;
3825
3826                 maxValue += attrMaxValue;
3827         }
3828
3829         return 1.0f / maxValue;
3830 }
3831
3832 float DrawTest::getColorScale (const DrawTestSpec& spec) const
3833 {
3834         float colorScale = 1.0f;
3835
3836         for (int arrayNdx = 1; arrayNdx < (int)spec.attribs.size(); arrayNdx++)
3837         {
3838                 DrawTestSpec::AttributeSpec attribSpec          = spec.attribs[arrayNdx];
3839                 const bool                                      isPositionAttr  = (arrayNdx == 0) || (attribSpec.additionalPositionAttribute);
3840
3841                 if (isPositionAttr)
3842                         continue;
3843
3844                 if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
3845                 {
3846                         if (!attribSpec.normalize)
3847                                 colorScale *= 1.0f / 1024.0f;
3848                 }
3849                 else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
3850                 {
3851                         if (!attribSpec.normalize)
3852                                 colorScale *= 1.0f / 512.0f;
3853                 }
3854                 else
3855                 {
3856                         const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat();
3857
3858                         colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max)));
3859                         if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4 ||
3860                                 attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4 ||
3861                                 attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4)
3862                                 colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max)));
3863                 }
3864         }
3865
3866         return colorScale;
3867 }
3868
3869 } // gls
3870 } // deqp