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