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