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