• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
alignmentSafeAssignment(char * dst,T val)380 static inline void alignmentSafeAssignment (char* dst, T val)
381 {
382 	std::memcpy(dst, &val, sizeof(T));
383 }
384 
ContextArray(Storage storage,sglr::Context & context)385 ContextArray::ContextArray (Storage storage, sglr::Context& context)
386 	: m_storage			(storage)
387 	, m_ctx				(context)
388 	, m_glBuffer		(0)
389 	, m_bound			(false)
390 	, m_attribNdx		(0)
391 	, m_size			(0)
392 	, m_data			(DE_NULL)
393 	, m_componentCount	(1)
394 	, m_target			(Array::TARGET_ARRAY)
395 	, m_inputType		(Array::INPUTTYPE_FLOAT)
396 	, m_outputType		(Array::OUTPUTTYPE_VEC4)
397 	, m_normalize		(false)
398 	, m_stride			(0)
399 	, m_offset			(0)
400 {
401 	if (m_storage == STORAGE_BUFFER)
402 	{
403 		m_ctx.genBuffers(1, &m_glBuffer);
404 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glGenBuffers()");
405 	}
406 }
407 
~ContextArray(void)408 ContextArray::~ContextArray	(void)
409 {
410 	if (m_storage == STORAGE_BUFFER)
411 	{
412 		m_ctx.deleteBuffers(1, &m_glBuffer);
413 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDeleteBuffers()");
414 	}
415 	else if (m_storage == STORAGE_USER)
416 		delete[] m_data;
417 	else
418 		DE_ASSERT(false);
419 }
420 
getArray(int i)421 Array* ContextArrayPack::getArray (int i)
422 {
423 	return m_arrays.at(i);
424 }
425 
data(Target target,int size,const char * ptr,Usage usage)426 void ContextArray::data (Target target, int size, const char* ptr, Usage usage)
427 {
428 	m_size = size;
429 	m_target = target;
430 
431 	if (m_storage == STORAGE_BUFFER)
432 	{
433 		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
434 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
435 
436 		m_ctx.bufferData(targetToGL(target), size, ptr, usageToGL(usage));
437 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferData()");
438 	}
439 	else if (m_storage == STORAGE_USER)
440 	{
441 		if (m_data)
442 			delete[] m_data;
443 
444 		m_data = new char[size];
445 		std::memcpy(m_data, ptr, size);
446 	}
447 	else
448 		DE_ASSERT(false);
449 }
450 
subdata(Target target,int offset,int size,const char * ptr)451 void ContextArray::subdata (Target target, int offset, int size, const char* ptr)
452 {
453 	m_target = target;
454 
455 	if (m_storage == STORAGE_BUFFER)
456 	{
457 		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
458 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
459 
460 		m_ctx.bufferSubData(targetToGL(target), offset, size, ptr);
461 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferSubData()");
462 	}
463 	else if (m_storage == STORAGE_USER)
464 		std::memcpy(m_data + offset, ptr, size);
465 	else
466 		DE_ASSERT(false);
467 }
468 
bind(int attribNdx,int offset,int size,InputType inputType,OutputType outType,bool normalized,int stride)469 void ContextArray::bind (int attribNdx, int offset, int size, InputType inputType, OutputType outType, bool normalized, int stride)
470 {
471 	m_attribNdx			= attribNdx;
472 	m_bound				= true;
473 	m_componentCount	= size;
474 	m_inputType			= inputType;
475 	m_outputType		= outType;
476 	m_normalize			= normalized;
477 	m_stride			= stride;
478 	m_offset			= offset;
479 }
480 
bindIndexArray(Array::Target target)481 void ContextArray::bindIndexArray (Array::Target target)
482 {
483 	if (m_storage == STORAGE_USER)
484 	{
485 	}
486 	else if (m_storage == STORAGE_BUFFER)
487 	{
488 		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
489 	}
490 }
491 
glBind(deUint32 loc)492 void ContextArray::glBind (deUint32 loc)
493 {
494 	if (m_storage == STORAGE_BUFFER)
495 	{
496 		m_ctx.bindBuffer(targetToGL(m_target), m_glBuffer);
497 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
498 
499 		if (!inputTypeIsFloatType(m_inputType))
500 		{
501 			// Input is not float type
502 
503 			if (outputTypeIsFloatType(m_outputType))
504 			{
505 				// Output type is float type
506 				m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, (GLvoid*)((GLintptr)m_offset));
507 				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
508 			}
509 			else
510 			{
511 				// Output type is int type
512 				m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, (GLvoid*)((GLintptr)m_offset));
513 				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
514 			}
515 		}
516 		else
517 		{
518 			// Input type is float type
519 
520 			// Output type must be float type
521 			DE_ASSERT(m_outputType == OUTPUTTYPE_FLOAT || m_outputType == OUTPUTTYPE_VEC2 || m_outputType == OUTPUTTYPE_VEC3 || m_outputType == OUTPUTTYPE_VEC4);
522 
523 			m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, (GLvoid*)((GLintptr)m_offset));
524 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
525 		}
526 
527 		m_ctx.bindBuffer(targetToGL(m_target), 0);
528 	}
529 	else if (m_storage == STORAGE_USER)
530 	{
531 		m_ctx.bindBuffer(targetToGL(m_target), 0);
532 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
533 
534 		if (!inputTypeIsFloatType(m_inputType))
535 		{
536 			// Input is not float type
537 
538 			if (outputTypeIsFloatType(m_outputType))
539 			{
540 				// Output type is float type
541 				m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, m_data + m_offset);
542 				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
543 			}
544 			else
545 			{
546 				// Output type is int type
547 				m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, m_data + m_offset);
548 				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
549 			}
550 		}
551 		else
552 		{
553 			// Input type is float type
554 
555 			// Output type must be float type
556 			DE_ASSERT(m_outputType == OUTPUTTYPE_FLOAT || m_outputType == OUTPUTTYPE_VEC2 || m_outputType == OUTPUTTYPE_VEC3 || m_outputType == OUTPUTTYPE_VEC4);
557 
558 			m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, m_data + m_offset);
559 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
560 		}
561 	}
562 	else
563 		DE_ASSERT(false);
564 }
565 
targetToGL(Array::Target target)566 GLenum ContextArray::targetToGL (Array::Target target)
567 {
568 	static const GLenum targets[] =
569 	{
570 		GL_ELEMENT_ARRAY_BUFFER,	// TARGET_ELEMENT_ARRAY = 0,
571 		GL_ARRAY_BUFFER				// TARGET_ARRAY,
572 	};
573 
574 	return de::getSizedArrayElement<Array::TARGET_LAST>(targets, (int)target);
575 }
576 
usageToGL(Array::Usage usage)577 GLenum ContextArray::usageToGL (Array::Usage usage)
578 {
579 	static const GLenum usages[] =
580 	{
581 		GL_DYNAMIC_DRAW,	// USAGE_DYNAMIC_DRAW = 0,
582 		GL_STATIC_DRAW,		// USAGE_STATIC_DRAW,
583 		GL_STREAM_DRAW,		// USAGE_STREAM_DRAW,
584 
585 		GL_STREAM_READ,		// USAGE_STREAM_READ,
586 		GL_STREAM_COPY,		// USAGE_STREAM_COPY,
587 
588 		GL_STATIC_READ,		// USAGE_STATIC_READ,
589 		GL_STATIC_COPY,		// USAGE_STATIC_COPY,
590 
591 		GL_DYNAMIC_READ,	// USAGE_DYNAMIC_READ,
592 		GL_DYNAMIC_COPY		// USAGE_DYNAMIC_COPY,
593 	};
594 
595 	return de::getSizedArrayElement<Array::USAGE_LAST>(usages, (int)usage);
596 }
597 
inputTypeToGL(Array::InputType type)598 GLenum ContextArray::inputTypeToGL (Array::InputType type)
599 {
600 	static const GLenum types[] =
601 	{
602 		GL_FLOAT,				// INPUTTYPE_FLOAT = 0,
603 		GL_FIXED,				// INPUTTYPE_FIXED,
604 		GL_DOUBLE,				// INPUTTYPE_DOUBLE
605 		GL_BYTE,				// INPUTTYPE_BYTE,
606 		GL_SHORT,				// INPUTTYPE_SHORT,
607 		GL_UNSIGNED_BYTE,		// INPUTTYPE_UNSIGNED_BYTE,
608 		GL_UNSIGNED_SHORT,		// INPUTTYPE_UNSIGNED_SHORT,
609 
610 		GL_INT,					// INPUTTYPE_INT,
611 		GL_UNSIGNED_INT,		// INPUTTYPE_UNSIGNED_INT,
612 		GL_HALF_FLOAT,			// INPUTTYPE_HALF,
613 		GL_UNSIGNED_INT_2_10_10_10_REV, // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
614 		GL_INT_2_10_10_10_REV			// INPUTTYPE_INT_2_10_10_10,
615 	};
616 
617 	return de::getSizedArrayElement<Array::INPUTTYPE_LAST>(types, (int)type);
618 }
619 
outputTypeToGLType(Array::OutputType type)620 std::string ContextArray::outputTypeToGLType (Array::OutputType type)
621 {
622 	static const char* types[] =
623 	{
624 		"float",		// OUTPUTTYPE_FLOAT = 0,
625 		"vec2",			// OUTPUTTYPE_VEC2,
626 		"vec3",			// OUTPUTTYPE_VEC3,
627 		"vec4",			// OUTPUTTYPE_VEC4,
628 
629 		"int",			// OUTPUTTYPE_INT,
630 		"uint",			// OUTPUTTYPE_UINT,
631 
632 		"ivec2",		// OUTPUTTYPE_IVEC2,
633 		"ivec3",		// OUTPUTTYPE_IVEC3,
634 		"ivec4",		// OUTPUTTYPE_IVEC4,
635 
636 		"uvec2",		// OUTPUTTYPE_UVEC2,
637 		"uvec3",		// OUTPUTTYPE_UVEC3,
638 		"uvec4",		// OUTPUTTYPE_UVEC4,
639 	};
640 
641 	return de::getSizedArrayElement<Array::OUTPUTTYPE_LAST>(types, (int)type);
642 }
643 
primitiveToGL(Array::Primitive primitive)644 GLenum ContextArray::primitiveToGL (Array::Primitive primitive)
645 {
646 	static const GLenum primitives[] =
647 	{
648 		GL_POINTS,			// PRIMITIVE_POINTS = 0,
649 		GL_TRIANGLES,		// PRIMITIVE_TRIANGLES,
650 		GL_TRIANGLE_FAN,	// PRIMITIVE_TRIANGLE_FAN,
651 		GL_TRIANGLE_STRIP	// PRIMITIVE_TRIANGLE_STRIP,
652 	};
653 
654 	return de::getSizedArrayElement<Array::PRIMITIVE_LAST>(primitives, (int)primitive);
655 }
656 
ContextArrayPack(glu::RenderContext & renderCtx,sglr::Context & drawContext)657 ContextArrayPack::ContextArrayPack (glu::RenderContext& renderCtx, sglr::Context& drawContext)
658 	: m_renderCtx	(renderCtx)
659 	, m_ctx			(drawContext)
660 	, m_program		(DE_NULL)
661 	, m_screen		(std::min(512, renderCtx.getRenderTarget().getWidth()), std::min(512, renderCtx.getRenderTarget().getHeight()))
662 {
663 }
664 
~ContextArrayPack(void)665 ContextArrayPack::~ContextArrayPack (void)
666 {
667 	for (std::vector<ContextArray*>::iterator itr = m_arrays.begin(); itr != m_arrays.end(); itr++)
668 		delete *itr;
669 
670 	delete m_program;
671 }
672 
getArrayCount(void)673 int ContextArrayPack::getArrayCount (void)
674 {
675 	return (int)m_arrays.size();
676 }
677 
newArray(Array::Storage storage)678 void ContextArrayPack::newArray (Array::Storage storage)
679 {
680 	m_arrays.push_back(new ContextArray(storage, m_ctx));
681 }
682 
683 class ContextShaderProgram : public sglr::ShaderProgram
684 {
685 public:
686 												ContextShaderProgram		(const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
687 
688 	void										shadeVertices				(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
689 	void										shadeFragments				(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
690 
691 private:
692 	static std::string							genVertexSource				(const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
693 	static std::string							genFragmentSource			(const glu::RenderContext& ctx);
694 	static rr::GenericVecType					mapOutputType				(const Array::OutputType& type);
695 	static int									getComponentCount			(const Array::OutputType& type);
696 
697 	static sglr::pdec::ShaderProgramDeclaration createProgramDeclaration	(const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays);
698 
699 	std::vector<int>							m_componentCount;
700 	std::vector<rr::GenericVecType>				m_attrType;
701 };
702 
ContextShaderProgram(const glu::RenderContext & ctx,const std::vector<ContextArray * > & arrays)703 ContextShaderProgram::ContextShaderProgram (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
704 	: sglr::ShaderProgram	(createProgramDeclaration(ctx, arrays))
705 	, m_componentCount		(arrays.size())
706 	, m_attrType			(arrays.size())
707 {
708 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
709 	{
710 		m_componentCount[arrayNdx]	= getComponentCount(arrays[arrayNdx]->getOutputType());
711 		m_attrType[arrayNdx]		= mapOutputType(arrays[arrayNdx]->getOutputType());
712 	}
713 }
714 
715 template <typename T>
calcShaderColorCoord(tcu::Vec2 & coord,tcu::Vec3 & color,const tcu::Vector<T,4> & attribValue,bool isCoordinate,int numComponents)716 void calcShaderColorCoord (tcu::Vec2& coord, tcu::Vec3& color, const tcu::Vector<T, 4>& attribValue, bool isCoordinate, int numComponents)
717 {
718 	if (isCoordinate)
719 		switch (numComponents)
720 		{
721 			case 1:	coord = tcu::Vec2((float)attribValue.x(),							(float)attribValue.x());							break;
722 			case 2:	coord = tcu::Vec2((float)attribValue.x(),							(float)attribValue.y());							break;
723 			case 3:	coord = tcu::Vec2((float)attribValue.x() + (float)attribValue.z(),	(float)attribValue.y());							break;
724 			case 4:	coord = tcu::Vec2((float)attribValue.x() + (float)attribValue.z(),	(float)attribValue.y() + (float)attribValue.w());	break;
725 
726 			default:
727 				DE_ASSERT(false);
728 		}
729 	else
730 	{
731 		switch (numComponents)
732 		{
733 			case 1:
734 				color = color * (float)attribValue.x();
735 				break;
736 
737 			case 2:
738 				color.x() = color.x() * (float)attribValue.x();
739 				color.y() = color.y() * (float)attribValue.y();
740 				break;
741 
742 			case 3:
743 				color.x() = color.x() * (float)attribValue.x();
744 				color.y() = color.y() * (float)attribValue.y();
745 				color.z() = color.z() * (float)attribValue.z();
746 				break;
747 
748 			case 4:
749 				color.x() = color.x() * (float)attribValue.x() * (float)attribValue.w();
750 				color.y() = color.y() * (float)attribValue.y() * (float)attribValue.w();
751 				color.z() = color.z() * (float)attribValue.z() * (float)attribValue.w();
752 				break;
753 
754 			default:
755 				DE_ASSERT(false);
756 		}
757 	}
758 }
759 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const760 void ContextShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
761 {
762 	const float	u_coordScale = getUniformByName("u_coordScale").value.f;
763 	const float u_colorScale = getUniformByName("u_colorScale").value.f;
764 
765 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
766 	{
767 		const size_t varyingLocColor = 0;
768 
769 		rr::VertexPacket& packet = *packets[packetNdx];
770 
771 		// Calc output color
772 		tcu::Vec2 coord = tcu::Vec2(1.0, 1.0);
773 		tcu::Vec3 color = tcu::Vec3(1.0, 1.0, 1.0);
774 
775 		for (int attribNdx = 0; attribNdx < (int)m_attrType.size(); attribNdx++)
776 		{
777 			const int numComponents = m_componentCount[attribNdx];
778 
779 			switch (m_attrType[attribNdx])
780 			{
781 				case rr::GENERICVECTYPE_FLOAT:	calcShaderColorCoord(coord, color, rr::readVertexAttribFloat(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents);	break;
782 				case rr::GENERICVECTYPE_INT32:	calcShaderColorCoord(coord, color, rr::readVertexAttribInt	(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents);	break;
783 				case rr::GENERICVECTYPE_UINT32:	calcShaderColorCoord(coord, color, rr::readVertexAttribUint	(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), attribNdx == 0, numComponents);	break;
784 				default:
785 					DE_ASSERT(false);
786 			}
787 		}
788 
789 		// Transform position
790 		{
791 			packet.position = tcu::Vec4(u_coordScale * coord.x(), u_coordScale * coord.y(), 1.0f, 1.0f);
792 		}
793 
794 		// Pass color to FS
795 		{
796 			packet.outputs[varyingLocColor] = tcu::Vec4(u_colorScale * color.x(), u_colorScale * color.y(), u_colorScale * color.z(), 1.0f);
797 		}
798 	}
799 }
800 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const801 void ContextShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
802 {
803 	const size_t varyingLocColor = 0;
804 
805 	// Triangles are flashaded
806 	tcu::Vec4 color = rr::readTriangleVarying<float>(packets[0], context, varyingLocColor, 0);
807 
808 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
809 		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
810 			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
811 }
812 
genVertexSource(const glu::RenderContext & ctx,const std::vector<ContextArray * > & arrays)813 std::string ContextShaderProgram::genVertexSource (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
814 {
815 	std::stringstream vertexShaderTmpl;
816 	std::map<std::string, std::string> params;
817 
818 	if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_300_ES))
819 	{
820 		params["VTX_IN"]		= "in";
821 		params["VTX_OUT"]		= "out";
822 		params["FRAG_IN"]		= "in";
823 		params["FRAG_COLOR"]	= "dEQP_FragColor";
824 		params["VTX_HDR"]		= "#version 300 es\n";
825 		params["FRAG_HDR"]		= "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
826 	}
827 	else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_100_ES))
828 	{
829 		params["VTX_IN"]		= "attribute";
830 		params["VTX_OUT"]		= "varying";
831 		params["FRAG_IN"]		= "varying";
832 		params["FRAG_COLOR"]	= "gl_FragColor";
833 		params["VTX_HDR"]		= "";
834 		params["FRAG_HDR"]		= "";
835 	}
836 	else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_330))
837 	{
838 		params["VTX_IN"]		= "in";
839 		params["VTX_OUT"]		= "out";
840 		params["FRAG_IN"]		= "in";
841 		params["FRAG_COLOR"]	= "dEQP_FragColor";
842 		params["VTX_HDR"]		= "#version 330\n";
843 		params["FRAG_HDR"]		= "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
844 	}
845 	else
846 		DE_ASSERT(DE_FALSE);
847 
848 	vertexShaderTmpl << "${VTX_HDR}";
849 
850 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
851 	{
852 		vertexShaderTmpl
853 			<< "${VTX_IN} highp " <<  ContextArray::outputTypeToGLType(arrays[arrayNdx]->getOutputType()) << " a_" << arrays[arrayNdx]->getAttribNdx() << ";\n";
854 	}
855 
856 	vertexShaderTmpl <<
857 		"uniform highp float u_coordScale;\n"
858 		"uniform highp float u_colorScale;\n"
859 		"${VTX_OUT} mediump vec4 v_color;\n"
860 		"void main(void)\n"
861 		"{\n"
862 		"\tgl_PointSize = 1.0;\n"
863 		"\thighp vec2 coord = vec2(1.0, 1.0);\n"
864 		"\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n";
865 
866 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
867 	{
868 		if (arrays[arrayNdx]->getAttribNdx() == 0)
869 		{
870 			switch (arrays[arrayNdx]->getOutputType())
871 			{
872 				case (Array::OUTPUTTYPE_FLOAT):
873 					vertexShaderTmpl <<
874 						"\tcoord = vec2(a_0);\n";
875 					break;
876 
877 				case (Array::OUTPUTTYPE_VEC2):
878 					vertexShaderTmpl <<
879 						"\tcoord = a_0.xy;\n";
880 					break;
881 
882 				case (Array::OUTPUTTYPE_VEC3):
883 					vertexShaderTmpl <<
884 						"\tcoord = a_0.xy;\n"
885 						"\tcoord.x = coord.x + a_0.z;\n";
886 					break;
887 
888 				case (Array::OUTPUTTYPE_VEC4):
889 					vertexShaderTmpl <<
890 						"\tcoord = a_0.xy;\n"
891 						"\tcoord += a_0.zw;\n";
892 					break;
893 
894 				case (Array::OUTPUTTYPE_IVEC2):
895 				case (Array::OUTPUTTYPE_UVEC2):
896 					vertexShaderTmpl <<
897 						"\tcoord = vec2(a_0.xy);\n";
898 					break;
899 
900 				case (Array::OUTPUTTYPE_IVEC3):
901 				case (Array::OUTPUTTYPE_UVEC3):
902 					vertexShaderTmpl <<
903 						"\tcoord = vec2(a_0.xy);\n"
904 						"\tcoord.x = coord.x + float(a_0.z);\n";
905 					break;
906 
907 				case (Array::OUTPUTTYPE_IVEC4):
908 				case (Array::OUTPUTTYPE_UVEC4):
909 					vertexShaderTmpl <<
910 						"\tcoord = vec2(a_0.xy);\n"
911 						"\tcoord += vec2(a_0.zw);\n";
912 					break;
913 
914 				default:
915 					DE_ASSERT(false);
916 					break;
917 			}
918 			continue;
919 		}
920 
921 		switch (arrays[arrayNdx]->getOutputType())
922 		{
923 			case (Array::OUTPUTTYPE_FLOAT):
924 				vertexShaderTmpl <<
925 					"\tcolor = color * a_" << arrays[arrayNdx]->getAttribNdx() << ";\n";
926 				break;
927 
928 			case (Array::OUTPUTTYPE_VEC2):
929 				vertexShaderTmpl <<
930 					"\tcolor.rg = color.rg * a_" << arrays[arrayNdx]->getAttribNdx() << ".xy;\n";
931 				break;
932 
933 			case (Array::OUTPUTTYPE_VEC3):
934 				vertexShaderTmpl <<
935 					"\tcolor = color.rgb * a_" << arrays[arrayNdx]->getAttribNdx() << ".xyz;\n";
936 				break;
937 
938 			case (Array::OUTPUTTYPE_VEC4):
939 				vertexShaderTmpl <<
940 					"\tcolor = color.rgb * a_" << arrays[arrayNdx]->getAttribNdx() << ".xyz * a_" << arrays[arrayNdx]->getAttribNdx() << ".w;\n";
941 				break;
942 
943 			default:
944 				DE_ASSERT(false);
945 				break;
946 		}
947 	}
948 
949 	vertexShaderTmpl <<
950 		"\tv_color = vec4(u_colorScale * color, 1.0);\n"
951 		"\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n"
952 		"}\n";
953 
954 	return tcu::StringTemplate(vertexShaderTmpl.str().c_str()).specialize(params);
955 }
956 
genFragmentSource(const glu::RenderContext & ctx)957 std::string ContextShaderProgram::genFragmentSource (const glu::RenderContext& ctx)
958 {
959 	std::map<std::string, std::string> params;
960 
961 	if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_300_ES))
962 	{
963 		params["VTX_IN"]		= "in";
964 		params["VTX_OUT"]		= "out";
965 		params["FRAG_IN"]		= "in";
966 		params["FRAG_COLOR"]	= "dEQP_FragColor";
967 		params["VTX_HDR"]		= "#version 300 es\n";
968 		params["FRAG_HDR"]		= "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
969 	}
970 	else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_100_ES))
971 	{
972 		params["VTX_IN"]		= "attribute";
973 		params["VTX_OUT"]		= "varying";
974 		params["FRAG_IN"]		= "varying";
975 		params["FRAG_COLOR"]	= "gl_FragColor";
976 		params["VTX_HDR"]		= "";
977 		params["FRAG_HDR"]		= "";
978 	}
979 	else if (glu::isGLSLVersionSupported(ctx.getType(), glu::GLSL_VERSION_330))
980 	{
981 		params["VTX_IN"]		= "in";
982 		params["VTX_OUT"]		= "out";
983 		params["FRAG_IN"]		= "in";
984 		params["FRAG_COLOR"]	= "dEQP_FragColor";
985 		params["VTX_HDR"]		= "#version 330\n";
986 		params["FRAG_HDR"]		= "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
987 	}
988 	else
989 		DE_ASSERT(DE_FALSE);
990 
991 	static const char* fragmentShaderTmpl =
992 		"${FRAG_HDR}"
993 		"${FRAG_IN} mediump vec4 v_color;\n"
994 		"void main(void)\n"
995 		"{\n"
996 		"\t${FRAG_COLOR} = v_color;\n"
997 		"}\n";
998 
999 	return tcu::StringTemplate(fragmentShaderTmpl).specialize(params);
1000 }
1001 
mapOutputType(const Array::OutputType & type)1002 rr::GenericVecType ContextShaderProgram::mapOutputType (const Array::OutputType& type)
1003 {
1004 	switch (type)
1005 	{
1006 		case (Array::OUTPUTTYPE_FLOAT):
1007 		case (Array::OUTPUTTYPE_VEC2):
1008 		case (Array::OUTPUTTYPE_VEC3):
1009 		case (Array::OUTPUTTYPE_VEC4):
1010 			return rr::GENERICVECTYPE_FLOAT;
1011 
1012 		case (Array::OUTPUTTYPE_INT):
1013 		case (Array::OUTPUTTYPE_IVEC2):
1014 		case (Array::OUTPUTTYPE_IVEC3):
1015 		case (Array::OUTPUTTYPE_IVEC4):
1016 			return rr::GENERICVECTYPE_INT32;
1017 
1018 		case (Array::OUTPUTTYPE_UINT):
1019 		case (Array::OUTPUTTYPE_UVEC2):
1020 		case (Array::OUTPUTTYPE_UVEC3):
1021 		case (Array::OUTPUTTYPE_UVEC4):
1022 			return rr::GENERICVECTYPE_UINT32;
1023 
1024 		default:
1025 			DE_ASSERT(false);
1026 			return rr::GENERICVECTYPE_LAST;
1027 	}
1028 }
1029 
getComponentCount(const Array::OutputType & type)1030 int ContextShaderProgram::getComponentCount (const Array::OutputType& type)
1031 {
1032 	switch (type)
1033 	{
1034 		case (Array::OUTPUTTYPE_FLOAT):
1035 		case (Array::OUTPUTTYPE_INT):
1036 		case (Array::OUTPUTTYPE_UINT):
1037 			return 1;
1038 
1039 		case (Array::OUTPUTTYPE_VEC2):
1040 		case (Array::OUTPUTTYPE_IVEC2):
1041 		case (Array::OUTPUTTYPE_UVEC2):
1042 			return 2;
1043 
1044 		case (Array::OUTPUTTYPE_VEC3):
1045 		case (Array::OUTPUTTYPE_IVEC3):
1046 		case (Array::OUTPUTTYPE_UVEC3):
1047 			return 3;
1048 
1049 		case (Array::OUTPUTTYPE_VEC4):
1050 		case (Array::OUTPUTTYPE_IVEC4):
1051 		case (Array::OUTPUTTYPE_UVEC4):
1052 			return 4;
1053 
1054 		default:
1055 			DE_ASSERT(false);
1056 			return 0;
1057 	}
1058 }
1059 
createProgramDeclaration(const glu::RenderContext & ctx,const std::vector<ContextArray * > & arrays)1060 sglr::pdec::ShaderProgramDeclaration ContextShaderProgram::createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<ContextArray*>& arrays)
1061 {
1062 	sglr::pdec::ShaderProgramDeclaration decl;
1063 
1064 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1065 		decl << sglr::pdec::VertexAttribute(std::string("a_") + de::toString(arrayNdx), mapOutputType(arrays[arrayNdx]->getOutputType()));
1066 
1067 	decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
1068 	decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT);
1069 
1070 	decl << sglr::pdec::VertexSource(genVertexSource(ctx, arrays));
1071 	decl << sglr::pdec::FragmentSource(genFragmentSource(ctx));
1072 
1073 	decl << sglr::pdec::Uniform("u_coordScale", glu::TYPE_FLOAT);
1074 	decl << sglr::pdec::Uniform("u_colorScale", glu::TYPE_FLOAT);
1075 
1076 	return decl;
1077 }
1078 
updateProgram(void)1079 void ContextArrayPack::updateProgram (void)
1080 {
1081 	delete m_program;
1082 	m_program = new ContextShaderProgram(m_renderCtx, m_arrays);
1083 }
1084 
render(Array::Primitive primitive,int firstVertex,int vertexCount,bool useVao,float coordScale,float colorScale)1085 void ContextArrayPack::render (Array::Primitive primitive, int firstVertex, int vertexCount, bool useVao, float coordScale, float colorScale)
1086 {
1087 	deUint32 program = 0;
1088 	deUint32 vaoId = 0;
1089 
1090 	updateProgram();
1091 
1092 	m_ctx.viewport(0, 0, m_screen.getWidth(), m_screen.getHeight());
1093 	m_ctx.clearColor(0.0, 0.0, 0.0, 1.0);
1094 	m_ctx.clear(GL_COLOR_BUFFER_BIT);
1095 
1096 	program = m_ctx.createProgram(m_program);
1097 
1098 	m_ctx.useProgram(program);
1099 	GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glUseProgram()");
1100 
1101 	m_ctx.uniform1f(m_ctx.getUniformLocation(program, "u_coordScale"), coordScale);
1102 	m_ctx.uniform1f(m_ctx.getUniformLocation(program, "u_colorScale"), colorScale);
1103 
1104 	if (useVao)
1105 	{
1106 		m_ctx.genVertexArrays(1, &vaoId);
1107 		m_ctx.bindVertexArray(vaoId);
1108 	}
1109 
1110 	for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
1111 	{
1112 		if (m_arrays[arrayNdx]->isBound())
1113 		{
1114 			std::stringstream attribName;
1115 			attribName << "a_" << m_arrays[arrayNdx]->getAttribNdx();
1116 
1117 			deUint32 loc = m_ctx.getAttribLocation(program, attribName.str().c_str());
1118 			m_ctx.enableVertexAttribArray(loc);
1119 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glEnableVertexAttribArray()");
1120 
1121 			m_arrays[arrayNdx]->glBind(loc);
1122 		}
1123 	}
1124 
1125 	DE_ASSERT((firstVertex % 6) == 0);
1126 	m_ctx.drawArrays(ContextArray::primitiveToGL(primitive), firstVertex, vertexCount - firstVertex);
1127 	GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArrays()");
1128 
1129 	for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
1130 	{
1131 		if (m_arrays[arrayNdx]->isBound())
1132 		{
1133 			std::stringstream attribName;
1134 			attribName << "a_" << m_arrays[arrayNdx]->getAttribNdx();
1135 
1136 			deUint32 loc = m_ctx.getAttribLocation(program, attribName.str().c_str());
1137 
1138 			m_ctx.disableVertexAttribArray(loc);
1139 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDisableVertexAttribArray()");
1140 		}
1141 	}
1142 
1143 	if (useVao)
1144 		m_ctx.deleteVertexArrays(1, &vaoId);
1145 
1146 	m_ctx.deleteProgram(program);
1147 	m_ctx.useProgram(0);
1148 	m_ctx.readPixels(m_screen, 0, 0, m_screen.getWidth(), m_screen.getHeight());
1149 }
1150 
1151 // GLValue
1152 
getMaxValue(Array::InputType type)1153 GLValue GLValue::getMaxValue (Array::InputType type)
1154 {
1155 	GLValue rangesHi[(int)Array::INPUTTYPE_LAST];
1156 
1157 	rangesHi[(int)Array::INPUTTYPE_FLOAT]			= GLValue(Float::create(127.0f));
1158 	rangesHi[(int)Array::INPUTTYPE_DOUBLE]			= GLValue(Double::create(127.0f));
1159 	rangesHi[(int)Array::INPUTTYPE_BYTE]			= GLValue(Byte::create(127));
1160 	rangesHi[(int)Array::INPUTTYPE_UNSIGNED_BYTE]	= GLValue(Ubyte::create(255));
1161 	rangesHi[(int)Array::INPUTTYPE_UNSIGNED_SHORT]	= GLValue(Ushort::create(65530));
1162 	rangesHi[(int)Array::INPUTTYPE_SHORT]			= GLValue(Short::create(32760));
1163 	rangesHi[(int)Array::INPUTTYPE_FIXED]			= GLValue(Fixed::create(32760));
1164 	rangesHi[(int)Array::INPUTTYPE_INT]				= GLValue(Int::create(2147483647));
1165 	rangesHi[(int)Array::INPUTTYPE_UNSIGNED_INT]	= GLValue(Uint::create(4294967295u));
1166 	rangesHi[(int)Array::INPUTTYPE_HALF]			= GLValue(Half::create(256.0f));
1167 
1168 	return rangesHi[(int)type];
1169 }
1170 
getMinValue(Array::InputType type)1171 GLValue GLValue::getMinValue (Array::InputType type)
1172 {
1173 	GLValue rangesLo[(int)Array::INPUTTYPE_LAST];
1174 
1175 	rangesLo[(int)Array::INPUTTYPE_FLOAT]			= GLValue(Float::create(-127.0f));
1176 	rangesLo[(int)Array::INPUTTYPE_DOUBLE]			= GLValue(Double::create(-127.0f));
1177 	rangesLo[(int)Array::INPUTTYPE_BYTE]			= GLValue(Byte::create(-127));
1178 	rangesLo[(int)Array::INPUTTYPE_UNSIGNED_BYTE]	= GLValue(Ubyte::create(0));
1179 	rangesLo[(int)Array::INPUTTYPE_UNSIGNED_SHORT]	= GLValue(Ushort::create(0));
1180 	rangesLo[(int)Array::INPUTTYPE_SHORT]			= GLValue(Short::create(-32760));
1181 	rangesLo[(int)Array::INPUTTYPE_FIXED]			= GLValue(Fixed::create(-32760));
1182 	rangesLo[(int)Array::INPUTTYPE_INT]				= GLValue(Int::create(-2147483647));
1183 	rangesLo[(int)Array::INPUTTYPE_UNSIGNED_INT]	= GLValue(Uint::create(0));
1184 	rangesLo[(int)Array::INPUTTYPE_HALF]			= GLValue(Half::create(-256.0f));
1185 
1186 	return rangesLo[(int)type];
1187 }
1188 
toFloat(void) const1189 float 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 
1232 class RandomArrayGenerator
1233 {
1234 public:
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 
1239 private:
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 
setData(char * data,Array::InputType type,deRandom & rnd,GLValue min,GLValue max)1248 void 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 
generateArray(int seed,GLValue min,GLValue max,int count,int componentCount,int stride,Array::InputType type)1318 char* 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 
generateQuads(int seed,int count,int componentCount,int offset,int stride,Array::Primitive primitive,Array::InputType type,GLValue min,GLValue max,float gridSize)1341 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)
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 
createQuadsPacked(int seed,int count,int componentCount,int offset,int stride,Array::Primitive primitive)1400 char* 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 
1472 template<typename T>
roundTo(const T & step,const T & value)1473 T roundTo (const T& step, const T& value)
1474 {
1475 	return value - (value % step);
1476 }
1477 
1478 template<typename T>
createQuads(int seed,int count,int componentCount,int offset,int stride,Array::Primitive primitive,T min,T max,float gridSize)1479 char* 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 
generatePerQuad(int seed,int count,int componentCount,int stride,Array::Primitive primitive,Array::InputType type,GLValue min,GLValue max)1582 char* 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 
1636 template<typename T>
createPerQuads(int seed,int count,int componentCount,int stride,Array::Primitive primitive,T min,T max)1637 char* 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 
VertexArrayTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc)1682 VertexArrayTest::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 
~VertexArrayTest(void)1697 VertexArrayTest::~VertexArrayTest (void)
1698 {
1699 	deinit();
1700 }
1701 
init(void)1702 void 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 
deinit(void)1717 void 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 
compare(void)1732 void 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 
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_)1836 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_)
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 
getName(void) const1850 std::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 
getDesc(void) const1897 std::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 
MultiVertexArrayTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const Spec & spec,const char * name,const char * desc)1938 MultiVertexArrayTest::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 
~MultiVertexArrayTest(void)1945 MultiVertexArrayTest::~MultiVertexArrayTest	(void)
1946 {
1947 }
1948 
iterate(void)1949 MultiVertexArrayTest::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 
isUnalignedBufferOffsetTest(void) const2098 bool 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 
isUnalignedBufferStrideTest(void) const2119 bool 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