1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) Module
3  * -----------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Vertex array and buffer tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "glsVertexArrayTests.hpp"
25 
26 #include "deRandom.h"
27 
28 #include "tcuTestLog.hpp"
29 #include "tcuPixelFormat.hpp"
30 #include "tcuRGBA.hpp"
31 #include "tcuSurface.hpp"
32 #include "tcuVector.hpp"
33 #include "tcuTestLog.hpp"
34 #include "tcuRenderTarget.hpp"
35 #include "tcuStringTemplate.hpp"
36 #include "tcuImageCompare.hpp"
37 
38 #include "gluPixelTransfer.hpp"
39 #include "gluCallLogWrapper.hpp"
40 
41 #include "sglrContext.hpp"
42 #include "sglrReferenceContext.hpp"
43 #include "sglrGLContext.hpp"
44 
45 #include "deMath.h"
46 #include "deStringUtil.hpp"
47 #include "deArrayUtil.hpp"
48 
49 #include <cstring>
50 #include <cmath>
51 #include <vector>
52 #include <sstream>
53 #include <limits>
54 #include <algorithm>
55 
56 #include "glwDefs.hpp"
57 #include "glwEnums.hpp"
58 
59 namespace deqp
60 {
61 namespace gls
62 {
63 
64 using tcu::TestLog;
65 using namespace glw; // GL types
66 
targetToString(Target target)67 std::string Array::targetToString(Target target)
68 {
69 	static const char* targets[] =
70 	{
71 		"element_array",	// TARGET_ELEMENT_ARRAY = 0,
72 		"array"				// TARGET_ARRAY,
73 	};
74 
75 	return de::getSizedArrayElement<Array::TARGET_LAST>(targets, (int)target);
76 }
77 
inputTypeToString(InputType type)78 std::string Array::inputTypeToString(InputType type)
79 {
80 	static const char* types[] =
81 	{
82 		"float",			// INPUTTYPE_FLOAT = 0,
83 		"fixed",			// INPUTTYPE_FIXED,
84 		"double",			// INPUTTYPE_DOUBLE
85 
86 		"byte",				// INPUTTYPE_BYTE,
87 		"short",			// INPUTTYPE_SHORT,
88 
89 		"unsigned_byte",	// INPUTTYPE_UNSIGNED_BYTE,
90 		"unsigned_short",	// INPUTTYPE_UNSIGNED_SHORT,
91 
92 		"int",						// INPUTTYPE_INT,
93 		"unsigned_int",				// INPUTTYPE_UNSIGNED_INT,
94 		"half",						// INPUTTYPE_HALF,
95 		"usigned_int2_10_10_10",	// INPUTTYPE_UNSIGNED_INT_2_10_10_10,
96 		"int2_10_10_10"				// INPUTTYPE_INT_2_10_10_10,
97 	};
98 
99 	return de::getSizedArrayElement<Array::INPUTTYPE_LAST>(types, (int)type);
100 }
101 
outputTypeToString(OutputType type)102 std::string Array::outputTypeToString(OutputType type)
103 {
104 	static const char* types[] =
105 	{
106 		"float",		// OUTPUTTYPE_FLOAT = 0,
107 		"vec2",			// OUTPUTTYPE_VEC2,
108 		"vec3",			// OUTPUTTYPE_VEC3,
109 		"vec4",			// OUTPUTTYPE_VEC4,
110 
111 		"int",			// OUTPUTTYPE_INT,
112 		"uint",			// OUTPUTTYPE_UINT,
113 
114 		"ivec2",		// OUTPUTTYPE_IVEC2,
115 		"ivec3",		// OUTPUTTYPE_IVEC3,
116 		"ivec4",		// OUTPUTTYPE_IVEC4,
117 
118 		"uvec2",		// OUTPUTTYPE_UVEC2,
119 		"uvec3",		// OUTPUTTYPE_UVEC3,
120 		"uvec4",		// OUTPUTTYPE_UVEC4,
121 	};
122 
123 	return de::getSizedArrayElement<Array::OUTPUTTYPE_LAST>(types, (int)type);
124 }
125 
usageTypeToString(Usage usage)126 std::string Array::usageTypeToString(Usage usage)
127 {
128 	static const char* usages[] =
129 	{
130 		"dynamic_draw",	// USAGE_DYNAMIC_DRAW = 0,
131 		"static_draw",	// USAGE_STATIC_DRAW,
132 		"stream_draw",	// USAGE_STREAM_DRAW,
133 
134 		"stream_read",	// USAGE_STREAM_READ,
135 		"stream_copy",	// USAGE_STREAM_COPY,
136 
137 		"static_read",	// USAGE_STATIC_READ,
138 		"static_copy",	// USAGE_STATIC_COPY,
139 
140 		"dynamic_read",	// USAGE_DYNAMIC_READ,
141 		"dynamic_copy",	// USAGE_DYNAMIC_COPY,
142 	};
143 
144 	return de::getSizedArrayElement<Array::USAGE_LAST>(usages, (int)usage);
145 }
146 
storageToString(Storage storage)147 std::string	Array::storageToString (Storage storage)
148 {
149 	static const char* storages[] =
150 	{
151 		"user_ptr",	// STORAGE_USER = 0,
152 		"buffer"	// STORAGE_BUFFER,
153 	};
154 
155 	return de::getSizedArrayElement<Array::STORAGE_LAST>(storages, (int)storage);
156 }
157 
primitiveToString(Primitive primitive)158 std::string Array::primitiveToString (Primitive primitive)
159 {
160 	static const char* primitives[] =
161 	{
162 		"points",			// PRIMITIVE_POINTS ,
163 		"triangles",		// PRIMITIVE_TRIANGLES,
164 		"triangle_fan",		// PRIMITIVE_TRIANGLE_FAN,
165 		"triangle_strip"	// PRIMITIVE_TRIANGLE_STRIP,
166 	};
167 
168 	return de::getSizedArrayElement<Array::PRIMITIVE_LAST>(primitives, (int)primitive);
169 }
170 
inputTypeSize(InputType type)171 int Array::inputTypeSize (InputType type)
172 {
173 	static const int size[] =
174 	{
175 		(int)sizeof(float),			// INPUTTYPE_FLOAT = 0,
176 		(int)sizeof(deInt32),		// INPUTTYPE_FIXED,
177 		(int)sizeof(double),		// INPUTTYPE_DOUBLE
178 
179 		(int)sizeof(deInt8),		// INPUTTYPE_BYTE,
180 		(int)sizeof(deInt16),		// INPUTTYPE_SHORT,
181 
182 		(int)sizeof(deUint8),		// INPUTTYPE_UNSIGNED_BYTE,
183 		(int)sizeof(deUint16),		// INPUTTYPE_UNSIGNED_SHORT,
184 
185 		(int)sizeof(deInt32),		// INPUTTYPE_INT,
186 		(int)sizeof(deUint32),		// INPUTTYPE_UNSIGNED_INT,
187 		(int)sizeof(deFloat16),		// INPUTTYPE_HALF,
188 		(int)sizeof(deUint32) / 4,	// INPUTTYPE_UNSIGNED_INT_2_10_10_10,
189 		(int)sizeof(deUint32) / 4	// INPUTTYPE_INT_2_10_10_10,
190 	};
191 
192 	return de::getSizedArrayElement<Array::INPUTTYPE_LAST>(size, (int)type);
193 }
194 
inputTypeIsFloatType(Array::InputType type)195 static bool inputTypeIsFloatType (Array::InputType type)
196 {
197 	if (type == Array::INPUTTYPE_FLOAT)
198 		return true;
199 	if (type == Array::INPUTTYPE_FIXED)
200 		return true;
201 	if (type == Array::INPUTTYPE_DOUBLE)
202 		return true;
203 	if (type == Array::INPUTTYPE_HALF)
204 		return true;
205 	return false;
206 }
207 
outputTypeIsFloatType(Array::OutputType type)208 static bool outputTypeIsFloatType (Array::OutputType type)
209 {
210 	if (type == Array::OUTPUTTYPE_FLOAT
211 		|| type == Array::OUTPUTTYPE_VEC2
212 		|| type == Array::OUTPUTTYPE_VEC3
213 		|| type == Array::OUTPUTTYPE_VEC4)
214 		return true;
215 
216 	return false;
217 }
218 
219 template<class T>
220 inline T getRandom (deRandom& rnd, T min, T max);
221 
222 template<>
getRandom(deRandom & rnd,GLValue::Float min,GLValue::Float max)223 inline GLValue::Float getRandom (deRandom& rnd, GLValue::Float min, GLValue::Float max)
224 {
225 	if (max < min)
226 		return min;
227 
228 	return GLValue::Float::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>()));
229 }
230 
231 template<>
getRandom(deRandom & rnd,GLValue::Short min,GLValue::Short max)232 inline GLValue::Short getRandom (deRandom& rnd, GLValue::Short min, GLValue::Short max)
233 {
234 	if (max < min)
235 		return min;
236 
237 	return GLValue::Short::create((min == max ? min : (deInt16)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
238 }
239 
240 template<>
getRandom(deRandom & rnd,GLValue::Ushort min,GLValue::Ushort max)241 inline GLValue::Ushort getRandom (deRandom& rnd, GLValue::Ushort min, GLValue::Ushort max)
242 {
243 	if (max < min)
244 		return min;
245 
246 	return GLValue::Ushort::create((min == max ? min : (deUint16)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
247 }
248 
249 template<>
getRandom(deRandom & rnd,GLValue::Byte min,GLValue::Byte max)250 inline GLValue::Byte getRandom (deRandom& rnd, GLValue::Byte min, GLValue::Byte max)
251 {
252 	if (max < min)
253 		return min;
254 
255 	return GLValue::Byte::create((min == max ? min : (deInt8)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
256 }
257 
258 template<>
getRandom(deRandom & rnd,GLValue::Ubyte min,GLValue::Ubyte max)259 inline GLValue::Ubyte getRandom (deRandom& rnd, GLValue::Ubyte min, GLValue::Ubyte max)
260 {
261 	if (max < min)
262 		return min;
263 
264 	return GLValue::Ubyte::create((min == max ? min : (deUint8)(min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))));
265 }
266 
267 template<>
getRandom(deRandom & rnd,GLValue::Fixed min,GLValue::Fixed max)268 inline GLValue::Fixed getRandom (deRandom& rnd, GLValue::Fixed min, GLValue::Fixed max)
269 {
270 	if (max < min)
271 		return min;
272 
273 	return GLValue::Fixed::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
274 }
275 
276 template<>
getRandom(deRandom & rnd,GLValue::Half min,GLValue::Half max)277 inline GLValue::Half getRandom (deRandom& rnd, GLValue::Half min, GLValue::Half max)
278 {
279 	if (max < min)
280 		return min;
281 
282 	float fMax = max.to<float>();
283 	float fMin = min.to<float>();
284 	GLValue::Half h = GLValue::Half::create(fMin + deRandom_getFloat(&rnd) * (fMax - fMin));
285 	return h;
286 }
287 
288 template<>
getRandom(deRandom & rnd,GLValue::Int min,GLValue::Int max)289 inline GLValue::Int getRandom (deRandom& rnd, GLValue::Int min, GLValue::Int max)
290 {
291 	if (max < min)
292 		return min;
293 
294 	return GLValue::Int::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
295 }
296 
297 template<>
getRandom(deRandom & rnd,GLValue::Uint min,GLValue::Uint max)298 inline GLValue::Uint getRandom (deRandom& rnd, GLValue::Uint min, GLValue::Uint max)
299 {
300 	if (max < min)
301 		return min;
302 
303 	return GLValue::Uint::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
304 }
305 
306 template<>
getRandom(deRandom & rnd,GLValue::Double min,GLValue::Double max)307 inline GLValue::Double getRandom (deRandom& rnd, GLValue::Double min, GLValue::Double max)
308 {
309 	if (max < min)
310 		return min;
311 
312 	return GLValue::Double::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>()));
313 }
314 
315 // Minimum difference required between coordinates
316 template<class T>
317 inline T minValue (void);
318 
319 template<>
minValue(void)320 inline GLValue::Float minValue (void)
321 {
322 	return GLValue::Float::create(4 * 1.0f);
323 }
324 
325 template<>
minValue(void)326 inline GLValue::Short minValue (void)
327 {
328 	return GLValue::Short::create(4 * 256);
329 }
330 
331 template<>
minValue(void)332 inline GLValue::Ushort minValue (void)
333 {
334 	return GLValue::Ushort::create(4 * 256);
335 }
336 
337 template<>
minValue(void)338 inline GLValue::Byte minValue (void)
339 {
340 	return GLValue::Byte::create(4 * 1);
341 }
342 
343 template<>
minValue(void)344 inline GLValue::Ubyte minValue (void)
345 {
346 	return GLValue::Ubyte::create(4 * 2);
347 }
348 
349 template<>
minValue(void)350 inline GLValue::Fixed minValue (void)
351 {
352 	return GLValue::Fixed::create(4 * 512);
353 }
354 
355 template<>
minValue(void)356 inline GLValue::Int minValue (void)
357 {
358 	return GLValue::Int::create(4 * 16777216);
359 }
360 
361 template<>
minValue(void)362 inline GLValue::Uint minValue (void)
363 {
364 	return GLValue::Uint::create(4 * 16777216);
365 }
366 
367 template<>
minValue(void)368 inline GLValue::Half minValue (void)
369 {
370 	return GLValue::Half::create(4 * 1.0f);
371 }
372 
373 template<>
minValue(void)374 inline GLValue::Double minValue (void)
375 {
376 	return GLValue::Double::create(4 * 1.0f);
377 }
378 
379 template<class T>
380 inline T abs (T val);
381 
382 template<>
abs(GLValue::Fixed val)383 inline GLValue::Fixed abs (GLValue::Fixed val)
384 {
385 	return GLValue::Fixed::create(0x7FFFu & val.getValue());
386 }
387 
388 template<>
abs(GLValue::Ubyte val)389 inline GLValue::Ubyte abs (GLValue::Ubyte val)
390 {
391 	return val;
392 }
393 
394 template<>
abs(GLValue::Byte val)395 inline GLValue::Byte abs (GLValue::Byte val)
396 {
397 	return GLValue::Byte::create(0x7Fu & val.getValue());
398 }
399 
400 template<>
abs(GLValue::Ushort val)401 inline GLValue::Ushort abs (GLValue::Ushort val)
402 {
403 	return val;
404 }
405 
406 template<>
abs(GLValue::Short val)407 inline GLValue::Short abs (GLValue::Short val)
408 {
409 	return GLValue::Short::create(0x7FFFu & val.getValue());
410 }
411 
412 template<>
abs(GLValue::Float val)413 inline GLValue::Float abs (GLValue::Float val)
414 {
415 	return GLValue::Float::create(std::fabs(val.to<float>()));
416 }
417 
418 template<>
abs(GLValue::Uint val)419 inline GLValue::Uint abs (GLValue::Uint val)
420 {
421 	return val;
422 }
423 
424 template<>
abs(GLValue::Int val)425 inline GLValue::Int abs (GLValue::Int val)
426 {
427 	return GLValue::Int::create(0x7FFFFFFFu & val.getValue());
428 }
429 
430 template<>
abs(GLValue::Half val)431 inline GLValue::Half abs (GLValue::Half val)
432 {
433 	return GLValue::Half::create(std::fabs(val.to<float>()));
434 }
435 
436 template<>
abs(GLValue::Double val)437 inline GLValue::Double abs (GLValue::Double val)
438 {
439 	return GLValue::Double::create(std::fabs(val.to<float>()));
440 }
441 
442 template<class T>
alignmentSafeAssignment(char * dst,T val)443 static inline void alignmentSafeAssignment (char* dst, T val)
444 {
445 	std::memcpy(dst, &val, sizeof(T));
446 }
447 
ContextArray(Storage storage,sglr::Context & context)448 ContextArray::ContextArray (Storage storage, sglr::Context& context)
449 	: m_storage			(storage)
450 	, m_ctx				(context)
451 	, m_glBuffer		(0)
452 	, m_bound			(false)
453 	, m_attribNdx		(0)
454 	, m_size			(0)
455 	, m_data			(DE_NULL)
456 	, m_componentCount	(1)
457 	, m_target			(Array::TARGET_ARRAY)
458 	, m_inputType		(Array::INPUTTYPE_FLOAT)
459 	, m_outputType		(Array::OUTPUTTYPE_VEC4)
460 	, m_normalize		(false)
461 	, m_stride			(0)
462 	, m_offset			(0)
463 {
464 	if (m_storage == STORAGE_BUFFER)
465 	{
466 		m_ctx.genBuffers(1, &m_glBuffer);
467 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glGenBuffers()");
468 	}
469 }
470 
~ContextArray(void)471 ContextArray::~ContextArray	(void)
472 {
473 	if (m_storage == STORAGE_BUFFER)
474 	{
475 		m_ctx.deleteBuffers(1, &m_glBuffer);
476 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDeleteBuffers()");
477 	}
478 	else if (m_storage == STORAGE_USER)
479 		delete[] m_data;
480 	else
481 		DE_ASSERT(false);
482 }
483 
getArray(int i)484 Array* ContextArrayPack::getArray (int i)
485 {
486 	return m_arrays.at(i);
487 }
488 
data(Target target,int size,const char * ptr,Usage usage)489 void ContextArray::data (Target target, int size, const char* ptr, Usage usage)
490 {
491 	m_size = size;
492 	m_target = target;
493 
494 	if (m_storage == STORAGE_BUFFER)
495 	{
496 		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
497 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
498 
499 		m_ctx.bufferData(targetToGL(target), size, ptr, usageToGL(usage));
500 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferData()");
501 	}
502 	else if (m_storage == STORAGE_USER)
503 	{
504 		if (m_data)
505 			delete[] m_data;
506 
507 		m_data = new char[size];
508 		std::memcpy(m_data, ptr, size);
509 	}
510 	else
511 		DE_ASSERT(false);
512 }
513 
subdata(Target target,int offset,int size,const char * ptr)514 void ContextArray::subdata (Target target, int offset, int size, const char* ptr)
515 {
516 	m_target = target;
517 
518 	if (m_storage == STORAGE_BUFFER)
519 	{
520 		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
521 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
522 
523 		m_ctx.bufferSubData(targetToGL(target), offset, size, ptr);
524 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferSubData()");
525 	}
526 	else if (m_storage == STORAGE_USER)
527 		std::memcpy(m_data + offset, ptr, size);
528 	else
529 		DE_ASSERT(false);
530 }
531 
bind(int attribNdx,int offset,int size,InputType inputType,OutputType outType,bool normalized,int stride)532 void ContextArray::bind (int attribNdx, int offset, int size, InputType inputType, OutputType outType, bool normalized, int stride)
533 {
534 	m_attribNdx			= attribNdx;
535 	m_bound				= true;
536 	m_componentCount	= size;
537 	m_inputType			= inputType;
538 	m_outputType		= outType;
539 	m_normalize			= normalized;
540 	m_stride			= stride;
541 	m_offset			= offset;
542 }
543 
bindIndexArray(Array::Target target)544 void ContextArray::bindIndexArray (Array::Target target)
545 {
546 	if (m_storage == STORAGE_USER)
547 	{
548 	}
549 	else if (m_storage == STORAGE_BUFFER)
550 	{
551 		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
552 	}
553 }
554 
glBind(deUint32 loc)555 void ContextArray::glBind (deUint32 loc)
556 {
557 	if (m_storage == STORAGE_BUFFER)
558 	{
559 		m_ctx.bindBuffer(targetToGL(m_target), m_glBuffer);
560 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
561 
562 		if (!inputTypeIsFloatType(m_inputType))
563 		{
564 			// Input is not float type
565 
566 			if (outputTypeIsFloatType(m_outputType))
567 			{
568 				// Output type is float type
569 				m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, (GLvoid*)((GLintptr)m_offset));
570 				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
571 			}
572 			else
573 			{
574 				// Output type is int type
575 				m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, (GLvoid*)((GLintptr)m_offset));
576 				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
577 			}
578 		}
579 		else
580 		{
581 			// Input type is float type
582 
583 			// Output type must be float type
584 			DE_ASSERT(m_outputType == OUTPUTTYPE_FLOAT || m_outputType == OUTPUTTYPE_VEC2 || m_outputType == OUTPUTTYPE_VEC3 || m_outputType == OUTPUTTYPE_VEC4);
585 
586 			m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, (GLvoid*)((GLintptr)m_offset));
587 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
588 		}
589 
590 		m_ctx.bindBuffer(targetToGL(m_target), 0);
591 	}
592 	else if (m_storage == STORAGE_USER)
593 	{
594 		m_ctx.bindBuffer(targetToGL(m_target), 0);
595 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
596 
597 		if (!inputTypeIsFloatType(m_inputType))
598 		{
599 			// Input is not float type
600 
601 			if (outputTypeIsFloatType(m_outputType))
602 			{
603 				// Output type is float type
604 				m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, m_data + m_offset);
605 				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
606 			}
607 			else
608 			{
609 				// Output type is int type
610 				m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, m_data + m_offset);
611 				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
612 			}
613 		}
614 		else
615 		{
616 			// Input type is float type
617 
618 			// Output type must be float type
619 			DE_ASSERT(m_outputType == OUTPUTTYPE_FLOAT || m_outputType == OUTPUTTYPE_VEC2 || m_outputType == OUTPUTTYPE_VEC3 || m_outputType == OUTPUTTYPE_VEC4);
620 
621 			m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, m_data + m_offset);
622 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
623 		}
624 	}
625 	else
626 		DE_ASSERT(false);
627 }
628 
targetToGL(Array::Target target)629 GLenum ContextArray::targetToGL (Array::Target target)
630 {
631 	static const GLenum targets[] =
632 	{
633 		GL_ELEMENT_ARRAY_BUFFER,	// TARGET_ELEMENT_ARRAY = 0,
634 		GL_ARRAY_BUFFER				// TARGET_ARRAY,
635 	};
636 
637 	return de::getSizedArrayElement<Array::TARGET_LAST>(targets, (int)target);
638 }
639 
usageToGL(Array::Usage usage)640 GLenum ContextArray::usageToGL (Array::Usage usage)
641 {
642 	static const GLenum usages[] =
643 	{
644 		GL_DYNAMIC_DRAW,	// USAGE_DYNAMIC_DRAW = 0,
645 		GL_STATIC_DRAW,		// USAGE_STATIC_DRAW,
646 		GL_STREAM_DRAW,		// USAGE_STREAM_DRAW,
647 
648 		GL_STREAM_READ,		// USAGE_STREAM_READ,
649 		GL_STREAM_COPY,		// USAGE_STREAM_COPY,
650 
651 		GL_STATIC_READ,		// USAGE_STATIC_READ,
652 		GL_STATIC_COPY,		// USAGE_STATIC_COPY,
653 
654 		GL_DYNAMIC_READ,	// USAGE_DYNAMIC_READ,
655 		GL_DYNAMIC_COPY		// USAGE_DYNAMIC_COPY,
656 	};
657 
658 	return de::getSizedArrayElement<Array::USAGE_LAST>(usages, (int)usage);
659 }
660 
inputTypeToGL(Array::InputType type)661 GLenum ContextArray::inputTypeToGL (Array::InputType type)
662 {
663 	static const GLenum types[] =
664 	{
665 		GL_FLOAT,				// INPUTTYPE_FLOAT = 0,
666 		GL_FIXED,				// INPUTTYPE_FIXED,
667 		GL_DOUBLE,				// INPUTTYPE_DOUBLE
668 		GL_BYTE,				// INPUTTYPE_BYTE,
669 		GL_SHORT,				// INPUTTYPE_SHORT,
670 		GL_UNSIGNED_BYTE,		// INPUTTYPE_UNSIGNED_BYTE,
671 		GL_UNSIGNED_SHORT,		// INPUTTYPE_UNSIGNED_SHORT,
672 
673 		GL_INT,					// INPUTTYPE_INT,
674 		GL_UNSIGNED_INT,		// INPUTTYPE_UNSIGNED_INT,
675 		GL_HALF_FLOAT,			// INPUTTYPE_HALF,
676 		GL_UNSIGNED_INT_2_10_10_10_REV, // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
677 		GL_INT_2_10_10_10_REV			// INPUTTYPE_INT_2_10_10_10,
678 	};
679 
680 	return de::getSizedArrayElement<Array::INPUTTYPE_LAST>(types, (int)type);
681 }
682 
outputTypeToGLType(Array::OutputType type)683 std::string ContextArray::outputTypeToGLType (Array::OutputType type)
684 {
685 	static const char* types[] =
686 	{
687 		"float",		// OUTPUTTYPE_FLOAT = 0,
688 		"vec2",			// OUTPUTTYPE_VEC2,
689 		"vec3",			// OUTPUTTYPE_VEC3,
690 		"vec4",			// OUTPUTTYPE_VEC4,
691 
692 		"int",			// OUTPUTTYPE_INT,
693 		"uint",			// OUTPUTTYPE_UINT,
694 
695 		"ivec2",		// OUTPUTTYPE_IVEC2,
696 		"ivec3",		// OUTPUTTYPE_IVEC3,
697 		"ivec4",		// OUTPUTTYPE_IVEC4,
698 
699 		"uvec2",		// OUTPUTTYPE_UVEC2,
700 		"uvec3",		// OUTPUTTYPE_UVEC3,
701 		"uvec4",		// OUTPUTTYPE_UVEC4,
702 	};
703 
704 	return de::getSizedArrayElement<Array::OUTPUTTYPE_LAST>(types, (int)type);
705 }
706 
primitiveToGL(Array::Primitive primitive)707 GLenum ContextArray::primitiveToGL (Array::Primitive primitive)
708 {
709 	static const GLenum primitives[] =
710 	{
711 		GL_POINTS,			// PRIMITIVE_POINTS = 0,
712 		GL_TRIANGLES,		// PRIMITIVE_TRIANGLES,
713 		GL_TRIANGLE_FAN,	// PRIMITIVE_TRIANGLE_FAN,
714 		GL_TRIANGLE_STRIP	// PRIMITIVE_TRIANGLE_STRIP,
715 	};
716 
717 	return de::getSizedArrayElement<Array::PRIMITIVE_LAST>(primitives, (int)primitive);
718 }
719 
ContextArrayPack(glu::RenderContext & renderCtx,sglr::Context & drawContext)720 ContextArrayPack::ContextArrayPack (glu::RenderContext& renderCtx, sglr::Context& drawContext)
721 	: m_renderCtx	(renderCtx)
722 	, m_ctx			(drawContext)
723 	, m_program		(DE_NULL)
724 	, m_screen		(std::min(512, renderCtx.getRenderTarget().getWidth()), std::min(512, renderCtx.getRenderTarget().getHeight()))
725 {
726 }
727 
~ContextArrayPack(void)728 ContextArrayPack::~ContextArrayPack (void)
729 {
730 	for (std::vector<ContextArray*>::iterator itr = m_arrays.begin(); itr != m_arrays.end(); itr++)
731 		delete *itr;
732 
733 	delete m_program;
734 }
735 
getArrayCount(void)736 int ContextArrayPack::getArrayCount (void)
737 {
738 	return (int)m_arrays.size();
739 }
740 
newArray(Array::Storage storage)741 void ContextArrayPack::newArray (Array::Storage storage)
742 {
743 	m_arrays.push_back(new ContextArray(storage, m_ctx));
744 }
745 
746 class ContextShaderProgram : public sglr::ShaderProgram
747 {
748 public:
749 												ContextShaderProgram		(const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
750 
751 	void										shadeVertices				(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
752 	void										shadeFragments				(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
753 
754 private:
755 	static std::string							genVertexSource				(const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
756 	static std::string							genFragmentSource			(const glu::RenderContext& ctx);
757 	static rr::GenericVecType					mapOutputType				(const Array::OutputType& type);
758 	static int									getComponentCount			(const Array::OutputType& type);
759 
760 	static sglr::pdec::ShaderProgramDeclaration createProgramDeclaration	(const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
761 
762 	std::vector<int>							m_componentCount;
763 	std::vector<rr::GenericVecType>				m_attrType;
764 };
765 
ContextShaderProgram(const glu::RenderContext & ctx,const std::vector<ContextArray * > & arrays)766 ContextShaderProgram::ContextShaderProgram (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
767 	: sglr::ShaderProgram	(createProgramDeclaration(ctx, arrays))
768 	, m_componentCount		(arrays.size())
769 	, m_attrType			(arrays.size())
770 {
771 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
772 	{
773 		m_componentCount[arrayNdx]	= getComponentCount(arrays[arrayNdx]->getOutputType());
774 		m_attrType[arrayNdx]		= mapOutputType(arrays[arrayNdx]->getOutputType());
775 	}
776 }
777 
778 template <typename T>
calcShaderColorCoord(tcu::Vec2 & coord,tcu::Vec3 & color,const tcu::Vector<T,4> & attribValue,bool isCoordinate,int numComponents)779 void calcShaderColorCoord (tcu::Vec2& coord, tcu::Vec3& color, const tcu::Vector<T, 4>& attribValue, bool isCoordinate, int numComponents)
780 {
781 	if (isCoordinate)
782 		switch (numComponents)
783 		{
784 			case 1:	coord = tcu::Vec2((float)attribValue.x(),							(float)attribValue.x());							break;
785 			case 2:	coord = tcu::Vec2((float)attribValue.x(),							(float)attribValue.y());							break;
786 			case 3:	coord = tcu::Vec2((float)attribValue.x() + (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 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const823 void ContextShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
824 {
825 	const float	u_coordScale = getUniformByName("u_coordScale").value.f;
826 	const float u_colorScale = getUniformByName("u_colorScale").value.f;
827 
828 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
829 	{
830 		const size_t varyingLocColor = 0;
831 
832 		rr::VertexPacket& packet = *packets[packetNdx];
833 
834 		// Calc output color
835 		tcu::Vec2 coord = tcu::Vec2(1.0, 1.0);
836 		tcu::Vec3 color = tcu::Vec3(1.0, 1.0, 1.0);
837 
838 		for (int attribNdx = 0; attribNdx < (int)m_attrType.size(); attribNdx++)
839 		{
840 			const int numComponents = m_componentCount[attribNdx];
841 
842 			switch (m_attrType[attribNdx])
843 			{
844 				case rr::GENERICVECTYPE_FLOAT:	calcShaderColorCoord(coord, color, rr::readVertexAttribFloat(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents);	break;
845 				case rr::GENERICVECTYPE_INT32:	calcShaderColorCoord(coord, color, rr::readVertexAttribInt	(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents);	break;
846 				case rr::GENERICVECTYPE_UINT32:	calcShaderColorCoord(coord, color, rr::readVertexAttribUint	(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents);	break;
847 				default:
848 					DE_ASSERT(false);
849 			}
850 		}
851 
852 		// Transform position
853 		{
854 			packet.position = tcu::Vec4(u_coordScale * coord.x(), u_coordScale * coord.y(), 1.0f, 1.0f);
855 		}
856 
857 		// Pass color to FS
858 		{
859 			packet.outputs[varyingLocColor] = tcu::Vec4(u_colorScale * color.x(), u_colorScale * color.y(), u_colorScale * color.z(), 1.0f);
860 		}
861 	}
862 }
863 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const864 void ContextShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
865 {
866 	const size_t varyingLocColor = 0;
867 
868 	// Triangles are flashaded
869 	tcu::Vec4 color = rr::readTriangleVarying<float>(packets[0], context, varyingLocColor, 0);
870 
871 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
872 		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
873 			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
874 }
875 
genVertexSource(const glu::RenderContext & ctx,const std::vector<ContextArray * > & arrays)876 std::string ContextShaderProgram::genVertexSource (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
877 {
878 	std::stringstream vertexShaderTmpl;
879 	std::map<std::string, std::string> params;
880 
881 	if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_300_ES))
882 	{
883 		params["VTX_IN"]		= "in";
884 		params["VTX_OUT"]		= "out";
885 		params["FRAG_IN"]		= "in";
886 		params["FRAG_COLOR"]	= "dEQP_FragColor";
887 		params["VTX_HDR"]		= "#version 300 es\n";
888 		params["FRAG_HDR"]		= "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
889 	}
890 	else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_100_ES))
891 	{
892 		params["VTX_IN"]		= "attribute";
893 		params["VTX_OUT"]		= "varying";
894 		params["FRAG_IN"]		= "varying";
895 		params["FRAG_COLOR"]	= "gl_FragColor";
896 		params["VTX_HDR"]		= "";
897 		params["FRAG_HDR"]		= "";
898 	}
899 	else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_330))
900 	{
901 		params["VTX_IN"]		= "in";
902 		params["VTX_OUT"]		= "out";
903 		params["FRAG_IN"]		= "in";
904 		params["FRAG_COLOR"]	= "dEQP_FragColor";
905 		params["VTX_HDR"]		= "#version 330\n";
906 		params["FRAG_HDR"]		= "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
907 	}
908 	else
909 		DE_ASSERT(DE_FALSE);
910 
911 	vertexShaderTmpl << "${VTX_HDR}";
912 
913 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
914 	{
915 		vertexShaderTmpl
916 			<< "${VTX_IN} highp " <<  ContextArray::outputTypeToGLType(arrays[arrayNdx]->getOutputType()) << " a_" << arrays[arrayNdx]->getAttribNdx() << ";\n";
917 	}
918 
919 	vertexShaderTmpl <<
920 		"uniform highp float u_coordScale;\n"
921 		"uniform highp float u_colorScale;\n"
922 		"${VTX_OUT} mediump vec4 v_color;\n"
923 		"void main(void)\n"
924 		"{\n"
925 		"\tgl_PointSize = 1.0;\n"
926 		"\thighp vec2 coord = vec2(1.0, 1.0);\n"
927 		"\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n";
928 
929 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
930 	{
931 		if (arrays[arrayNdx]->getAttribNdx() == 0)
932 		{
933 			switch (arrays[arrayNdx]->getOutputType())
934 			{
935 				case (Array::OUTPUTTYPE_FLOAT):
936 					vertexShaderTmpl <<
937 						"\tcoord = vec2(a_0);\n";
938 					break;
939 
940 				case (Array::OUTPUTTYPE_VEC2):
941 					vertexShaderTmpl <<
942 						"\tcoord = a_0.xy;\n";
943 					break;
944 
945 				case (Array::OUTPUTTYPE_VEC3):
946 					vertexShaderTmpl <<
947 						"\tcoord = a_0.xy;\n"
948 						"\tcoord.x = coord.x + a_0.z;\n";
949 					break;
950 
951 				case (Array::OUTPUTTYPE_VEC4):
952 					vertexShaderTmpl <<
953 						"\tcoord = a_0.xy;\n"
954 						"\tcoord += a_0.zw;\n";
955 					break;
956 
957 				case (Array::OUTPUTTYPE_IVEC2):
958 				case (Array::OUTPUTTYPE_UVEC2):
959 					vertexShaderTmpl <<
960 						"\tcoord = vec2(a_0.xy);\n";
961 					break;
962 
963 				case (Array::OUTPUTTYPE_IVEC3):
964 				case (Array::OUTPUTTYPE_UVEC3):
965 					vertexShaderTmpl <<
966 						"\tcoord = vec2(a_0.xy);\n"
967 						"\tcoord.x = coord.x + float(a_0.z);\n";
968 					break;
969 
970 				case (Array::OUTPUTTYPE_IVEC4):
971 				case (Array::OUTPUTTYPE_UVEC4):
972 					vertexShaderTmpl <<
973 						"\tcoord = vec2(a_0.xy);\n"
974 						"\tcoord += vec2(a_0.zw);\n";
975 					break;
976 
977 				default:
978 					DE_ASSERT(false);
979 					break;
980 			}
981 			continue;
982 		}
983 
984 		switch (arrays[arrayNdx]->getOutputType())
985 		{
986 			case (Array::OUTPUTTYPE_FLOAT):
987 				vertexShaderTmpl <<
988 					"\tcolor = color * a_" << arrays[arrayNdx]->getAttribNdx() << ";\n";
989 				break;
990 
991 			case (Array::OUTPUTTYPE_VEC2):
992 				vertexShaderTmpl <<
993 					"\tcolor.rg = color.rg * a_" << arrays[arrayNdx]->getAttribNdx() << ".xy;\n";
994 				break;
995 
996 			case (Array::OUTPUTTYPE_VEC3):
997 				vertexShaderTmpl <<
998 					"\tcolor = color.rgb * a_" << arrays[arrayNdx]->getAttribNdx() << ".xyz;\n";
999 				break;
1000 
1001 			case (Array::OUTPUTTYPE_VEC4):
1002 				vertexShaderTmpl <<
1003 					"\tcolor = color.rgb * a_" << arrays[arrayNdx]->getAttribNdx() << ".xyz * a_" << arrays[arrayNdx]->getAttribNdx() << ".w;\n";
1004 				break;
1005 
1006 			default:
1007 				DE_ASSERT(false);
1008 				break;
1009 		}
1010 	}
1011 
1012 	vertexShaderTmpl <<
1013 		"\tv_color = vec4(u_colorScale * color, 1.0);\n"
1014 		"\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n"
1015 		"}\n";
1016 
1017 	return tcu::StringTemplate(vertexShaderTmpl.str().c_str()).specialize(params);
1018 }
1019 
genFragmentSource(const glu::RenderContext & ctx)1020 std::string ContextShaderProgram::genFragmentSource (const glu::RenderContext& ctx)
1021 {
1022 	std::map<std::string, std::string> params;
1023 
1024 	if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_300_ES))
1025 	{
1026 		params["VTX_IN"]		= "in";
1027 		params["VTX_OUT"]		= "out";
1028 		params["FRAG_IN"]		= "in";
1029 		params["FRAG_COLOR"]	= "dEQP_FragColor";
1030 		params["VTX_HDR"]		= "#version 300 es\n";
1031 		params["FRAG_HDR"]		= "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1032 	}
1033 	else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_100_ES))
1034 	{
1035 		params["VTX_IN"]		= "attribute";
1036 		params["VTX_OUT"]		= "varying";
1037 		params["FRAG_IN"]		= "varying";
1038 		params["FRAG_COLOR"]	= "gl_FragColor";
1039 		params["VTX_HDR"]		= "";
1040 		params["FRAG_HDR"]		= "";
1041 	}
1042 	else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_330))
1043 	{
1044 		params["VTX_IN"]		= "in";
1045 		params["VTX_OUT"]		= "out";
1046 		params["FRAG_IN"]		= "in";
1047 		params["FRAG_COLOR"]	= "dEQP_FragColor";
1048 		params["VTX_HDR"]		= "#version 330\n";
1049 		params["FRAG_HDR"]		= "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1050 	}
1051 	else
1052 		DE_ASSERT(DE_FALSE);
1053 
1054 	static const char* fragmentShaderTmpl =
1055 		"${FRAG_HDR}"
1056 		"${FRAG_IN} mediump vec4 v_color;\n"
1057 		"void main(void)\n"
1058 		"{\n"
1059 		"\t${FRAG_COLOR} = v_color;\n"
1060 		"}\n";
1061 
1062 	return tcu::StringTemplate(fragmentShaderTmpl).specialize(params);
1063 }
1064 
mapOutputType(const Array::OutputType & type)1065 rr::GenericVecType ContextShaderProgram::mapOutputType (const Array::OutputType& type)
1066 {
1067 	switch (type)
1068 	{
1069 		case (Array::OUTPUTTYPE_FLOAT):
1070 		case (Array::OUTPUTTYPE_VEC2):
1071 		case (Array::OUTPUTTYPE_VEC3):
1072 		case (Array::OUTPUTTYPE_VEC4):
1073 			return rr::GENERICVECTYPE_FLOAT;
1074 
1075 		case (Array::OUTPUTTYPE_INT):
1076 		case (Array::OUTPUTTYPE_IVEC2):
1077 		case (Array::OUTPUTTYPE_IVEC3):
1078 		case (Array::OUTPUTTYPE_IVEC4):
1079 			return rr::GENERICVECTYPE_INT32;
1080 
1081 		case (Array::OUTPUTTYPE_UINT):
1082 		case (Array::OUTPUTTYPE_UVEC2):
1083 		case (Array::OUTPUTTYPE_UVEC3):
1084 		case (Array::OUTPUTTYPE_UVEC4):
1085 			return rr::GENERICVECTYPE_UINT32;
1086 
1087 		default:
1088 			DE_ASSERT(false);
1089 			return rr::GENERICVECTYPE_LAST;
1090 	}
1091 }
1092 
getComponentCount(const Array::OutputType & type)1093 int ContextShaderProgram::getComponentCount (const Array::OutputType& type)
1094 {
1095 	switch (type)
1096 	{
1097 		case (Array::OUTPUTTYPE_FLOAT):
1098 		case (Array::OUTPUTTYPE_INT):
1099 		case (Array::OUTPUTTYPE_UINT):
1100 			return 1;
1101 
1102 		case (Array::OUTPUTTYPE_VEC2):
1103 		case (Array::OUTPUTTYPE_IVEC2):
1104 		case (Array::OUTPUTTYPE_UVEC2):
1105 			return 2;
1106 
1107 		case (Array::OUTPUTTYPE_VEC3):
1108 		case (Array::OUTPUTTYPE_IVEC3):
1109 		case (Array::OUTPUTTYPE_UVEC3):
1110 			return 3;
1111 
1112 		case (Array::OUTPUTTYPE_VEC4):
1113 		case (Array::OUTPUTTYPE_IVEC4):
1114 		case (Array::OUTPUTTYPE_UVEC4):
1115 			return 4;
1116 
1117 		default:
1118 			DE_ASSERT(false);
1119 			return 0;
1120 	}
1121 }
1122 
createProgramDeclaration(const glu::RenderContext & ctx,const std::vector<ContextArray * > & arrays)1123 sglr::pdec::ShaderProgramDeclaration ContextShaderProgram::createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
1124 {
1125 	sglr::pdec::ShaderProgramDeclaration decl;
1126 
1127 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1128 		decl << sglr::pdec::VertexAttribute(std::string("a_") + de::toString(arrayNdx), mapOutputType(arrays[arrayNdx]->getOutputType()));
1129 
1130 	decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
1131 	decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT);
1132 
1133 	decl << sglr::pdec::VertexSource(genVertexSource(ctx, arrays));
1134 	decl << sglr::pdec::FragmentSource(genFragmentSource(ctx));
1135 
1136 	decl << sglr::pdec::Uniform("u_coordScale", glu::TYPE_FLOAT);
1137 	decl << sglr::pdec::Uniform("u_colorScale", glu::TYPE_FLOAT);
1138 
1139 	return decl;
1140 }
1141 
updateProgram(void)1142 void ContextArrayPack::updateProgram (void)
1143 {
1144 	delete m_program;
1145 	m_program = new ContextShaderProgram(m_renderCtx, m_arrays);
1146 }
1147 
render(Array::Primitive primitive,int firstVertex,int vertexCount,bool useVao,float coordScale,float colorScale)1148 void ContextArrayPack::render (Array::Primitive primitive, int firstVertex, int vertexCount, bool useVao, float coordScale, float colorScale)
1149 {
1150 	deUint32 program = 0;
1151 	deUint32 vaoId = 0;
1152 
1153 	updateProgram();
1154 
1155 	m_ctx.viewport(0, 0, m_screen.getWidth(), m_screen.getHeight());
1156 	m_ctx.clearColor(0.0, 0.0, 0.0, 1.0);
1157 	m_ctx.clear(GL_COLOR_BUFFER_BIT);
1158 
1159 	program = m_ctx.createProgram(m_program);
1160 
1161 	m_ctx.useProgram(program);
1162 	GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glUseProgram()");
1163 
1164 	m_ctx.uniform1f(m_ctx.getUniformLocation(program, "u_coordScale"), coordScale);
1165 	m_ctx.uniform1f(m_ctx.getUniformLocation(program, "u_colorScale"), colorScale);
1166 
1167 	if (useVao)
1168 	{
1169 		m_ctx.genVertexArrays(1, &vaoId);
1170 		m_ctx.bindVertexArray(vaoId);
1171 	}
1172 
1173 	for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
1174 	{
1175 		if (m_arrays[arrayNdx]->isBound())
1176 		{
1177 			std::stringstream attribName;
1178 			attribName << "a_" << m_arrays[arrayNdx]->getAttribNdx();
1179 
1180 			deUint32 loc = m_ctx.getAttribLocation(program, attribName.str().c_str());
1181 			m_ctx.enableVertexAttribArray(loc);
1182 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glEnableVertexAttribArray()");
1183 
1184 			m_arrays[arrayNdx]->glBind(loc);
1185 		}
1186 	}
1187 
1188 	DE_ASSERT((firstVertex % 6) == 0);
1189 	m_ctx.drawArrays(ContextArray::primitiveToGL(primitive), firstVertex, vertexCount - firstVertex);
1190 	GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArrays()");
1191 
1192 	for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
1193 	{
1194 		if (m_arrays[arrayNdx]->isBound())
1195 		{
1196 			std::stringstream attribName;
1197 			attribName << "a_" << m_arrays[arrayNdx]->getAttribNdx();
1198 
1199 			deUint32 loc = m_ctx.getAttribLocation(program, attribName.str().c_str());
1200 
1201 			m_ctx.disableVertexAttribArray(loc);
1202 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDisableVertexAttribArray()");
1203 		}
1204 	}
1205 
1206 	if (useVao)
1207 		m_ctx.deleteVertexArrays(1, &vaoId);
1208 
1209 	m_ctx.deleteProgram(program);
1210 	m_ctx.useProgram(0);
1211 	m_ctx.readPixels(m_screen, 0, 0, m_screen.getWidth(), m_screen.getHeight());
1212 }
1213 
1214 // GLValue
1215 
getMaxValue(Array::InputType type)1216 GLValue GLValue::getMaxValue (Array::InputType type)
1217 {
1218 	GLValue rangesHi[(int)Array::INPUTTYPE_LAST];
1219 
1220 	rangesHi[(int)Array::INPUTTYPE_FLOAT]			= GLValue(Float::create(127.0f));
1221 	rangesHi[(int)Array::INPUTTYPE_DOUBLE]			= GLValue(Double::create(127.0f));
1222 	rangesHi[(int)Array::INPUTTYPE_BYTE]			= GLValue(Byte::create(127));
1223 	rangesHi[(int)Array::INPUTTYPE_UNSIGNED_BYTE]	= GLValue(Ubyte::create(255));
1224 	rangesHi[(int)Array::INPUTTYPE_UNSIGNED_SHORT]	= GLValue(Ushort::create(65530));
1225 	rangesHi[(int)Array::INPUTTYPE_SHORT]			= GLValue(Short::create(32760));
1226 	rangesHi[(int)Array::INPUTTYPE_FIXED]			= GLValue(Fixed::create(32760));
1227 	rangesHi[(int)Array::INPUTTYPE_INT]				= GLValue(Int::create(2147483647));
1228 	rangesHi[(int)Array::INPUTTYPE_UNSIGNED_INT]	= GLValue(Uint::create(4294967295u));
1229 	rangesHi[(int)Array::INPUTTYPE_HALF]			= GLValue(Half::create(256.0f));
1230 
1231 	return rangesHi[(int)type];
1232 }
1233 
getMinValue(Array::InputType type)1234 GLValue GLValue::getMinValue (Array::InputType type)
1235 {
1236 	GLValue rangesLo[(int)Array::INPUTTYPE_LAST];
1237 
1238 	rangesLo[(int)Array::INPUTTYPE_FLOAT]			= GLValue(Float::create(-127.0f));
1239 	rangesLo[(int)Array::INPUTTYPE_DOUBLE]			= GLValue(Double::create(-127.0f));
1240 	rangesLo[(int)Array::INPUTTYPE_BYTE]			= GLValue(Byte::create(-127));
1241 	rangesLo[(int)Array::INPUTTYPE_UNSIGNED_BYTE]	= GLValue(Ubyte::create(0));
1242 	rangesLo[(int)Array::INPUTTYPE_UNSIGNED_SHORT]	= GLValue(Ushort::create(0));
1243 	rangesLo[(int)Array::INPUTTYPE_SHORT]			= GLValue(Short::create(-32760));
1244 	rangesLo[(int)Array::INPUTTYPE_FIXED]			= GLValue(Fixed::create(-32760));
1245 	rangesLo[(int)Array::INPUTTYPE_INT]				= GLValue(Int::create(-2147483647));
1246 	rangesLo[(int)Array::INPUTTYPE_UNSIGNED_INT]	= GLValue(Uint::create(0));
1247 	rangesLo[(int)Array::INPUTTYPE_HALF]			= GLValue(Half::create(-256.0f));
1248 
1249 	return rangesLo[(int)type];
1250 }
1251 
toFloat(void) const1252 float GLValue::toFloat (void) const
1253 {
1254 	switch (type)
1255 	{
1256 		case Array::INPUTTYPE_FLOAT:
1257 			return fl.getValue();
1258 			break;
1259 
1260 		case Array::INPUTTYPE_BYTE:
1261 			return b.getValue();
1262 			break;
1263 
1264 		case Array::INPUTTYPE_UNSIGNED_BYTE:
1265 			return ub.getValue();
1266 			break;
1267 
1268 		case Array::INPUTTYPE_SHORT:
1269 			return s.getValue();
1270 			break;
1271 
1272 		case Array::INPUTTYPE_UNSIGNED_SHORT:
1273 			return us.getValue();
1274 			break;
1275 
1276 		case Array::INPUTTYPE_FIXED:
1277 		{
1278 			int maxValue = 65536;
1279 			return (float)(double(2 * fi.getValue() + 1) / (maxValue - 1));
1280 
1281 			break;
1282 		}
1283 
1284 		case Array::INPUTTYPE_UNSIGNED_INT:
1285 			return (float)ui.getValue();
1286 			break;
1287 
1288 		case Array::INPUTTYPE_INT:
1289 			return (float)i.getValue();
1290 			break;
1291 
1292 		case Array::INPUTTYPE_HALF:
1293 			return h.to<float>();
1294 			break;
1295 
1296 		case Array::INPUTTYPE_DOUBLE:
1297 			return (float)d.getValue();
1298 			break;
1299 
1300 		default:
1301 			DE_ASSERT(false);
1302 			return 0.0f;
1303 			break;
1304 	};
1305 }
1306 
1307 class RandomArrayGenerator
1308 {
1309 public:
1310 	static char*	generateArray			(int seed, GLValue min, GLValue max, int count, int componentCount, int stride, Array::InputType type);
1311 	static char*	generateQuads			(int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max, 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 
1314 private:
1315 	template<typename T>
1316 	static char*	createQuads		(int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, T min, T max, 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 
setData(char * data,Array::InputType type,deRandom & rnd,GLValue min,GLValue max)1323 void RandomArrayGenerator::setData (char* data, Array::InputType type, deRandom& rnd, GLValue min, GLValue max)
1324 {
1325 	switch (type)
1326 	{
1327 		case Array::INPUTTYPE_FLOAT:
1328 		{
1329 			alignmentSafeAssignment<float>(data, getRandom<GLValue::Float>(rnd, min.fl, max.fl));
1330 			break;
1331 		}
1332 
1333 		case Array::INPUTTYPE_DOUBLE:
1334 		{
1335 			alignmentSafeAssignment<double>(data, getRandom<GLValue::Float>(rnd, min.fl, max.fl));
1336 			break;
1337 		}
1338 
1339 		case Array::INPUTTYPE_SHORT:
1340 		{
1341 			alignmentSafeAssignment<deInt16>(data, getRandom<GLValue::Short>(rnd, min.s, max.s));
1342 			break;
1343 		}
1344 
1345 		case Array::INPUTTYPE_UNSIGNED_SHORT:
1346 		{
1347 			alignmentSafeAssignment<deUint16>(data, getRandom<GLValue::Ushort>(rnd, min.us, max.us));
1348 			break;
1349 		}
1350 
1351 		case Array::INPUTTYPE_BYTE:
1352 		{
1353 			alignmentSafeAssignment<deInt8>(data, getRandom<GLValue::Byte>(rnd, min.b, max.b));
1354 			break;
1355 		}
1356 
1357 		case Array::INPUTTYPE_UNSIGNED_BYTE:
1358 		{
1359 			alignmentSafeAssignment<deUint8>(data, getRandom<GLValue::Ubyte>(rnd, min.ub, max.ub));
1360 			break;
1361 		}
1362 
1363 		case Array::INPUTTYPE_FIXED:
1364 		{
1365 			alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Fixed>(rnd, min.fi, max.fi));
1366 			break;
1367 		}
1368 
1369 		case Array::INPUTTYPE_INT:
1370 		{
1371 			alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Int>(rnd, min.i, max.i));
1372 			break;
1373 		}
1374 
1375 		case Array::INPUTTYPE_UNSIGNED_INT:
1376 		{
1377 			alignmentSafeAssignment<deUint32>(data, getRandom<GLValue::Uint>(rnd, min.ui, max.ui));
1378 			break;
1379 		}
1380 
1381 		case Array::INPUTTYPE_HALF:
1382 		{
1383 			alignmentSafeAssignment<deFloat16>(data, getRandom<GLValue::Half>(rnd, min.h, max.h).getValue());
1384 			break;
1385 		}
1386 
1387 		default:
1388 			DE_ASSERT(false);
1389 			break;
1390 	}
1391 }
1392 
generateArray(int seed,GLValue min,GLValue max,int count,int componentCount,int stride,Array::InputType type)1393 char* RandomArrayGenerator::generateArray (int seed, GLValue min, GLValue max, int count, int componentCount, int stride, Array::InputType type)
1394 {
1395 	char* data = NULL;
1396 
1397 	deRandom rnd;
1398 	deRandom_init(&rnd, seed);
1399 
1400 	if (stride == 0)
1401 		stride = componentCount * Array::inputTypeSize(type);
1402 
1403 	data = new char[stride * count];
1404 
1405 	for (int vertexNdx = 0; vertexNdx < count; vertexNdx++)
1406 	{
1407 		for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1408 		{
1409 			setData(&(data[vertexNdx * stride + Array::inputTypeSize(type) * componentNdx]), type, rnd, min, max);
1410 		}
1411 	}
1412 
1413 	return data;
1414 }
1415 
generateQuads(int seed,int count,int componentCount,int offset,int stride,Array::Primitive primitive,Array::InputType type,GLValue min,GLValue max,float gridSize)1416 char* RandomArrayGenerator::generateQuads (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max, float gridSize)
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 
createQuadsPacked(int seed,int count,int componentCount,int offset,int stride,Array::Primitive primitive)1475 char* RandomArrayGenerator::createQuadsPacked (int seed, int count, int componentCount, int offset, int stride, Array::Primitive primitive)
1476 {
1477 	DE_ASSERT(componentCount == 4);
1478 	DE_UNREF(componentCount);
1479 	int quadStride = 0;
1480 
1481 	if (stride == 0)
1482 		stride = sizeof(deUint32);
1483 
1484 	switch (primitive)
1485 	{
1486 		case Array::PRIMITIVE_TRIANGLES:
1487 			quadStride = stride * 6;
1488 			break;
1489 
1490 		default:
1491 			DE_ASSERT(false);
1492 			break;
1493 	}
1494 
1495 	char* const _data		= new char[offset + quadStride * (count - 1) + stride * 5 + componentCount * Array::inputTypeSize(Array::INPUTTYPE_INT_2_10_10_10)]; // last element must be fully in the array
1496 	char* const resultData	= _data + offset;
1497 
1498 	const deUint32 max		= 1024;
1499 	const deUint32 min		= 10;
1500 	const deUint32 max2		= 4;
1501 
1502 	deRandom rnd;
1503 	deRandom_init(&rnd,  seed);
1504 
1505 	switch (primitive)
1506 	{
1507 		case Array::PRIMITIVE_TRIANGLES:
1508 		{
1509 			for (int quadNdx = 0; quadNdx < count; quadNdx++)
1510 			{
1511 				deUint32 x1	= min + deRandom_getUint32(&rnd) % (max - min);
1512 				deUint32 x2	= min + deRandom_getUint32(&rnd) % (max - x1);
1513 
1514 				deUint32 y1	= min + deRandom_getUint32(&rnd) % (max - min);
1515 				deUint32 y2	= min + deRandom_getUint32(&rnd) % (max - y1);
1516 
1517 				deUint32 z	= min + deRandom_getUint32(&rnd) % (max - min);
1518 				deUint32 w	= deRandom_getUint32(&rnd) % max2;
1519 
1520 				deUint32 val1 = (w << 30) | (z << 20) | (y1 << 10) | x1;
1521 				deUint32 val2 = (w << 30) | (z << 20) | (y1 << 10) | x2;
1522 				deUint32 val3 = (w << 30) | (z << 20) | (y2 << 10) | x1;
1523 
1524 				deUint32 val4 = (w << 30) | (z << 20) | (y2 << 10) | x1;
1525 				deUint32 val5 = (w << 30) | (z << 20) | (y1 << 10) | x2;
1526 				deUint32 val6 = (w << 30) | (z << 20) | (y2 << 10) | x2;
1527 
1528 				alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 0]), val1);
1529 				alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 1]), val2);
1530 				alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 2]), val3);
1531 				alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 3]), val4);
1532 				alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 4]), val5);
1533 				alignmentSafeAssignment<deUint32>(&(resultData[quadNdx * quadStride + stride * 5]), val6);
1534 			}
1535 
1536 			break;
1537 		}
1538 
1539 		default:
1540 			DE_ASSERT(false);
1541 			break;
1542 	}
1543 
1544 	return _data;
1545 }
1546 
1547 template<typename T>
roundTo(const T & step,const T & value)1548 T roundTo (const T& step, const T& value)
1549 {
1550 	return value - (value % step);
1551 }
1552 
1553 template<typename T>
createQuads(int seed,int count,int componentCount,int offset,int stride,Array::Primitive primitive,T min,T max,float gridSize)1554 char* 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 
generatePerQuad(int seed,int count,int componentCount,int stride,Array::Primitive primitive,Array::InputType type,GLValue min,GLValue max)1664 char* 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 
1718 template<typename T>
createPerQuads(int seed,int count,int componentCount,int stride,Array::Primitive primitive,T min,T max)1719 char* 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 
VertexArrayTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc)1764 VertexArrayTest::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 
~VertexArrayTest(void)1779 VertexArrayTest::~VertexArrayTest (void)
1780 {
1781 	deinit();
1782 }
1783 
init(void)1784 void 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 
deinit(void)1799 void 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 
compare(void)1814 void 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 
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_)1918 MultiVertexArrayTest::Spec::ArraySpec::ArraySpec(Array::InputType inputType_, Array::OutputType outputType_, Array::Storage storage_, Array::Usage usage_, int componentCount_, int offset_, int stride_, bool normalize_, GLValue min_, GLValue max_)
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 
getName(void) const1932 std::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 
getDesc(void) const1979 std::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 
MultiVertexArrayTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const Spec & spec,const char * name,const char * desc)2020 MultiVertexArrayTest::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 
~MultiVertexArrayTest(void)2027 MultiVertexArrayTest::~MultiVertexArrayTest	(void)
2028 {
2029 }
2030 
iterate(void)2031 MultiVertexArrayTest::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 
isUnalignedBufferOffsetTest(void) const2179 bool 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 
isUnalignedBufferStrideTest(void) const2200 bool 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