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