Lower correlation threshold in flush-finish tests again am: 6455e6f987 am: 2e18b48b04...
[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((Type)(m_value + other.getValue())); }
401                 inline WrappedType<Type>        operator*               (const WrappedType<Type>& other) const  { return WrappedType<Type>::create((Type)(m_value * other.getValue())); }
402                 inline WrappedType<Type>        operator/               (const WrappedType<Type>& other) const  { return WrappedType<Type>::create((Type)(m_value / other.getValue())); }
403                 inline WrappedType<Type>        operator-               (const WrappedType<Type>& other) const  { return WrappedType<Type>::create((Type)(m_value - other.getValue())); }
404
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 : (deInt16)(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 : (deUint16)(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 : (deInt8)(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 : (deUint8)(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 // AttributeArray
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                                            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);
898         void                                            bindAttribute           (deUint32 loc);
899         void                                            bindIndexArray          (DrawTestSpec::Target storage);
900
901         int                                                     getComponentCount       (void) const { return m_componentCount; }
902         DrawTestSpec::Target            getTarget                       (void) const { return m_target; }
903         DrawTestSpec::InputType         getInputType            (void) const { return m_inputType; }
904         DrawTestSpec::OutputType        getOutputType           (void) const { return m_outputType; }
905         DrawTestSpec::Storage           getStorageType          (void) const { return m_storage; }
906         bool                                            getNormalized           (void) const { return m_normalize; }
907         int                                                     getStride                       (void) const { return m_stride; }
908         bool                                            isBound                         (void) const { return m_bound; }
909         bool                                            isPositionAttribute     (void) const { return m_isPositionAttr; }
910
911 private:
912         DrawTestSpec::Storage           m_storage;
913         sglr::Context&                          m_ctx;
914         deUint32                                        m_glBuffer;
915
916         int                                                     m_size;
917         char*                                           m_data;
918         int                                                     m_componentCount;
919         bool                                            m_bound;
920         DrawTestSpec::Target            m_target;
921         DrawTestSpec::InputType         m_inputType;
922         DrawTestSpec::OutputType        m_outputType;
923         bool                                            m_normalize;
924         int                                                     m_stride;
925         int                                                     m_offset;
926         rr::GenericVec4                         m_defaultAttrib;
927         int                                                     m_instanceDivisor;
928         bool                                            m_isPositionAttr;
929         bool                                            m_bgraOrder;
930 };
931
932 AttributeArray::AttributeArray (DrawTestSpec::Storage storage, sglr::Context& context)
933         : m_storage                     (storage)
934         , m_ctx                         (context)
935         , m_glBuffer            (0)
936         , m_size                        (0)
937         , m_data                        (DE_NULL)
938         , m_componentCount      (1)
939         , m_bound                       (false)
940         , m_target                      (DrawTestSpec::TARGET_ARRAY)
941         , m_inputType           (DrawTestSpec::INPUTTYPE_FLOAT)
942         , m_outputType          (DrawTestSpec::OUTPUTTYPE_VEC4)
943         , m_normalize           (false)
944         , m_stride                      (0)
945         , m_offset                      (0)
946         , m_instanceDivisor     (0)
947         , m_isPositionAttr      (false)
948         , m_bgraOrder           (false)
949 {
950         if (m_storage == DrawTestSpec::STORAGE_BUFFER)
951         {
952                 m_ctx.genBuffers(1, &m_glBuffer);
953                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glGenBuffers()");
954         }
955 }
956
957 AttributeArray::~AttributeArray (void)
958 {
959         if (m_storage == DrawTestSpec::STORAGE_BUFFER)
960         {
961                 m_ctx.deleteBuffers(1, &m_glBuffer);
962                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDeleteBuffers()");
963         }
964         else if (m_storage == DrawTestSpec::STORAGE_USER)
965                 delete[] m_data;
966         else
967                 DE_ASSERT(false);
968 }
969
970 void AttributeArray::data (DrawTestSpec::Target target, size_t size, const char* ptr, DrawTestSpec::Usage usage)
971 {
972         m_size = (int)size;
973         m_target = target;
974
975         if (m_storage == DrawTestSpec::STORAGE_BUFFER)
976         {
977                 m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
978                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
979
980                 m_ctx.bufferData(targetToGL(target), size, ptr, usageToGL(usage));
981                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferData()");
982         }
983         else if (m_storage == DrawTestSpec::STORAGE_USER)
984         {
985                 if (m_data)
986                         delete[] m_data;
987
988                 m_data = new char[size];
989                 std::memcpy(m_data, ptr, size);
990         }
991         else
992                 DE_ASSERT(false);
993 }
994
995 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)
996 {
997         m_componentCount        = size;
998         m_bound                         = bound;
999         m_inputType                     = inputType;
1000         m_outputType            = outType;
1001         m_normalize                     = normalized;
1002         m_stride                        = stride;
1003         m_offset                        = offset;
1004         m_defaultAttrib         = defaultAttrib;
1005         m_instanceDivisor       = instanceDivisor;
1006         m_isPositionAttr        = isPositionAttr;
1007         m_bgraOrder                     = bgraComponentOrder;
1008 }
1009
1010 void AttributeArray::bindAttribute (deUint32 loc)
1011 {
1012         if (!isBound())
1013         {
1014                 switch (m_inputType)
1015                 {
1016                         case DrawTestSpec::INPUTTYPE_FLOAT:
1017                         {
1018                                 tcu::Vec4 attr = m_defaultAttrib.get<float>();
1019
1020                                 switch (m_componentCount)
1021                                 {
1022                                         case 1: m_ctx.vertexAttrib1f(loc, attr.x()); break;
1023                                         case 2: m_ctx.vertexAttrib2f(loc, attr.x(), attr.y()); break;
1024                                         case 3: m_ctx.vertexAttrib3f(loc, attr.x(), attr.y(), attr.z()); break;
1025                                         case 4: m_ctx.vertexAttrib4f(loc, attr.x(), attr.y(), attr.z(), attr.w()); break;
1026                                         default: DE_ASSERT(DE_FALSE); break;
1027                                 }
1028                                 break;
1029                         }
1030                         case DrawTestSpec::INPUTTYPE_INT:
1031                         {
1032                                 tcu::IVec4 attr = m_defaultAttrib.get<deInt32>();
1033                                 m_ctx.vertexAttribI4i(loc, attr.x(), attr.y(), attr.z(), attr.w());
1034                                 break;
1035                         }
1036                         case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
1037                         {
1038                                 tcu::UVec4 attr = m_defaultAttrib.get<deUint32>();
1039                                 m_ctx.vertexAttribI4ui(loc, attr.x(), attr.y(), attr.z(), attr.w());
1040                                 break;
1041                         }
1042                         default:
1043                                 DE_ASSERT(DE_FALSE);
1044                                 break;
1045                 }
1046         }
1047         else
1048         {
1049                 const deUint8* basePtr = DE_NULL;
1050
1051                 if (m_storage == DrawTestSpec::STORAGE_BUFFER)
1052                 {
1053                         m_ctx.bindBuffer(targetToGL(m_target), m_glBuffer);
1054                         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
1055
1056                         basePtr = DE_NULL;
1057                 }
1058                 else if (m_storage == DrawTestSpec::STORAGE_USER)
1059                 {
1060                         m_ctx.bindBuffer(targetToGL(m_target), 0);
1061                         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
1062
1063                         basePtr = (const deUint8*)m_data;
1064                 }
1065                 else
1066                         DE_ASSERT(DE_FALSE);
1067
1068                 if (!inputTypeIsFloatType(m_inputType))
1069                 {
1070                         // Input is not float type
1071
1072                         if (outputTypeIsFloatType(m_outputType))
1073                         {
1074                                 const int size = (m_bgraOrder) ? (GL_BGRA) : (m_componentCount);
1075
1076                                 DE_ASSERT(!(m_bgraOrder && m_componentCount != 4));
1077
1078                                 // Output type is float type
1079                                 m_ctx.vertexAttribPointer(loc, size, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset);
1080                                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
1081                         }
1082                         else
1083                         {
1084                                 // Output type is int type
1085                                 m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, basePtr + m_offset);
1086                                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
1087                         }
1088                 }
1089                 else
1090                 {
1091                         // Input type is float type
1092
1093                         // Output type must be float type
1094                         DE_ASSERT(outputTypeIsFloatType(m_outputType));
1095
1096                         m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset);
1097                         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
1098                 }
1099
1100                 if (m_instanceDivisor)
1101                         m_ctx.vertexAttribDivisor(loc, m_instanceDivisor);
1102         }
1103 }
1104
1105 void AttributeArray::bindIndexArray (DrawTestSpec::Target target)
1106 {
1107         if (m_storage == DrawTestSpec::STORAGE_USER)
1108         {
1109         }
1110         else if (m_storage == DrawTestSpec::STORAGE_BUFFER)
1111         {
1112                 m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
1113         }
1114 }
1115
1116 // DrawTestShaderProgram
1117
1118 class DrawTestShaderProgram : public sglr::ShaderProgram
1119 {
1120 public:
1121                                                                                                 DrawTestShaderProgram           (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
1122
1123         void                                                                            shadeVertices                           (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
1124         void                                                                            shadeFragments                          (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
1125
1126 private:
1127         static std::string                                                      genVertexSource                         (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
1128         static std::string                                                      genFragmentSource                       (const glu::RenderContext& ctx);
1129         static void                                                                     generateShaderParams            (std::map<std::string, std::string>& params, glu::ContextType type);
1130         static rr::GenericVecType                                       mapOutputType                           (const DrawTestSpec::OutputType& type);
1131         static int                                                                      getComponentCount                       (const DrawTestSpec::OutputType& type);
1132
1133         static sglr::pdec::ShaderProgramDeclaration createProgramDeclaration    (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
1134
1135         std::vector<int>                                                        m_componentCount;
1136         std::vector<bool>                                                       m_isCoord;
1137         std::vector<rr::GenericVecType>                         m_attrType;
1138 };
1139
1140 DrawTestShaderProgram::DrawTestShaderProgram (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
1141         : sglr::ShaderProgram   (createProgramDeclaration(ctx, arrays))
1142         , m_componentCount              (arrays.size())
1143         , m_isCoord                             (arrays.size())
1144         , m_attrType                    (arrays.size())
1145 {
1146         for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1147         {
1148                 m_componentCount[arrayNdx]      = getComponentCount(arrays[arrayNdx]->getOutputType());
1149                 m_isCoord[arrayNdx]                     = arrays[arrayNdx]->isPositionAttribute();
1150                 m_attrType[arrayNdx]            = mapOutputType(arrays[arrayNdx]->getOutputType());
1151         }
1152 }
1153
1154 template <typename T>
1155 void calcShaderColorCoord (tcu::Vec2& coord, tcu::Vec3& color, const tcu::Vector<T, 4>& attribValue, bool isCoordinate, int numComponents)
1156 {
1157         if (isCoordinate)
1158                 switch (numComponents)
1159                 {
1160                         case 1: coord += tcu::Vec2((float)attribValue.x(),                                                      (float)attribValue.x());                                                        break;
1161                         case 2: coord += tcu::Vec2((float)attribValue.x(),                                                      (float)attribValue.y());                                                        break;
1162                         case 3: coord += tcu::Vec2((float)attribValue.x() + (float)attribValue.z(),     (float)attribValue.y());                                                        break;
1163                         case 4: coord += tcu::Vec2((float)attribValue.x() + (float)attribValue.z(),     (float)attribValue.y() + (float)attribValue.w());       break;
1164
1165                         default:
1166                                 DE_ASSERT(false);
1167                 }
1168         else
1169         {
1170                 switch (numComponents)
1171                 {
1172                         case 1:
1173                                 color = color * (float)attribValue.x();
1174                                 break;
1175
1176                         case 2:
1177                                 color.x() = color.x() * (float)attribValue.x();
1178                                 color.y() = color.y() * (float)attribValue.y();
1179                                 break;
1180
1181                         case 3:
1182                                 color.x() = color.x() * (float)attribValue.x();
1183                                 color.y() = color.y() * (float)attribValue.y();
1184                                 color.z() = color.z() * (float)attribValue.z();
1185                                 break;
1186
1187                         case 4:
1188                                 color.x() = color.x() * (float)attribValue.x() * (float)attribValue.w();
1189                                 color.y() = color.y() * (float)attribValue.y() * (float)attribValue.w();
1190                                 color.z() = color.z() * (float)attribValue.z() * (float)attribValue.w();
1191                                 break;
1192
1193                         default:
1194                                 DE_ASSERT(false);
1195                 }
1196         }
1197 }
1198
1199 void DrawTestShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
1200 {
1201         const float     u_coordScale = getUniformByName("u_coordScale").value.f;
1202         const float u_colorScale = getUniformByName("u_colorScale").value.f;
1203
1204         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1205         {
1206                 const size_t varyingLocColor = 0;
1207
1208                 rr::VertexPacket& packet = *packets[packetNdx];
1209
1210                 // Calc output color
1211                 tcu::Vec2 coord = tcu::Vec2(0.0, 0.0);
1212                 tcu::Vec3 color = tcu::Vec3(1.0, 1.0, 1.0);
1213
1214                 for (int attribNdx = 0; attribNdx < (int)m_attrType.size(); attribNdx++)
1215                 {
1216                         const int       numComponents   = m_componentCount[attribNdx];
1217                         const bool      isCoord                 = m_isCoord[attribNdx];
1218
1219                         switch (m_attrType[attribNdx])
1220                         {
1221                                 case rr::GENERICVECTYPE_FLOAT:  calcShaderColorCoord(coord, color, rr::readVertexAttribFloat(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents); break;
1222                                 case rr::GENERICVECTYPE_INT32:  calcShaderColorCoord(coord, color, rr::readVertexAttribInt      (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents);     break;
1223                                 case rr::GENERICVECTYPE_UINT32: calcShaderColorCoord(coord, color, rr::readVertexAttribUint     (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents);     break;
1224                                 default:
1225                                         DE_ASSERT(false);
1226                         }
1227                 }
1228
1229                 // Transform position
1230                 {
1231                         packet.position = tcu::Vec4(u_coordScale * coord.x(), u_coordScale * coord.y(), 1.0f, 1.0f);
1232                         packet.pointSize = 1.0f;
1233                 }
1234
1235                 // Pass color to FS
1236                 {
1237                         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);
1238                 }
1239         }
1240 }
1241
1242 void DrawTestShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
1243 {
1244         const size_t varyingLocColor = 0;
1245
1246         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1247         {
1248                 rr::FragmentPacket& packet = packets[packetNdx];
1249
1250                 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1251                         rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, varyingLocColor, fragNdx));
1252         }
1253 }
1254
1255 std::string DrawTestShaderProgram::genVertexSource (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
1256 {
1257         std::map<std::string, std::string>      params;
1258         std::stringstream                                       vertexShaderTmpl;
1259
1260         generateShaderParams(params, ctx.getType());
1261
1262         vertexShaderTmpl << "${VTX_HDR}";
1263
1264         for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1265         {
1266                 vertexShaderTmpl
1267                         << "${VTX_IN} highp " << outputTypeToGLType(arrays[arrayNdx]->getOutputType()) << " a_" << arrayNdx << ";\n";
1268         }
1269
1270         vertexShaderTmpl <<
1271                 "uniform highp float u_coordScale;\n"
1272                 "uniform highp float u_colorScale;\n"
1273                 "${VTX_OUT} ${COL_PRECISION} vec4 v_color;\n"
1274                 "void main(void)\n"
1275                 "{\n"
1276                 "\tgl_PointSize = 1.0;\n"
1277                 "\thighp vec2 coord = vec2(0.0, 0.0);\n"
1278                 "\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n";
1279
1280         for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1281         {
1282                 const bool isPositionAttr = arrays[arrayNdx]->isPositionAttribute();
1283
1284                 if (isPositionAttr)
1285                 {
1286                         switch (arrays[arrayNdx]->getOutputType())
1287                         {
1288                                 case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1289                                 case (DrawTestSpec::OUTPUTTYPE_INT):
1290                                 case (DrawTestSpec::OUTPUTTYPE_UINT):
1291                                         vertexShaderTmpl <<
1292                                                 "\tcoord += vec2(float(a_" << arrayNdx << "), float(a_" << arrayNdx << "));\n";
1293                                         break;
1294
1295                                 case (DrawTestSpec::OUTPUTTYPE_VEC2):
1296                                 case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1297                                 case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1298                                         vertexShaderTmpl <<
1299                                                 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n";
1300                                         break;
1301
1302                                 case (DrawTestSpec::OUTPUTTYPE_VEC3):
1303                                 case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1304                                 case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1305                                         vertexShaderTmpl <<
1306                                                 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n"
1307                                                 "\tcoord.x += float(a_" << arrayNdx << ".z);\n";
1308                                         break;
1309
1310                                 case (DrawTestSpec::OUTPUTTYPE_VEC4):
1311                                 case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1312                                 case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1313                                         vertexShaderTmpl <<
1314                                                 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n"
1315                                                 "\tcoord += vec2(a_" << arrayNdx << ".zw);\n";
1316                                         break;
1317
1318                                 default:
1319                                         DE_ASSERT(false);
1320                                         break;
1321                         }
1322                 }
1323                 else
1324                 {
1325                         switch (arrays[arrayNdx]->getOutputType())
1326                         {
1327                                 case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1328                                 case (DrawTestSpec::OUTPUTTYPE_INT):
1329                                 case (DrawTestSpec::OUTPUTTYPE_UINT):
1330                                         vertexShaderTmpl <<
1331                                                 "\tcolor = color * float(a_" << arrayNdx << ");\n";
1332                                         break;
1333
1334                                 case (DrawTestSpec::OUTPUTTYPE_VEC2):
1335                                 case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1336                                 case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1337                                         vertexShaderTmpl <<
1338                                                 "\tcolor.rg = color.rg * vec2(a_" << arrayNdx << ".xy);\n";
1339                                         break;
1340
1341                                 case (DrawTestSpec::OUTPUTTYPE_VEC3):
1342                                 case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1343                                 case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1344                                         vertexShaderTmpl <<
1345                                                 "\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz);\n";
1346                                         break;
1347
1348                                 case (DrawTestSpec::OUTPUTTYPE_VEC4):
1349                                 case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1350                                 case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1351                                         vertexShaderTmpl <<
1352                                                 "\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz) * float(a_" << arrayNdx << ".w);\n";
1353                                         break;
1354
1355                                 default:
1356                                         DE_ASSERT(false);
1357                                         break;
1358                         }
1359                 }
1360         }
1361
1362         vertexShaderTmpl <<
1363                 "\tv_color = vec4(u_colorScale * color, 1.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);\n"
1364                 "\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n"
1365                 "}\n";
1366
1367         return tcu::StringTemplate(vertexShaderTmpl.str().c_str()).specialize(params);
1368 }
1369
1370 std::string DrawTestShaderProgram::genFragmentSource (const glu::RenderContext& ctx)
1371 {
1372         std::map<std::string, std::string> params;
1373
1374         generateShaderParams(params, ctx.getType());
1375
1376         static const char* fragmentShaderTmpl =
1377                 "${FRAG_HDR}"
1378                 "${FRAG_IN} ${COL_PRECISION} vec4 v_color;\n"
1379                 "void main(void)\n"
1380                 "{\n"
1381                 "\t${FRAG_COLOR} = v_color;\n"
1382                 "}\n";
1383
1384         return tcu::StringTemplate(fragmentShaderTmpl).specialize(params);
1385 }
1386
1387 void DrawTestShaderProgram::generateShaderParams (std::map<std::string, std::string>& params, glu::ContextType type)
1388 {
1389         if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_300_ES))
1390         {
1391                 params["VTX_IN"]                = "in";
1392                 params["VTX_OUT"]               = "out";
1393                 params["FRAG_IN"]               = "in";
1394                 params["FRAG_COLOR"]    = "dEQP_FragColor";
1395                 params["VTX_HDR"]               = "#version 300 es\n";
1396                 params["FRAG_HDR"]              = "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1397                 params["COL_PRECISION"] = "mediump";
1398         }
1399         else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_100_ES))
1400         {
1401                 params["VTX_IN"]                = "attribute";
1402                 params["VTX_OUT"]               = "varying";
1403                 params["FRAG_IN"]               = "varying";
1404                 params["FRAG_COLOR"]    = "gl_FragColor";
1405                 params["VTX_HDR"]               = "";
1406                 params["FRAG_HDR"]              = "";
1407                 params["COL_PRECISION"] = "mediump";
1408         }
1409         else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_430))
1410         {
1411                 params["VTX_IN"]                = "in";
1412                 params["VTX_OUT"]               = "out";
1413                 params["FRAG_IN"]               = "in";
1414                 params["FRAG_COLOR"]    = "dEQP_FragColor";
1415                 params["VTX_HDR"]               = "#version 430\n";
1416                 params["FRAG_HDR"]              = "#version 430\nlayout(location = 0) out highp vec4 dEQP_FragColor;\n";
1417                 params["COL_PRECISION"] = "highp";
1418         }
1419         else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_330))
1420         {
1421                 params["VTX_IN"]                = "in";
1422                 params["VTX_OUT"]               = "out";
1423                 params["FRAG_IN"]               = "in";
1424                 params["FRAG_COLOR"]    = "dEQP_FragColor";
1425                 params["VTX_HDR"]               = "#version 330\n";
1426                 params["FRAG_HDR"]              = "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1427                 params["COL_PRECISION"] = "mediump";
1428         }
1429         else
1430                 DE_ASSERT(DE_FALSE);
1431 }
1432
1433 rr::GenericVecType DrawTestShaderProgram::mapOutputType (const DrawTestSpec::OutputType& type)
1434 {
1435         switch (type)
1436         {
1437                 case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1438                 case (DrawTestSpec::OUTPUTTYPE_VEC2):
1439                 case (DrawTestSpec::OUTPUTTYPE_VEC3):
1440                 case (DrawTestSpec::OUTPUTTYPE_VEC4):
1441                         return rr::GENERICVECTYPE_FLOAT;
1442
1443                 case (DrawTestSpec::OUTPUTTYPE_INT):
1444                 case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1445                 case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1446                 case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1447                         return rr::GENERICVECTYPE_INT32;
1448
1449                 case (DrawTestSpec::OUTPUTTYPE_UINT):
1450                 case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1451                 case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1452                 case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1453                         return rr::GENERICVECTYPE_UINT32;
1454
1455                 default:
1456                         DE_ASSERT(false);
1457                         return rr::GENERICVECTYPE_LAST;
1458         }
1459 }
1460
1461 int DrawTestShaderProgram::getComponentCount (const DrawTestSpec::OutputType& type)
1462 {
1463         switch (type)
1464         {
1465                 case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1466                 case (DrawTestSpec::OUTPUTTYPE_INT):
1467                 case (DrawTestSpec::OUTPUTTYPE_UINT):
1468                         return 1;
1469
1470                 case (DrawTestSpec::OUTPUTTYPE_VEC2):
1471                 case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1472                 case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1473                         return 2;
1474
1475                 case (DrawTestSpec::OUTPUTTYPE_VEC3):
1476                 case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1477                 case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1478                         return 3;
1479
1480                 case (DrawTestSpec::OUTPUTTYPE_VEC4):
1481                 case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1482                 case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1483                         return 4;
1484
1485                 default:
1486                         DE_ASSERT(false);
1487                         return 0;
1488         }
1489 }
1490
1491 sglr::pdec::ShaderProgramDeclaration DrawTestShaderProgram::createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
1492 {
1493         sglr::pdec::ShaderProgramDeclaration decl;
1494
1495         for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1496                 decl << sglr::pdec::VertexAttribute(std::string("a_") + de::toString(arrayNdx), mapOutputType(arrays[arrayNdx]->getOutputType()));
1497
1498         decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
1499         decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT);
1500
1501         decl << sglr::pdec::VertexSource(genVertexSource(ctx, arrays));
1502         decl << sglr::pdec::FragmentSource(genFragmentSource(ctx));
1503
1504         decl << sglr::pdec::Uniform("u_coordScale", glu::TYPE_FLOAT);
1505         decl << sglr::pdec::Uniform("u_colorScale", glu::TYPE_FLOAT);
1506
1507         return decl;
1508 }
1509
1510 class RandomArrayGenerator
1511 {
1512 public:
1513         static char*                    generateArray                   (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type);
1514         static char*                    generateIndices                 (int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase);
1515         static rr::GenericVec4  generateAttributeValue  (int seed, DrawTestSpec::InputType type);
1516
1517 private:
1518         template<typename T>
1519         static char*                    createIndices                   (int seed, int elementCount, int offset, int min, int max, int indexBase);
1520
1521         static char*                    generateBasicArray              (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type);
1522         template<typename T, typename GLType>
1523         static char*                    createBasicArray                (int seed, int elementCount, int componentCount, int offset, int stride);
1524         static char*                    generatePackedArray             (int seed, int elementCount, int componentCount, int offset, int stride);
1525 };
1526
1527 char* RandomArrayGenerator::generateArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type)
1528 {
1529         if (type == DrawTestSpec::INPUTTYPE_INT_2_10_10_10 || type == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
1530                 return generatePackedArray(seed, elementCount, componentCount, offset, stride);
1531         else
1532                 return generateBasicArray(seed, elementCount, componentCount, offset, stride, type);
1533 }
1534
1535 char* RandomArrayGenerator::generateBasicArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type)
1536 {
1537         switch (type)
1538         {
1539                 case DrawTestSpec::INPUTTYPE_FLOAT:                             return createBasicArray<float,          GLValue::Float> (seed, elementCount, componentCount, offset, stride);
1540                 case DrawTestSpec::INPUTTYPE_DOUBLE:                    return createBasicArray<double,         GLValue::Double>(seed, elementCount, componentCount, offset, stride);
1541                 case DrawTestSpec::INPUTTYPE_SHORT:                             return createBasicArray<deInt16,        GLValue::Short> (seed, elementCount, componentCount, offset, stride);
1542                 case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT:    return createBasicArray<deUint16,       GLValue::Ushort>(seed, elementCount, componentCount, offset, stride);
1543                 case DrawTestSpec::INPUTTYPE_BYTE:                              return createBasicArray<deInt8,         GLValue::Byte>  (seed, elementCount, componentCount, offset, stride);
1544                 case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE:             return createBasicArray<deUint8,        GLValue::Ubyte> (seed, elementCount, componentCount, offset, stride);
1545                 case DrawTestSpec::INPUTTYPE_FIXED:                             return createBasicArray<deInt32,        GLValue::Fixed> (seed, elementCount, componentCount, offset, stride);
1546                 case DrawTestSpec::INPUTTYPE_INT:                               return createBasicArray<deInt32,        GLValue::Int>   (seed, elementCount, componentCount, offset, stride);
1547                 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:              return createBasicArray<deUint32,       GLValue::Uint>  (seed, elementCount, componentCount, offset, stride);
1548                 case DrawTestSpec::INPUTTYPE_HALF:                              return createBasicArray<deFloat16,      GLValue::Half>  (seed, elementCount, componentCount, offset, stride);
1549                 default:
1550                         DE_ASSERT(false);
1551                         break;
1552         }
1553         return DE_NULL;
1554 }
1555
1556 #if (DE_COMPILER == DE_COMPILER_GCC) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)
1557         // GCC 4.8/4.9 incorrectly emits array-bounds warning from createBasicArray()
1558 #       define GCC_ARRAY_BOUNDS_FALSE_NEGATIVE 1
1559 #endif
1560
1561 #if defined(GCC_ARRAY_BOUNDS_FALSE_NEGATIVE)
1562 #       pragma GCC diagnostic push
1563 #       pragma GCC diagnostic ignored "-Warray-bounds"
1564 #endif
1565
1566 template<typename T, typename GLType>
1567 char* RandomArrayGenerator::createBasicArray (int seed, int elementCount, int componentCount, int offset, int stride)
1568 {
1569         DE_ASSERT(componentCount >= 1 && componentCount <= 4);
1570
1571         const GLType min = extractGLValue<GLType>(GLValue::getMinValue(GLValueTypeTraits<GLType>::Type));
1572         const GLType max = extractGLValue<GLType>(GLValue::getMaxValue(GLValueTypeTraits<GLType>::Type));
1573
1574         const size_t componentSize      = sizeof(T);
1575         const size_t elementSize        = componentSize * componentCount;
1576         const size_t bufferSize         = offset + (elementCount - 1) * stride + elementSize;
1577
1578         char* data = new char[bufferSize];
1579         char* writePtr = data + offset;
1580
1581         GLType previousComponents[4];
1582
1583         deRandom rnd;
1584         deRandom_init(&rnd, seed);
1585
1586         for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++)
1587         {
1588                 GLType components[4];
1589
1590                 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1591                 {
1592                         components[componentNdx] = getRandom<GLType>(rnd, min, max);
1593
1594                         // Try to not create vertex near previous
1595                         if (vertexNdx != 0 && abs(components[componentNdx] - previousComponents[componentNdx]) < minValue<GLType>())
1596                         {
1597                                 // Too close, try again (but only once)
1598                                 components[componentNdx] = getRandom<GLType>(rnd, min, max);
1599                         }
1600                 }
1601
1602                 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1603                         previousComponents[componentNdx] = components[componentNdx];
1604
1605                 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1606                         alignmentSafeAssignment(writePtr + componentNdx*componentSize, components[componentNdx].getValue());
1607
1608                 writePtr += stride;
1609         }
1610
1611         return data;
1612 }
1613
1614 #if defined(GCC_ARRAY_BOUNDS_FALSE_NEGATIVE)
1615 #       pragma GCC diagnostic pop
1616 #endif
1617
1618 char* RandomArrayGenerator::generatePackedArray (int seed, int elementCount, int componentCount, int offset, int stride)
1619 {
1620         DE_ASSERT(componentCount == 4);
1621         DE_UNREF(componentCount);
1622
1623         const deUint32 limit10          = (1 << 10);
1624         const deUint32 limit2           = (1 << 2);
1625         const size_t elementSize        = 4;
1626         const size_t bufferSize         = offset + (elementCount - 1) * stride + elementSize;
1627
1628         char* data = new char[bufferSize];
1629         char* writePtr = data + offset;
1630
1631         deRandom rnd;
1632         deRandom_init(&rnd, seed);
1633
1634         for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++)
1635         {
1636                 const deUint32 x                        = deRandom_getUint32(&rnd) % limit10;
1637                 const deUint32 y                        = deRandom_getUint32(&rnd) % limit10;
1638                 const deUint32 z                        = deRandom_getUint32(&rnd) % limit10;
1639                 const deUint32 w                        = deRandom_getUint32(&rnd) % limit2;
1640                 const deUint32 packedValue      = (w << 30) | (z << 20) | (y << 10) | (x);
1641
1642                 alignmentSafeAssignment(writePtr, packedValue);
1643                 writePtr += stride;
1644         }
1645
1646         return data;
1647 }
1648
1649 char* RandomArrayGenerator::generateIndices (int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase)
1650 {
1651         char* data = DE_NULL;
1652
1653         switch (type)
1654         {
1655                 case DrawTestSpec::INDEXTYPE_BYTE:
1656                         data = createIndices<deUint8>(seed, elementCount, offset, min, max, indexBase);
1657                         break;
1658
1659                 case DrawTestSpec::INDEXTYPE_SHORT:
1660                         data = createIndices<deUint16>(seed, elementCount, offset, min, max, indexBase);
1661                         break;
1662
1663                 case DrawTestSpec::INDEXTYPE_INT:
1664                         data = createIndices<deUint32>(seed, elementCount, offset, min, max, indexBase);
1665                         break;
1666
1667                 default:
1668                         DE_ASSERT(false);
1669                         break;
1670         }
1671
1672         return data;
1673 }
1674
1675 template<typename T>
1676 char* RandomArrayGenerator::createIndices (int seed, int elementCount, int offset, int min, int max, int indexBase)
1677 {
1678         const size_t elementSize        = sizeof(T);
1679         const size_t bufferSize         = offset + elementCount * elementSize;
1680
1681         char* data = new char[bufferSize];
1682         char* writePtr = data + offset;
1683
1684         deUint32 oldNdx1 = deUint32(-1);
1685         deUint32 oldNdx2 = deUint32(-1);
1686
1687         deRandom rnd;
1688         deRandom_init(&rnd, seed);
1689
1690         DE_ASSERT(indexBase >= 0); // watch for underflows
1691
1692         if (min < 0 || (size_t)min > std::numeric_limits<T>::max() ||
1693                 max < 0 || (size_t)max > std::numeric_limits<T>::max() ||
1694                 min > max)
1695                 DE_FATAL("Invalid range");
1696
1697         for (int elementNdx = 0; elementNdx < elementCount; ++elementNdx)
1698         {
1699                 deUint32 ndx = getRandom(rnd, GLValue::Uint::create(min), GLValue::Uint::create(max)).getValue();
1700
1701                 // Try not to generate same index as any of previous two. This prevents
1702                 // generation of degenerate triangles and lines. If [min, max] is too
1703                 // small this cannot be guaranteed.
1704
1705                 if (ndx == oldNdx1)                     ++ndx;
1706                 if (ndx > (deUint32)max)        ndx = min;
1707                 if (ndx == oldNdx2)                     ++ndx;
1708                 if (ndx > (deUint32)max)        ndx = min;
1709                 if (ndx == oldNdx1)                     ++ndx;
1710                 if (ndx > (deUint32)max)        ndx = min;
1711
1712                 oldNdx2 = oldNdx1;
1713                 oldNdx1 = ndx;
1714
1715                 ndx += indexBase;
1716
1717                 alignmentSafeAssignment<T>(writePtr + elementSize * elementNdx, T(ndx));
1718         }
1719
1720         return data;
1721 }
1722
1723 rr::GenericVec4 RandomArrayGenerator::generateAttributeValue (int seed, DrawTestSpec::InputType type)
1724 {
1725         de::Random random(seed);
1726
1727         switch (type)
1728         {
1729                 case DrawTestSpec::INPUTTYPE_FLOAT:
1730                         return rr::GenericVec4(generateRandomVec4(random));
1731
1732                 case DrawTestSpec::INPUTTYPE_INT:
1733                         return rr::GenericVec4(generateRandomIVec4(random));
1734
1735                 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
1736                         return rr::GenericVec4(generateRandomUVec4(random));
1737
1738                 default:
1739                         DE_ASSERT(false);
1740                         return rr::GenericVec4(tcu::Vec4(1, 1, 1, 1));
1741         }
1742 }
1743
1744 } // anonymous
1745
1746 // AttributePack
1747
1748 class AttributePack
1749 {
1750 public:
1751
1752                                                                 AttributePack           (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled);
1753                                                                 ~AttributePack          (void);
1754
1755         AttributeArray*                         getArray                        (int i);
1756         int                                                     getArrayCount           (void);
1757
1758         void                                            newArray                        (DrawTestSpec::Storage storage);
1759         void                                            clearArrays                     (void);
1760         void                                            updateProgram           (void);
1761
1762         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);
1763
1764         const tcu::Surface&                     getSurface                      (void) const { return m_screen; }
1765 private:
1766         tcu::TestContext&                       m_testCtx;
1767         glu::RenderContext&                     m_renderCtx;
1768         sglr::Context&                          m_ctx;
1769
1770         std::vector<AttributeArray*>m_arrays;
1771         sglr::ShaderProgram*            m_program;
1772         tcu::Surface                            m_screen;
1773         const bool                                      m_useVao;
1774         const bool                                      m_logEnabled;
1775         deUint32                                        m_programID;
1776         deUint32                                        m_vaoID;
1777 };
1778
1779 AttributePack::AttributePack (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled)
1780         : m_testCtx             (testCtx)
1781         , m_renderCtx   (renderCtx)
1782         , m_ctx                 (drawContext)
1783         , m_program             (DE_NULL)
1784         , m_screen              (screenSize.x(), screenSize.y())
1785         , m_useVao              (useVao)
1786         , m_logEnabled  (logEnabled)
1787         , m_programID   (0)
1788         , m_vaoID               (0)
1789 {
1790         if (m_useVao)
1791                 m_ctx.genVertexArrays(1, &m_vaoID);
1792 }
1793
1794 AttributePack::~AttributePack (void)
1795 {
1796         clearArrays();
1797
1798         if (m_programID)
1799                 m_ctx.deleteProgram(m_programID);
1800
1801         if (m_program)
1802                 delete m_program;
1803
1804         if (m_useVao)
1805                 m_ctx.deleteVertexArrays(1, &m_vaoID);
1806 }
1807
1808 AttributeArray* AttributePack::getArray (int i)
1809 {
1810         return m_arrays.at(i);
1811 }
1812
1813 int AttributePack::getArrayCount (void)
1814 {
1815         return (int)m_arrays.size();
1816 }
1817
1818 void AttributePack::newArray (DrawTestSpec::Storage storage)
1819 {
1820         m_arrays.push_back(new AttributeArray(storage, m_ctx));
1821 }
1822
1823 void AttributePack::clearArrays (void)
1824 {
1825         for (std::vector<AttributeArray*>::iterator itr = m_arrays.begin(); itr != m_arrays.end(); itr++)
1826                 delete *itr;
1827         m_arrays.clear();
1828 }
1829
1830 void AttributePack::updateProgram (void)
1831 {
1832         if (m_programID)
1833                 m_ctx.deleteProgram(m_programID);
1834         if (m_program)
1835                 delete m_program;
1836
1837         m_program = new DrawTestShaderProgram(m_renderCtx, m_arrays);
1838         m_programID = m_ctx.createProgram(m_program);
1839 }
1840
1841 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)
1842 {
1843         DE_ASSERT(m_program != DE_NULL);
1844         DE_ASSERT(m_programID != 0);
1845
1846         m_ctx.viewport(0, 0, m_screen.getWidth(), m_screen.getHeight());
1847         m_ctx.clearColor(0.0, 0.0, 0.0, 1.0);
1848         m_ctx.clear(GL_COLOR_BUFFER_BIT);
1849
1850         m_ctx.useProgram(m_programID);
1851         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glUseProgram()");
1852
1853         m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_coordScale"), coordScale);
1854         m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_colorScale"), colorScale);
1855
1856         if (m_useVao)
1857                 m_ctx.bindVertexArray(m_vaoID);
1858
1859         if (indexArray)
1860                 indexArray->bindIndexArray(DrawTestSpec::TARGET_ELEMENT_ARRAY);
1861
1862         for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
1863         {
1864                 std::stringstream attribName;
1865                 attribName << "a_" << arrayNdx;
1866
1867                 deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str());
1868
1869                 if (m_arrays[arrayNdx]->isBound())
1870                 {
1871                         m_ctx.enableVertexAttribArray(loc);
1872                         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glEnableVertexAttribArray()");
1873                 }
1874
1875                 m_arrays[arrayNdx]->bindAttribute(loc);
1876         }
1877
1878         if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS)
1879         {
1880                 m_ctx.drawArrays(primitiveToGL(primitive), firstVertex, vertexCount);
1881                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArrays()");
1882         }
1883         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED)
1884         {
1885                 m_ctx.drawArraysInstanced(primitiveToGL(primitive), firstVertex, vertexCount, instanceCount);
1886                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysInstanced()");
1887         }
1888         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS)
1889         {
1890                 m_ctx.drawElements(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset);
1891                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElements()");
1892         }
1893         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED)
1894         {
1895                 m_ctx.drawRangeElements(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset);
1896                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElements()");
1897         }
1898         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED)
1899         {
1900                 m_ctx.drawElementsInstanced(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount);
1901                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstanced()");
1902         }
1903         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT)
1904         {
1905                 struct DrawCommand
1906                 {
1907                         GLuint count;
1908                         GLuint primCount;
1909                         GLuint first;
1910                         GLuint reservedMustBeZero;
1911                 };
1912                 deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset];
1913
1914                 {
1915                         DrawCommand command;
1916
1917                         command.count                           = vertexCount;
1918                         command.primCount                       = instanceCount;
1919                         command.first                           = firstVertex;
1920                         command.reservedMustBeZero      = 0;
1921
1922                         memcpy(buffer + indirectOffset, &command, sizeof(command));
1923
1924                         if (m_logEnabled)
1925                                 m_testCtx.getLog()
1926                                         << tcu::TestLog::Message
1927                                         << "DrawArraysIndirectCommand:\n"
1928                                         << "\tcount: " << command.count << "\n"
1929                                         << "\tprimCount: " << command.primCount << "\n"
1930                                         << "\tfirst: " << command.first << "\n"
1931                                         << "\treservedMustBeZero: " << command.reservedMustBeZero << "\n"
1932                                         << tcu::TestLog::EndMessage;
1933                 }
1934
1935                 GLuint indirectBuf = 0;
1936                 m_ctx.genBuffers(1, &indirectBuf);
1937                 m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf);
1938                 m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW);
1939                 delete [] buffer;
1940
1941                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer");
1942
1943                 m_ctx.drawArraysIndirect(primitiveToGL(primitive), (const deInt8*)DE_NULL + indirectOffset);
1944                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()");
1945
1946                 m_ctx.deleteBuffers(1, &indirectBuf);
1947         }
1948         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT)
1949         {
1950                 struct DrawCommand
1951                 {
1952                         GLuint count;
1953                         GLuint primCount;
1954                         GLuint firstIndex;
1955                         GLint  baseVertex;
1956                         GLuint reservedMustBeZero;
1957                 };
1958                 deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset];
1959
1960                 {
1961                         DrawCommand command;
1962
1963                         // index offset must be converted to firstIndex by dividing with the index element size
1964                         DE_ASSERT(((const deUint8*)indexOffset - (const deUint8*)DE_NULL) % gls::DrawTestSpec::indexTypeSize(indexType) == 0); // \note This is checked in spec validation
1965
1966                         command.count                           = vertexCount;
1967                         command.primCount                       = instanceCount;
1968                         command.firstIndex                      = (glw::GLuint)(((const deUint8*)indexOffset - (const deUint8*)DE_NULL) / gls::DrawTestSpec::indexTypeSize(indexType));
1969                         command.baseVertex                      = baseVertex;
1970                         command.reservedMustBeZero      = 0;
1971
1972                         memcpy(buffer + indirectOffset, &command, sizeof(command));
1973
1974                         if (m_logEnabled)
1975                                 m_testCtx.getLog()
1976                                         << tcu::TestLog::Message
1977                                         << "DrawElementsIndirectCommand:\n"
1978                                         << "\tcount: " << command.count << "\n"
1979                                         << "\tprimCount: " << command.primCount << "\n"
1980                                         << "\tfirstIndex: " << command.firstIndex << "\n"
1981                                         << "\tbaseVertex: " << command.baseVertex << "\n"
1982                                         << "\treservedMustBeZero: " << command.reservedMustBeZero << "\n"
1983                                         << tcu::TestLog::EndMessage;
1984                 }
1985
1986                 GLuint indirectBuf = 0;
1987                 m_ctx.genBuffers(1, &indirectBuf);
1988                 m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf);
1989                 m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW);
1990                 delete [] buffer;
1991
1992                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer");
1993
1994                 m_ctx.drawElementsIndirect(primitiveToGL(primitive), indexTypeToGL(indexType), (const deInt8*)DE_NULL + indirectOffset);
1995                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()");
1996
1997                 m_ctx.deleteBuffers(1, &indirectBuf);
1998         }
1999         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX)
2000         {
2001                 m_ctx.drawElementsBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex);
2002                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsBaseVertex()");
2003         }
2004         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX)
2005         {
2006                 m_ctx.drawElementsInstancedBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount, baseVertex);
2007                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstancedBaseVertex()");
2008         }
2009         else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
2010         {
2011                 m_ctx.drawRangeElementsBaseVertex(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex);
2012                 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElementsBaseVertex()");
2013         }
2014         else
2015                 DE_ASSERT(DE_FALSE);
2016
2017         for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
2018         {
2019                 if (m_arrays[arrayNdx]->isBound())
2020                 {
2021                         std::stringstream attribName;
2022                         attribName << "a_" << arrayNdx;
2023
2024                         deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str());
2025
2026                         m_ctx.disableVertexAttribArray(loc);
2027                         GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDisableVertexAttribArray()");
2028                 }
2029         }
2030
2031         if (m_useVao)
2032                 m_ctx.bindVertexArray(0);
2033
2034         m_ctx.useProgram(0);
2035         m_ctx.readPixels(m_screen, 0, 0, m_screen.getWidth(), m_screen.getHeight());
2036 }
2037
2038 // DrawTestSpec
2039
2040 DrawTestSpec::AttributeSpec     DrawTestSpec::AttributeSpec::createAttributeArray (InputType inputType, OutputType outputType, Storage storage, Usage usage, int componentCount, int offset, int stride, bool normalize, int instanceDivisor)
2041 {
2042         DrawTestSpec::AttributeSpec spec;
2043
2044         spec.inputType                  = inputType;
2045         spec.outputType                 = outputType;
2046         spec.storage                    = storage;
2047         spec.usage                              = usage;
2048         spec.componentCount             = componentCount;
2049         spec.offset                             = offset;
2050         spec.stride                             = stride;
2051         spec.normalize                  = normalize;
2052         spec.instanceDivisor    = instanceDivisor;
2053
2054         spec.useDefaultAttribute= false;
2055
2056         return spec;
2057 }
2058
2059 DrawTestSpec::AttributeSpec     DrawTestSpec::AttributeSpec::createDefaultAttribute (InputType inputType, OutputType outputType, int componentCount)
2060 {
2061         DE_ASSERT(inputType == INPUTTYPE_INT || inputType == INPUTTYPE_UNSIGNED_INT || inputType == INPUTTYPE_FLOAT);
2062         DE_ASSERT(inputType == INPUTTYPE_FLOAT || componentCount == 4);
2063
2064         DrawTestSpec::AttributeSpec spec;
2065
2066         spec.inputType                          = inputType;
2067         spec.outputType                         = outputType;
2068         spec.storage                            = DrawTestSpec::STORAGE_LAST;
2069         spec.usage                                      = DrawTestSpec::USAGE_LAST;
2070         spec.componentCount                     = componentCount;
2071         spec.offset                                     = 0;
2072         spec.stride                                     = 0;
2073         spec.normalize                          = 0;
2074         spec.instanceDivisor            = 0;
2075
2076         spec.useDefaultAttribute        = true;
2077
2078         return spec;
2079 }
2080
2081 DrawTestSpec::AttributeSpec::AttributeSpec (void)
2082 {
2083         inputType                                       = DrawTestSpec::INPUTTYPE_LAST;
2084         outputType                                      = DrawTestSpec::OUTPUTTYPE_LAST;
2085         storage                                         = DrawTestSpec::STORAGE_LAST;
2086         usage                                           = DrawTestSpec::USAGE_LAST;
2087         componentCount                          = 0;
2088         offset                                          = 0;
2089         stride                                          = 0;
2090         normalize                                       = false;
2091         instanceDivisor                         = 0;
2092         useDefaultAttribute                     = false;
2093         additionalPositionAttribute = false;
2094         bgraComponentOrder                      = false;
2095 }
2096
2097 int DrawTestSpec::AttributeSpec::hash (void) const
2098 {
2099         if (useDefaultAttribute)
2100         {
2101                 return 1 * int(inputType) + 7 * int(outputType) + 13 * componentCount;
2102         }
2103         else
2104         {
2105                 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;
2106         }
2107 }
2108
2109 bool DrawTestSpec::AttributeSpec::valid (glu::ApiType ctxType) const
2110 {
2111         const bool inputTypeFloat                               = inputType == DrawTestSpec::INPUTTYPE_FLOAT || inputType  == DrawTestSpec::INPUTTYPE_FIXED || inputType == DrawTestSpec::INPUTTYPE_HALF;
2112         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;
2113         const bool inputTypeSignedInteger               = inputType == DrawTestSpec::INPUTTYPE_BYTE  || inputType == DrawTestSpec::INPUTTYPE_SHORT || inputType == DrawTestSpec::INPUTTYPE_INT || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2114         const bool inputTypePacked                              = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2115
2116         const bool outputTypeFloat                              = outputType == DrawTestSpec::OUTPUTTYPE_FLOAT || outputType == DrawTestSpec::OUTPUTTYPE_VEC2  || outputType == DrawTestSpec::OUTPUTTYPE_VEC3  || outputType == DrawTestSpec::OUTPUTTYPE_VEC4;
2117         const bool outputTypeSignedInteger              = outputType == DrawTestSpec::OUTPUTTYPE_INT   || outputType == DrawTestSpec::OUTPUTTYPE_IVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC4;
2118         const bool outputTypeUnsignedInteger    = outputType == DrawTestSpec::OUTPUTTYPE_UINT  || outputType == DrawTestSpec::OUTPUTTYPE_UVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC4;
2119
2120         if (useDefaultAttribute)
2121         {
2122                 if (inputType != DrawTestSpec::INPUTTYPE_INT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT && inputType != DrawTestSpec::INPUTTYPE_FLOAT)
2123                         return false;
2124
2125                 if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && componentCount != 4)
2126                         return false;
2127
2128                 // no casting allowed (undefined results)
2129                 if (inputType == DrawTestSpec::INPUTTYPE_INT && !outputTypeSignedInteger)
2130                         return false;
2131                 if (inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT && !outputTypeUnsignedInteger)
2132                         return false;
2133         }
2134
2135         if (inputTypePacked && componentCount != 4)
2136                 return false;
2137
2138         // Invalid conversions:
2139
2140         // float -> [u]int
2141         if (inputTypeFloat && !outputTypeFloat)
2142                 return false;
2143
2144         // uint -> int          (undefined results)
2145         if (inputTypeUnsignedInteger && outputTypeSignedInteger)
2146                 return false;
2147
2148         // int -> uint          (undefined results)
2149         if (inputTypeSignedInteger && outputTypeUnsignedInteger)
2150                 return false;
2151
2152         // packed -> non-float (packed formats are converted to floats)
2153         if (inputTypePacked && !outputTypeFloat)
2154                 return false;
2155
2156         // Invalid normalize. Normalize is only valid if output type is float
2157         if (normalize && !outputTypeFloat)
2158                 return false;
2159
2160         // Allow reverse order (GL_BGRA) only for packed and 4-component ubyte
2161         if (bgraComponentOrder && componentCount != 4)
2162                 return false;
2163         if (bgraComponentOrder && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE)
2164                 return false;
2165         if (bgraComponentOrder && normalize != true)
2166                 return false;
2167
2168         // GLES2 limits
2169         if (ctxType == glu::ApiType::es(2,0))
2170         {
2171                 if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && inputType != DrawTestSpec::INPUTTYPE_FIXED &&
2172                         inputType != DrawTestSpec::INPUTTYPE_BYTE  && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE &&
2173                         inputType != DrawTestSpec::INPUTTYPE_SHORT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT)
2174                         return false;
2175
2176                 if (!outputTypeFloat)
2177                         return false;
2178
2179                 if (bgraComponentOrder)
2180                         return false;
2181         }
2182
2183         // GLES3 limits
2184         if (ctxType.getProfile() == glu::PROFILE_ES && ctxType.getMajorVersion() == 3)
2185         {
2186                 if (bgraComponentOrder)
2187                         return false;
2188         }
2189
2190         // No user pointers in GL core
2191         if (ctxType.getProfile() == glu::PROFILE_CORE)
2192         {
2193                 if (!useDefaultAttribute && storage == DrawTestSpec::STORAGE_USER)
2194                         return false;
2195         }
2196
2197         return true;
2198 }
2199
2200 bool DrawTestSpec::AttributeSpec::isBufferAligned (void) const
2201 {
2202         const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2203
2204         // Buffer alignment, offset is a multiple of underlying data type size?
2205         if (storage == STORAGE_BUFFER)
2206         {
2207                 int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType);
2208                 if (inputTypePacked)
2209                         dataTypeSize = 4;
2210
2211                 if (offset % dataTypeSize != 0)
2212                         return false;
2213         }
2214
2215         return true;
2216 }
2217
2218 bool DrawTestSpec::AttributeSpec::isBufferStrideAligned (void) const
2219 {
2220         const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2221
2222         // Buffer alignment, offset is a multiple of underlying data type size?
2223         if (storage == STORAGE_BUFFER)
2224         {
2225                 int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType);
2226                 if (inputTypePacked)
2227                         dataTypeSize = 4;
2228
2229                 if (stride % dataTypeSize != 0)
2230                         return false;
2231         }
2232
2233         return true;
2234 }
2235
2236 std::string DrawTestSpec::targetToString(Target target)
2237 {
2238         static const char* targets[] =
2239         {
2240                 "element_array",        // TARGET_ELEMENT_ARRAY = 0,
2241                 "array"                         // TARGET_ARRAY,
2242         };
2243
2244         return de::getSizedArrayElement<DrawTestSpec::TARGET_LAST>(targets, (int)target);
2245 }
2246
2247 std::string DrawTestSpec::inputTypeToString(InputType type)
2248 {
2249         static const char* types[] =
2250         {
2251                 "float",                        // INPUTTYPE_FLOAT = 0,
2252                 "fixed",                        // INPUTTYPE_FIXED,
2253                 "double",                       // INPUTTYPE_DOUBLE
2254
2255                 "byte",                         // INPUTTYPE_BYTE,
2256                 "short",                        // INPUTTYPE_SHORT,
2257
2258                 "unsigned_byte",        // INPUTTYPE_UNSIGNED_BYTE,
2259                 "unsigned_short",       // INPUTTYPE_UNSIGNED_SHORT,
2260
2261                 "int",                                          // INPUTTYPE_INT,
2262                 "unsigned_int",                         // INPUTTYPE_UNSIGNED_INT,
2263                 "half",                                         // INPUTTYPE_HALF,
2264                 "unsigned_int2_10_10_10",       // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
2265                 "int2_10_10_10"                         // INPUTTYPE_INT_2_10_10_10,
2266         };
2267
2268         return de::getSizedArrayElement<DrawTestSpec::INPUTTYPE_LAST>(types, (int)type);
2269 }
2270
2271 std::string DrawTestSpec::outputTypeToString(OutputType type)
2272 {
2273         static const char* types[] =
2274         {
2275                 "float",                // OUTPUTTYPE_FLOAT = 0,
2276                 "vec2",                 // OUTPUTTYPE_VEC2,
2277                 "vec3",                 // OUTPUTTYPE_VEC3,
2278                 "vec4",                 // OUTPUTTYPE_VEC4,
2279
2280                 "int",                  // OUTPUTTYPE_INT,
2281                 "uint",                 // OUTPUTTYPE_UINT,
2282
2283                 "ivec2",                // OUTPUTTYPE_IVEC2,
2284                 "ivec3",                // OUTPUTTYPE_IVEC3,
2285                 "ivec4",                // OUTPUTTYPE_IVEC4,
2286
2287                 "uvec2",                // OUTPUTTYPE_UVEC2,
2288                 "uvec3",                // OUTPUTTYPE_UVEC3,
2289                 "uvec4",                // OUTPUTTYPE_UVEC4,
2290         };
2291
2292         return de::getSizedArrayElement<DrawTestSpec::OUTPUTTYPE_LAST>(types, (int)type);
2293 }
2294
2295 std::string DrawTestSpec::usageTypeToString(Usage usage)
2296 {
2297         static const char* usages[] =
2298         {
2299                 "dynamic_draw", // USAGE_DYNAMIC_DRAW = 0,
2300                 "static_draw",  // USAGE_STATIC_DRAW,
2301                 "stream_draw",  // USAGE_STREAM_DRAW,
2302
2303                 "stream_read",  // USAGE_STREAM_READ,
2304                 "stream_copy",  // USAGE_STREAM_COPY,
2305
2306                 "static_read",  // USAGE_STATIC_READ,
2307                 "static_copy",  // USAGE_STATIC_COPY,
2308
2309                 "dynamic_read", // USAGE_DYNAMIC_READ,
2310                 "dynamic_copy", // USAGE_DYNAMIC_COPY,
2311         };
2312
2313         return de::getSizedArrayElement<DrawTestSpec::USAGE_LAST>(usages, (int)usage);
2314 }
2315
2316 std::string     DrawTestSpec::storageToString (Storage storage)
2317 {
2318         static const char* storages[] =
2319         {
2320                 "user_ptr",     // STORAGE_USER = 0,
2321                 "buffer"        // STORAGE_BUFFER,
2322         };
2323
2324         return de::getSizedArrayElement<DrawTestSpec::STORAGE_LAST>(storages, (int)storage);
2325 }
2326
2327 std::string DrawTestSpec::primitiveToString (Primitive primitive)
2328 {
2329         static const char* primitives[] =
2330         {
2331                 "points",                                       // PRIMITIVE_POINTS ,
2332                 "triangles",                            // PRIMITIVE_TRIANGLES,
2333                 "triangle_fan",                         // PRIMITIVE_TRIANGLE_FAN,
2334                 "triangle_strip",                       // PRIMITIVE_TRIANGLE_STRIP,
2335                 "lines",                                        // PRIMITIVE_LINES
2336                 "line_strip",                           // PRIMITIVE_LINE_STRIP
2337                 "line_loop",                            // PRIMITIVE_LINE_LOOP
2338                 "lines_adjacency",                      // PRIMITIVE_LINES_ADJACENCY
2339                 "line_strip_adjacency",         // PRIMITIVE_LINE_STRIP_ADJACENCY
2340                 "triangles_adjacency",          // PRIMITIVE_TRIANGLES_ADJACENCY
2341                 "triangle_strip_adjacency",     // PRIMITIVE_TRIANGLE_STRIP_ADJACENCY
2342         };
2343
2344         return de::getSizedArrayElement<DrawTestSpec::PRIMITIVE_LAST>(primitives, (int)primitive);
2345 }
2346
2347 std::string DrawTestSpec::indexTypeToString (IndexType type)
2348 {
2349         static const char* indexTypes[] =
2350         {
2351                 "byte",         // INDEXTYPE_BYTE = 0,
2352                 "short",        // INDEXTYPE_SHORT,
2353                 "int",          // INDEXTYPE_INT,
2354         };
2355
2356         return de::getSizedArrayElement<DrawTestSpec::INDEXTYPE_LAST>(indexTypes, (int)type);
2357 }
2358
2359 std::string DrawTestSpec::drawMethodToString (DrawTestSpec::DrawMethod method)
2360 {
2361         static const char* methods[] =
2362         {
2363                 "draw_arrays",                                                  //!< DRAWMETHOD_DRAWARRAYS
2364                 "draw_arrays_instanced",                                //!< DRAWMETHOD_DRAWARRAYS_INSTANCED
2365                 "draw_arrays_indirect",                                 //!< DRAWMETHOD_DRAWARRAYS_INDIRECT
2366                 "draw_elements",                                                //!< DRAWMETHOD_DRAWELEMENTS
2367                 "draw_range_elements",                                  //!< DRAWMETHOD_DRAWELEMENTS_RANGED
2368                 "draw_elements_instanced",                              //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED
2369                 "draw_elements_indirect",                               //!< DRAWMETHOD_DRAWELEMENTS_INDIRECT
2370                 "draw_elements_base_vertex",                    //!< DRAWMETHOD_DRAWELEMENTS_BASEVERTEX,
2371                 "draw_elements_instanced_base_vertex",  //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX,
2372                 "draw_range_elements_base_vertex",              //!< DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX,
2373         };
2374
2375         return de::getSizedArrayElement<DrawTestSpec::DRAWMETHOD_LAST>(methods, (int)method);
2376 }
2377
2378 int DrawTestSpec::inputTypeSize (InputType type)
2379 {
2380         static const int size[] =
2381         {
2382                 (int)sizeof(float),                     // INPUTTYPE_FLOAT = 0,
2383                 (int)sizeof(deInt32),           // INPUTTYPE_FIXED,
2384                 (int)sizeof(double),            // INPUTTYPE_DOUBLE
2385
2386                 (int)sizeof(deInt8),            // INPUTTYPE_BYTE,
2387                 (int)sizeof(deInt16),           // INPUTTYPE_SHORT,
2388
2389                 (int)sizeof(deUint8),           // INPUTTYPE_UNSIGNED_BYTE,
2390                 (int)sizeof(deUint16),          // INPUTTYPE_UNSIGNED_SHORT,
2391
2392                 (int)sizeof(deInt32),           // INPUTTYPE_INT,
2393                 (int)sizeof(deUint32),          // INPUTTYPE_UNSIGNED_INT,
2394                 (int)sizeof(deFloat16),         // INPUTTYPE_HALF,
2395                 (int)sizeof(deUint32) / 4,      // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
2396                 (int)sizeof(deUint32) / 4       // INPUTTYPE_INT_2_10_10_10,
2397         };
2398
2399         return de::getSizedArrayElement<DrawTestSpec::INPUTTYPE_LAST>(size, (int)type);
2400 }
2401
2402 int DrawTestSpec::indexTypeSize (IndexType type)
2403 {
2404         static const int size[] =
2405         {
2406                 sizeof(deUint8),        // INDEXTYPE_BYTE,
2407                 sizeof(deUint16),       // INDEXTYPE_SHORT,
2408                 sizeof(deUint32),       // INDEXTYPE_INT,
2409         };
2410
2411         return de::getSizedArrayElement<DrawTestSpec::INDEXTYPE_LAST>(size, (int)type);
2412 }
2413
2414 std::string DrawTestSpec::getName (void) const
2415 {
2416         const MethodInfo        methodInfo      = getMethodInfo(drawMethod);
2417         const bool                      hasFirst        = methodInfo.first;
2418         const bool                      instanced       = methodInfo.instanced;
2419         const bool                      ranged          = methodInfo.ranged;
2420         const bool                      indexed         = methodInfo.indexed;
2421
2422         std::stringstream name;
2423
2424         for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
2425         {
2426                 const AttributeSpec& attrib = attribs[ndx];
2427
2428                 if (attribs.size() > 1)
2429                         name << "attrib" << ndx << "_";
2430
2431                 if (ndx == 0|| attrib.additionalPositionAttribute)
2432                         name << "pos_";
2433                 else
2434                         name << "col_";
2435
2436                 if (attrib.useDefaultAttribute)
2437                 {
2438                         name
2439                                 << "non_array_"
2440                                 << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "_"
2441                                 << attrib.componentCount << "_"
2442                                 << DrawTestSpec::outputTypeToString(attrib.outputType) << "_";
2443                 }
2444                 else
2445                 {
2446                         name
2447                                 << DrawTestSpec::storageToString(attrib.storage) << "_"
2448                                 << attrib.offset << "_"
2449                                 << attrib.stride << "_"
2450                                 << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType);
2451                         if (attrib.inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && attrib.inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
2452                                 name << attrib.componentCount;
2453                         name
2454                                 << "_"
2455                                 << (attrib.normalize ? "normalized_" : "")
2456                                 << DrawTestSpec::outputTypeToString(attrib.outputType) << "_"
2457                                 << DrawTestSpec::usageTypeToString(attrib.usage) << "_"
2458                                 << attrib.instanceDivisor << "_";
2459                 }
2460         }
2461
2462         if (indexed)
2463                 name
2464                         << "index_" << DrawTestSpec::indexTypeToString(indexType) << "_"
2465                         << DrawTestSpec::storageToString(indexStorage) << "_"
2466                         << "offset" << indexPointerOffset << "_";
2467         if (hasFirst)
2468                 name << "first" << first << "_";
2469         if (ranged)
2470                 name << "ranged_" << indexMin << "_" << indexMax << "_";
2471         if (instanced)
2472                 name << "instances" << instanceCount << "_";
2473
2474         switch (primitive)
2475         {
2476                 case DrawTestSpec::PRIMITIVE_POINTS:
2477                         name << "points_";
2478                         break;
2479                 case DrawTestSpec::PRIMITIVE_TRIANGLES:
2480                         name << "triangles_";
2481                         break;
2482                 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
2483                         name << "triangle_fan_";
2484                         break;
2485                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
2486                         name << "triangle_strip_";
2487                         break;
2488                 case DrawTestSpec::PRIMITIVE_LINES:
2489                         name << "lines_";
2490                         break;
2491                 case DrawTestSpec::PRIMITIVE_LINE_STRIP:
2492                         name << "line_strip_";
2493                         break;
2494                 case DrawTestSpec::PRIMITIVE_LINE_LOOP:
2495                         name << "line_loop_";
2496                         break;
2497                 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
2498                         name << "line_adjancency";
2499                         break;
2500                 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
2501                         name << "line_strip_adjancency";
2502                         break;
2503                 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
2504                         name << "triangles_adjancency";
2505                         break;
2506                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
2507                         name << "triangle_strip_adjancency";
2508                         break;
2509                 default:
2510                         DE_ASSERT(false);
2511                         break;
2512         }
2513
2514         name << primitiveCount;
2515
2516         return name.str();
2517 }
2518
2519 std::string DrawTestSpec::getDesc (void) const
2520 {
2521         std::stringstream desc;
2522
2523         for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
2524         {
2525                 const AttributeSpec& attrib = attribs[ndx];
2526
2527                 if (attrib.useDefaultAttribute)
2528                 {
2529                         desc
2530                                 << "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,"))
2531                                 << "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", "
2532                                 << "input component count " << attrib.componentCount << ", "
2533                                 << "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", ";
2534                 }
2535                 else
2536                 {
2537                         desc
2538                                 << "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,"))
2539                                 << "Storage in " << DrawTestSpec::storageToString(attrib.storage) << ", "
2540                                 << "stride " << attrib.stride << ", "
2541                                 << "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", "
2542                                 << "input component count " << attrib.componentCount << ", "
2543                                 << (attrib.normalize ? "normalized, " : "")
2544                                 << "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", "
2545                                 << "instance divisor " << attrib.instanceDivisor << ", ";
2546                 }
2547         }
2548
2549         if (drawMethod == DRAWMETHOD_DRAWARRAYS)
2550         {
2551                 desc
2552                         << "drawArrays(), "
2553                         << "first " << first << ", ";
2554         }
2555         else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED)
2556         {
2557                 desc
2558                         << "drawArraysInstanced(), "
2559                         << "first " << first << ", "
2560                         << "instance count " << instanceCount << ", ";
2561         }
2562         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS)
2563         {
2564                 desc
2565                         << "drawElements(), "
2566                         << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2567                         << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2568                         << "index offset " << indexPointerOffset << ", ";
2569         }
2570         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED)
2571         {
2572                 desc
2573                         << "drawElementsRanged(), "
2574                         << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2575                         << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2576                         << "index offset " << indexPointerOffset << ", "
2577                         << "range start " << indexMin << ", "
2578                         << "range end " << indexMax << ", ";
2579         }
2580         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED)
2581         {
2582                 desc
2583                         << "drawElementsInstanced(), "
2584                         << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2585                         << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2586                         << "index offset " << indexPointerOffset << ", "
2587                         << "instance count " << instanceCount << ", ";
2588         }
2589         else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT)
2590         {
2591                 desc
2592                         << "drawArraysIndirect(), "
2593                         << "first " << first << ", "
2594                         << "instance count " << instanceCount << ", "
2595                         << "indirect offset " << indirectOffset << ", ";
2596         }
2597         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2598         {
2599                 desc
2600                         << "drawElementsIndirect(), "
2601                         << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2602                         << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2603                         << "index offset " << indexPointerOffset << ", "
2604                         << "instance count " << instanceCount << ", "
2605                         << "indirect offset " << indirectOffset << ", "
2606                         << "base vertex " << baseVertex << ", ";
2607         }
2608         else
2609                 DE_ASSERT(DE_FALSE);
2610
2611         desc << primitiveCount;
2612
2613         switch (primitive)
2614         {
2615                 case DrawTestSpec::PRIMITIVE_POINTS:
2616                         desc << "points";
2617                         break;
2618                 case DrawTestSpec::PRIMITIVE_TRIANGLES:
2619                         desc << "triangles";
2620                         break;
2621                 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
2622                         desc << "triangles (fan)";
2623                         break;
2624                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
2625                         desc << "triangles (strip)";
2626                         break;
2627                 case DrawTestSpec::PRIMITIVE_LINES:
2628                         desc << "lines";
2629                         break;
2630                 case DrawTestSpec::PRIMITIVE_LINE_STRIP:
2631                         desc << "lines (strip)";
2632                         break;
2633                 case DrawTestSpec::PRIMITIVE_LINE_LOOP:
2634                         desc << "lines (loop)";
2635                         break;
2636                 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
2637                         desc << "lines (adjancency)";
2638                         break;
2639                 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
2640                         desc << "lines (strip, adjancency)";
2641                         break;
2642                 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
2643                         desc << "triangles (adjancency)";
2644                         break;
2645                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
2646                         desc << "triangles (strip, adjancency)";
2647                         break;
2648                 default:
2649                         DE_ASSERT(false);
2650                         break;
2651         }
2652
2653         return desc.str();
2654 }
2655
2656 std::string DrawTestSpec::getMultilineDesc (void) const
2657 {
2658         std::stringstream desc;
2659
2660         for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
2661         {
2662                 const AttributeSpec& attrib = attribs[ndx];
2663
2664                 if (attrib.useDefaultAttribute)
2665                 {
2666                         desc
2667                                 << "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n"))
2668                                 << "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n"
2669                                 << "\tinput component count " << attrib.componentCount << "\n"
2670                                 << "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n";
2671                 }
2672                 else
2673                 {
2674                         desc
2675                                 << "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n"))
2676                                 << "\tStorage in " << DrawTestSpec::storageToString(attrib.storage) << "\n"
2677                                 << "\tstride " << attrib.stride << "\n"
2678                                 << "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n"
2679                                 << "\tinput component count " << attrib.componentCount << "\n"
2680                                 << (attrib.normalize ? "\tnormalized\n" : "")
2681                                 << "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n"
2682                                 << "\tinstance divisor " << attrib.instanceDivisor << "\n";
2683                 }
2684         }
2685
2686         if (drawMethod == DRAWMETHOD_DRAWARRAYS)
2687         {
2688                 desc
2689                         << "drawArrays()\n"
2690                         << "\tfirst " << first << "\n";
2691         }
2692         else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED)
2693         {
2694                 desc
2695                         << "drawArraysInstanced()\n"
2696                         << "\tfirst " << first << "\n"
2697                         << "\tinstance count " << instanceCount << "\n";
2698         }
2699         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS)
2700         {
2701                 desc
2702                         << "drawElements()\n"
2703                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2704                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2705                         << "\tindex offset " << indexPointerOffset << "\n";
2706         }
2707         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED)
2708         {
2709                 desc
2710                         << "drawElementsRanged()\n"
2711                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2712                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2713                         << "\tindex offset " << indexPointerOffset << "\n"
2714                         << "\trange start " << indexMin << "\n"
2715                         << "\trange end " << indexMax << "\n";
2716         }
2717         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED)
2718         {
2719                 desc
2720                         << "drawElementsInstanced()\n"
2721                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2722                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2723                         << "\tindex offset " << indexPointerOffset << "\n"
2724                         << "\tinstance count " << instanceCount << "\n";
2725         }
2726         else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT)
2727         {
2728                 desc
2729                         << "drawArraysIndirect()\n"
2730                         << "\tfirst " << first << "\n"
2731                         << "\tinstance count " << instanceCount << "\n"
2732                         << "\tindirect offset " << indirectOffset << "\n";
2733         }
2734         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2735         {
2736                 desc
2737                         << "drawElementsIndirect()\n"
2738                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2739                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2740                         << "\tindex offset " << indexPointerOffset << "\n"
2741                         << "\tinstance count " << instanceCount << "\n"
2742                         << "\tindirect offset " << indirectOffset << "\n"
2743                         << "\tbase vertex " << baseVertex << "\n";
2744         }
2745         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_BASEVERTEX)
2746         {
2747                 desc
2748                         << "drawElementsBaseVertex()\n"
2749                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2750                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2751                         << "\tindex offset " << indexPointerOffset << "\n"
2752                         << "\tbase vertex " << baseVertex << "\n";
2753         }
2754         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX)
2755         {
2756                 desc
2757                         << "drawElementsInstancedBaseVertex()\n"
2758                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2759                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2760                         << "\tindex offset " << indexPointerOffset << "\n"
2761                         << "\tinstance count " << instanceCount << "\n"
2762                         << "\tbase vertex " << baseVertex << "\n";
2763         }
2764         else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
2765         {
2766                 desc
2767                         << "drawRangeElementsBaseVertex()\n"
2768                         << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2769                         << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2770                         << "\tindex offset " << indexPointerOffset << "\n"
2771                         << "\tbase vertex " << baseVertex << "\n"
2772                         << "\trange start " << indexMin << "\n"
2773                         << "\trange end " << indexMax << "\n";
2774         }
2775         else
2776                 DE_ASSERT(DE_FALSE);
2777
2778         desc << "\t" << primitiveCount << " ";
2779
2780         switch (primitive)
2781         {
2782                 case DrawTestSpec::PRIMITIVE_POINTS:
2783                         desc << "points";
2784                         break;
2785                 case DrawTestSpec::PRIMITIVE_TRIANGLES:
2786                         desc << "triangles";
2787                         break;
2788                 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
2789                         desc << "triangles (fan)";
2790                         break;
2791                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
2792                         desc << "triangles (strip)";
2793                         break;
2794                 case DrawTestSpec::PRIMITIVE_LINES:
2795                         desc << "lines";
2796                         break;
2797                 case DrawTestSpec::PRIMITIVE_LINE_STRIP:
2798                         desc << "lines (strip)";
2799                         break;
2800                 case DrawTestSpec::PRIMITIVE_LINE_LOOP:
2801                         desc << "lines (loop)";
2802                         break;
2803                 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
2804                         desc << "lines (adjancency)";
2805                         break;
2806                 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
2807                         desc << "lines (strip, adjancency)";
2808                         break;
2809                 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
2810                         desc << "triangles (adjancency)";
2811                         break;
2812                 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
2813                         desc << "triangles (strip, adjancency)";
2814                         break;
2815                 default:
2816                         DE_ASSERT(false);
2817                         break;
2818         }
2819
2820         desc << "\n";
2821
2822         return desc.str();
2823 }
2824
2825 DrawTestSpec::DrawTestSpec (void)
2826 {
2827         primitive                       = PRIMITIVE_LAST;
2828         primitiveCount          = 0;
2829         drawMethod                      = DRAWMETHOD_LAST;
2830         indexType                       = INDEXTYPE_LAST;
2831         indexPointerOffset      = 0;
2832         indexStorage            = STORAGE_LAST;
2833         first                           = 0;
2834         indexMin                        = 0;
2835         indexMax                        = 0;
2836         instanceCount           = 0;
2837         indirectOffset          = 0;
2838         baseVertex                      = 0;
2839 }
2840
2841 int DrawTestSpec::hash (void) const
2842 {
2843         // Use only drawmode-relevant values in "hashing" as the unrelevant values might not be set (causing non-deterministic behavior).
2844         const MethodInfo        methodInfo              = getMethodInfo(drawMethod);
2845         const bool                      arrayed                 = methodInfo.first;
2846         const bool                      instanced               = methodInfo.instanced;
2847         const bool                      ranged                  = methodInfo.ranged;
2848         const bool                      indexed                 = methodInfo.indexed;
2849         const bool                      indirect                = methodInfo.indirect;
2850         const bool                      hasBaseVtx              = methodInfo.baseVertex;
2851
2852         const int                       indexHash               = (!indexed)    ? (0) : (int(indexType) + 10 * indexPointerOffset + 100 * int(indexStorage));
2853         const int                       arrayHash               = (!arrayed)    ? (0) : (first);
2854         const int                       indexRangeHash  = (!ranged)             ? (0) : (indexMin + 10 * indexMax);
2855         const int                       instanceHash    = (!instanced)  ? (0) : (instanceCount);
2856         const int                       indirectHash    = (!indirect)   ? (0) : (indirectOffset);
2857         const int                       baseVtxHash             = (!hasBaseVtx) ? (0) : (baseVertex);
2858         const int                       basicHash               = int(primitive) + 10 * primitiveCount + 100 * int(drawMethod);
2859
2860         return indexHash + 3 * arrayHash + 5 * indexRangeHash + 7 * instanceHash + 13 * basicHash + 17 * (int)attribs.size() + 19 * primitiveCount + 23 * indirectHash + 27 * baseVtxHash;
2861 }
2862
2863 bool DrawTestSpec::valid (void) const
2864 {
2865         DE_ASSERT(apiType.getProfile() != glu::PROFILE_LAST);
2866         DE_ASSERT(primitive != PRIMITIVE_LAST);
2867         DE_ASSERT(drawMethod != DRAWMETHOD_LAST);
2868
2869         const MethodInfo methodInfo = getMethodInfo(drawMethod);
2870
2871         for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
2872                 if (!attribs[ndx].valid(apiType))
2873                         return false;
2874
2875         if (methodInfo.ranged)
2876         {
2877                 deUint32 maxIndexValue = 0;
2878                 if (indexType == INDEXTYPE_BYTE)
2879                         maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_BYTE).ub.getValue();
2880                 else if (indexType == INDEXTYPE_SHORT)
2881                         maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_SHORT).us.getValue();
2882                 else if (indexType == INDEXTYPE_INT)
2883                         maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_INT).ui.getValue();
2884                 else
2885                         DE_ASSERT(DE_FALSE);
2886
2887                 if (indexMin > indexMax)
2888                         return false;
2889                 if (indexMin < 0 || indexMax < 0)
2890                         return false;
2891                 if ((deUint32)indexMin > maxIndexValue || (deUint32)indexMax > maxIndexValue)
2892                         return false;
2893         }
2894
2895         if (methodInfo.first && first < 0)
2896                 return false;
2897
2898         // GLES2 limits
2899         if (apiType == glu::ApiType::es(2,0))
2900         {
2901                 if (drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS && drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS)
2902                         return false;
2903                 if (drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS && (indexType != INDEXTYPE_BYTE && indexType != INDEXTYPE_SHORT))
2904                         return false;
2905         }
2906
2907         // Indirect limitations
2908         if (methodInfo.indirect)
2909         {
2910                 // Indirect offset alignment
2911                 if (indirectOffset % 4 != 0)
2912                         return false;
2913
2914                 // All attribute arrays must be stored in a buffer
2915                 for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
2916                         if (!attribs[ndx].useDefaultAttribute && attribs[ndx].storage == gls::DrawTestSpec::STORAGE_USER)
2917                                 return false;
2918         }
2919         if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2920         {
2921                 // index offset must be convertable to firstIndex
2922                 if (indexPointerOffset % gls::DrawTestSpec::indexTypeSize(indexType) != 0)
2923                         return false;
2924
2925                 // Indices must be in a buffer
2926                 if (indexStorage != STORAGE_BUFFER)
2927                         return false;
2928         }
2929
2930         // Do not allow user pointer in GL core
2931         if (apiType.getProfile() == glu::PROFILE_CORE)
2932         {
2933                 if (methodInfo.indexed && indexStorage == DrawTestSpec::STORAGE_USER)
2934                         return false;
2935         }
2936
2937         return true;
2938 }
2939
2940 DrawTestSpec::CompatibilityTestType DrawTestSpec::isCompatibilityTest (void) const
2941 {
2942         const MethodInfo methodInfo = getMethodInfo(drawMethod);
2943
2944         bool bufferAlignmentBad = false;
2945         bool strideAlignmentBad = false;
2946
2947         // Attribute buffer alignment
2948         for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
2949                 if (!attribs[ndx].isBufferAligned())
2950                         bufferAlignmentBad = true;
2951
2952         // Attribute stride alignment
2953         for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
2954                 if (!attribs[ndx].isBufferStrideAligned())
2955                         strideAlignmentBad = true;
2956
2957         // Index buffer alignment
2958         if (methodInfo.indexed)
2959         {
2960                 if (indexStorage == STORAGE_BUFFER)
2961                 {
2962                         int indexSize = 0;
2963                         if (indexType == INDEXTYPE_BYTE)
2964                                 indexSize = 1;
2965                         else if (indexType == INDEXTYPE_SHORT)
2966                                 indexSize = 2;
2967                         else if (indexType == INDEXTYPE_INT)
2968                                 indexSize = 4;
2969                         else
2970                                 DE_ASSERT(DE_FALSE);
2971
2972                         if (indexPointerOffset % indexSize != 0)
2973                                 bufferAlignmentBad = true;
2974                 }
2975         }
2976
2977         // \note combination bad alignment & stride is treated as bad offset
2978         if (bufferAlignmentBad)
2979                 return COMPATIBILITY_UNALIGNED_OFFSET;
2980         else if (strideAlignmentBad)
2981                 return COMPATIBILITY_UNALIGNED_STRIDE;
2982         else
2983                 return COMPATIBILITY_NONE;
2984 }
2985
2986 enum PrimitiveClass
2987 {
2988         PRIMITIVECLASS_POINT = 0,
2989         PRIMITIVECLASS_LINE,
2990         PRIMITIVECLASS_TRIANGLE,
2991
2992         PRIMITIVECLASS_LAST
2993 };
2994
2995 static PrimitiveClass getDrawPrimitiveClass (gls::DrawTestSpec::Primitive primitiveType)
2996 {
2997         switch (primitiveType)
2998         {
2999                 case gls::DrawTestSpec::PRIMITIVE_POINTS:
3000                         return PRIMITIVECLASS_POINT;
3001
3002                 case gls::DrawTestSpec::PRIMITIVE_LINES:
3003                 case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP:
3004                 case gls::DrawTestSpec::PRIMITIVE_LINE_LOOP:
3005                 case gls::DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
3006                 case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
3007                         return PRIMITIVECLASS_LINE;
3008
3009                 case gls::DrawTestSpec::PRIMITIVE_TRIANGLES:
3010                 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
3011                 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
3012                 case gls::DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
3013                 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
3014                         return PRIMITIVECLASS_TRIANGLE;
3015
3016                 default:
3017                         DE_ASSERT(false);
3018                         return PRIMITIVECLASS_LAST;
3019         }
3020 }
3021
3022 static bool containsLineCases (const std::vector<DrawTestSpec>& m_specs)
3023 {
3024         for (int ndx = 0; ndx < (int)m_specs.size(); ++ndx)
3025         {
3026                 if (getDrawPrimitiveClass(m_specs[ndx].primitive) == PRIMITIVECLASS_LINE)
3027                         return true;
3028         }
3029         return false;
3030 }
3031
3032 // DrawTest
3033
3034 DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const DrawTestSpec& spec, const char* name, const char* desc)
3035         : TestCase                      (testCtx, name, desc)
3036         , m_renderCtx           (renderCtx)
3037         , m_refBuffers          (DE_NULL)
3038         , m_refContext          (DE_NULL)
3039         , m_glesContext         (DE_NULL)
3040         , m_glArrayPack         (DE_NULL)
3041         , m_rrArrayPack         (DE_NULL)
3042         , m_maxDiffRed          (-1)
3043         , m_maxDiffGreen        (-1)
3044         , m_maxDiffBlue         (-1)
3045         , m_iteration           (0)
3046         , m_result                      ()      // \note no per-iteration result logging (only one iteration)
3047 {
3048         addIteration(spec);
3049 }
3050
3051 DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc)
3052         : TestCase                      (testCtx, name, desc)
3053         , m_renderCtx           (renderCtx)
3054         , m_refBuffers          (DE_NULL)
3055         , m_refContext          (DE_NULL)
3056         , m_glesContext         (DE_NULL)
3057         , m_glArrayPack         (DE_NULL)
3058         , m_rrArrayPack         (DE_NULL)
3059         , m_maxDiffRed          (-1)
3060         , m_maxDiffGreen        (-1)
3061         , m_maxDiffBlue         (-1)
3062         , m_iteration           (0)
3063         , m_result                      (testCtx.getLog(), "Iteration result: ")
3064 {
3065 }
3066
3067 DrawTest::~DrawTest     (void)
3068 {
3069         deinit();
3070 }
3071
3072 void DrawTest::addIteration (const DrawTestSpec& spec, const char* description)
3073 {
3074         // Validate spec
3075         const bool validSpec = spec.valid();
3076         DE_ASSERT(validSpec);
3077
3078         if (!validSpec)
3079                 return;
3080
3081         // Check the context type is the same with other iterations
3082         if (!m_specs.empty())
3083         {
3084                 const bool validContext = m_specs[0].apiType == spec.apiType;
3085                 DE_ASSERT(validContext);
3086
3087                 if (!validContext)
3088                         return;
3089         }
3090
3091         m_specs.push_back(spec);
3092
3093         if (description)
3094                 m_iteration_descriptions.push_back(std::string(description));
3095         else
3096                 m_iteration_descriptions.push_back(std::string());
3097 }
3098
3099 void DrawTest::init (void)
3100 {
3101         DE_ASSERT(!m_specs.empty());
3102         DE_ASSERT(contextSupports(m_renderCtx.getType(), m_specs[0].apiType));
3103
3104         const int                                               renderTargetWidth       = de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getWidth());
3105         const int                                               renderTargetHeight      = de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getHeight());
3106
3107         // lines have significantly different rasterization in MSAA mode
3108         const bool                                              isLineCase                      = containsLineCases(m_specs);
3109         const bool                                              isMSAACase                      = m_renderCtx.getRenderTarget().getNumSamples() > 1;
3110         const int                                               renderTargetSamples     = (isMSAACase && isLineCase) ? (4) : (1);
3111
3112         sglr::ReferenceContextLimits    limits                          (m_renderCtx);
3113         bool                                                    useVao                          = false;
3114
3115         m_glesContext = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
3116
3117         if (m_renderCtx.getType().getAPI() == glu::ApiType::es(2,0) || m_renderCtx.getType().getAPI() == glu::ApiType::es(3,0))
3118                 useVao = false;
3119         else if (contextSupports(m_renderCtx.getType(), glu::ApiType::es(3,1)) || glu::isContextTypeGLCore(m_renderCtx.getType()))
3120                 useVao = true;
3121         else
3122                 DE_FATAL("Unknown context type");
3123
3124         m_refBuffers    = new sglr::ReferenceContextBuffers(m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, renderTargetWidth, renderTargetHeight, renderTargetSamples);
3125         m_refContext    = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
3126
3127         m_glArrayPack   = new AttributePack(m_testCtx, m_renderCtx, *m_glesContext, tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, true);
3128         m_rrArrayPack   = new AttributePack(m_testCtx, m_renderCtx, *m_refContext,  tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, false);
3129
3130         m_maxDiffRed    = deCeilFloatToInt32(256.0f * (6.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().redBits)));
3131         m_maxDiffGreen  = deCeilFloatToInt32(256.0f * (6.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().greenBits)));
3132         m_maxDiffBlue   = deCeilFloatToInt32(256.0f * (6.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().blueBits)));
3133 }
3134
3135 void DrawTest::deinit (void)
3136 {
3137         delete m_glArrayPack;
3138         delete m_rrArrayPack;
3139         delete m_refBuffers;
3140         delete m_refContext;
3141         delete m_glesContext;
3142
3143         m_glArrayPack   = DE_NULL;
3144         m_rrArrayPack   = DE_NULL;
3145         m_refBuffers    = DE_NULL;
3146         m_refContext    = DE_NULL;
3147         m_glesContext   = DE_NULL;
3148 }
3149
3150 DrawTest::IterateResult DrawTest::iterate (void)
3151 {
3152         const int                                       specNdx                 = (m_iteration / 2);
3153         const bool                                      drawStep                = (m_iteration % 2) == 0;
3154         const bool                                      compareStep             = (m_iteration % 2) == 1;
3155         const IterateResult                     iterateResult   = ((size_t)m_iteration + 1 == m_specs.size()*2) ? (STOP) : (CONTINUE);
3156         const DrawTestSpec&                     spec                    = m_specs[specNdx];
3157         const bool                                      updateProgram   = (m_iteration == 0) || (drawStep && !checkSpecsShaderCompatible(m_specs[specNdx], m_specs[specNdx-1])); // try to use the same shader in all iterations
3158         IterationLogSectionEmitter      sectionEmitter  (m_testCtx.getLog(), specNdx, m_specs.size(), m_iteration_descriptions[specNdx], drawStep && m_specs.size()!=1);
3159
3160         if (drawStep)
3161         {
3162                 const MethodInfo        methodInfo                              = getMethodInfo(spec.drawMethod);
3163                 const bool                      indexed                                 = methodInfo.indexed;
3164                 const bool                      instanced                               = methodInfo.instanced;
3165                 const bool                      ranged                                  = methodInfo.ranged;
3166                 const bool                      hasFirst                                = methodInfo.first;
3167                 const bool                      hasBaseVtx                              = methodInfo.baseVertex;
3168
3169                 const size_t            primitiveElementCount   = getElementCount(spec.primitive, spec.primitiveCount);                                         // !< elements to be drawn
3170                 const int                       indexMin                                = (ranged) ? (spec.indexMin) : (0);
3171                 const int                       firstAddition                   = (hasFirst) ? (spec.first) : (0);
3172                 const int                       baseVertexAddition              = (hasBaseVtx && spec.baseVertex > 0) ? ( spec.baseVertex) : (0);                       // spec.baseVertex > 0 => Create bigger attribute buffer
3173                 const int                       indexBase                               = (hasBaseVtx && spec.baseVertex < 0) ? (-spec.baseVertex) : (0);                       // spec.baseVertex < 0 => Create bigger indices
3174                 const size_t            elementCount                    = primitiveElementCount + indexMin + firstAddition + baseVertexAddition;        // !< elements in buffer (buffer should have at least primitiveElementCount ACCESSIBLE (index range, first) elements)
3175                 const int                       maxElementIndex                 = (int)primitiveElementCount + indexMin + firstAddition - 1;
3176                 const int                       indexMax                                = de::max(0, (ranged) ? (de::clamp<int>(spec.indexMax, 0, maxElementIndex)) : (maxElementIndex));
3177                 float                           coordScale                              = getCoordScale(spec);
3178                 float                           colorScale                              = getColorScale(spec);
3179
3180                 rr::GenericVec4         nullAttribValue;
3181
3182                 // Log info
3183                 m_testCtx.getLog() << TestLog::Message << spec.getMultilineDesc() << TestLog::EndMessage;
3184                 m_testCtx.getLog() << TestLog::Message << TestLog::EndMessage; // extra line for clarity
3185
3186                 // Data
3187
3188                 m_glArrayPack->clearArrays();
3189                 m_rrArrayPack->clearArrays();
3190
3191                 for (int attribNdx = 0; attribNdx < (int)spec.attribs.size(); attribNdx++)
3192                 {
3193                         DrawTestSpec::AttributeSpec attribSpec          = spec.attribs[attribNdx];
3194                         const bool                                      isPositionAttr  = (attribNdx == 0) || (attribSpec.additionalPositionAttribute);
3195
3196                         if (attribSpec.useDefaultAttribute)
3197                         {
3198                                 const int               seed            = 10 * attribSpec.hash() + 100 * spec.hash() + attribNdx;
3199                                 rr::GenericVec4 attribValue = RandomArrayGenerator::generateAttributeValue(seed, attribSpec.inputType);
3200
3201                                 m_glArrayPack->newArray(DrawTestSpec::STORAGE_USER);
3202                                 m_rrArrayPack->newArray(DrawTestSpec::STORAGE_USER);
3203
3204                                 m_glArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false);
3205                                 m_rrArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false);
3206                         }
3207                         else
3208                         {
3209                                 const int                                       seed                                    = attribSpec.hash() + 100 * spec.hash() + attribNdx;
3210                                 const size_t                            elementSize                             = attribSpec.componentCount * DrawTestSpec::inputTypeSize(attribSpec.inputType);
3211                                 const size_t                            stride                                  = (attribSpec.stride == 0) ? (elementSize) : (attribSpec.stride);
3212                                 const size_t                            evaluatedElementCount   = (instanced && attribSpec.instanceDivisor > 0) ? (spec.instanceCount / attribSpec.instanceDivisor + 1) : (elementCount);
3213                                 const size_t                            referencedElementCount  = (ranged) ? (de::max<size_t>(evaluatedElementCount, spec.indexMax + 1)) : (evaluatedElementCount);
3214                                 const size_t                            bufferSize                              = attribSpec.offset + stride * (referencedElementCount - 1) + elementSize;
3215                                 const char*                                     data                                    = RandomArrayGenerator::generateArray(seed, (int)referencedElementCount, attribSpec.componentCount, attribSpec.offset, (int)stride, attribSpec.inputType);
3216
3217                                 try
3218                                 {
3219                                         m_glArrayPack->newArray(attribSpec.storage);
3220                                         m_rrArrayPack->newArray(attribSpec.storage);
3221
3222                                         m_glArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage);
3223                                         m_rrArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage);
3224
3225                                         m_glArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder);
3226                                         m_rrArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder);
3227
3228                                         delete [] data;
3229                                         data = NULL;
3230                                 }
3231                                 catch (...)
3232                                 {
3233                                         delete [] data;
3234                                         throw;
3235                                 }
3236                         }
3237                 }
3238
3239                 // Shader program
3240                 if (updateProgram)
3241                 {
3242                         m_glArrayPack->updateProgram();
3243                         m_rrArrayPack->updateProgram();
3244                 }
3245
3246                 // Draw
3247                 try
3248                 {
3249                         // indices
3250                         if (indexed)
3251                         {
3252                                 const int               seed                            = spec.hash();
3253                                 const size_t    indexElementSize        = DrawTestSpec::indexTypeSize(spec.indexType);
3254                                 const size_t    indexArraySize          = spec.indexPointerOffset + indexElementSize * elementCount;
3255                                 const char*             indexArray                      = RandomArrayGenerator::generateIndices(seed, (int)elementCount, spec.indexType, spec.indexPointerOffset, indexMin, indexMax, indexBase);
3256                                 const char*             indexPointerBase        = (spec.indexStorage == DrawTestSpec::STORAGE_USER) ? (indexArray) : ((char*)DE_NULL);
3257                                 const char*             indexPointer            = indexPointerBase + spec.indexPointerOffset;
3258
3259                                 de::UniquePtr<AttributeArray> glArray   (new AttributeArray(spec.indexStorage, *m_glesContext));
3260                                 de::UniquePtr<AttributeArray> rrArray   (new AttributeArray(spec.indexStorage, *m_refContext));
3261
3262                                 try
3263                                 {
3264                                         glArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW);
3265                                         rrArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW);
3266
3267                                         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());
3268                                         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());
3269
3270                                         delete [] indexArray;
3271                                         indexArray = NULL;
3272                                 }
3273                                 catch (...)
3274                                 {
3275                                         delete [] indexArray;
3276                                         throw;
3277                                 }
3278                         }
3279                         else
3280                         {
3281                                 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);
3282                                 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);
3283                         }
3284                 }
3285                 catch (glu::Error& err)
3286                 {
3287                         // GL Errors are ok if the mode is not properly aligned
3288
3289                         const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest();
3290
3291                         m_testCtx.getLog() << TestLog::Message << "Got error: " << err.what() << TestLog::EndMessage;
3292
3293                         if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET)
3294                                 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
3295                         else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
3296                                 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
3297                         else
3298                                 throw;
3299                 }
3300         }
3301         else if (compareStep)
3302         {
3303                 if (!compare(spec.primitive))
3304                 {
3305                         const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest();
3306
3307                         if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET)
3308                                 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
3309                         else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
3310                                 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
3311                         else
3312                                 m_result.addResult(QP_TEST_RESULT_FAIL, "Image comparison failed.");
3313                 }
3314         }
3315         else
3316         {
3317                 DE_ASSERT(false);
3318                 return STOP;
3319         }
3320
3321         m_result.setTestContextResult(m_testCtx);
3322
3323         m_iteration++;
3324         return iterateResult;
3325 }
3326
3327 static bool isBlack (const tcu::RGBA& c)
3328 {
3329         // ignore alpha channel
3330         return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0;
3331 }
3332
3333 static bool isEdgeTripletComponent (int c1, int c2, int c3, int renderTargetDifference)
3334 {
3335         const int       roundingDifference      = 2 * renderTargetDifference; // src and dst pixels rounded to different directions
3336         const int       d1                                      = c2 - c1;
3337         const int       d2                                      = c3 - c2;
3338         const int       rampDiff                        = de::abs(d2 - d1);
3339
3340         return rampDiff > roundingDifference;
3341 }
3342
3343 static bool isEdgeTriplet (const tcu::RGBA& c1, const tcu::RGBA& c2, const tcu::RGBA& c3, const tcu::IVec3& renderTargetThreshold)
3344 {
3345         // black (background color) and non-black is always an edge
3346         {
3347                 const bool b1 = isBlack(c1);
3348                 const bool b2 = isBlack(c2);
3349                 const bool b3 = isBlack(c3);
3350
3351                 // both pixels with coverage and pixels without coverage
3352                 if ((b1 && b2 && b3) == false && (b1 || b2 || b3) == true)
3353                         return true;
3354                 // all black
3355                 if (b1 && b2 && b3)
3356                         return false;
3357                 // all with coverage
3358                 DE_ASSERT(!b1 && !b2 && !b3);
3359         }
3360
3361         // Color is always linearly interpolated => component values change nearly linearly
3362         // in any constant direction on triangle hull. (df/dx ~= C).
3363
3364         // Edge detection (this function) is run against the reference image
3365         // => no dithering to worry about
3366
3367         return  isEdgeTripletComponent(c1.getRed(),             c2.getRed(),    c3.getRed(),    renderTargetThreshold.x())      ||
3368                         isEdgeTripletComponent(c1.getGreen(),   c2.getGreen(),  c3.getGreen(),  renderTargetThreshold.y())      ||
3369                         isEdgeTripletComponent(c1.getBlue(),    c2.getBlue(),   c3.getBlue(),   renderTargetThreshold.z());
3370 }
3371
3372 static bool pixelNearEdge (int x, int y, const tcu::Surface& ref, const tcu::IVec3& renderTargetThreshold)
3373 {
3374         // should not be called for edge pixels
3375         DE_ASSERT(x >= 1 && x <= ref.getWidth()-2);
3376         DE_ASSERT(y >= 1 && y <= ref.getHeight()-2);
3377
3378         // horizontal
3379
3380         for (int dy = -1; dy < 2; ++dy)
3381         {
3382                 const tcu::RGBA c1 = ref.getPixel(x-1, y+dy);
3383                 const tcu::RGBA c2 = ref.getPixel(x,   y+dy);
3384                 const tcu::RGBA c3 = ref.getPixel(x+1, y+dy);
3385                 if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold))
3386                         return true;
3387         }
3388
3389         // vertical
3390
3391         for (int dx = -1; dx < 2; ++dx)
3392         {
3393                 const tcu::RGBA c1 = ref.getPixel(x+dx, y-1);
3394                 const tcu::RGBA c2 = ref.getPixel(x+dx, y);
3395                 const tcu::RGBA c3 = ref.getPixel(x+dx, y+1);
3396                 if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold))
3397                         return true;
3398         }
3399
3400         return false;
3401 }
3402
3403 static deUint32 getVisualizationGrayscaleColor (const tcu::RGBA& c)
3404 {
3405         // make triangle coverage and error pixels obvious by converting coverage to grayscale
3406         if (isBlack(c))
3407                 return 0;
3408         else
3409                 return 50u + (deUint32)(c.getRed() + c.getBlue() + c.getGreen()) / 8u;
3410 }
3411
3412 static bool pixelNearLineIntersection (int x, int y, const tcu::Surface& target)
3413 {
3414         // should not be called for edge pixels
3415         DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
3416         DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
3417
3418         int coveredPixels = 0;
3419
3420         for (int dy = -1; dy < 2; dy++)
3421         for (int dx = -1; dx < 2; dx++)
3422         {
3423                 const bool targetCoverage = !isBlack(target.getPixel(x+dx, y+dy));
3424                 if (targetCoverage)
3425                 {
3426                         ++coveredPixels;
3427
3428                         // A single thin line cannot have more than 3 covered pixels in a 3x3 area
3429                         if (coveredPixels >= 4)
3430                                 return true;
3431                 }
3432         }
3433
3434         return false;
3435 }
3436
3437 static inline bool colorsEqual (const tcu::RGBA& colorA, const tcu::RGBA& colorB, const tcu::IVec3& compareThreshold)
3438 {
3439         enum
3440         {
3441                 TCU_RGBA_RGB_MASK = tcu::RGBA::RED_MASK | tcu::RGBA::GREEN_MASK | tcu::RGBA::BLUE_MASK
3442         };
3443
3444         return tcu::compareThresholdMasked(colorA, colorB, tcu::RGBA(compareThreshold.x(), compareThreshold.y(), compareThreshold.z(), 0), TCU_RGBA_RGB_MASK);
3445 }
3446
3447 // search 3x3 are for matching color
3448 static bool pixelNeighborhoodContainsColor (const tcu::Surface& target, int x, int y, const tcu::RGBA& color, const tcu::IVec3& compareThreshold)
3449 {
3450         // should not be called for edge pixels
3451         DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
3452         DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
3453
3454         for (int dy = -1; dy < 2; dy++)
3455         for (int dx = -1; dx < 2; dx++)
3456         {
3457                 const tcu::RGBA targetCmpPixel = target.getPixel(x+dx, y+dy);
3458                 if (colorsEqual(color, targetCmpPixel, compareThreshold))
3459                         return true;
3460         }
3461
3462         return false;
3463 }
3464
3465 // search 3x3 are for matching coverage (coverage == (color != background color))
3466 static bool pixelNeighborhoodContainsCoverage (const tcu::Surface& target, int x, int y, bool coverage)
3467 {
3468         // should not be called for edge pixels
3469         DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
3470         DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
3471
3472         for (int dy = -1; dy < 2; dy++)
3473         for (int dx = -1; dx < 2; dx++)
3474         {
3475                 const bool targetCmpCoverage = !isBlack(target.getPixel(x+dx, y+dy));
3476                 if (targetCmpCoverage == coverage)
3477                         return true;
3478         }
3479
3480         return false;
3481 }
3482
3483 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)
3484 {
3485         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3486
3487         const tcu::IVec4                                green                                           (0, 255, 0, 255);
3488         const tcu::IVec4                                red                                                     (255, 0, 0, 255);
3489         const int                                               width                                           = reference.getWidth();
3490         const int                                               height                                          = reference.getHeight();
3491         tcu::TextureLevel                               errorMask                                       (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height);
3492         const tcu::PixelBufferAccess    errorAccess                                     = errorMask.getAccess();
3493         int                                                             numFailingPixels                        = 0;
3494
3495         // clear errormask edges which would otherwise be transparent
3496
3497         tcu::clear(tcu::getSubregion(errorAccess, 0,                    0,                      width,  1),                     green);
3498         tcu::clear(tcu::getSubregion(errorAccess, 0,                    height-1,       width,  1),                     green);
3499         tcu::clear(tcu::getSubregion(errorAccess, 0,                    0,                      1,              height),        green);
3500         tcu::clear(tcu::getSubregion(errorAccess, width-1,              0,                      1,              height),        green);
3501
3502         // skip edge pixels since coverage on edge cannot be verified
3503
3504         for (int y = 1; y < height - 1; ++y)
3505         for (int x = 1; x < width - 1; ++x)
3506         {
3507                 const tcu::RGBA refPixel                        = reference.getPixel(x, y);
3508                 const tcu::RGBA screenPixel                     = result.getPixel(x, y);
3509                 const bool              directMatch                     = colorsEqual(refPixel, screenPixel, compareThreshold);
3510                 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.)
3511                 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.)
3512
3513                 if (isOkScreenPixel && isOkReferencePixel)
3514                 {
3515                         // pixel valid, write greenish pixels to make the result image easier to read
3516                         const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3517                         errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3518                 }
3519                 else if (!pixelNearEdge(x, y, reference, renderTargetThreshold))
3520                 {
3521                         // non-edge pixel values must be within threshold of the reference values
3522                         errorAccess.setPixel(red, x, y);
3523                         ++numFailingPixels;
3524                 }
3525                 else
3526                 {
3527                         // we are on/near an edge, verify only coverage (coverage == not background colored)
3528                         const bool      referenceCoverage               = !isBlack(refPixel);
3529                         const bool      screenCoverage                  = !isBlack(screenPixel);
3530                         const bool      isOkReferenceCoverage   = pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage);   // Check reference pixel against screen pixel
3531                         const bool      isOkScreenCoverage              = pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage);   // Check screen pixels against reference pixel
3532
3533                         if (isOkScreenCoverage && isOkReferenceCoverage)
3534                         {
3535                                 // pixel valid, write greenish pixels to make the result image easier to read
3536                                 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3537                                 errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3538                         }
3539                         else
3540                         {
3541                                 // coverage does not match
3542                                 errorAccess.setPixel(red, x, y);
3543                                 ++numFailingPixels;
3544                         }
3545                 }
3546         }
3547
3548         log     << TestLog::Message
3549                 << "Comparing images:\n"
3550                 << "\tallowed deviation in pixel positions = 1\n"
3551                 << "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n"
3552                 << "\tnumber of invalid pixels = " << numFailingPixels
3553                 << TestLog::EndMessage;
3554
3555         if (numFailingPixels > maxAllowedInvalidPixels)
3556         {
3557                 log << TestLog::Message
3558                         << "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")"
3559                         << TestLog::EndMessage
3560                         << TestLog::ImageSet(imageSetName, imageSetDesc)
3561                         << TestLog::Image("Result",             "Result",               result)
3562                         << TestLog::Image("Reference",  "Reference",    reference)
3563                         << TestLog::Image("ErrorMask",  "Error mask",   errorMask)
3564                         << TestLog::EndImageSet;
3565
3566                 return false;
3567         }
3568         else
3569         {
3570                 log << TestLog::ImageSet(imageSetName, imageSetDesc)
3571                         << TestLog::Image("Result", "Result", result)
3572                         << TestLog::EndImageSet;
3573
3574                 return true;
3575         }
3576 }
3577
3578 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)
3579 {
3580         DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3581
3582         const tcu::IVec4                                green                                           (0, 255, 0, 255);
3583         const tcu::IVec4                                red                                                     (255, 0, 0, 255);
3584         const int                                               width                                           = reference.getWidth();
3585         const int                                               height                                          = reference.getHeight();
3586         tcu::TextureLevel                               errorMask                                       (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height);
3587         const tcu::PixelBufferAccess    errorAccess                                     = errorMask.getAccess();
3588         int                                                             numFailingPixels                        = 0;
3589
3590         // clear errormask edges which would otherwise be transparent
3591
3592         tcu::clear(tcu::getSubregion(errorAccess, 0,                    0,                      width,  1),                     green);
3593         tcu::clear(tcu::getSubregion(errorAccess, 0,                    height-1,       width,  1),                     green);
3594         tcu::clear(tcu::getSubregion(errorAccess, 0,                    0,                      1,              height),        green);
3595         tcu::clear(tcu::getSubregion(errorAccess, width-1,              0,                      1,              height),        green);
3596
3597         // skip edge pixels since coverage on edge cannot be verified
3598
3599         for (int y = 1; y < height - 1; ++y)
3600         for (int x = 1; x < width - 1; ++x)
3601         {
3602                 const tcu::RGBA refPixel                        = reference.getPixel(x, y);
3603                 const tcu::RGBA screenPixel                     = result.getPixel(x, y);
3604                 const bool              directMatch                     = colorsEqual(refPixel, screenPixel, compareThreshold);
3605                 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.)
3606                 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.)
3607
3608                 if (isOkScreenPixel && isOkReferencePixel)
3609                 {
3610                         // pixel valid, write greenish pixels to make the result image easier to read
3611                         const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3612                         errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3613                 }
3614                 else if (!pixelNearLineIntersection(x, y, reference) &&
3615                                  !pixelNearLineIntersection(x, y, result))
3616                 {
3617                         // non-intersection pixel values must be within threshold of the reference values
3618                         errorAccess.setPixel(red, x, y);
3619                         ++numFailingPixels;
3620                 }
3621                 else
3622                 {
3623                         // pixel is near a line intersection
3624                         // we are on/near an edge, verify only coverage (coverage == not background colored)
3625                         const bool      referenceCoverage               = !isBlack(refPixel);
3626                         const bool      screenCoverage                  = !isBlack(screenPixel);
3627                         const bool      isOkScreenCoverage              = pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage);   // Check screen pixels against reference pixel
3628                         const bool      isOkReferenceCoverage   = pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage);   // Check reference pixel against screen pixel
3629
3630                         if (isOkScreenCoverage && isOkReferenceCoverage)
3631                         {
3632                                 // pixel valid, write greenish pixels to make the result image easier to read
3633                                 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3634                                 errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3635                         }
3636                         else
3637                         {
3638                                 // coverage does not match
3639                                 errorAccess.setPixel(red, x, y);
3640                                 ++numFailingPixels;
3641                         }
3642                 }
3643         }
3644
3645         log     << TestLog::Message
3646                 << "Comparing images:\n"
3647                 << "\tallowed deviation in pixel positions = 1\n"
3648                 << "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n"
3649                 << "\tnumber of invalid pixels = " << numFailingPixels
3650                 << TestLog::EndMessage;
3651
3652         if (numFailingPixels > maxAllowedInvalidPixels)
3653         {
3654                 log << TestLog::Message
3655                         << "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")"
3656                         << TestLog::EndMessage
3657                         << TestLog::ImageSet(imageSetName, imageSetDesc)
3658                         << TestLog::Image("Result",             "Result",               result)
3659                         << TestLog::Image("Reference",  "Reference",    reference)
3660                         << TestLog::Image("ErrorMask",  "Error mask",   errorMask)
3661                         << TestLog::EndImageSet;
3662
3663                 return false;
3664         }
3665         else
3666         {
3667                 log << TestLog::ImageSet(imageSetName, imageSetDesc)
3668                         << TestLog::Image("Result", "Result", result)
3669                         << TestLog::EndImageSet;
3670
3671                 return true;
3672         }
3673 }
3674
3675 bool DrawTest::compare (gls::DrawTestSpec::Primitive primitiveType)
3676 {
3677         const tcu::Surface&     ref             = m_rrArrayPack->getSurface();
3678         const tcu::Surface&     screen  = m_glArrayPack->getSurface();
3679
3680         if (m_renderCtx.getRenderTarget().getNumSamples() > 1)
3681         {
3682                 // \todo [mika] Improve compare when using multisampling
3683                 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;
3684                 return tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", ref.getAccess(), screen.getAccess(), 0.3f, tcu::COMPARE_LOG_RESULT);
3685         }
3686         else
3687         {
3688                 const PrimitiveClass    primitiveClass                                                  = getDrawPrimitiveClass(primitiveType);
3689                 const int                               maxAllowedInvalidPixelsWithPoints               = 0;    //!< points are unlikely to have overlapping fragments
3690                 const int                               maxAllowedInvalidPixelsWithLines                = 5;    //!< line are allowed to have a few bad pixels
3691                 const int                               maxAllowedInvalidPixelsWithTriangles    = 10;
3692
3693                 switch (primitiveClass)
3694                 {
3695                         case PRIMITIVECLASS_POINT:
3696                         {
3697                                 // Point are extremely unlikely to have overlapping regions, don't allow any no extra / missing pixels
3698                                 return tcu::intThresholdPositionDeviationErrorThresholdCompare(m_testCtx.getLog(),
3699                                                                                                                                                            "CompareResult",
3700                                                                                                                                                            "Result of rendering",
3701                                                                                                                                                            ref.getAccess(),
3702                                                                                                                                                            screen.getAccess(),
3703                                                                                                                                                            tcu::UVec4(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue, 256),
3704                                                                                                                                                            tcu::IVec3(1, 1, 0),                                 //!< 3x3 search kernel
3705                                                                                                                                                            true,                                                                //!< relax comparison on the image boundary
3706                                                                                                                                                            maxAllowedInvalidPixelsWithPoints,   //!< error threshold
3707                                                                                                                                                            tcu::COMPARE_LOG_RESULT);
3708                         }
3709
3710                         case PRIMITIVECLASS_LINE:
3711                         {
3712                                 // Lines can potentially have a large number of overlapping pixels. Pixel comparison may potentially produce
3713                                 // false negatives in such pixels if for example the pixel in question is overdrawn by another line in the
3714                                 // reference image but not in the resultin image. Relax comparison near line intersection points (areas) and
3715                                 // compare only coverage, not color, in such pixels
3716                                 return intersectionRelaxedLineImageCompare(m_testCtx.getLog(),
3717                                                                                                                    "CompareResult",
3718                                                                                                                    "Result of rendering",
3719                                                                                                                    ref,
3720                                                                                                                    screen,
3721                                                                                                                    tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue),
3722                                                                                                                    maxAllowedInvalidPixelsWithLines);
3723                         }
3724
3725                         case PRIMITIVECLASS_TRIANGLE:
3726                         {
3727                                 // Triangles are likely to partially or fully overlap. Pixel difference comparison is fragile in pixels
3728                                 // where there could be potential overlapping since the  pixels might be covered by one triangle in the
3729                                 // reference image and by the other in the result image. Relax comparsion near primitive edges and
3730                                 // compare only coverage, not color, in such pixels.
3731                                 const tcu::IVec3        renderTargetThreshold                                   = m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold().toIVec().xyz();
3732
3733                                 return edgeRelaxedImageCompare(m_testCtx.getLog(),
3734                                                                                            "CompareResult",
3735                                                                                            "Result of rendering",
3736                                                                                            ref,
3737                                                                                            screen,
3738                                                                                            tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue),
3739                                                                                            renderTargetThreshold,
3740                                                                                            maxAllowedInvalidPixelsWithTriangles);
3741                         }
3742
3743                         default:
3744                                 DE_ASSERT(false);
3745                                 return false;
3746                 }
3747         }
3748 }
3749
3750 float DrawTest::getCoordScale (const DrawTestSpec& spec) const
3751 {
3752         float maxValue = 1.0f;
3753
3754         for (int arrayNdx = 0; arrayNdx < (int)spec.attribs.size(); arrayNdx++)
3755         {
3756                 DrawTestSpec::AttributeSpec attribSpec          = spec.attribs[arrayNdx];
3757                 const bool                                      isPositionAttr  = (arrayNdx == 0) || (attribSpec.additionalPositionAttribute);
3758                 float                                           attrMaxValue    = 0;
3759
3760                 if (!isPositionAttr)
3761                         continue;
3762
3763                 if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
3764                 {
3765                         if (attribSpec.normalize)
3766                                 attrMaxValue += 1.0f;
3767                         else
3768                                 attrMaxValue += 1024.0f;
3769                 }
3770                 else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
3771                 {
3772                         if (attribSpec.normalize)
3773                                 attrMaxValue += 1.0f;
3774                         else
3775                                 attrMaxValue += 512.0f;
3776                 }
3777                 else
3778                 {
3779                         const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat();
3780
3781                         attrMaxValue += (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType)) ? (1.0f) : (max * 1.1f);
3782                 }
3783
3784                 if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4
3785                         || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4
3786                         || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4)
3787                                 attrMaxValue *= 2;
3788
3789                 maxValue += attrMaxValue;
3790         }
3791
3792         return 1.0f / maxValue;
3793 }
3794
3795 float DrawTest::getColorScale (const DrawTestSpec& spec) const
3796 {
3797         float colorScale = 1.0f;
3798
3799         for (int arrayNdx = 1; arrayNdx < (int)spec.attribs.size(); arrayNdx++)
3800         {
3801                 DrawTestSpec::AttributeSpec attribSpec          = spec.attribs[arrayNdx];
3802                 const bool                                      isPositionAttr  = (arrayNdx == 0) || (attribSpec.additionalPositionAttribute);
3803
3804                 if (isPositionAttr)
3805                         continue;
3806
3807                 if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
3808                 {
3809                         if (!attribSpec.normalize)
3810                                 colorScale *= 1.0f / 1024.0f;
3811                 }
3812                 else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
3813                 {
3814                         if (!attribSpec.normalize)
3815                                 colorScale *= 1.0f / 512.0f;
3816                 }
3817                 else
3818                 {
3819                         const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat();
3820
3821                         colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max)));
3822                         if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4 ||
3823                                 attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4 ||
3824                                 attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4)
3825                                 colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max)));
3826                 }
3827         }
3828
3829         return colorScale;
3830 }
3831
3832 } // gls
3833 } // deqp