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 Vertex array and buffer tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "glsVertexArrayTests.hpp"
25
26 #include "deRandom.h"
27
28 #include "tcuTestLog.hpp"
29 #include "tcuPixelFormat.hpp"
30 #include "tcuRGBA.hpp"
31 #include "tcuSurface.hpp"
32 #include "tcuVector.hpp"
33 #include "tcuTestLog.hpp"
34 #include "tcuRenderTarget.hpp"
35 #include "tcuStringTemplate.hpp"
36 #include "tcuImageCompare.hpp"
37
38 #include "gluPixelTransfer.hpp"
39 #include "gluCallLogWrapper.hpp"
40
41 #include "sglrContext.hpp"
42 #include "sglrReferenceContext.hpp"
43 #include "sglrGLContext.hpp"
44
45 #include "deMath.h"
46 #include "deStringUtil.hpp"
47 #include "deArrayUtil.hpp"
48
49 #include <cstring>
50 #include <cmath>
51 #include <vector>
52 #include <sstream>
53 #include <limits>
54 #include <algorithm>
55
56 #include "glwDefs.hpp"
57 #include "glwEnums.hpp"
58
59 namespace deqp
60 {
61 namespace gls
62 {
63
64 using tcu::TestLog;
65 using namespace glw; // GL types
66
targetToString(Target target)67 std::string Array::targetToString(Target target)
68 {
69 static const char* targets[] =
70 {
71 "element_array", // TARGET_ELEMENT_ARRAY = 0,
72 "array" // TARGET_ARRAY,
73 };
74
75 return de::getSizedArrayElement<Array::TARGET_LAST>(targets, (int)target);
76 }
77
inputTypeToString(InputType type)78 std::string Array::inputTypeToString(InputType type)
79 {
80 static const char* types[] =
81 {
82 "float", // INPUTTYPE_FLOAT = 0,
83 "fixed", // INPUTTYPE_FIXED,
84 "double", // INPUTTYPE_DOUBLE
85
86 "byte", // INPUTTYPE_BYTE,
87 "short", // INPUTTYPE_SHORT,
88
89 "unsigned_byte", // INPUTTYPE_UNSIGNED_BYTE,
90 "unsigned_short", // INPUTTYPE_UNSIGNED_SHORT,
91
92 "int", // INPUTTYPE_INT,
93 "unsigned_int", // INPUTTYPE_UNSIGNED_INT,
94 "half", // INPUTTYPE_HALF,
95 "usigned_int2_10_10_10", // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
96 "int2_10_10_10" // INPUTTYPE_INT_2_10_10_10,
97 };
98
99 return de::getSizedArrayElement<Array::INPUTTYPE_LAST>(types, (int)type);
100 }
101
outputTypeToString(OutputType type)102 std::string Array::outputTypeToString(OutputType type)
103 {
104 static const char* types[] =
105 {
106 "float", // OUTPUTTYPE_FLOAT = 0,
107 "vec2", // OUTPUTTYPE_VEC2,
108 "vec3", // OUTPUTTYPE_VEC3,
109 "vec4", // OUTPUTTYPE_VEC4,
110
111 "int", // OUTPUTTYPE_INT,
112 "uint", // OUTPUTTYPE_UINT,
113
114 "ivec2", // OUTPUTTYPE_IVEC2,
115 "ivec3", // OUTPUTTYPE_IVEC3,
116 "ivec4", // OUTPUTTYPE_IVEC4,
117
118 "uvec2", // OUTPUTTYPE_UVEC2,
119 "uvec3", // OUTPUTTYPE_UVEC3,
120 "uvec4", // OUTPUTTYPE_UVEC4,
121 };
122
123 return de::getSizedArrayElement<Array::OUTPUTTYPE_LAST>(types, (int)type);
124 }
125
usageTypeToString(Usage usage)126 std::string Array::usageTypeToString(Usage usage)
127 {
128 static const char* usages[] =
129 {
130 "dynamic_draw", // USAGE_DYNAMIC_DRAW = 0,
131 "static_draw", // USAGE_STATIC_DRAW,
132 "stream_draw", // USAGE_STREAM_DRAW,
133
134 "stream_read", // USAGE_STREAM_READ,
135 "stream_copy", // USAGE_STREAM_COPY,
136
137 "static_read", // USAGE_STATIC_READ,
138 "static_copy", // USAGE_STATIC_COPY,
139
140 "dynamic_read", // USAGE_DYNAMIC_READ,
141 "dynamic_copy", // USAGE_DYNAMIC_COPY,
142 };
143
144 return de::getSizedArrayElement<Array::USAGE_LAST>(usages, (int)usage);
145 }
146
storageToString(Storage storage)147 std::string Array::storageToString (Storage storage)
148 {
149 static const char* storages[] =
150 {
151 "user_ptr", // STORAGE_USER = 0,
152 "buffer" // STORAGE_BUFFER,
153 };
154
155 return de::getSizedArrayElement<Array::STORAGE_LAST>(storages, (int)storage);
156 }
157
primitiveToString(Primitive primitive)158 std::string Array::primitiveToString (Primitive primitive)
159 {
160 static const char* primitives[] =
161 {
162 "points", // PRIMITIVE_POINTS ,
163 "triangles", // PRIMITIVE_TRIANGLES,
164 "triangle_fan", // PRIMITIVE_TRIANGLE_FAN,
165 "triangle_strip" // PRIMITIVE_TRIANGLE_STRIP,
166 };
167
168 return de::getSizedArrayElement<Array::PRIMITIVE_LAST>(primitives, (int)primitive);
169 }
170
inputTypeSize(InputType type)171 int Array::inputTypeSize (InputType type)
172 {
173 static const int size[] =
174 {
175 (int)sizeof(float), // INPUTTYPE_FLOAT = 0,
176 (int)sizeof(deInt32), // INPUTTYPE_FIXED,
177 (int)sizeof(double), // INPUTTYPE_DOUBLE
178
179 (int)sizeof(deInt8), // INPUTTYPE_BYTE,
180 (int)sizeof(deInt16), // INPUTTYPE_SHORT,
181
182 (int)sizeof(deUint8), // INPUTTYPE_UNSIGNED_BYTE,
183 (int)sizeof(deUint16), // INPUTTYPE_UNSIGNED_SHORT,
184
185 (int)sizeof(deInt32), // INPUTTYPE_INT,
186 (int)sizeof(deUint32), // INPUTTYPE_UNSIGNED_INT,
187 (int)sizeof(deFloat16), // INPUTTYPE_HALF,
188 (int)sizeof(deUint32) / 4, // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
189 (int)sizeof(deUint32) / 4 // INPUTTYPE_INT_2_10_10_10,
190 };
191
192 return de::getSizedArrayElement<Array::INPUTTYPE_LAST>(size, (int)type);
193 }
194
inputTypeIsFloatType(Array::InputType type)195 static bool inputTypeIsFloatType (Array::InputType type)
196 {
197 if (type == Array::INPUTTYPE_FLOAT)
198 return true;
199 if (type == Array::INPUTTYPE_FIXED)
200 return true;
201 if (type == Array::INPUTTYPE_DOUBLE)
202 return true;
203 if (type == Array::INPUTTYPE_HALF)
204 return true;
205 return false;
206 }
207
outputTypeIsFloatType(Array::OutputType type)208 static bool outputTypeIsFloatType (Array::OutputType type)
209 {
210 if (type == Array::OUTPUTTYPE_FLOAT
211 || type == Array::OUTPUTTYPE_VEC2
212 || type == Array::OUTPUTTYPE_VEC3
213 || type == Array::OUTPUTTYPE_VEC4)
214 return true;
215
216 return false;
217 }
218
219 template<class T>
220 inline T getRandom (deRandom& rnd, T min, T max);
221
222 template<>
getRandom(deRandom & rnd,GLValue::Float min,GLValue::Float max)223 inline GLValue::Float getRandom (deRandom& rnd, GLValue::Float min, GLValue::Float max)
224 {
225 if (max < min)
226 return min;
227
228 return GLValue::Float::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>()));
229 }
230
231 template<>
getRandom(deRandom & rnd,GLValue::Short min,GLValue::Short max)232 inline GLValue::Short getRandom (deRandom& rnd, GLValue::Short min, GLValue::Short max)
233 {
234 if (max < min)
235 return min;
236
237 return GLValue::Short::create((min == max ? min : (deInt16)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
238 }
239
240 template<>
getRandom(deRandom & rnd,GLValue::Ushort min,GLValue::Ushort max)241 inline GLValue::Ushort getRandom (deRandom& rnd, GLValue::Ushort min, GLValue::Ushort max)
242 {
243 if (max < min)
244 return min;
245
246 return GLValue::Ushort::create((min == max ? min : (deUint16)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
247 }
248
249 template<>
getRandom(deRandom & rnd,GLValue::Byte min,GLValue::Byte max)250 inline GLValue::Byte getRandom (deRandom& rnd, GLValue::Byte min, GLValue::Byte max)
251 {
252 if (max < min)
253 return min;
254
255 return GLValue::Byte::create((min == max ? min : (deInt8)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
256 }
257
258 template<>
getRandom(deRandom & rnd,GLValue::Ubyte min,GLValue::Ubyte max)259 inline GLValue::Ubyte getRandom (deRandom& rnd, GLValue::Ubyte min, GLValue::Ubyte max)
260 {
261 if (max < min)
262 return min;
263
264 return GLValue::Ubyte::create((min == max ? min : (deUint8)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
265 }
266
267 template<>
getRandom(deRandom & rnd,GLValue::Fixed min,GLValue::Fixed max)268 inline GLValue::Fixed getRandom (deRandom& rnd, GLValue::Fixed min, GLValue::Fixed max)
269 {
270 if (max < min)
271 return min;
272
273 return GLValue::Fixed::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
274 }
275
276 template<>
getRandom(deRandom & rnd,GLValue::Half min,GLValue::Half max)277 inline GLValue::Half getRandom (deRandom& rnd, GLValue::Half min, GLValue::Half max)
278 {
279 if (max < min)
280 return min;
281
282 float fMax = max.to<float>();
283 float fMin = min.to<float>();
284 GLValue::Half h = GLValue::Half::create(fMin + deRandom_getFloat(&rnd) * (fMax - fMin));
285 return h;
286 }
287
288 template<>
getRandom(deRandom & rnd,GLValue::Int min,GLValue::Int max)289 inline GLValue::Int getRandom (deRandom& rnd, GLValue::Int min, GLValue::Int max)
290 {
291 if (max < min)
292 return min;
293
294 return GLValue::Int::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
295 }
296
297 template<>
getRandom(deRandom & rnd,GLValue::Uint min,GLValue::Uint max)298 inline GLValue::Uint getRandom (deRandom& rnd, GLValue::Uint min, GLValue::Uint max)
299 {
300 if (max < min)
301 return min;
302
303 return GLValue::Uint::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
304 }
305
306 template<>
getRandom(deRandom & rnd,GLValue::Double min,GLValue::Double max)307 inline GLValue::Double getRandom (deRandom& rnd, GLValue::Double min, GLValue::Double max)
308 {
309 if (max < min)
310 return min;
311
312 return GLValue::Double::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>()));
313 }
314
315 // Minimum difference required between coordinates
316 template<class T>
317 inline T minValue (void);
318
319 template<>
minValue(void)320 inline GLValue::Float minValue (void)
321 {
322 return GLValue::Float::create(4 * 1.0f);
323 }
324
325 template<>
minValue(void)326 inline GLValue::Short minValue (void)
327 {
328 return GLValue::Short::create(4 * 256);
329 }
330
331 template<>
minValue(void)332 inline GLValue::Ushort minValue (void)
333 {
334 return GLValue::Ushort::create(4 * 256);
335 }
336
337 template<>
minValue(void)338 inline GLValue::Byte minValue (void)
339 {
340 return GLValue::Byte::create(4 * 1);
341 }
342
343 template<>
minValue(void)344 inline GLValue::Ubyte minValue (void)
345 {
346 return GLValue::Ubyte::create(4 * 2);
347 }
348
349 template<>
minValue(void)350 inline GLValue::Fixed minValue (void)
351 {
352 return GLValue::Fixed::create(4 * 512);
353 }
354
355 template<>
minValue(void)356 inline GLValue::Int minValue (void)
357 {
358 return GLValue::Int::create(4 * 16777216);
359 }
360
361 template<>
minValue(void)362 inline GLValue::Uint minValue (void)
363 {
364 return GLValue::Uint::create(4 * 16777216);
365 }
366
367 template<>
minValue(void)368 inline GLValue::Half minValue (void)
369 {
370 return GLValue::Half::create(4 * 1.0f);
371 }
372
373 template<>
minValue(void)374 inline GLValue::Double minValue (void)
375 {
376 return GLValue::Double::create(4 * 1.0f);
377 }
378
379 template<class T>
380 inline T abs (T val);
381
382 template<>
abs(GLValue::Fixed val)383 inline GLValue::Fixed abs (GLValue::Fixed val)
384 {
385 return GLValue::Fixed::create(0x7FFFu & val.getValue());
386 }
387
388 template<>
abs(GLValue::Ubyte val)389 inline GLValue::Ubyte abs (GLValue::Ubyte val)
390 {
391 return val;
392 }
393
394 template<>
abs(GLValue::Byte val)395 inline GLValue::Byte abs (GLValue::Byte val)
396 {
397 return GLValue::Byte::create(0x7Fu & val.getValue());
398 }
399
400 template<>
abs(GLValue::Ushort val)401 inline GLValue::Ushort abs (GLValue::Ushort val)
402 {
403 return val;
404 }
405
406 template<>
abs(GLValue::Short val)407 inline GLValue::Short abs (GLValue::Short val)
408 {
409 return GLValue::Short::create(0x7FFFu & val.getValue());
410 }
411
412 template<>
abs(GLValue::Float val)413 inline GLValue::Float abs (GLValue::Float val)
414 {
415 return GLValue::Float::create(std::fabs(val.to<float>()));
416 }
417
418 template<>
abs(GLValue::Uint val)419 inline GLValue::Uint abs (GLValue::Uint val)
420 {
421 return val;
422 }
423
424 template<>
abs(GLValue::Int val)425 inline GLValue::Int abs (GLValue::Int val)
426 {
427 return GLValue::Int::create(0x7FFFFFFFu & val.getValue());
428 }
429
430 template<>
abs(GLValue::Half val)431 inline GLValue::Half abs (GLValue::Half val)
432 {
433 return GLValue::Half::create(std::fabs(val.to<float>()));
434 }
435
436 template<>
abs(GLValue::Double val)437 inline GLValue::Double abs (GLValue::Double val)
438 {
439 return GLValue::Double::create(std::fabs(val.to<float>()));
440 }
441
442 template<class T>
alignmentSafeAssignment(char * dst,T val)443 static inline void alignmentSafeAssignment (char* dst, T val)
444 {
445 std::memcpy(dst, &val, sizeof(T));
446 }
447
ContextArray(Storage storage,sglr::Context & context)448 ContextArray::ContextArray (Storage storage, sglr::Context& context)
449 : m_storage (storage)
450 , m_ctx (context)
451 , m_glBuffer (0)
452 , m_bound (false)
453 , m_attribNdx (0)
454 , m_size (0)
455 , m_data (DE_NULL)
456 , m_componentCount (1)
457 , m_target (Array::TARGET_ARRAY)
458 , m_inputType (Array::INPUTTYPE_FLOAT)
459 , m_outputType (Array::OUTPUTTYPE_VEC4)
460 , m_normalize (false)
461 , m_stride (0)
462 , m_offset (0)
463 {
464 if (m_storage == STORAGE_BUFFER)
465 {
466 m_ctx.genBuffers(1, &m_glBuffer);
467 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glGenBuffers()");
468 }
469 }
470
~ContextArray(void)471 ContextArray::~ContextArray (void)
472 {
473 if (m_storage == STORAGE_BUFFER)
474 {
475 m_ctx.deleteBuffers(1, &m_glBuffer);
476 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDeleteBuffers()");
477 }
478 else if (m_storage == STORAGE_USER)
479 delete[] m_data;
480 else
481 DE_ASSERT(false);
482 }
483
getArray(int i)484 Array* ContextArrayPack::getArray (int i)
485 {
486 return m_arrays.at(i);
487 }
488
data(Target target,int size,const char * ptr,Usage usage)489 void ContextArray::data (Target target, int size, const char* ptr, Usage usage)
490 {
491 m_size = size;
492 m_target = target;
493
494 if (m_storage == STORAGE_BUFFER)
495 {
496 m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
497 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
498
499 m_ctx.bufferData(targetToGL(target), size, ptr, usageToGL(usage));
500 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferData()");
501 }
502 else if (m_storage == STORAGE_USER)
503 {
504 if (m_data)
505 delete[] m_data;
506
507 m_data = new char[size];
508 std::memcpy(m_data, ptr, size);
509 }
510 else
511 DE_ASSERT(false);
512 }
513
subdata(Target target,int offset,int size,const char * ptr)514 void ContextArray::subdata (Target target, int offset, int size, const char* ptr)
515 {
516 m_target = target;
517
518 if (m_storage == STORAGE_BUFFER)
519 {
520 m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
521 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
522
523 m_ctx.bufferSubData(targetToGL(target), offset, size, ptr);
524 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferSubData()");
525 }
526 else if (m_storage == STORAGE_USER)
527 std::memcpy(m_data + offset, ptr, size);
528 else
529 DE_ASSERT(false);
530 }
531
bind(int attribNdx,int offset,int size,InputType inputType,OutputType outType,bool normalized,int stride)532 void ContextArray::bind (int attribNdx, int offset, int size, InputType inputType, OutputType outType, bool normalized, int stride)
533 {
534 m_attribNdx = attribNdx;
535 m_bound = true;
536 m_componentCount = size;
537 m_inputType = inputType;
538 m_outputType = outType;
539 m_normalize = normalized;
540 m_stride = stride;
541 m_offset = offset;
542 }
543
bindIndexArray(Array::Target target)544 void ContextArray::bindIndexArray (Array::Target target)
545 {
546 if (m_storage == STORAGE_USER)
547 {
548 }
549 else if (m_storage == STORAGE_BUFFER)
550 {
551 m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
552 }
553 }
554
glBind(deUint32 loc)555 void ContextArray::glBind (deUint32 loc)
556 {
557 if (m_storage == STORAGE_BUFFER)
558 {
559 m_ctx.bindBuffer(targetToGL(m_target), m_glBuffer);
560 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
561
562 if (!inputTypeIsFloatType(m_inputType))
563 {
564 // Input is not float type
565
566 if (outputTypeIsFloatType(m_outputType))
567 {
568 // Output type is float type
569 m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, (GLvoid*)((GLintptr)m_offset));
570 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
571 }
572 else
573 {
574 // Output type is int type
575 m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, (GLvoid*)((GLintptr)m_offset));
576 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
577 }
578 }
579 else
580 {
581 // Input type is float type
582
583 // Output type must be float type
584 DE_ASSERT(m_outputType == OUTPUTTYPE_FLOAT || m_outputType == OUTPUTTYPE_VEC2 || m_outputType == OUTPUTTYPE_VEC3 || m_outputType == OUTPUTTYPE_VEC4);
585
586 m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, (GLvoid*)((GLintptr)m_offset));
587 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
588 }
589
590 m_ctx.bindBuffer(targetToGL(m_target), 0);
591 }
592 else if (m_storage == STORAGE_USER)
593 {
594 m_ctx.bindBuffer(targetToGL(m_target), 0);
595 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
596
597 if (!inputTypeIsFloatType(m_inputType))
598 {
599 // Input is not float type
600
601 if (outputTypeIsFloatType(m_outputType))
602 {
603 // Output type is float type
604 m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, m_data + m_offset);
605 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
606 }
607 else
608 {
609 // Output type is int type
610 m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, m_data + m_offset);
611 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
612 }
613 }
614 else
615 {
616 // Input type is float type
617
618 // Output type must be float type
619 DE_ASSERT(m_outputType == OUTPUTTYPE_FLOAT || m_outputType == OUTPUTTYPE_VEC2 || m_outputType == OUTPUTTYPE_VEC3 || m_outputType == OUTPUTTYPE_VEC4);
620
621 m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, m_data + m_offset);
622 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
623 }
624 }
625 else
626 DE_ASSERT(false);
627 }
628
targetToGL(Array::Target target)629 GLenum ContextArray::targetToGL (Array::Target target)
630 {
631 static const GLenum targets[] =
632 {
633 GL_ELEMENT_ARRAY_BUFFER, // TARGET_ELEMENT_ARRAY = 0,
634 GL_ARRAY_BUFFER // TARGET_ARRAY,
635 };
636
637 return de::getSizedArrayElement<Array::TARGET_LAST>(targets, (int)target);
638 }
639
usageToGL(Array::Usage usage)640 GLenum ContextArray::usageToGL (Array::Usage usage)
641 {
642 static const GLenum usages[] =
643 {
644 GL_DYNAMIC_DRAW, // USAGE_DYNAMIC_DRAW = 0,
645 GL_STATIC_DRAW, // USAGE_STATIC_DRAW,
646 GL_STREAM_DRAW, // USAGE_STREAM_DRAW,
647
648 GL_STREAM_READ, // USAGE_STREAM_READ,
649 GL_STREAM_COPY, // USAGE_STREAM_COPY,
650
651 GL_STATIC_READ, // USAGE_STATIC_READ,
652 GL_STATIC_COPY, // USAGE_STATIC_COPY,
653
654 GL_DYNAMIC_READ, // USAGE_DYNAMIC_READ,
655 GL_DYNAMIC_COPY // USAGE_DYNAMIC_COPY,
656 };
657
658 return de::getSizedArrayElement<Array::USAGE_LAST>(usages, (int)usage);
659 }
660
inputTypeToGL(Array::InputType type)661 GLenum ContextArray::inputTypeToGL (Array::InputType type)
662 {
663 static const GLenum types[] =
664 {
665 GL_FLOAT, // INPUTTYPE_FLOAT = 0,
666 GL_FIXED, // INPUTTYPE_FIXED,
667 GL_DOUBLE, // INPUTTYPE_DOUBLE
668 GL_BYTE, // INPUTTYPE_BYTE,
669 GL_SHORT, // INPUTTYPE_SHORT,
670 GL_UNSIGNED_BYTE, // INPUTTYPE_UNSIGNED_BYTE,
671 GL_UNSIGNED_SHORT, // INPUTTYPE_UNSIGNED_SHORT,
672
673 GL_INT, // INPUTTYPE_INT,
674 GL_UNSIGNED_INT, // INPUTTYPE_UNSIGNED_INT,
675 GL_HALF_FLOAT, // INPUTTYPE_HALF,
676 GL_UNSIGNED_INT_2_10_10_10_REV, // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
677 GL_INT_2_10_10_10_REV // INPUTTYPE_INT_2_10_10_10,
678 };
679
680 return de::getSizedArrayElement<Array::INPUTTYPE_LAST>(types, (int)type);
681 }
682
outputTypeToGLType(Array::OutputType type)683 std::string ContextArray::outputTypeToGLType (Array::OutputType type)
684 {
685 static const char* types[] =
686 {
687 "float", // OUTPUTTYPE_FLOAT = 0,
688 "vec2", // OUTPUTTYPE_VEC2,
689 "vec3", // OUTPUTTYPE_VEC3,
690 "vec4", // OUTPUTTYPE_VEC4,
691
692 "int", // OUTPUTTYPE_INT,
693 "uint", // OUTPUTTYPE_UINT,
694
695 "ivec2", // OUTPUTTYPE_IVEC2,
696 "ivec3", // OUTPUTTYPE_IVEC3,
697 "ivec4", // OUTPUTTYPE_IVEC4,
698
699 "uvec2", // OUTPUTTYPE_UVEC2,
700 "uvec3", // OUTPUTTYPE_UVEC3,
701 "uvec4", // OUTPUTTYPE_UVEC4,
702 };
703
704 return de::getSizedArrayElement<Array::OUTPUTTYPE_LAST>(types, (int)type);
705 }
706
primitiveToGL(Array::Primitive primitive)707 GLenum ContextArray::primitiveToGL (Array::Primitive primitive)
708 {
709 static const GLenum primitives[] =
710 {
711 GL_POINTS, // PRIMITIVE_POINTS = 0,
712 GL_TRIANGLES, // PRIMITIVE_TRIANGLES,
713 GL_TRIANGLE_FAN, // PRIMITIVE_TRIANGLE_FAN,
714 GL_TRIANGLE_STRIP // PRIMITIVE_TRIANGLE_STRIP,
715 };
716
717 return de::getSizedArrayElement<Array::PRIMITIVE_LAST>(primitives, (int)primitive);
718 }
719
ContextArrayPack(glu::RenderContext & renderCtx,sglr::Context & drawContext)720 ContextArrayPack::ContextArrayPack (glu::RenderContext& renderCtx, sglr::Context& drawContext)
721 : m_renderCtx (renderCtx)
722 , m_ctx (drawContext)
723 , m_program (DE_NULL)
724 , m_screen (std::min(512, renderCtx.getRenderTarget().getWidth()), std::min(512, renderCtx.getRenderTarget().getHeight()))
725 {
726 }
727
~ContextArrayPack(void)728 ContextArrayPack::~ContextArrayPack (void)
729 {
730 for (std::vector<ContextArray*>::iterator itr = m_arrays.begin(); itr != m_arrays.end(); itr++)
731 delete *itr;
732
733 delete m_program;
734 }
735
getArrayCount(void)736 int ContextArrayPack::getArrayCount (void)
737 {
738 return (int)m_arrays.size();
739 }
740
newArray(Array::Storage storage)741 void ContextArrayPack::newArray (Array::Storage storage)
742 {
743 m_arrays.push_back(new ContextArray(storage, m_ctx));
744 }
745
746 class ContextShaderProgram : public sglr::ShaderProgram
747 {
748 public:
749 ContextShaderProgram (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
750
751 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
752 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
753
754 private:
755 static std::string genVertexSource (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
756 static std::string genFragmentSource (const glu::RenderContext& ctx);
757 static rr::GenericVecType mapOutputType (const Array::OutputType& type);
758 static int getComponentCount (const Array::OutputType& type);
759
760 static sglr::pdec::ShaderProgramDeclaration createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
761
762 std::vector<int> m_componentCount;
763 std::vector<rr::GenericVecType> m_attrType;
764 };
765
ContextShaderProgram(const glu::RenderContext & ctx,const std::vector<ContextArray * > & arrays)766 ContextShaderProgram::ContextShaderProgram (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
767 : sglr::ShaderProgram (createProgramDeclaration(ctx, arrays))
768 , m_componentCount (arrays.size())
769 , m_attrType (arrays.size())
770 {
771 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
772 {
773 m_componentCount[arrayNdx] = getComponentCount(arrays[arrayNdx]->getOutputType());
774 m_attrType[arrayNdx] = mapOutputType(arrays[arrayNdx]->getOutputType());
775 }
776 }
777
778 template <typename T>
calcShaderColorCoord(tcu::Vec2 & coord,tcu::Vec3 & color,const tcu::Vector<T,4> & attribValue,bool isCoordinate,int numComponents)779 void calcShaderColorCoord (tcu::Vec2& coord, tcu::Vec3& color, const tcu::Vector<T, 4>& attribValue, bool isCoordinate, int numComponents)
780 {
781 if (isCoordinate)
782 switch (numComponents)
783 {
784 case 1: coord = tcu::Vec2((float)attribValue.x(), (float)attribValue.x()); break;
785 case 2: coord = tcu::Vec2((float)attribValue.x(), (float)attribValue.y()); break;
786 case 3: coord = tcu::Vec2((float)attribValue.x() + (float)attribValue.z(), (float)attribValue.y()); break;
787 case 4: coord = tcu::Vec2((float)attribValue.x() + (float)attribValue.z(), (float)attribValue.y() + (float)attribValue.w()); break;
788
789 default:
790 DE_ASSERT(false);
791 }
792 else
793 {
794 switch (numComponents)
795 {
796 case 1:
797 color = color * (float)attribValue.x();
798 break;
799
800 case 2:
801 color.x() = color.x() * (float)attribValue.x();
802 color.y() = color.y() * (float)attribValue.y();
803 break;
804
805 case 3:
806 color.x() = color.x() * (float)attribValue.x();
807 color.y() = color.y() * (float)attribValue.y();
808 color.z() = color.z() * (float)attribValue.z();
809 break;
810
811 case 4:
812 color.x() = color.x() * (float)attribValue.x() * (float)attribValue.w();
813 color.y() = color.y() * (float)attribValue.y() * (float)attribValue.w();
814 color.z() = color.z() * (float)attribValue.z() * (float)attribValue.w();
815 break;
816
817 default:
818 DE_ASSERT(false);
819 }
820 }
821 }
822
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const823 void ContextShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
824 {
825 const float u_coordScale = getUniformByName("u_coordScale").value.f;
826 const float u_colorScale = getUniformByName("u_colorScale").value.f;
827
828 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
829 {
830 const size_t varyingLocColor = 0;
831
832 rr::VertexPacket& packet = *packets[packetNdx];
833
834 // Calc output color
835 tcu::Vec2 coord = tcu::Vec2(1.0, 1.0);
836 tcu::Vec3 color = tcu::Vec3(1.0, 1.0, 1.0);
837
838 for (int attribNdx = 0; attribNdx < (int)m_attrType.size(); attribNdx++)
839 {
840 const int numComponents = m_componentCount[attribNdx];
841
842 switch (m_attrType[attribNdx])
843 {
844 case rr::GENERICVECTYPE_FLOAT: calcShaderColorCoord(coord, color, rr::readVertexAttribFloat(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents); break;
845 case rr::GENERICVECTYPE_INT32: calcShaderColorCoord(coord, color, rr::readVertexAttribInt (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents); break;
846 case rr::GENERICVECTYPE_UINT32: calcShaderColorCoord(coord, color, rr::readVertexAttribUint (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents); break;
847 default:
848 DE_ASSERT(false);
849 }
850 }
851
852 // Transform position
853 {
854 packet.position = tcu::Vec4(u_coordScale * coord.x(), u_coordScale * coord.y(), 1.0f, 1.0f);
855 }
856
857 // Pass color to FS
858 {
859 packet.outputs[varyingLocColor] = tcu::Vec4(u_colorScale * color.x(), u_colorScale * color.y(), u_colorScale * color.z(), 1.0f);
860 }
861 }
862 }
863
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const864 void ContextShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
865 {
866 const size_t varyingLocColor = 0;
867
868 // Triangles are flashaded
869 tcu::Vec4 color = rr::readTriangleVarying<float>(packets[0], context, varyingLocColor, 0);
870
871 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
872 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
873 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
874 }
875
genVertexSource(const glu::RenderContext & ctx,const std::vector<ContextArray * > & arrays)876 std::string ContextShaderProgram::genVertexSource (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
877 {
878 std::stringstream vertexShaderTmpl;
879 std::map<std::string, std::string> params;
880
881 if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_300_ES))
882 {
883 params["VTX_IN"] = "in";
884 params["VTX_OUT"] = "out";
885 params["FRAG_IN"] = "in";
886 params["FRAG_COLOR"] = "dEQP_FragColor";
887 params["VTX_HDR"] = "#version 300 es\n";
888 params["FRAG_HDR"] = "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
889 }
890 else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_100_ES))
891 {
892 params["VTX_IN"] = "attribute";
893 params["VTX_OUT"] = "varying";
894 params["FRAG_IN"] = "varying";
895 params["FRAG_COLOR"] = "gl_FragColor";
896 params["VTX_HDR"] = "";
897 params["FRAG_HDR"] = "";
898 }
899 else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_330))
900 {
901 params["VTX_IN"] = "in";
902 params["VTX_OUT"] = "out";
903 params["FRAG_IN"] = "in";
904 params["FRAG_COLOR"] = "dEQP_FragColor";
905 params["VTX_HDR"] = "#version 330\n";
906 params["FRAG_HDR"] = "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
907 }
908 else
909 DE_ASSERT(DE_FALSE);
910
911 vertexShaderTmpl << "${VTX_HDR}";
912
913 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
914 {
915 vertexShaderTmpl
916 << "${VTX_IN} highp " << ContextArray::outputTypeToGLType(arrays[arrayNdx]->getOutputType()) << " a_" << arrays[arrayNdx]->getAttribNdx() << ";\n";
917 }
918
919 vertexShaderTmpl <<
920 "uniform highp float u_coordScale;\n"
921 "uniform highp float u_colorScale;\n"
922 "${VTX_OUT} mediump vec4 v_color;\n"
923 "void main(void)\n"
924 "{\n"
925 "\tgl_PointSize = 1.0;\n"
926 "\thighp vec2 coord = vec2(1.0, 1.0);\n"
927 "\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n";
928
929 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
930 {
931 if (arrays[arrayNdx]->getAttribNdx() == 0)
932 {
933 switch (arrays[arrayNdx]->getOutputType())
934 {
935 case (Array::OUTPUTTYPE_FLOAT):
936 vertexShaderTmpl <<
937 "\tcoord = vec2(a_0);\n";
938 break;
939
940 case (Array::OUTPUTTYPE_VEC2):
941 vertexShaderTmpl <<
942 "\tcoord = a_0.xy;\n";
943 break;
944
945 case (Array::OUTPUTTYPE_VEC3):
946 vertexShaderTmpl <<
947 "\tcoord = a_0.xy;\n"
948 "\tcoord.x = coord.x + a_0.z;\n";
949 break;
950
951 case (Array::OUTPUTTYPE_VEC4):
952 vertexShaderTmpl <<
953 "\tcoord = a_0.xy;\n"
954 "\tcoord += a_0.zw;\n";
955 break;
956
957 case (Array::OUTPUTTYPE_IVEC2):
958 case (Array::OUTPUTTYPE_UVEC2):
959 vertexShaderTmpl <<
960 "\tcoord = vec2(a_0.xy);\n";
961 break;
962
963 case (Array::OUTPUTTYPE_IVEC3):
964 case (Array::OUTPUTTYPE_UVEC3):
965 vertexShaderTmpl <<
966 "\tcoord = vec2(a_0.xy);\n"
967 "\tcoord.x = coord.x + float(a_0.z);\n";
968 break;
969
970 case (Array::OUTPUTTYPE_IVEC4):
971 case (Array::OUTPUTTYPE_UVEC4):
972 vertexShaderTmpl <<
973 "\tcoord = vec2(a_0.xy);\n"
974 "\tcoord += vec2(a_0.zw);\n";
975 break;
976
977 default:
978 DE_ASSERT(false);
979 break;
980 }
981 continue;
982 }
983
984 switch (arrays[arrayNdx]->getOutputType())
985 {
986 case (Array::OUTPUTTYPE_FLOAT):
987 vertexShaderTmpl <<
988 "\tcolor = color * a_" << arrays[arrayNdx]->getAttribNdx() << ";\n";
989 break;
990
991 case (Array::OUTPUTTYPE_VEC2):
992 vertexShaderTmpl <<
993 "\tcolor.rg = color.rg * a_" << arrays[arrayNdx]->getAttribNdx() << ".xy;\n";
994 break;
995
996 case (Array::OUTPUTTYPE_VEC3):
997 vertexShaderTmpl <<
998 "\tcolor = color.rgb * a_" << arrays[arrayNdx]->getAttribNdx() << ".xyz;\n";
999 break;
1000
1001 case (Array::OUTPUTTYPE_VEC4):
1002 vertexShaderTmpl <<
1003 "\tcolor = color.rgb * a_" << arrays[arrayNdx]->getAttribNdx() << ".xyz * a_" << arrays[arrayNdx]->getAttribNdx() << ".w;\n";
1004 break;
1005
1006 default:
1007 DE_ASSERT(false);
1008 break;
1009 }
1010 }
1011
1012 vertexShaderTmpl <<
1013 "\tv_color = vec4(u_colorScale * color, 1.0);\n"
1014 "\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n"
1015 "}\n";
1016
1017 return tcu::StringTemplate(vertexShaderTmpl.str().c_str()).specialize(params);
1018 }
1019
genFragmentSource(const glu::RenderContext & ctx)1020 std::string ContextShaderProgram::genFragmentSource (const glu::RenderContext& ctx)
1021 {
1022 std::map<std::string, std::string> params;
1023
1024 if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_300_ES))
1025 {
1026 params["VTX_IN"] = "in";
1027 params["VTX_OUT"] = "out";
1028 params["FRAG_IN"] = "in";
1029 params["FRAG_COLOR"] = "dEQP_FragColor";
1030 params["VTX_HDR"] = "#version 300 es\n";
1031 params["FRAG_HDR"] = "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1032 }
1033 else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_100_ES))
1034 {
1035 params["VTX_IN"] = "attribute";
1036 params["VTX_OUT"] = "varying";
1037 params["FRAG_IN"] = "varying";
1038 params["FRAG_COLOR"] = "gl_FragColor";
1039 params["VTX_HDR"] = "";
1040 params["FRAG_HDR"] = "";
1041 }
1042 else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_330))
1043 {
1044 params["VTX_IN"] = "in";
1045 params["VTX_OUT"] = "out";
1046 params["FRAG_IN"] = "in";
1047 params["FRAG_COLOR"] = "dEQP_FragColor";
1048 params["VTX_HDR"] = "#version 330\n";
1049 params["FRAG_HDR"] = "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1050 }
1051 else
1052 DE_ASSERT(DE_FALSE);
1053
1054 static const char* fragmentShaderTmpl =
1055 "${FRAG_HDR}"
1056 "${FRAG_IN} mediump vec4 v_color;\n"
1057 "void main(void)\n"
1058 "{\n"
1059 "\t${FRAG_COLOR} = v_color;\n"
1060 "}\n";
1061
1062 return tcu::StringTemplate(fragmentShaderTmpl).specialize(params);
1063 }
1064
mapOutputType(const Array::OutputType & type)1065 rr::GenericVecType ContextShaderProgram::mapOutputType (const Array::OutputType& type)
1066 {
1067 switch (type)
1068 {
1069 case (Array::OUTPUTTYPE_FLOAT):
1070 case (Array::OUTPUTTYPE_VEC2):
1071 case (Array::OUTPUTTYPE_VEC3):
1072 case (Array::OUTPUTTYPE_VEC4):
1073 return rr::GENERICVECTYPE_FLOAT;
1074
1075 case (Array::OUTPUTTYPE_INT):
1076 case (Array::OUTPUTTYPE_IVEC2):
1077 case (Array::OUTPUTTYPE_IVEC3):
1078 case (Array::OUTPUTTYPE_IVEC4):
1079 return rr::GENERICVECTYPE_INT32;
1080
1081 case (Array::OUTPUTTYPE_UINT):
1082 case (Array::OUTPUTTYPE_UVEC2):
1083 case (Array::OUTPUTTYPE_UVEC3):
1084 case (Array::OUTPUTTYPE_UVEC4):
1085 return rr::GENERICVECTYPE_UINT32;
1086
1087 default:
1088 DE_ASSERT(false);
1089 return rr::GENERICVECTYPE_LAST;
1090 }
1091 }
1092
getComponentCount(const Array::OutputType & type)1093 int ContextShaderProgram::getComponentCount (const Array::OutputType& type)
1094 {
1095 switch (type)
1096 {
1097 case (Array::OUTPUTTYPE_FLOAT):
1098 case (Array::OUTPUTTYPE_INT):
1099 case (Array::OUTPUTTYPE_UINT):
1100 return 1;
1101
1102 case (Array::OUTPUTTYPE_VEC2):
1103 case (Array::OUTPUTTYPE_IVEC2):
1104 case (Array::OUTPUTTYPE_UVEC2):
1105 return 2;
1106
1107 case (Array::OUTPUTTYPE_VEC3):
1108 case (Array::OUTPUTTYPE_IVEC3):
1109 case (Array::OUTPUTTYPE_UVEC3):
1110 return 3;
1111
1112 case (Array::OUTPUTTYPE_VEC4):
1113 case (Array::OUTPUTTYPE_IVEC4):
1114 case (Array::OUTPUTTYPE_UVEC4):
1115 return 4;
1116
1117 default:
1118 DE_ASSERT(false);
1119 return 0;
1120 }
1121 }
1122
createProgramDeclaration(const glu::RenderContext & ctx,const std::vector<ContextArray * > & arrays)1123 sglr::pdec::ShaderProgramDeclaration ContextShaderProgram::createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
1124 {
1125 sglr::pdec::ShaderProgramDeclaration decl;
1126
1127 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1128 decl << sglr::pdec::VertexAttribute(std::string("a_") + de::toString(arrayNdx), mapOutputType(arrays[arrayNdx]->getOutputType()));
1129
1130 decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
1131 decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT);
1132
1133 decl << sglr::pdec::VertexSource(genVertexSource(ctx, arrays));
1134 decl << sglr::pdec::FragmentSource(genFragmentSource(ctx));
1135
1136 decl << sglr::pdec::Uniform("u_coordScale", glu::TYPE_FLOAT);
1137 decl << sglr::pdec::Uniform("u_colorScale", glu::TYPE_FLOAT);
1138
1139 return decl;
1140 }
1141
updateProgram(void)1142 void ContextArrayPack::updateProgram (void)
1143 {
1144 delete m_program;
1145 m_program = new ContextShaderProgram(m_renderCtx, m_arrays);
1146 }
1147
render(Array::Primitive primitive,int firstVertex,int vertexCount,bool useVao,float coordScale,float colorScale)1148 void ContextArrayPack::render (Array::Primitive primitive, int firstVertex, int vertexCount, bool useVao, float coordScale, float colorScale)
1149 {
1150 deUint32 program = 0;
1151 deUint32 vaoId = 0;
1152
1153 updateProgram();
1154
1155 m_ctx.viewport(0, 0, m_screen.getWidth(), m_screen.getHeight());
1156 m_ctx.clearColor(0.0, 0.0, 0.0, 1.0);
1157 m_ctx.clear(GL_COLOR_BUFFER_BIT);
1158
1159 program = m_ctx.createProgram(m_program);
1160
1161 m_ctx.useProgram(program);
1162 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glUseProgram()");
1163
1164 m_ctx.uniform1f(m_ctx.getUniformLocation(program, "u_coordScale"), coordScale);
1165 m_ctx.uniform1f(m_ctx.getUniformLocation(program, "u_colorScale"), colorScale);
1166
1167 if (useVao)
1168 {
1169 m_ctx.genVertexArrays(1, &vaoId);
1170 m_ctx.bindVertexArray(vaoId);
1171 }
1172
1173 for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
1174 {
1175 if (m_arrays[arrayNdx]->isBound())
1176 {
1177 std::stringstream attribName;
1178 attribName << "a_" << m_arrays[arrayNdx]->getAttribNdx();
1179
1180 deUint32 loc = m_ctx.getAttribLocation(program, attribName.str().c_str());
1181 m_ctx.enableVertexAttribArray(loc);
1182 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glEnableVertexAttribArray()");
1183
1184 m_arrays[arrayNdx]->glBind(loc);
1185 }
1186 }
1187
1188 DE_ASSERT((firstVertex % 6) == 0);
1189 m_ctx.drawArrays(ContextArray::primitiveToGL(primitive), firstVertex, vertexCount - firstVertex);
1190 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArrays()");
1191
1192 for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
1193 {
1194 if (m_arrays[arrayNdx]->isBound())
1195 {
1196 std::stringstream attribName;
1197 attribName << "a_" << m_arrays[arrayNdx]->getAttribNdx();
1198
1199 deUint32 loc = m_ctx.getAttribLocation(program, attribName.str().c_str());
1200
1201 m_ctx.disableVertexAttribArray(loc);
1202 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDisableVertexAttribArray()");
1203 }
1204 }
1205
1206 if (useVao)
1207 m_ctx.deleteVertexArrays(1, &vaoId);
1208
1209 m_ctx.deleteProgram(program);
1210 m_ctx.useProgram(0);
1211 m_ctx.readPixels(m_screen, 0, 0, m_screen.getWidth(), m_screen.getHeight());
1212 }
1213
1214 // GLValue
1215
getMaxValue(Array::InputType type)1216 GLValue GLValue::getMaxValue (Array::InputType type)
1217 {
1218 GLValue rangesHi[(int)Array::INPUTTYPE_LAST];
1219
1220 rangesHi[(int)Array::INPUTTYPE_FLOAT] = GLValue(Float::create(127.0f));
1221 rangesHi[(int)Array::INPUTTYPE_DOUBLE] = GLValue(Double::create(127.0f));
1222 rangesHi[(int)Array::INPUTTYPE_BYTE] = GLValue(Byte::create(127));
1223 rangesHi[(int)Array::INPUTTYPE_UNSIGNED_BYTE] = GLValue(Ubyte::create(255));
1224 rangesHi[(int)Array::INPUTTYPE_UNSIGNED_SHORT] = GLValue(Ushort::create(65530));
1225 rangesHi[(int)Array::INPUTTYPE_SHORT] = GLValue(Short::create(32760));
1226 rangesHi[(int)Array::INPUTTYPE_FIXED] = GLValue(Fixed::create(32760));
1227 rangesHi[(int)Array::INPUTTYPE_INT] = GLValue(Int::create(2147483647));
1228 rangesHi[(int)Array::INPUTTYPE_UNSIGNED_INT] = GLValue(Uint::create(4294967295u));
1229 rangesHi[(int)Array::INPUTTYPE_HALF] = GLValue(Half::create(256.0f));
1230
1231 return rangesHi[(int)type];
1232 }
1233
getMinValue(Array::InputType type)1234 GLValue GLValue::getMinValue (Array::InputType type)
1235 {
1236 GLValue rangesLo[(int)Array::INPUTTYPE_LAST];
1237
1238 rangesLo[(int)Array::INPUTTYPE_FLOAT] = GLValue(Float::create(-127.0f));
1239 rangesLo[(int)Array::INPUTTYPE_DOUBLE] = GLValue(Double::create(-127.0f));
1240 rangesLo[(int)Array::INPUTTYPE_BYTE] = GLValue(Byte::create(-127));
1241 rangesLo[(int)Array::INPUTTYPE_UNSIGNED_BYTE] = GLValue(Ubyte::create(0));
1242 rangesLo[(int)Array::INPUTTYPE_UNSIGNED_SHORT] = GLValue(Ushort::create(0));
1243 rangesLo[(int)Array::INPUTTYPE_SHORT] = GLValue(Short::create(-32760));
1244 rangesLo[(int)Array::INPUTTYPE_FIXED] = GLValue(Fixed::create(-32760));
1245 rangesLo[(int)Array::INPUTTYPE_INT] = GLValue(Int::create(-2147483647));
1246 rangesLo[(int)Array::INPUTTYPE_UNSIGNED_INT] = GLValue(Uint::create(0));
1247 rangesLo[(int)Array::INPUTTYPE_HALF] = GLValue(Half::create(-256.0f));
1248
1249 return rangesLo[(int)type];
1250 }
1251
toFloat(void) const1252 float GLValue::toFloat (void) const
1253 {
1254 switch (type)
1255 {
1256 case Array::INPUTTYPE_FLOAT:
1257 return fl.getValue();
1258 break;
1259
1260 case Array::INPUTTYPE_BYTE:
1261 return b.getValue();
1262 break;
1263
1264 case Array::INPUTTYPE_UNSIGNED_BYTE:
1265 return ub.getValue();
1266 break;
1267
1268 case Array::INPUTTYPE_SHORT:
1269 return s.getValue();
1270 break;
1271
1272 case Array::INPUTTYPE_UNSIGNED_SHORT:
1273 return us.getValue();
1274 break;
1275
1276 case Array::INPUTTYPE_FIXED:
1277 {
1278 int maxValue = 65536;
1279 return (float)(double(2 * fi.getValue() + 1) / (maxValue - 1));
1280
1281 break;
1282 }
1283
1284 case Array::INPUTTYPE_UNSIGNED_INT:
1285 return (float)ui.getValue();
1286 break;
1287
1288 case Array::INPUTTYPE_INT:
1289 return (float)i.getValue();
1290 break;
1291
1292 case Array::INPUTTYPE_HALF:
1293 return h.to<float>();
1294 break;
1295
1296 case Array::INPUTTYPE_DOUBLE:
1297 return (float)d.getValue();
1298 break;
1299
1300 default:
1301 DE_ASSERT(false);
1302 return 0.0f;
1303 break;
1304 };
1305 }
1306
1307 class RandomArrayGenerator
1308 {
1309 public:
1310 static char* generateArray (int seed, GLValue min, GLValue max, int count, int componentCount, int stride, Array::InputType type);
1311 static char* generateQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max, float gridSize);
1312 static char* generatePerQuad (int seed, int count, int componentCount, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max);
1313
1314 private:
1315 template<typename T>
1316 static char* createQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, T min, T max, float gridSize);
1317 template<typename T>
1318 static char* createPerQuads (int seed, int count, int componentCount, int stride, Array::Primitive primitive, T min, T max);
1319 static char* createQuadsPacked (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive);
1320 static void setData (char* data, Array::InputType type, deRandom& rnd, GLValue min, GLValue max);
1321 };
1322
setData(char * data,Array::InputType type,deRandom & rnd,GLValue min,GLValue max)1323 void RandomArrayGenerator::setData (char* data, Array::InputType type, deRandom& rnd, GLValue min, GLValue max)
1324 {
1325 switch (type)
1326 {
1327 case Array::INPUTTYPE_FLOAT:
1328 {
1329 alignmentSafeAssignment<float>(data, getRandom<GLValue::Float>(rnd, min.fl, max.fl));
1330 break;
1331 }
1332
1333 case Array::INPUTTYPE_DOUBLE:
1334 {
1335 alignmentSafeAssignment<double>(data, getRandom<GLValue::Float>(rnd, min.fl, max.fl));
1336 break;
1337 }
1338
1339 case Array::INPUTTYPE_SHORT:
1340 {
1341 alignmentSafeAssignment<deInt16>(data, getRandom<GLValue::Short>(rnd, min.s, max.s));
1342 break;
1343 }
1344
1345 case Array::INPUTTYPE_UNSIGNED_SHORT:
1346 {
1347 alignmentSafeAssignment<deUint16>(data, getRandom<GLValue::Ushort>(rnd, min.us, max.us));
1348 break;
1349 }
1350
1351 case Array::INPUTTYPE_BYTE:
1352 {
1353 alignmentSafeAssignment<deInt8>(data, getRandom<GLValue::Byte>(rnd, min.b, max.b));
1354 break;
1355 }
1356
1357 case Array::INPUTTYPE_UNSIGNED_BYTE:
1358 {
1359 alignmentSafeAssignment<deUint8>(data, getRandom<GLValue::Ubyte>(rnd, min.ub, max.ub));
1360 break;
1361 }
1362
1363 case Array::INPUTTYPE_FIXED:
1364 {
1365 alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Fixed>(rnd, min.fi, max.fi));
1366 break;
1367 }
1368
1369 case Array::INPUTTYPE_INT:
1370 {
1371 alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Int>(rnd, min.i, max.i));
1372 break;
1373 }
1374
1375 case Array::INPUTTYPE_UNSIGNED_INT:
1376 {
1377 alignmentSafeAssignment<deUint32>(data, getRandom<GLValue::Uint>(rnd, min.ui, max.ui));
1378 break;
1379 }
1380
1381 case Array::INPUTTYPE_HALF:
1382 {
1383 alignmentSafeAssignment<deFloat16>(data, getRandom<GLValue::Half>(rnd, min.h, max.h).getValue());
1384 break;
1385 }
1386
1387 default:
1388 DE_ASSERT(false);
1389 break;
1390 }
1391 }
1392
generateArray(int seed,GLValue min,GLValue max,int count,int componentCount,int stride,Array::InputType type)1393 char* RandomArrayGenerator::generateArray (int seed, GLValue min, GLValue max, int count, int componentCount, int stride, Array::InputType type)
1394 {
1395 char* data = NULL;
1396
1397 deRandom rnd;
1398 deRandom_init(&rnd, seed);
1399
1400 if (stride == 0)
1401 stride = componentCount * Array::inputTypeSize(type);
1402
1403 data = new char[stride * count];
1404
1405 for (int vertexNdx = 0; vertexNdx < count; vertexNdx++)
1406 {
1407 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1408 {
1409 setData(&(data[vertexNdx * stride + Array::inputTypeSize(type) * componentNdx]), type, rnd, min, max);
1410 }
1411 }
1412
1413 return data;
1414 }
1415
generateQuads(int seed,int count,int componentCount,int offset,int stride,Array::Primitive primitive,Array::InputType type,GLValue min,GLValue max,float gridSize)1416 char* RandomArrayGenerator::generateQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max, float gridSize)
1417 {
1418 char* data = DE_NULL;
1419
1420 switch (type)
1421 {
1422 case Array::INPUTTYPE_FLOAT:
1423 data = createQuads<GLValue::Float>(seed, count, componentCount, offset, stride, primitive, min.fl, max.fl, gridSize);
1424 break;
1425
1426 case Array::INPUTTYPE_FIXED:
1427 data = createQuads<GLValue::Fixed>(seed, count, componentCount, offset, stride, primitive, min.fi, max.fi, gridSize);
1428 break;
1429
1430 case Array::INPUTTYPE_DOUBLE:
1431 data = createQuads<GLValue::Double>(seed, count, componentCount, offset, stride, primitive, min.d, max.d, gridSize);
1432 break;
1433
1434 case Array::INPUTTYPE_BYTE:
1435 data = createQuads<GLValue::Byte>(seed, count, componentCount, offset, stride, primitive, min.b, max.b, gridSize);
1436 break;
1437
1438 case Array::INPUTTYPE_SHORT:
1439 data = createQuads<GLValue::Short>(seed, count, componentCount, offset, stride, primitive, min.s, max.s, gridSize);
1440 break;
1441
1442 case Array::INPUTTYPE_UNSIGNED_BYTE:
1443 data = createQuads<GLValue::Ubyte>(seed, count, componentCount, offset, stride, primitive, min.ub, max.ub, gridSize);
1444 break;
1445
1446 case Array::INPUTTYPE_UNSIGNED_SHORT:
1447 data = createQuads<GLValue::Ushort>(seed, count, componentCount, offset, stride, primitive, min.us, max.us, gridSize);
1448 break;
1449
1450 case Array::INPUTTYPE_UNSIGNED_INT:
1451 data = createQuads<GLValue::Uint>(seed, count, componentCount, offset, stride, primitive, min.ui, max.ui, gridSize);
1452 break;
1453
1454 case Array::INPUTTYPE_INT:
1455 data = createQuads<GLValue::Int>(seed, count, componentCount, offset, stride, primitive, min.i, max.i, gridSize);
1456 break;
1457
1458 case Array::INPUTTYPE_HALF:
1459 data = createQuads<GLValue::Half>(seed, count, componentCount, offset, stride, primitive, min.h, max.h, gridSize);
1460 break;
1461
1462 case Array::INPUTTYPE_INT_2_10_10_10:
1463 case Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10:
1464 data = createQuadsPacked(seed, count, componentCount, offset, stride, primitive);
1465 break;
1466
1467 default:
1468 DE_ASSERT(false);
1469 break;
1470 }
1471
1472 return data;
1473 }
1474
createQuadsPacked(int seed,int count,int componentCount,int offset,int stride,Array::Primitive primitive)1475 char* RandomArrayGenerator::createQuadsPacked (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive)
1476 {
1477 DE_ASSERT(componentCount == 4);
1478 DE_UNREF(componentCount);
1479 int quadStride = 0;
1480
1481 if (stride == 0)
1482 stride = sizeof(deUint32);
1483
1484 switch (primitive)
1485 {
1486 case Array::PRIMITIVE_TRIANGLES:
1487 quadStride = stride * 6;
1488 break;
1489
1490 default:
1491 DE_ASSERT(false);
1492 break;
1493 }
1494
1495 char* const _data = new char[offset + quadStride * (count - 1) + stride * 5 + componentCount * Array::inputTypeSize(Array::INPUTTYPE_INT_2_10_10_10)]; // last element must be fully in the array
1496 char* const resultData = _data + offset;
1497
1498 const deUint32 max = 1024;
1499 const deUint32 min = 10;
1500 const deUint32 max2 = 4;
1501
1502 deRandom rnd;
1503 deRandom_init(&rnd, seed);
1504
1505 switch (primitive)
1506 {
1507 case Array::PRIMITIVE_TRIANGLES:
1508 {
1509 for (int quadNdx = 0; quadNdx < count; quadNdx++)
1510 {
1511 deUint32 x1 = min + deRandom_getUint32(&rnd) % (max - min);
1512 deUint32 x2 = min + deRandom_getUint32(&rnd) % (max - x1);
1513
1514 deUint32 y1 = min + deRandom_getUint32(&rnd) % (max - min);
1515 deUint32 y2 = min + deRandom_getUint32(&rnd) % (max - y1);
1516
1517 deUint32 z = min + deRandom_getUint32(&rnd) % (max - min);
1518 deUint32 w = deRandom_getUint32(&rnd) % max2;
1519
1520 deUint32 val1 = (w << 30) | (z << 20) | (y1 << 10) | x1;
1521 deUint32 val2 = (w << 30) | (z << 20) | (y1 << 10) | x2;
1522 deUint32 val3 = (w << 30) | (z << 20) | (y2 << 10) | x1;
1523
1524 deUint32 val4 = (w << 30) | (z << 20) | (y2 << 10) | x1;
1525 deUint32 val5 = (w << 30) | (z << 20) | (y1 << 10) | x2;
1526 deUint32 val6 = (w << 30) | (z << 20) | (y2 << 10) | x2;
1527
1528 alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 0]), val1);
1529 alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 1]), val2);
1530 alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 2]), val3);
1531 alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 3]), val4);
1532 alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 4]), val5);
1533 alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 5]), val6);
1534 }
1535
1536 break;
1537 }
1538
1539 default:
1540 DE_ASSERT(false);
1541 break;
1542 }
1543
1544 return _data;
1545 }
1546
1547 template<typename T>
roundTo(const T & step,const T & value)1548 T roundTo (const T& step, const T& value)
1549 {
1550 return value - (value % step);
1551 }
1552
1553 template<typename T>
createQuads(int seed,int count,int componentCount,int offset,int stride,Array::Primitive primitive,T min,T max,float gridSize)1554 char* RandomArrayGenerator::createQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, T min, T max, float gridSize)
1555 {
1556 int componentStride = sizeof(T);
1557 int quadStride = 0;
1558
1559 if (stride == 0)
1560 stride = componentCount * componentStride;
1561
1562 DE_ASSERT(stride >= componentCount * componentStride);
1563
1564 switch (primitive)
1565 {
1566 case Array::PRIMITIVE_TRIANGLES:
1567 quadStride = stride * 6;
1568 break;
1569
1570 default:
1571 DE_ASSERT(false);
1572 break;
1573 }
1574
1575 char* resultData = new char[offset + quadStride * count];
1576 char* _data = resultData;
1577 resultData = resultData + offset;
1578
1579 deRandom rnd;
1580 deRandom_init(&rnd, seed);
1581
1582 switch (primitive)
1583 {
1584 case Array::PRIMITIVE_TRIANGLES:
1585 {
1586 const T minQuadSize = T::fromFloat(deFloatAbs(max.template to<float>() - min.template to<float>()) * gridSize);
1587 const T minDiff = minValue<T>() > minQuadSize
1588 ? minValue<T>()
1589 : minQuadSize;
1590
1591 for (int quadNdx = 0; quadNdx < count; ++quadNdx)
1592 {
1593 T x1, x2;
1594 T y1, y2;
1595 T z, w;
1596
1597 // attempt to find a good (i.e not extremely small) quad
1598 for (int attemptNdx = 0; attemptNdx < 4; ++attemptNdx)
1599 {
1600 x1 = roundTo(minDiff, getRandom<T>(rnd, min, max));
1601 x2 = roundTo(minDiff, getRandom<T>(rnd, minDiff, abs<T>(max - x1)));
1602
1603 y1 = roundTo(minDiff, getRandom<T>(rnd, min, max));
1604 y2 = roundTo(minDiff, getRandom<T>(rnd, minDiff, abs<T>(max - y1)));
1605
1606 z = (componentCount > 2) ? roundTo(minDiff, (getRandom<T>(rnd, min, max))) : (T::create(0));
1607 w = (componentCount > 3) ? roundTo(minDiff, (getRandom<T>(rnd, min, max))) : (T::create(1));
1608
1609 // no additional components, all is good
1610 if (componentCount <= 2)
1611 break;
1612
1613 // The result quad is too thin?
1614 if ((deFloatAbs(x2.template to<float>() + z.template to<float>()) < minDiff.template to<float>()) ||
1615 (deFloatAbs(y2.template to<float>() + w.template to<float>()) < minDiff.template to<float>()))
1616 continue;
1617
1618 // all ok
1619 break;
1620 }
1621
1622 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride]), x1);
1623 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + componentStride]), y1);
1624
1625 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride]), x1 + x2);
1626 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride + componentStride]), y1);
1627
1628 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 2]), x1);
1629 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 2 + componentStride]), y1 + y2);
1630
1631 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 3]), x1);
1632 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 3 + componentStride]), y1 + y2);
1633
1634 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 4]), x1 + x2);
1635 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 4 + componentStride]), y1);
1636
1637 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 5]), x1 + x2);
1638 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 5 + componentStride]), y1 + y2);
1639
1640 if (componentCount > 2)
1641 {
1642 for (int i = 0; i < 6; i++)
1643 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * i + componentStride * 2]), z);
1644 }
1645
1646 if (componentCount > 3)
1647 {
1648 for (int i = 0; i < 6; i++)
1649 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * i + componentStride * 3]), w);
1650 }
1651 }
1652
1653 break;
1654 }
1655
1656 default:
1657 DE_ASSERT(false);
1658 break;
1659 }
1660
1661 return _data;
1662 }
1663
generatePerQuad(int seed,int count,int componentCount,int stride,Array::Primitive primitive,Array::InputType type,GLValue min,GLValue max)1664 char* RandomArrayGenerator::generatePerQuad (int seed, int count, int componentCount, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max)
1665 {
1666 char* data = DE_NULL;
1667
1668 switch (type)
1669 {
1670 case Array::INPUTTYPE_FLOAT:
1671 data = createPerQuads<GLValue::Float>(seed, count, componentCount, stride, primitive, min.fl, max.fl);
1672 break;
1673
1674 case Array::INPUTTYPE_FIXED:
1675 data = createPerQuads<GLValue::Fixed>(seed, count, componentCount, stride, primitive, min.fi, max.fi);
1676 break;
1677
1678 case Array::INPUTTYPE_DOUBLE:
1679 data = createPerQuads<GLValue::Double>(seed, count, componentCount, stride, primitive, min.d, max.d);
1680 break;
1681
1682 case Array::INPUTTYPE_BYTE:
1683 data = createPerQuads<GLValue::Byte>(seed, count, componentCount, stride, primitive, min.b, max.b);
1684 break;
1685
1686 case Array::INPUTTYPE_SHORT:
1687 data = createPerQuads<GLValue::Short>(seed, count, componentCount, stride, primitive, min.s, max.s);
1688 break;
1689
1690 case Array::INPUTTYPE_UNSIGNED_BYTE:
1691 data = createPerQuads<GLValue::Ubyte>(seed, count, componentCount, stride, primitive, min.ub, max.ub);
1692 break;
1693
1694 case Array::INPUTTYPE_UNSIGNED_SHORT:
1695 data = createPerQuads<GLValue::Ushort>(seed, count, componentCount, stride, primitive, min.us, max.us);
1696 break;
1697
1698 case Array::INPUTTYPE_UNSIGNED_INT:
1699 data = createPerQuads<GLValue::Uint>(seed, count, componentCount, stride, primitive, min.ui, max.ui);
1700 break;
1701
1702 case Array::INPUTTYPE_INT:
1703 data = createPerQuads<GLValue::Int>(seed, count, componentCount, stride, primitive, min.i, max.i);
1704 break;
1705
1706 case Array::INPUTTYPE_HALF:
1707 data = createPerQuads<GLValue::Half>(seed, count, componentCount, stride, primitive, min.h, max.h);
1708 break;
1709
1710 default:
1711 DE_ASSERT(false);
1712 break;
1713 }
1714
1715 return data;
1716 }
1717
1718 template<typename T>
createPerQuads(int seed,int count,int componentCount,int stride,Array::Primitive primitive,T min,T max)1719 char* RandomArrayGenerator::createPerQuads (int seed, int count, int componentCount, int stride, Array::Primitive primitive, T min, T max)
1720 {
1721 deRandom rnd;
1722 deRandom_init(&rnd, seed);
1723
1724 int componentStride = sizeof(T);
1725
1726 if (stride == 0)
1727 stride = componentStride * componentCount;
1728
1729 int quadStride = 0;
1730
1731 switch (primitive)
1732 {
1733 case Array::PRIMITIVE_TRIANGLES:
1734 quadStride = stride * 6;
1735 break;
1736
1737 default:
1738 DE_ASSERT(false);
1739 break;
1740 }
1741
1742 char* data = new char[count * quadStride];
1743
1744 for (int quadNdx = 0; quadNdx < count; quadNdx++)
1745 {
1746 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1747 {
1748 T val = getRandom<T>(rnd, min, max);
1749
1750 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 0 + componentStride * componentNdx, val);
1751 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 1 + componentStride * componentNdx, val);
1752 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 2 + componentStride * componentNdx, val);
1753 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 3 + componentStride * componentNdx, val);
1754 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 4 + componentStride * componentNdx, val);
1755 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 5 + componentStride * componentNdx, val);
1756 }
1757 }
1758
1759 return data;
1760 }
1761
1762 // VertexArrayTest
1763
VertexArrayTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc)1764 VertexArrayTest::VertexArrayTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name ,const char* desc)
1765 : TestCase (testCtx, name, desc)
1766 , m_renderCtx (renderCtx)
1767 , m_refBuffers (DE_NULL)
1768 , m_refContext (DE_NULL)
1769 , m_glesContext (DE_NULL)
1770 , m_glArrayPack (DE_NULL)
1771 , m_rrArrayPack (DE_NULL)
1772 , m_isOk (false)
1773 , m_maxDiffRed (deCeilFloatToInt32(256.0f * (2.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().redBits))))
1774 , m_maxDiffGreen (deCeilFloatToInt32(256.0f * (2.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().greenBits))))
1775 , m_maxDiffBlue (deCeilFloatToInt32(256.0f * (2.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().blueBits))))
1776 {
1777 }
1778
~VertexArrayTest(void)1779 VertexArrayTest::~VertexArrayTest (void)
1780 {
1781 deinit();
1782 }
1783
init(void)1784 void VertexArrayTest::init (void)
1785 {
1786 const int renderTargetWidth = de::min(512, m_renderCtx.getRenderTarget().getWidth());
1787 const int renderTargetHeight = de::min(512, m_renderCtx.getRenderTarget().getHeight());
1788 sglr::ReferenceContextLimits limits (m_renderCtx);
1789
1790 m_glesContext = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
1791
1792 m_refBuffers = new sglr::ReferenceContextBuffers(m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, renderTargetWidth, renderTargetHeight);
1793 m_refContext = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
1794
1795 m_glArrayPack = new ContextArrayPack(m_renderCtx, *m_glesContext);
1796 m_rrArrayPack = new ContextArrayPack(m_renderCtx, *m_refContext);
1797 }
1798
deinit(void)1799 void VertexArrayTest::deinit (void)
1800 {
1801 delete m_glArrayPack;
1802 delete m_rrArrayPack;
1803 delete m_refBuffers;
1804 delete m_refContext;
1805 delete m_glesContext;
1806
1807 m_glArrayPack = DE_NULL;
1808 m_rrArrayPack = DE_NULL;
1809 m_refBuffers = DE_NULL;
1810 m_refContext = DE_NULL;
1811 m_glesContext = DE_NULL;
1812 }
1813
compare(void)1814 void VertexArrayTest::compare (void)
1815 {
1816 const tcu::Surface& ref = m_rrArrayPack->getSurface();
1817 const tcu::Surface& screen = m_glArrayPack->getSurface();
1818
1819 if (m_renderCtx.getRenderTarget().getNumSamples() > 1)
1820 {
1821 // \todo [mika] Improve compare when using multisampling
1822 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;
1823 m_isOk = tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", ref.getAccess(), screen.getAccess(), 1.5f, tcu::COMPARE_LOG_RESULT);
1824 }
1825 else
1826 {
1827 tcu::RGBA threshold (m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue, 255);
1828 tcu::Surface error (ref.getWidth(), ref.getHeight());
1829
1830 m_isOk = true;
1831
1832 for (int y = 0; y < ref.getHeight(); y++)
1833 {
1834 for (int x = 0; x < ref.getWidth(); x++)
1835 {
1836 tcu::RGBA refPixel = ref.getPixel(x, y);
1837 tcu::RGBA screenPixel = screen.getPixel(x, y);
1838 bool isOkPixel = false;
1839
1840 if (y == 0 || y + 1 == ref.getHeight() || x == 0 || x + 1 == ref.getWidth())
1841 {
1842 // Don't check borders since the pixel neighborhood is undefined
1843 error.setPixel(x, y, tcu::RGBA(screenPixel.getRed(), (screenPixel.getGreen() + 255) / 2, screenPixel.getBlue(), 255));
1844 continue;
1845 }
1846
1847 // Don't do comparisons for this pixel if it belongs to a one-pixel-thin part (i.e. it doesn't have similar-color neighbors in both x and y directions) in both result and reference.
1848 // This fixes some false negatives.
1849 bool refThin = (!tcu::compareThreshold(refPixel, ref.getPixel(x-1, y ), threshold) && !tcu::compareThreshold(refPixel, ref.getPixel(x+1, y ), threshold)) ||
1850 (!tcu::compareThreshold(refPixel, ref.getPixel(x , y-1), threshold) && !tcu::compareThreshold(refPixel, ref.getPixel(x , y+1), threshold));
1851 bool screenThin = (!tcu::compareThreshold(screenPixel, screen.getPixel(x-1, y ), threshold) && !tcu::compareThreshold(screenPixel, screen.getPixel(x+1, y ), threshold)) ||
1852 (!tcu::compareThreshold(screenPixel, screen.getPixel(x , y-1), threshold) && !tcu::compareThreshold(screenPixel, screen.getPixel(x , y+1), threshold));
1853
1854 if (refThin && screenThin)
1855 isOkPixel = true;
1856 else
1857 {
1858 for (int dy = -1; dy < 2 && !isOkPixel; dy++)
1859 {
1860 for (int dx = -1; dx < 2 && !isOkPixel; dx++)
1861 {
1862 // Check reference pixel against screen pixel
1863 {
1864 tcu::RGBA screenCmpPixel = screen.getPixel(x+dx, y+dy);
1865 deUint8 r = (deUint8)deAbs32(refPixel.getRed() - screenCmpPixel.getRed());
1866 deUint8 g = (deUint8)deAbs32(refPixel.getGreen() - screenCmpPixel.getGreen());
1867 deUint8 b = (deUint8)deAbs32(refPixel.getBlue() - screenCmpPixel.getBlue());
1868
1869 if (r <= m_maxDiffRed && g <= m_maxDiffGreen && b <= m_maxDiffBlue)
1870 isOkPixel = true;
1871 }
1872
1873 // Check screen pixels against reference pixel
1874 {
1875 tcu::RGBA refCmpPixel = ref.getPixel(x+dx, y+dy);
1876 deUint8 r = (deUint8)deAbs32(refCmpPixel.getRed() - screenPixel.getRed());
1877 deUint8 g = (deUint8)deAbs32(refCmpPixel.getGreen() - screenPixel.getGreen());
1878 deUint8 b = (deUint8)deAbs32(refCmpPixel.getBlue() - screenPixel.getBlue());
1879
1880 if (r <= m_maxDiffRed && g <= m_maxDiffGreen && b <= m_maxDiffBlue)
1881 isOkPixel = true;
1882 }
1883 }
1884 }
1885 }
1886
1887 if (isOkPixel)
1888 error.setPixel(x, y, tcu::RGBA(screen.getPixel(x, y).getRed(), (screen.getPixel(x, y).getGreen() + 255) / 2, screen.getPixel(x, y).getBlue(), 255));
1889 else
1890 {
1891 error.setPixel(x, y, tcu::RGBA(255, 0, 0, 255));
1892 m_isOk = false;
1893 }
1894 }
1895 }
1896
1897 tcu::TestLog& log = m_testCtx.getLog();
1898 if (!m_isOk)
1899 {
1900 log << TestLog::Message << "Image comparison failed, threshold = (" << m_maxDiffRed << ", " << m_maxDiffGreen << ", " << m_maxDiffBlue << ")" << TestLog::EndMessage;
1901 log << TestLog::ImageSet("Compare result", "Result of rendering")
1902 << TestLog::Image("Result", "Result", screen)
1903 << TestLog::Image("Reference", "Reference", ref)
1904 << TestLog::Image("ErrorMask", "Error mask", error)
1905 << TestLog::EndImageSet;
1906 }
1907 else
1908 {
1909 log << TestLog::ImageSet("Compare result", "Result of rendering")
1910 << TestLog::Image("Result", "Result", screen)
1911 << TestLog::EndImageSet;
1912 }
1913 }
1914 }
1915
1916 // MultiVertexArrayTest
1917
ArraySpec(Array::InputType inputType_,Array::OutputType outputType_,Array::Storage storage_,Array::Usage usage_,int componentCount_,int offset_,int stride_,bool normalize_,GLValue min_,GLValue max_)1918 MultiVertexArrayTest::Spec::ArraySpec::ArraySpec(Array::InputType inputType_, Array::OutputType outputType_, Array::Storage storage_, Array::Usage usage_, int componentCount_, int offset_, int stride_, bool normalize_, GLValue min_, GLValue max_)
1919 : inputType (inputType_)
1920 , outputType (outputType_)
1921 , storage (storage_)
1922 , usage (usage_)
1923 , componentCount(componentCount_)
1924 , offset (offset_)
1925 , stride (stride_)
1926 , normalize (normalize_)
1927 , min (min_)
1928 , max (max_)
1929 {
1930 }
1931
getName(void) const1932 std::string MultiVertexArrayTest::Spec::getName (void) const
1933 {
1934 std::stringstream name;
1935
1936 for (size_t ndx = 0; ndx < arrays.size(); ++ndx)
1937 {
1938 const ArraySpec& array = arrays[ndx];
1939
1940 if (arrays.size() > 1)
1941 name << "array" << ndx << "_";
1942
1943 name
1944 << Array::storageToString(array.storage) << "_"
1945 << array.offset << "_"
1946 << array.stride << "_"
1947 << Array::inputTypeToString((Array::InputType)array.inputType);
1948 if (array.inputType != Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && array.inputType != Array::INPUTTYPE_INT_2_10_10_10)
1949 name << array.componentCount;
1950 name
1951 << "_"
1952 << (array.normalize ? "normalized_" : "")
1953 << Array::outputTypeToString(array.outputType) << "_"
1954 << Array::usageTypeToString(array.usage) << "_";
1955 }
1956
1957 if (first)
1958 name << "first" << first << "_";
1959
1960 switch (primitive)
1961 {
1962 case Array::PRIMITIVE_TRIANGLES:
1963 name << "quads_";
1964 break;
1965 case Array::PRIMITIVE_POINTS:
1966 name << "points_";
1967 break;
1968
1969 default:
1970 DE_ASSERT(false);
1971 break;
1972 }
1973
1974 name << drawCount;
1975
1976 return name.str();
1977 }
1978
getDesc(void) const1979 std::string MultiVertexArrayTest::Spec::getDesc (void) const
1980 {
1981 std::stringstream desc;
1982
1983 for (size_t ndx = 0; ndx < arrays.size(); ++ndx)
1984 {
1985 const ArraySpec& array = arrays[ndx];
1986
1987 desc
1988 << "Array " << ndx << ": "
1989 << "Storage in " << Array::storageToString(array.storage) << ", "
1990 << "stride " << array.stride << ", "
1991 << "input datatype " << Array::inputTypeToString((Array::InputType)array.inputType) << ", "
1992 << "input component count " << array.componentCount << ", "
1993 << (array.normalize ? "normalized, " : "")
1994 << "used as " << Array::outputTypeToString(array.outputType) << ", ";
1995 }
1996
1997 desc
1998 << "drawArrays(), "
1999 << "first " << first << ", "
2000 << drawCount;
2001
2002 switch (primitive)
2003 {
2004 case Array::PRIMITIVE_TRIANGLES:
2005 desc << "quads ";
2006 break;
2007 case Array::PRIMITIVE_POINTS:
2008 desc << "points";
2009 break;
2010
2011 default:
2012 DE_ASSERT(false);
2013 break;
2014 }
2015
2016
2017 return desc.str();
2018 }
2019
MultiVertexArrayTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const Spec & spec,const char * name,const char * desc)2020 MultiVertexArrayTest::MultiVertexArrayTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const Spec& spec, const char* name, const char* desc)
2021 : VertexArrayTest (testCtx, renderCtx, name, desc)
2022 , m_spec (spec)
2023 , m_iteration (0)
2024 {
2025 }
2026
~MultiVertexArrayTest(void)2027 MultiVertexArrayTest::~MultiVertexArrayTest (void)
2028 {
2029 }
2030
iterate(void)2031 MultiVertexArrayTest::IterateResult MultiVertexArrayTest::iterate (void)
2032 {
2033 if (m_iteration == 0)
2034 {
2035 const size_t primitiveSize = (m_spec.primitive == Array::PRIMITIVE_TRIANGLES) ? (6) : (1); // in non-indexed draw Triangles means rectangles
2036 float coordScale = 1.0f;
2037 float colorScale = 1.0f;
2038 const bool useVao = m_renderCtx.getType().getProfile() == glu::PROFILE_CORE;
2039
2040 // Log info
2041 m_testCtx.getLog() << TestLog::Message << m_spec.getDesc() << TestLog::EndMessage;
2042
2043 // Color and Coord scale
2044 {
2045 // First array is always position
2046 {
2047 Spec::ArraySpec arraySpec = m_spec.arrays[0];
2048 if (arraySpec.inputType == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
2049 {
2050 if (arraySpec.normalize)
2051 coordScale = 1.0f;
2052 else
2053 coordScale = 1.0 / 1024.0;
2054 }
2055 else if (arraySpec.inputType == Array::INPUTTYPE_INT_2_10_10_10)
2056 {
2057 if (arraySpec.normalize)
2058 coordScale = 1.0f;
2059 else
2060 coordScale = 1.0 / 512.0;
2061 }
2062 else
2063 coordScale = (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(0.9 / double(arraySpec.max.toFloat())));
2064
2065 if (arraySpec.outputType == Array::OUTPUTTYPE_VEC3 || arraySpec.outputType == Array::OUTPUTTYPE_VEC4
2066 || arraySpec.outputType == Array::OUTPUTTYPE_IVEC3 || arraySpec.outputType == Array::OUTPUTTYPE_IVEC4
2067 || arraySpec.outputType == Array::OUTPUTTYPE_UVEC3 || arraySpec.outputType == Array::OUTPUTTYPE_UVEC4)
2068 coordScale = coordScale * 0.5f;
2069 }
2070
2071 // And other arrays are color-like
2072 for (int arrayNdx = 1; arrayNdx < (int)m_spec.arrays.size(); arrayNdx++)
2073 {
2074 Spec::ArraySpec arraySpec = m_spec.arrays[arrayNdx];
2075
2076 colorScale *= (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(1.0 / double(arraySpec.max.toFloat())));
2077 if (arraySpec.outputType == Array::OUTPUTTYPE_VEC4)
2078 colorScale *= (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(1.0 / double(arraySpec.max.toFloat())));
2079 }
2080 }
2081
2082 // Data
2083 for (int arrayNdx = 0; arrayNdx < (int)m_spec.arrays.size(); arrayNdx++)
2084 {
2085 Spec::ArraySpec arraySpec = m_spec.arrays[arrayNdx];
2086 const int seed = int(arraySpec.inputType) + 10 * int(arraySpec.outputType) + 100 * int(arraySpec.storage) + 1000 * int(m_spec.primitive) + 10000 * int(arraySpec.usage) + int(m_spec.drawCount) + 12 * int(arraySpec.componentCount) + int(arraySpec.stride) + int(arraySpec.normalize);
2087 const char* data = DE_NULL;
2088 const size_t stride = (arraySpec.stride == 0) ? (arraySpec.componentCount * Array::inputTypeSize(arraySpec.inputType)) : (arraySpec.stride);
2089 const size_t bufferSize = arraySpec.offset + stride * (m_spec.drawCount * primitiveSize - 1) + arraySpec.componentCount * Array::inputTypeSize(arraySpec.inputType);
2090 // Snap values to at least 3x3 grid
2091 const float gridSize = 3.0f / (float)(de::min(m_renderCtx.getRenderTarget().getWidth(), m_renderCtx.getRenderTarget().getHeight()) - 1);
2092
2093 switch (m_spec.primitive)
2094 {
2095 // case Array::PRIMITIVE_POINTS:
2096 // data = RandomArrayGenerator::generateArray(seed, arraySpec.min, arraySpec.max, arraySpec.count, arraySpec.componentCount, arraySpec.stride, arraySpec.inputType);
2097 // break;
2098 case Array::PRIMITIVE_TRIANGLES:
2099 if (arrayNdx == 0)
2100 {
2101 data = RandomArrayGenerator::generateQuads(seed, m_spec.drawCount, arraySpec.componentCount, arraySpec.offset, arraySpec.stride, m_spec.primitive, arraySpec.inputType, arraySpec.min, arraySpec.max, gridSize);
2102 }
2103 else
2104 {
2105 DE_ASSERT(arraySpec.offset == 0); // \note [jarkko] it just hasn't been implemented
2106 data = RandomArrayGenerator::generatePerQuad(seed, m_spec.drawCount, arraySpec.componentCount, arraySpec.stride, m_spec.primitive, arraySpec.inputType, arraySpec.min, arraySpec.max);
2107 }
2108 break;
2109
2110 default:
2111 DE_ASSERT(false);
2112 break;
2113 }
2114
2115 m_glArrayPack->newArray(arraySpec.storage);
2116 m_rrArrayPack->newArray(arraySpec.storage);
2117
2118 m_glArrayPack->getArray(arrayNdx)->data(Array::TARGET_ARRAY, (int)bufferSize, data, arraySpec.usage);
2119 m_rrArrayPack->getArray(arrayNdx)->data(Array::TARGET_ARRAY, (int)bufferSize, data, arraySpec.usage);
2120
2121 m_glArrayPack->getArray(arrayNdx)->bind(arrayNdx, arraySpec.offset, arraySpec.componentCount, arraySpec.inputType, arraySpec.outputType, arraySpec.normalize, arraySpec.stride);
2122 m_rrArrayPack->getArray(arrayNdx)->bind(arrayNdx, arraySpec.offset, arraySpec.componentCount, arraySpec.inputType, arraySpec.outputType, arraySpec.normalize, arraySpec.stride);
2123
2124 delete [] data;
2125 }
2126
2127 try
2128 {
2129 m_glArrayPack->render(m_spec.primitive, m_spec.first, m_spec.drawCount * (int)primitiveSize, useVao, coordScale, colorScale);
2130 m_testCtx.touchWatchdog();
2131 m_rrArrayPack->render(m_spec.primitive, m_spec.first, m_spec.drawCount * (int)primitiveSize, useVao, coordScale, colorScale);
2132 }
2133 catch (glu::Error& err)
2134 {
2135 // GL Errors are ok if the mode is not properly aligned
2136
2137 m_testCtx.getLog() << TestLog::Message << "Got error: " << err.what() << TestLog::EndMessage;
2138
2139 if (isUnalignedBufferOffsetTest())
2140 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
2141 else if (isUnalignedBufferStrideTest())
2142 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
2143 else
2144 throw;
2145
2146 return STOP;
2147 }
2148
2149 m_iteration++;
2150 return CONTINUE;
2151 }
2152 else if (m_iteration == 1)
2153 {
2154 compare();
2155
2156 if (m_isOk)
2157 {
2158 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2159 }
2160 else
2161 {
2162 if (isUnalignedBufferOffsetTest())
2163 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
2164 else if (isUnalignedBufferStrideTest())
2165 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
2166 else
2167 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed.");
2168 }
2169
2170 m_iteration++;
2171 return STOP;
2172 }
2173 else
2174 {
2175 DE_ASSERT(false);
2176 return STOP;
2177 }
2178 }
2179
isUnalignedBufferOffsetTest(void) const2180 bool MultiVertexArrayTest::isUnalignedBufferOffsetTest (void) const
2181 {
2182 // Buffer offsets should be data type size aligned
2183 for (size_t i = 0; i < m_spec.arrays.size(); ++i)
2184 {
2185 if (m_spec.arrays[i].storage == Array::STORAGE_BUFFER)
2186 {
2187 const bool inputTypePacked = m_spec.arrays[i].inputType == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || m_spec.arrays[i].inputType == Array::INPUTTYPE_INT_2_10_10_10;
2188
2189 int dataTypeSize = Array::inputTypeSize(m_spec.arrays[i].inputType);
2190 if (inputTypePacked)
2191 dataTypeSize = 4;
2192
2193 if (m_spec.arrays[i].offset % dataTypeSize != 0)
2194 return true;
2195 }
2196 }
2197
2198 return false;
2199 }
2200
isUnalignedBufferStrideTest(void) const2201 bool MultiVertexArrayTest::isUnalignedBufferStrideTest (void) const
2202 {
2203 // Buffer strides should be data type size aligned
2204 for (size_t i = 0; i < m_spec.arrays.size(); ++i)
2205 {
2206 if (m_spec.arrays[i].storage == Array::STORAGE_BUFFER)
2207 {
2208 const bool inputTypePacked = m_spec.arrays[i].inputType == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || m_spec.arrays[i].inputType == Array::INPUTTYPE_INT_2_10_10_10;
2209
2210 int dataTypeSize = Array::inputTypeSize(m_spec.arrays[i].inputType);
2211 if (inputTypePacked)
2212 dataTypeSize = 4;
2213
2214 if (m_spec.arrays[i].stride % dataTypeSize != 0)
2215 return true;
2216 }
2217 }
2218
2219 return false;
2220 }
2221
2222 } // gls
2223 } // deqp
2224