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