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