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