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