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