GetDevices: Also allow `\.` to be part of the host name
[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                 sizeof(float),          // INPUTTYPE_FLOAT = 0,
176                 sizeof(deInt32),        // INPUTTYPE_FIXED,
177                 sizeof(double),         // INPUTTYPE_DOUBLE
178
179                 sizeof(deInt8),         // INPUTTYPE_BYTE,
180                 sizeof(deInt16),        // INPUTTYPE_SHORT,
181
182                 sizeof(deUint8),        // INPUTTYPE_UNSIGNED_BYTE,
183                 sizeof(deUint16),       // INPUTTYPE_UNSIGNED_SHORT,
184
185                 sizeof(deInt32),                // INPUTTYPE_INT,
186                 sizeof(deUint32),               // INPUTTYPE_UNSIGNED_INT,
187                 sizeof(deFloat16),              // INPUTTYPE_HALF,
188                 sizeof(deUint32) / 4,           // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
189                 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 : 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 : 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 : 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 : 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() + attribValue.z(),     (float)attribValue.y());                                        break;
787                         case 4: coord = tcu::Vec2((float)attribValue.x() + attribValue.z(),     (float)attribValue.y() + 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() * attribValue.x();
802                                 color.y() = color.y() * attribValue.y();
803                                 break;
804
805                         case 3:
806                                 color.x() = color.x() * attribValue.x();
807                                 color.y() = color.y() * attribValue.y();
808                                 color.z() = color.z() * attribValue.z();
809                                 break;
810
811                         case 4:
812                                 color.x() = color.x() * attribValue.x() * attribValue.w();
813                                 color.y() = color.y() * attribValue.y() * attribValue.w();
814                                 color.z() = color.z() * attribValue.z() * 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);
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);
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)
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);
1424                         break;
1425
1426                 case Array::INPUTTYPE_FIXED:
1427                         data = createQuads<GLValue::Fixed>(seed, count, componentCount, offset, stride, primitive, min.fi, max.fi);
1428                         break;
1429
1430                 case Array::INPUTTYPE_DOUBLE:
1431                         data = createQuads<GLValue::Double>(seed, count, componentCount, offset, stride, primitive, min.d, max.d);
1432                         break;
1433
1434                 case Array::INPUTTYPE_BYTE:
1435                         data = createQuads<GLValue::Byte>(seed, count, componentCount, offset, stride, primitive, min.b, max.b);
1436                         break;
1437
1438                 case Array::INPUTTYPE_SHORT:
1439                         data = createQuads<GLValue::Short>(seed, count, componentCount, offset, stride, primitive, min.s, max.s);
1440                         break;
1441
1442                 case Array::INPUTTYPE_UNSIGNED_BYTE:
1443                         data = createQuads<GLValue::Ubyte>(seed, count, componentCount, offset, stride, primitive, min.ub, max.ub);
1444                         break;
1445
1446                 case Array::INPUTTYPE_UNSIGNED_SHORT:
1447                         data = createQuads<GLValue::Ushort>(seed, count, componentCount, offset, stride, primitive, min.us, max.us);
1448                         break;
1449
1450                 case Array::INPUTTYPE_UNSIGNED_INT:
1451                         data = createQuads<GLValue::Uint>(seed, count, componentCount, offset, stride, primitive, min.ui, max.ui);
1452                         break;
1453
1454                 case Array::INPUTTYPE_INT:
1455                         data = createQuads<GLValue::Int>(seed, count, componentCount, offset, stride, primitive, min.i, max.i);
1456                         break;
1457
1458                 case Array::INPUTTYPE_HALF:
1459                         data = createQuads<GLValue::Half>(seed, count, componentCount, offset, stride, primitive, min.h, max.h);
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 char* RandomArrayGenerator::createQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, T min, T max)
1549 {
1550         int componentStride = sizeof(T);
1551         int quadStride = 0;
1552
1553         if (stride == 0)
1554                 stride = componentCount * componentStride;
1555         DE_ASSERT(stride >= componentCount * componentStride);
1556
1557         switch (primitive)
1558         {
1559                 case Array::PRIMITIVE_TRIANGLES:
1560                         quadStride = stride * 6;
1561                         break;
1562
1563                 default:
1564                         DE_ASSERT(false);
1565                         break;
1566         }
1567
1568         char* resultData = new char[offset + quadStride * count];
1569         char* _data = resultData;
1570         resultData = resultData + offset;
1571
1572         deRandom rnd;
1573         deRandom_init(&rnd,  seed);
1574
1575         switch (primitive)
1576         {
1577                 case Array::PRIMITIVE_TRIANGLES:
1578                 {
1579                         for (int quadNdx = 0; quadNdx < count; ++quadNdx)
1580                         {
1581                                 T x1, x2;
1582                                 T y1, y2;
1583                                 T z, w;
1584
1585                                 // attempt to find a good (i.e not extremely small) quad
1586                                 for (int attemptNdx = 0; attemptNdx < 4; ++attemptNdx)
1587                                 {
1588                                         x1 = getRandom<T>(rnd, min, max);
1589                                         x2 = getRandom<T>(rnd, minValue<T>(), abs<T>(max - x1));
1590
1591                                         y1 = getRandom<T>(rnd, min, max);
1592                                         y2 = getRandom<T>(rnd, minValue<T>(), abs<T>(max - y1));
1593
1594                                         z = (componentCount > 2) ? (getRandom<T>(rnd, min, max)) : (T::create(0));
1595                                         w = (componentCount > 3) ? (getRandom<T>(rnd, min, max)) : (T::create(1));
1596
1597                                         // no additional components, all is good
1598                                         if (componentCount <= 2)
1599                                                 break;
1600
1601                                         // The result quad is too thin?
1602                                         if ((deFloatAbs(x2.template to<float>() + z.template to<float>()) < minValue<T>().template to<float>()) ||
1603                                                 (deFloatAbs(y2.template to<float>() + w.template to<float>()) < minValue<T>().template to<float>()))
1604                                                 continue;
1605
1606                                         // all ok
1607                                         break;
1608                                 }
1609
1610                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride]), x1);
1611                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + componentStride]), y1);
1612
1613                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride]), x1 + x2);
1614                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride + componentStride]), y1);
1615
1616                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 2]), x1);
1617                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 2 + componentStride]), y1 + y2);
1618
1619                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 3]), x1);
1620                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 3 + componentStride]), y1 + y2);
1621
1622                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 4]), x1 + x2);
1623                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 4 + componentStride]), y1);
1624
1625                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 5]), x1 + x2);
1626                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 5 + componentStride]), y1 + y2);
1627
1628                                 if (componentCount > 2)
1629                                 {
1630                                         for (int i = 0; i < 6; i++)
1631                                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * i + componentStride * 2]), z);
1632                                 }
1633
1634                                 if (componentCount > 3)
1635                                 {
1636                                         for (int i = 0; i < 6; i++)
1637                                                 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * i + componentStride * 3]), w);
1638                                 }
1639                         }
1640
1641                         break;
1642                 }
1643
1644                 default:
1645                         DE_ASSERT(false);
1646                         break;
1647         }
1648
1649         return _data;
1650 }
1651
1652 char* RandomArrayGenerator::generatePerQuad (int seed, int count, int componentCount, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max)
1653 {
1654         char* data = DE_NULL;
1655
1656         switch (type)
1657         {
1658                 case Array::INPUTTYPE_FLOAT:
1659                         data = createPerQuads<GLValue::Float>(seed, count, componentCount, stride, primitive, min.fl, max.fl);
1660                         break;
1661
1662                 case Array::INPUTTYPE_FIXED:
1663                         data = createPerQuads<GLValue::Fixed>(seed, count, componentCount, stride, primitive, min.fi, max.fi);
1664                         break;
1665
1666                 case Array::INPUTTYPE_DOUBLE:
1667                         data = createPerQuads<GLValue::Double>(seed, count, componentCount, stride, primitive, min.d, max.d);
1668                         break;
1669
1670                 case Array::INPUTTYPE_BYTE:
1671                         data = createPerQuads<GLValue::Byte>(seed, count, componentCount, stride, primitive, min.b, max.b);
1672                         break;
1673
1674                 case Array::INPUTTYPE_SHORT:
1675                         data = createPerQuads<GLValue::Short>(seed, count, componentCount, stride, primitive, min.s, max.s);
1676                         break;
1677
1678                 case Array::INPUTTYPE_UNSIGNED_BYTE:
1679                         data = createPerQuads<GLValue::Ubyte>(seed, count, componentCount, stride, primitive, min.ub, max.ub);
1680                         break;
1681
1682                 case Array::INPUTTYPE_UNSIGNED_SHORT:
1683                         data = createPerQuads<GLValue::Ushort>(seed, count, componentCount, stride, primitive, min.us, max.us);
1684                         break;
1685
1686                 case Array::INPUTTYPE_UNSIGNED_INT:
1687                         data = createPerQuads<GLValue::Uint>(seed, count, componentCount, stride, primitive, min.ui, max.ui);
1688                         break;
1689
1690                 case Array::INPUTTYPE_INT:
1691                         data = createPerQuads<GLValue::Int>(seed, count, componentCount, stride, primitive, min.i, max.i);
1692                         break;
1693
1694                 case Array::INPUTTYPE_HALF:
1695                         data = createPerQuads<GLValue::Half>(seed, count, componentCount, stride, primitive, min.h, max.h);
1696                         break;
1697
1698                 default:
1699                         DE_ASSERT(false);
1700                         break;
1701         }
1702
1703         return data;
1704 }
1705
1706 template<typename T>
1707 char* RandomArrayGenerator::createPerQuads (int seed, int count, int componentCount, int stride, Array::Primitive primitive, T min, T max)
1708 {
1709         deRandom rnd;
1710         deRandom_init(&rnd, seed);
1711
1712         int componentStride = sizeof(T);
1713
1714         if (stride == 0)
1715                 stride = componentStride * componentCount;
1716
1717         int quadStride = 0;
1718
1719         switch (primitive)
1720         {
1721                 case Array::PRIMITIVE_TRIANGLES:
1722                         quadStride = stride * 6;
1723                         break;
1724
1725                 default:
1726                         DE_ASSERT(false);
1727                         break;
1728         }
1729
1730         char* data = new char[count * quadStride];
1731
1732         for (int quadNdx = 0; quadNdx < count; quadNdx++)
1733         {
1734                 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1735                 {
1736                         T val = getRandom<T>(rnd, min, max);
1737
1738                         alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 0 + componentStride * componentNdx, val);
1739                         alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 1 + componentStride * componentNdx, val);
1740                         alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 2 + componentStride * componentNdx, val);
1741                         alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 3 + componentStride * componentNdx, val);
1742                         alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 4 + componentStride * componentNdx, val);
1743                         alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 5 + componentStride * componentNdx, val);
1744                 }
1745         }
1746
1747         return data;
1748 }
1749
1750 // VertexArrayTest
1751
1752 VertexArrayTest::VertexArrayTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name ,const char* desc)
1753         : TestCase                      (testCtx, name, desc)
1754         , m_renderCtx           (renderCtx)
1755         , m_refBuffers          (DE_NULL)
1756         , m_refContext          (DE_NULL)
1757         , m_glesContext         (DE_NULL)
1758         , m_glArrayPack         (DE_NULL)
1759         , m_rrArrayPack         (DE_NULL)
1760         , m_isOk                        (false)
1761         , m_maxDiffRed          (deCeilFloatToInt32(256.0f * (2.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().redBits))))
1762         , m_maxDiffGreen        (deCeilFloatToInt32(256.0f * (2.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().greenBits))))
1763         , m_maxDiffBlue         (deCeilFloatToInt32(256.0f * (2.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().blueBits))))
1764 {
1765 }
1766
1767 VertexArrayTest::~VertexArrayTest (void)
1768 {
1769         deinit();
1770 }
1771
1772 void VertexArrayTest::init (void)
1773 {
1774         const int                                               renderTargetWidth       = de::min(512, m_renderCtx.getRenderTarget().getWidth());
1775         const int                                               renderTargetHeight      = de::min(512, m_renderCtx.getRenderTarget().getHeight());
1776         sglr::ReferenceContextLimits    limits                          (m_renderCtx);
1777
1778         m_glesContext           = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
1779
1780         m_refBuffers            = new sglr::ReferenceContextBuffers(m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, renderTargetWidth, renderTargetHeight);
1781         m_refContext            = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
1782
1783         m_glArrayPack           = new ContextArrayPack(m_renderCtx, *m_glesContext);
1784         m_rrArrayPack           = new ContextArrayPack(m_renderCtx, *m_refContext);
1785 }
1786
1787 void VertexArrayTest::deinit (void)
1788 {
1789         delete m_glArrayPack;
1790         delete m_rrArrayPack;
1791         delete m_refBuffers;
1792         delete m_refContext;
1793         delete m_glesContext;
1794
1795         m_glArrayPack   = DE_NULL;
1796         m_rrArrayPack   = DE_NULL;
1797         m_refBuffers    = DE_NULL;
1798         m_refContext    = DE_NULL;
1799         m_glesContext   = DE_NULL;
1800 }
1801
1802 void VertexArrayTest::compare (void)
1803 {
1804         const tcu::Surface&     ref             = m_rrArrayPack->getSurface();
1805         const tcu::Surface&     screen  = m_glArrayPack->getSurface();
1806
1807         if (m_renderCtx.getRenderTarget().getNumSamples() > 1)
1808         {
1809                 // \todo [mika] Improve compare when using multisampling
1810                 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;
1811                 m_isOk = tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", ref.getAccess(), screen.getAccess(), 1.5f, tcu::COMPARE_LOG_RESULT);
1812         }
1813         else
1814         {
1815                 tcu::RGBA               threshold       (m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue, 255);
1816                 tcu::Surface    error           (ref.getWidth(), ref.getHeight());
1817
1818                 m_isOk = true;
1819
1820                 for (int y = 1; y < ref.getHeight()-1; y++)
1821                 {
1822                         for (int x = 1; x < ref.getWidth()-1; x++)
1823                         {
1824                                 tcu::RGBA       refPixel                = ref.getPixel(x, y);
1825                                 tcu::RGBA       screenPixel             = screen.getPixel(x, y);
1826                                 bool            isOkPixel               = false;
1827
1828                                 // 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.
1829                                 // This fixes some false negatives.
1830                                 bool            refThin                 = (!tcu::compareThreshold(refPixel, ref.getPixel(x-1, y  ), threshold) && !tcu::compareThreshold(refPixel, ref.getPixel(x+1, y  ), threshold)) ||
1831                                                                                           (!tcu::compareThreshold(refPixel, ref.getPixel(x  , y-1), threshold) && !tcu::compareThreshold(refPixel, ref.getPixel(x  , y+1), threshold));
1832                                 bool            screenThin              = (!tcu::compareThreshold(screenPixel, screen.getPixel(x-1, y  ), threshold) && !tcu::compareThreshold(screenPixel, screen.getPixel(x+1, y  ), threshold)) ||
1833                                                                                           (!tcu::compareThreshold(screenPixel, screen.getPixel(x  , y-1), threshold) && !tcu::compareThreshold(screenPixel, screen.getPixel(x  , y+1), threshold));
1834
1835                                 if (refThin && screenThin)
1836                                         isOkPixel = true;
1837                                 else
1838                                 {
1839                                         for (int dy = -1; dy < 2 && !isOkPixel; dy++)
1840                                         {
1841                                                 for (int dx = -1; dx < 2 && !isOkPixel; dx++)
1842                                                 {
1843                                                         // Check reference pixel against screen pixel
1844                                                         {
1845                                                                 tcu::RGBA       screenCmpPixel  = screen.getPixel(x+dx, y+dy);
1846                                                                 deUint8         r                               = deAbs32(refPixel.getRed()             - screenCmpPixel.getRed());
1847                                                                 deUint8         g                               = deAbs32(refPixel.getGreen()   - screenCmpPixel.getGreen());
1848                                                                 deUint8         b                               = deAbs32(refPixel.getBlue()    - screenCmpPixel.getBlue());
1849
1850                                                                 if (r <= m_maxDiffRed && g <= m_maxDiffGreen && b <= m_maxDiffBlue)
1851                                                                         isOkPixel = true;
1852                                                         }
1853
1854                                                         // Check screen pixels against reference pixel
1855                                                         {
1856                                                                 tcu::RGBA       refCmpPixel             = ref.getPixel(x+dx, y+dy);
1857                                                                 deUint8         r                               = deAbs32(refCmpPixel.getRed()          - screenPixel.getRed());
1858                                                                 deUint8         g                               = deAbs32(refCmpPixel.getGreen()        - screenPixel.getGreen());
1859                                                                 deUint8         b                               = deAbs32(refCmpPixel.getBlue()         - screenPixel.getBlue());
1860
1861                                                                 if (r <= m_maxDiffRed && g <= m_maxDiffGreen && b <= m_maxDiffBlue)
1862                                                                         isOkPixel = true;
1863                                                         }
1864                                                 }
1865                                         }
1866                                 }
1867
1868                                 if (isOkPixel)
1869                                         error.setPixel(x, y, tcu::RGBA(screen.getPixel(x, y).getRed(), (screen.getPixel(x, y).getGreen() + 255) / 2, screen.getPixel(x, y).getBlue(), 255));
1870                                 else
1871                                 {
1872                                         error.setPixel(x, y, tcu::RGBA(255, 0, 0, 255));
1873                                         m_isOk = false;
1874                                 }
1875                         }
1876                 }
1877
1878                 tcu::TestLog& log = m_testCtx.getLog();
1879                 if (!m_isOk)
1880                 {
1881                         log << TestLog::Message << "Image comparison failed, threshold = (" << m_maxDiffRed << ", " << m_maxDiffGreen << ", " << m_maxDiffBlue << ")" << TestLog::EndMessage;
1882                         log << TestLog::ImageSet("Compare result", "Result of rendering")
1883                                 << TestLog::Image("Result",             "Result",               screen)
1884                                 << TestLog::Image("Reference",  "Reference",    ref)
1885                                 << TestLog::Image("ErrorMask",  "Error mask",   error)
1886                                 << TestLog::EndImageSet;
1887                 }
1888                 else
1889                 {
1890                         log << TestLog::ImageSet("Compare result", "Result of rendering")
1891                                 << TestLog::Image("Result", "Result", screen)
1892                                 << TestLog::EndImageSet;
1893                 }
1894         }
1895 }
1896
1897 // MultiVertexArrayTest
1898
1899 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_)
1900         : inputType             (inputType_)
1901         , outputType    (outputType_)
1902         , storage               (storage_)
1903         , usage                 (usage_)
1904         , componentCount(componentCount_)
1905         , offset                (offset_)
1906         , stride                (stride_)
1907         , normalize             (normalize_)
1908         , min                   (min_)
1909         , max                   (max_)
1910 {
1911 }
1912
1913 std::string MultiVertexArrayTest::Spec::getName (void) const
1914 {
1915         std::stringstream name;
1916
1917         for (size_t ndx = 0; ndx < arrays.size(); ++ndx)
1918         {
1919                 const ArraySpec& array = arrays[ndx];
1920
1921                 if (arrays.size() > 1)
1922                         name << "array" << ndx << "_";
1923
1924                 name
1925                         << Array::storageToString(array.storage) << "_"
1926                         << array.offset << "_"
1927                         << array.stride << "_"
1928                         << Array::inputTypeToString((Array::InputType)array.inputType);
1929                 if (array.inputType != Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && array.inputType != Array::INPUTTYPE_INT_2_10_10_10)
1930                         name << array.componentCount;
1931                 name
1932                         << "_"
1933                         << (array.normalize ? "normalized_" : "")
1934                         << Array::outputTypeToString(array.outputType) << "_"
1935                         << Array::usageTypeToString(array.usage) << "_";
1936         }
1937
1938         if (first)
1939                 name << "first" << first << "_";
1940
1941         switch (primitive)
1942         {
1943                 case Array::PRIMITIVE_TRIANGLES:
1944                         name << "quads_";
1945                         break;
1946                 case Array::PRIMITIVE_POINTS:
1947                         name << "points_";
1948                         break;
1949
1950                 default:
1951                         DE_ASSERT(false);
1952                         break;
1953         }
1954
1955         name << drawCount;
1956
1957         return name.str();
1958 }
1959
1960 std::string MultiVertexArrayTest::Spec::getDesc (void) const
1961 {
1962         std::stringstream desc;
1963
1964         for (size_t ndx = 0; ndx < arrays.size(); ++ndx)
1965         {
1966                 const ArraySpec& array = arrays[ndx];
1967
1968                 desc
1969                         << "Array " << ndx << ": "
1970                         << "Storage in " << Array::storageToString(array.storage) << ", "
1971                         << "stride " << array.stride << ", "
1972                         << "input datatype " << Array::inputTypeToString((Array::InputType)array.inputType) << ", "
1973                         << "input component count " << array.componentCount << ", "
1974                         << (array.normalize ? "normalized, " : "")
1975                         << "used as " << Array::outputTypeToString(array.outputType) << ", ";
1976         }
1977
1978         desc
1979                 << "drawArrays(), "
1980                 << "first " << first << ", "
1981                 << drawCount;
1982
1983         switch (primitive)
1984         {
1985                 case Array::PRIMITIVE_TRIANGLES:
1986                         desc << "quads ";
1987                         break;
1988                 case Array::PRIMITIVE_POINTS:
1989                         desc << "points";
1990                         break;
1991
1992                 default:
1993                         DE_ASSERT(false);
1994                         break;
1995         }
1996
1997
1998         return desc.str();
1999 }
2000
2001 MultiVertexArrayTest::MultiVertexArrayTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const Spec& spec, const char* name, const char* desc)
2002         : VertexArrayTest       (testCtx, renderCtx, name, desc)
2003         , m_spec                        (spec)
2004         , m_iteration           (0)
2005 {
2006 }
2007
2008 MultiVertexArrayTest::~MultiVertexArrayTest     (void)
2009 {
2010 }
2011
2012 MultiVertexArrayTest::IterateResult MultiVertexArrayTest::iterate (void)
2013 {
2014         if (m_iteration == 0)
2015         {
2016                 const size_t    primitiveSize           = (m_spec.primitive == Array::PRIMITIVE_TRIANGLES) ? (6) : (1); // in non-indexed draw Triangles means rectangles
2017                 float                   coordScale                      = 1.0f;
2018                 float                   colorScale                      = 1.0f;
2019                 const bool              useVao                          = m_renderCtx.getType().getProfile() == glu::PROFILE_CORE;
2020
2021                 // Log info
2022                 m_testCtx.getLog() << TestLog::Message << m_spec.getDesc() << TestLog::EndMessage;
2023
2024                 // Color and Coord scale
2025                 {
2026                         // First array is always position
2027                         {
2028                                 Spec::ArraySpec arraySpec = m_spec.arrays[0];
2029                                 if (arraySpec.inputType == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
2030                                 {
2031                                         if (arraySpec.normalize)
2032                                                 coordScale = 1.0f;
2033                                         else
2034                                                 coordScale = 1.0 / 1024.0;
2035                                 }
2036                                 else if (arraySpec.inputType == Array::INPUTTYPE_INT_2_10_10_10)
2037                                 {
2038                                         if (arraySpec.normalize)
2039                                                 coordScale = 1.0f;
2040                                         else
2041                                                 coordScale = 1.0 / 512.0;
2042                                 }
2043                                 else
2044                                         coordScale = (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(0.9 / double(arraySpec.max.toFloat())));
2045
2046                                 if (arraySpec.outputType == Array::OUTPUTTYPE_VEC3 || arraySpec.outputType == Array::OUTPUTTYPE_VEC4
2047                                         || arraySpec.outputType == Array::OUTPUTTYPE_IVEC3 || arraySpec.outputType == Array::OUTPUTTYPE_IVEC4
2048                                         || arraySpec.outputType == Array::OUTPUTTYPE_UVEC3 || arraySpec.outputType == Array::OUTPUTTYPE_UVEC4)
2049                                                 coordScale = coordScale * 0.5f;
2050                         }
2051
2052                         // And other arrays are color-like
2053                         for (int arrayNdx = 1; arrayNdx < (int)m_spec.arrays.size(); arrayNdx++)
2054                         {
2055                                 Spec::ArraySpec arraySpec       = m_spec.arrays[arrayNdx];
2056
2057                                 colorScale *= (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(1.0 / double(arraySpec.max.toFloat())));
2058                                 if (arraySpec.outputType == Array::OUTPUTTYPE_VEC4)
2059                                         colorScale *= (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(1.0 / double(arraySpec.max.toFloat())));
2060                         }
2061                 }
2062
2063                 // Data
2064                 for (int arrayNdx = 0; arrayNdx < (int)m_spec.arrays.size(); arrayNdx++)
2065                 {
2066                         Spec::ArraySpec arraySpec               = m_spec.arrays[arrayNdx];
2067                         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);
2068                         const char*             data                    = DE_NULL;
2069                         const size_t    stride                  = (arraySpec.stride == 0) ? (arraySpec.componentCount * Array::inputTypeSize(arraySpec.inputType)) : (arraySpec.stride);
2070                         const size_t    bufferSize              = arraySpec.offset + stride * (m_spec.drawCount * primitiveSize - 1) + arraySpec.componentCount  * Array::inputTypeSize(arraySpec.inputType);
2071
2072                         switch (m_spec.primitive)
2073                         {
2074         //                      case Array::PRIMITIVE_POINTS:
2075         //                              data = RandomArrayGenerator::generateArray(seed, arraySpec.min, arraySpec.max, arraySpec.count, arraySpec.componentCount, arraySpec.stride, arraySpec.inputType);
2076         //                              break;
2077                                 case Array::PRIMITIVE_TRIANGLES:
2078                                         if (arrayNdx == 0)
2079                                         {
2080                                                 data = RandomArrayGenerator::generateQuads(seed, m_spec.drawCount, arraySpec.componentCount, arraySpec.offset, arraySpec.stride, m_spec.primitive, arraySpec.inputType, arraySpec.min, arraySpec.max);
2081                                         }
2082                                         else
2083                                         {
2084                                                 DE_ASSERT(arraySpec.offset == 0); // \note [jarkko] it just hasn't been implemented
2085                                                 data = RandomArrayGenerator::generatePerQuad(seed, m_spec.drawCount, arraySpec.componentCount, arraySpec.stride, m_spec.primitive, arraySpec.inputType, arraySpec.min, arraySpec.max);
2086                                         }
2087                                         break;
2088
2089                                 default:
2090                                         DE_ASSERT(false);
2091                                         break;
2092                         }
2093
2094                         m_glArrayPack->newArray(arraySpec.storage);
2095                         m_rrArrayPack->newArray(arraySpec.storage);
2096
2097                         m_glArrayPack->getArray(arrayNdx)->data(Array::TARGET_ARRAY, (int)bufferSize, data, arraySpec.usage);
2098                         m_rrArrayPack->getArray(arrayNdx)->data(Array::TARGET_ARRAY, (int)bufferSize, data, arraySpec.usage);
2099
2100                         m_glArrayPack->getArray(arrayNdx)->bind(arrayNdx, arraySpec.offset, arraySpec.componentCount, arraySpec.inputType, arraySpec.outputType, arraySpec.normalize, arraySpec.stride);
2101                         m_rrArrayPack->getArray(arrayNdx)->bind(arrayNdx, arraySpec.offset, arraySpec.componentCount, arraySpec.inputType, arraySpec.outputType, arraySpec.normalize, arraySpec.stride);
2102
2103                         delete [] data;
2104                 }
2105
2106                 try
2107                 {
2108                         m_glArrayPack->render(m_spec.primitive, m_spec.first, m_spec.drawCount * (int)primitiveSize, useVao, coordScale, colorScale);
2109                         m_rrArrayPack->render(m_spec.primitive, m_spec.first, m_spec.drawCount * (int)primitiveSize, useVao, coordScale, colorScale);
2110                 }
2111                 catch (glu::Error& err)
2112                 {
2113                         // GL Errors are ok if the mode is not properly aligned
2114
2115                         m_testCtx.getLog() << TestLog::Message << "Got error: " << err.what() << TestLog::EndMessage;
2116
2117                         if (isUnalignedBufferOffsetTest())
2118                                 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
2119                         else if (isUnalignedBufferStrideTest())
2120                                 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
2121                         else
2122                                 throw;
2123
2124                         return STOP;
2125                 }
2126
2127                 m_iteration++;
2128                 return CONTINUE;
2129         }
2130         else if (m_iteration == 1)
2131         {
2132                 compare();
2133
2134                 if (m_isOk)
2135                 {
2136                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2137                 }
2138                 else
2139                 {
2140                         if (isUnalignedBufferOffsetTest())
2141                                 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
2142                         else if (isUnalignedBufferStrideTest())
2143                                 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
2144                         else
2145                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed.");
2146                 }
2147
2148                 m_iteration++;
2149                 return STOP;
2150         }
2151         else
2152         {
2153                 DE_ASSERT(false);
2154                 return STOP;
2155         }
2156 }
2157
2158 bool MultiVertexArrayTest::isUnalignedBufferOffsetTest (void) const
2159 {
2160         // Buffer offsets should be data type size aligned
2161         for (size_t i = 0; i < m_spec.arrays.size(); ++i)
2162         {
2163                 if (m_spec.arrays[i].storage == Array::STORAGE_BUFFER)
2164                 {
2165                         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;
2166
2167                         int dataTypeSize = Array::inputTypeSize(m_spec.arrays[i].inputType);
2168                         if (inputTypePacked)
2169                                 dataTypeSize = 4;
2170
2171                         if (m_spec.arrays[i].offset % dataTypeSize != 0)
2172                                 return true;
2173                 }
2174         }
2175
2176         return false;
2177 }
2178
2179 bool MultiVertexArrayTest::isUnalignedBufferStrideTest (void) const
2180 {
2181         // Buffer strides 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].stride % dataTypeSize != 0)
2193                                 return true;
2194                 }
2195         }
2196
2197         return false;
2198 }
2199
2200 } // gls
2201 } // deqp