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