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