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