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