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