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