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