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