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
1516 for (int quadNdx = 0; quadNdx < count; ++quadNdx)
1517 {
1518 T x1, x2;
1519 T y1, y2;
1520 T z, w;
1521
1522 // attempt to find a good (i.e not extremely small) quad
1523 for (int attemptNdx = 0; attemptNdx < 4; ++attemptNdx)
1524 {
1525 x1 = roundTo(minDiff, getRandom<T>(rnd, min, max - minDiff));
1526 x2 = roundTo(minDiff, getRandom<T>(rnd, x1 + minDiff, max));
1527
1528 y1 = roundTo(minDiff, getRandom<T>(rnd, min, max - minDiff));
1529 y2 = roundTo(minDiff, getRandom<T>(rnd, y1 + minDiff, max));
1530
1531 z = (componentCount > 2) ? roundTo(minDiff, (getRandom<T>(rnd, min, max))) : (T::create(0));
1532 w = (componentCount > 3) ? roundTo(minDiff, (getRandom<T>(rnd, min, max))) : (T::create(1));
1533
1534 // no additional components, all is good
1535 if (componentCount <= 2)
1536 break;
1537
1538 // The result quad is too thin?
1539 if ((deFloatAbs(x2.template to<float>() - x1.template to<float>()) < minDiff.template to<float>()) ||
1540 (deFloatAbs(y2.template to<float>() - y1.template to<float>()) < minDiff.template to<float>()))
1541 {
1542 DE_ASSERT(attemptNdx < 3);
1543 continue;
1544 }
1545
1546 // all ok
1547 break;
1548 }
1549
1550 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride]), x1);
1551 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + componentStride]), y1);
1552
1553 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride]), x2);
1554 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride + componentStride]), y1);
1555
1556 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 2]), x1);
1557 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 2 + componentStride]), y2);
1558
1559 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 3]), x1);
1560 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 3 + componentStride]), y2);
1561
1562 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 4]), x2);
1563 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 4 + componentStride]), y1);
1564
1565 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 5]), x2);
1566 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * 5 + componentStride]), y2);
1567
1568 if (componentCount > 2)
1569 {
1570 for (int i = 0; i < 6; i++)
1571 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * i + componentStride * 2]), z);
1572 }
1573
1574 if (componentCount > 3)
1575 {
1576 for (int i = 0; i < 6; i++)
1577 alignmentSafeAssignment<T>(&(resultData[quadNdx * quadStride + stride * i + componentStride * 3]), w);
1578 }
1579 }
1580
1581 break;
1582 }
1583
1584 default:
1585 DE_ASSERT(false);
1586 break;
1587 }
1588
1589 return _data;
1590 }
1591
generatePerQuad(int seed,int count,int componentCount,int stride,Array::Primitive primitive,Array::InputType type,GLValue min,GLValue max)1592 char* RandomArrayGenerator::generatePerQuad (int seed, int count, int componentCount, int stride, Array::Primitive primitive, Array::InputType type, GLValue min, GLValue max)
1593 {
1594 char* data = DE_NULL;
1595
1596 switch (type)
1597 {
1598 case Array::INPUTTYPE_FLOAT:
1599 data = createPerQuads<GLValue::Float>(seed, count, componentCount, stride, primitive, min.fl, max.fl);
1600 break;
1601
1602 case Array::INPUTTYPE_FIXED:
1603 data = createPerQuads<GLValue::Fixed>(seed, count, componentCount, stride, primitive, min.fi, max.fi);
1604 break;
1605
1606 case Array::INPUTTYPE_DOUBLE:
1607 data = createPerQuads<GLValue::Double>(seed, count, componentCount, stride, primitive, min.d, max.d);
1608 break;
1609
1610 case Array::INPUTTYPE_BYTE:
1611 data = createPerQuads<GLValue::Byte>(seed, count, componentCount, stride, primitive, min.b, max.b);
1612 break;
1613
1614 case Array::INPUTTYPE_SHORT:
1615 data = createPerQuads<GLValue::Short>(seed, count, componentCount, stride, primitive, min.s, max.s);
1616 break;
1617
1618 case Array::INPUTTYPE_UNSIGNED_BYTE:
1619 data = createPerQuads<GLValue::Ubyte>(seed, count, componentCount, stride, primitive, min.ub, max.ub);
1620 break;
1621
1622 case Array::INPUTTYPE_UNSIGNED_SHORT:
1623 data = createPerQuads<GLValue::Ushort>(seed, count, componentCount, stride, primitive, min.us, max.us);
1624 break;
1625
1626 case Array::INPUTTYPE_UNSIGNED_INT:
1627 data = createPerQuads<GLValue::Uint>(seed, count, componentCount, stride, primitive, min.ui, max.ui);
1628 break;
1629
1630 case Array::INPUTTYPE_INT:
1631 data = createPerQuads<GLValue::Int>(seed, count, componentCount, stride, primitive, min.i, max.i);
1632 break;
1633
1634 case Array::INPUTTYPE_HALF:
1635 data = createPerQuads<GLValue::Half>(seed, count, componentCount, stride, primitive, min.h, max.h);
1636 break;
1637
1638 default:
1639 DE_ASSERT(false);
1640 break;
1641 }
1642
1643 return data;
1644 }
1645
1646 template<typename T>
createPerQuads(int seed,int count,int componentCount,int stride,Array::Primitive primitive,T min,T max)1647 char* RandomArrayGenerator::createPerQuads (int seed, int count, int componentCount, int stride, Array::Primitive primitive, T min, T max)
1648 {
1649 deRandom rnd;
1650 deRandom_init(&rnd, seed);
1651
1652 int componentStride = sizeof(T);
1653
1654 if (stride == 0)
1655 stride = componentStride * componentCount;
1656
1657 int quadStride = 0;
1658
1659 switch (primitive)
1660 {
1661 case Array::PRIMITIVE_TRIANGLES:
1662 quadStride = stride * 6;
1663 break;
1664
1665 default:
1666 DE_ASSERT(false);
1667 break;
1668 }
1669
1670 char* data = new char[count * quadStride];
1671
1672 for (int quadNdx = 0; quadNdx < count; quadNdx++)
1673 {
1674 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1675 {
1676 T val = getRandom<T>(rnd, min, max);
1677
1678 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 0 + componentStride * componentNdx, val);
1679 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 1 + componentStride * componentNdx, val);
1680 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 2 + componentStride * componentNdx, val);
1681 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 3 + componentStride * componentNdx, val);
1682 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 4 + componentStride * componentNdx, val);
1683 alignmentSafeAssignment<T>(data + quadNdx * quadStride + stride * 5 + componentStride * componentNdx, val);
1684 }
1685 }
1686
1687 return data;
1688 }
1689
1690 // VertexArrayTest
1691
VertexArrayTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc)1692 VertexArrayTest::VertexArrayTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name ,const char* desc)
1693 : TestCase (testCtx, name, desc)
1694 , m_renderCtx (renderCtx)
1695 , m_refBuffers (DE_NULL)
1696 , m_refContext (DE_NULL)
1697 , m_glesContext (DE_NULL)
1698 , m_glArrayPack (DE_NULL)
1699 , m_rrArrayPack (DE_NULL)
1700 , m_isOk (false)
1701 , m_maxDiffRed (deCeilFloatToInt32(256.0f * (2.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().redBits))))
1702 , m_maxDiffGreen (deCeilFloatToInt32(256.0f * (2.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().greenBits))))
1703 , m_maxDiffBlue (deCeilFloatToInt32(256.0f * (2.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().blueBits))))
1704 {
1705 }
1706
~VertexArrayTest(void)1707 VertexArrayTest::~VertexArrayTest (void)
1708 {
1709 deinit();
1710 }
1711
init(void)1712 void VertexArrayTest::init (void)
1713 {
1714 const int renderTargetWidth = de::min(512, m_renderCtx.getRenderTarget().getWidth());
1715 const int renderTargetHeight = de::min(512, m_renderCtx.getRenderTarget().getHeight());
1716 sglr::ReferenceContextLimits limits (m_renderCtx);
1717
1718 m_glesContext = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
1719
1720 m_refBuffers = new sglr::ReferenceContextBuffers(m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, renderTargetWidth, renderTargetHeight);
1721 m_refContext = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
1722
1723 m_glArrayPack = new ContextArrayPack(m_renderCtx, *m_glesContext);
1724 m_rrArrayPack = new ContextArrayPack(m_renderCtx, *m_refContext);
1725 }
1726
deinit(void)1727 void VertexArrayTest::deinit (void)
1728 {
1729 delete m_glArrayPack;
1730 delete m_rrArrayPack;
1731 delete m_refBuffers;
1732 delete m_refContext;
1733 delete m_glesContext;
1734
1735 m_glArrayPack = DE_NULL;
1736 m_rrArrayPack = DE_NULL;
1737 m_refBuffers = DE_NULL;
1738 m_refContext = DE_NULL;
1739 m_glesContext = DE_NULL;
1740 }
1741
compare(void)1742 void VertexArrayTest::compare (void)
1743 {
1744 const tcu::Surface& ref = m_rrArrayPack->getSurface();
1745 const tcu::Surface& screen = m_glArrayPack->getSurface();
1746
1747 if (m_renderCtx.getRenderTarget().getNumSamples() > 1)
1748 {
1749 // \todo [mika] Improve compare when using multisampling
1750 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;
1751 m_isOk = tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", ref.getAccess(), screen.getAccess(), 1.5f, tcu::COMPARE_LOG_RESULT);
1752 }
1753 else
1754 {
1755 tcu::RGBA threshold (m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue, 255);
1756 tcu::Surface error (ref.getWidth(), ref.getHeight());
1757
1758 m_isOk = true;
1759
1760 for (int y = 0; y < ref.getHeight(); y++)
1761 {
1762 for (int x = 0; x < ref.getWidth(); x++)
1763 {
1764 tcu::RGBA refPixel = ref.getPixel(x, y);
1765 tcu::RGBA screenPixel = screen.getPixel(x, y);
1766 bool isOkPixel = false;
1767
1768 if (y == 0 || y + 1 == ref.getHeight() || x == 0 || x + 1 == ref.getWidth())
1769 {
1770 // Don't check borders since the pixel neighborhood is undefined
1771 error.setPixel(x, y, tcu::RGBA(screenPixel.getRed(), (screenPixel.getGreen() + 255) / 2, screenPixel.getBlue(), 255));
1772 continue;
1773 }
1774
1775 // 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.
1776 // This fixes some false negatives.
1777 bool refThin = (!tcu::compareThreshold(refPixel, ref.getPixel(x-1, y ), threshold) && !tcu::compareThreshold(refPixel, ref.getPixel(x+1, y ), threshold)) ||
1778 (!tcu::compareThreshold(refPixel, ref.getPixel(x , y-1), threshold) && !tcu::compareThreshold(refPixel, ref.getPixel(x , y+1), threshold));
1779 bool screenThin = (!tcu::compareThreshold(screenPixel, screen.getPixel(x-1, y ), threshold) && !tcu::compareThreshold(screenPixel, screen.getPixel(x+1, y ), threshold)) ||
1780 (!tcu::compareThreshold(screenPixel, screen.getPixel(x , y-1), threshold) && !tcu::compareThreshold(screenPixel, screen.getPixel(x , y+1), threshold));
1781
1782 if (refThin && screenThin)
1783 isOkPixel = true;
1784 else
1785 {
1786 for (int dy = -1; dy < 2 && !isOkPixel; dy++)
1787 {
1788 for (int dx = -1; dx < 2 && !isOkPixel; dx++)
1789 {
1790 // Check reference pixel against screen pixel
1791 {
1792 tcu::RGBA screenCmpPixel = screen.getPixel(x+dx, y+dy);
1793 deUint8 r = (deUint8)deAbs32(refPixel.getRed() - screenCmpPixel.getRed());
1794 deUint8 g = (deUint8)deAbs32(refPixel.getGreen() - screenCmpPixel.getGreen());
1795 deUint8 b = (deUint8)deAbs32(refPixel.getBlue() - screenCmpPixel.getBlue());
1796
1797 if (r <= m_maxDiffRed && g <= m_maxDiffGreen && b <= m_maxDiffBlue)
1798 isOkPixel = true;
1799 }
1800
1801 // Check screen pixels against reference pixel
1802 {
1803 tcu::RGBA refCmpPixel = ref.getPixel(x+dx, y+dy);
1804 deUint8 r = (deUint8)deAbs32(refCmpPixel.getRed() - screenPixel.getRed());
1805 deUint8 g = (deUint8)deAbs32(refCmpPixel.getGreen() - screenPixel.getGreen());
1806 deUint8 b = (deUint8)deAbs32(refCmpPixel.getBlue() - screenPixel.getBlue());
1807
1808 if (r <= m_maxDiffRed && g <= m_maxDiffGreen && b <= m_maxDiffBlue)
1809 isOkPixel = true;
1810 }
1811 }
1812 }
1813 }
1814
1815 if (isOkPixel)
1816 error.setPixel(x, y, tcu::RGBA(screen.getPixel(x, y).getRed(), (screen.getPixel(x, y).getGreen() + 255) / 2, screen.getPixel(x, y).getBlue(), 255));
1817 else
1818 {
1819 error.setPixel(x, y, tcu::RGBA(255, 0, 0, 255));
1820 m_isOk = false;
1821 }
1822 }
1823 }
1824
1825 tcu::TestLog& log = m_testCtx.getLog();
1826 if (!m_isOk)
1827 {
1828 log << TestLog::Message << "Image comparison failed, threshold = (" << m_maxDiffRed << ", " << m_maxDiffGreen << ", " << m_maxDiffBlue << ")" << TestLog::EndMessage;
1829 log << TestLog::ImageSet("Compare result", "Result of rendering")
1830 << TestLog::Image("Result", "Result", screen)
1831 << TestLog::Image("Reference", "Reference", ref)
1832 << TestLog::Image("ErrorMask", "Error mask", error)
1833 << TestLog::EndImageSet;
1834 }
1835 else
1836 {
1837 log << TestLog::ImageSet("Compare result", "Result of rendering")
1838 << TestLog::Image("Result", "Result", screen)
1839 << TestLog::EndImageSet;
1840 }
1841 }
1842 }
1843
1844 // MultiVertexArrayTest
1845
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_)1846 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_)
1847 : inputType (inputType_)
1848 , outputType (outputType_)
1849 , storage (storage_)
1850 , usage (usage_)
1851 , componentCount(componentCount_)
1852 , offset (offset_)
1853 , stride (stride_)
1854 , normalize (normalize_)
1855 , min (min_)
1856 , max (max_)
1857 {
1858 }
1859
getName(void) const1860 std::string MultiVertexArrayTest::Spec::getName (void) const
1861 {
1862 std::stringstream name;
1863
1864 for (size_t ndx = 0; ndx < arrays.size(); ++ndx)
1865 {
1866 const ArraySpec& array = arrays[ndx];
1867
1868 if (arrays.size() > 1)
1869 name << "array" << ndx << "_";
1870
1871 name
1872 << Array::storageToString(array.storage) << "_"
1873 << array.offset << "_"
1874 << array.stride << "_"
1875 << Array::inputTypeToString((Array::InputType)array.inputType);
1876 if (array.inputType != Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && array.inputType != Array::INPUTTYPE_INT_2_10_10_10)
1877 name << array.componentCount;
1878 name
1879 << "_"
1880 << (array.normalize ? "normalized_" : "")
1881 << Array::outputTypeToString(array.outputType) << "_"
1882 << Array::usageTypeToString(array.usage) << "_";
1883 }
1884
1885 if (first)
1886 name << "first" << first << "_";
1887
1888 switch (primitive)
1889 {
1890 case Array::PRIMITIVE_TRIANGLES:
1891 name << "quads_";
1892 break;
1893 case Array::PRIMITIVE_POINTS:
1894 name << "points_";
1895 break;
1896
1897 default:
1898 DE_ASSERT(false);
1899 break;
1900 }
1901
1902 name << drawCount;
1903
1904 return name.str();
1905 }
1906
getDesc(void) const1907 std::string MultiVertexArrayTest::Spec::getDesc (void) const
1908 {
1909 std::stringstream desc;
1910
1911 for (size_t ndx = 0; ndx < arrays.size(); ++ndx)
1912 {
1913 const ArraySpec& array = arrays[ndx];
1914
1915 desc
1916 << "Array " << ndx << ": "
1917 << "Storage in " << Array::storageToString(array.storage) << ", "
1918 << "stride " << array.stride << ", "
1919 << "input datatype " << Array::inputTypeToString((Array::InputType)array.inputType) << ", "
1920 << "input component count " << array.componentCount << ", "
1921 << (array.normalize ? "normalized, " : "")
1922 << "used as " << Array::outputTypeToString(array.outputType) << ", ";
1923 }
1924
1925 desc
1926 << "drawArrays(), "
1927 << "first " << first << ", "
1928 << drawCount;
1929
1930 switch (primitive)
1931 {
1932 case Array::PRIMITIVE_TRIANGLES:
1933 desc << "quads ";
1934 break;
1935 case Array::PRIMITIVE_POINTS:
1936 desc << "points";
1937 break;
1938
1939 default:
1940 DE_ASSERT(false);
1941 break;
1942 }
1943
1944
1945 return desc.str();
1946 }
1947
MultiVertexArrayTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const Spec & spec,const char * name,const char * desc)1948 MultiVertexArrayTest::MultiVertexArrayTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const Spec& spec, const char* name, const char* desc)
1949 : VertexArrayTest (testCtx, renderCtx, name, desc)
1950 , m_spec (spec)
1951 , m_iteration (0)
1952 {
1953 }
1954
~MultiVertexArrayTest(void)1955 MultiVertexArrayTest::~MultiVertexArrayTest (void)
1956 {
1957 }
1958
iterate(void)1959 MultiVertexArrayTest::IterateResult MultiVertexArrayTest::iterate (void)
1960 {
1961 if (m_iteration == 0)
1962 {
1963 const size_t primitiveSize = (m_spec.primitive == Array::PRIMITIVE_TRIANGLES) ? (6) : (1); // in non-indexed draw Triangles means rectangles
1964 float coordScale = 1.0f;
1965 float colorScale = 1.0f;
1966 const bool useVao = m_renderCtx.getType().getProfile() == glu::PROFILE_CORE;
1967
1968 // Log info
1969 m_testCtx.getLog() << TestLog::Message << m_spec.getDesc() << TestLog::EndMessage;
1970
1971 // Color and Coord scale
1972 {
1973 // First array is always position
1974 {
1975 Spec::ArraySpec arraySpec = m_spec.arrays[0];
1976 if (arraySpec.inputType == Array::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
1977 {
1978 if (arraySpec.normalize)
1979 coordScale = 1.0f;
1980 else
1981 coordScale = 1.0 / 1024.0;
1982 }
1983 else if (arraySpec.inputType == Array::INPUTTYPE_INT_2_10_10_10)
1984 {
1985 if (arraySpec.normalize)
1986 coordScale = 1.0f;
1987 else
1988 coordScale = 1.0 / 512.0;
1989 }
1990 else
1991 coordScale = (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(0.9 / double(arraySpec.max.toFloat())));
1992
1993 if (arraySpec.outputType == Array::OUTPUTTYPE_VEC3 || arraySpec.outputType == Array::OUTPUTTYPE_VEC4
1994 || arraySpec.outputType == Array::OUTPUTTYPE_IVEC3 || arraySpec.outputType == Array::OUTPUTTYPE_IVEC4
1995 || arraySpec.outputType == Array::OUTPUTTYPE_UVEC3 || arraySpec.outputType == Array::OUTPUTTYPE_UVEC4)
1996 coordScale = coordScale * 0.5f;
1997 }
1998
1999 // And other arrays are color-like
2000 for (int arrayNdx = 1; arrayNdx < (int)m_spec.arrays.size(); arrayNdx++)
2001 {
2002 Spec::ArraySpec arraySpec = m_spec.arrays[arrayNdx];
2003
2004 colorScale *= (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(1.0 / double(arraySpec.max.toFloat())));
2005 if (arraySpec.outputType == Array::OUTPUTTYPE_VEC4)
2006 colorScale *= (arraySpec.normalize && !inputTypeIsFloatType(arraySpec.inputType) ? 1.0f : float(1.0 / double(arraySpec.max.toFloat())));
2007 }
2008 }
2009
2010 // Data
2011 for (int arrayNdx = 0; arrayNdx < (int)m_spec.arrays.size(); arrayNdx++)
2012 {
2013 Spec::ArraySpec arraySpec = m_spec.arrays[arrayNdx];
2014 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);
2015 const char* data = DE_NULL;
2016 const size_t stride = (arraySpec.stride == 0) ? (arraySpec.componentCount * Array::inputTypeSize(arraySpec.inputType)) : (arraySpec.stride);
2017 const size_t bufferSize = arraySpec.offset + stride * (m_spec.drawCount * primitiveSize - 1) + arraySpec.componentCount * Array::inputTypeSize(arraySpec.inputType);
2018 // Snap values to at least 3x3 grid
2019 const float gridSize = 3.0f / (float)(de::min(m_renderCtx.getRenderTarget().getWidth(), m_renderCtx.getRenderTarget().getHeight()) - 1);
2020
2021 switch (m_spec.primitive)
2022 {
2023 // case Array::PRIMITIVE_POINTS:
2024 // data = RandomArrayGenerator::generateArray(seed, arraySpec.min, arraySpec.max, arraySpec.count, arraySpec.componentCount, arraySpec.stride, arraySpec.inputType);
2025 // break;
2026 case Array::PRIMITIVE_TRIANGLES:
2027 if (arrayNdx == 0)
2028 {
2029 data = RandomArrayGenerator::generateQuads(seed, m_spec.drawCount, arraySpec.componentCount, arraySpec.offset, arraySpec.stride, m_spec.primitive, arraySpec.inputType, arraySpec.min, arraySpec.max, gridSize);
2030 }
2031 else
2032 {
2033 DE_ASSERT(arraySpec.offset == 0); // \note [jarkko] it just hasn't been implemented
2034 data = RandomArrayGenerator::generatePerQuad(seed, m_spec.drawCount, arraySpec.componentCount, arraySpec.stride, m_spec.primitive, arraySpec.inputType, arraySpec.min, arraySpec.max);
2035 }
2036 break;
2037
2038 default:
2039 DE_ASSERT(false);
2040 break;
2041 }
2042
2043 m_glArrayPack->newArray(arraySpec.storage);
2044 m_rrArrayPack->newArray(arraySpec.storage);
2045
2046 m_glArrayPack->getArray(arrayNdx)->data(Array::TARGET_ARRAY, (int)bufferSize, data, arraySpec.usage);
2047 m_rrArrayPack->getArray(arrayNdx)->data(Array::TARGET_ARRAY, (int)bufferSize, data, arraySpec.usage);
2048
2049 m_glArrayPack->getArray(arrayNdx)->bind(arrayNdx, arraySpec.offset, arraySpec.componentCount, arraySpec.inputType, arraySpec.outputType, arraySpec.normalize, arraySpec.stride);
2050 m_rrArrayPack->getArray(arrayNdx)->bind(arrayNdx, arraySpec.offset, arraySpec.componentCount, arraySpec.inputType, arraySpec.outputType, arraySpec.normalize, arraySpec.stride);
2051
2052 delete [] data;
2053 }
2054
2055 try
2056 {
2057 m_glArrayPack->render(m_spec.primitive, m_spec.first, m_spec.drawCount * (int)primitiveSize, useVao, coordScale, colorScale);
2058 m_testCtx.touchWatchdog();
2059 m_rrArrayPack->render(m_spec.primitive, m_spec.first, m_spec.drawCount * (int)primitiveSize, useVao, coordScale, colorScale);
2060 }
2061 catch (glu::Error& err)
2062 {
2063 // GL Errors are ok if the mode is not properly aligned
2064
2065 m_testCtx.getLog() << TestLog::Message << "Got error: " << err.what() << TestLog::EndMessage;
2066
2067 if (isUnalignedBufferOffsetTest())
2068 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
2069 else if (isUnalignedBufferStrideTest())
2070 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
2071 else
2072 throw;
2073
2074 return STOP;
2075 }
2076
2077 m_iteration++;
2078 return CONTINUE;
2079 }
2080 else if (m_iteration == 1)
2081 {
2082 compare();
2083
2084 if (m_isOk)
2085 {
2086 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2087 }
2088 else
2089 {
2090 if (isUnalignedBufferOffsetTest())
2091 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
2092 else if (isUnalignedBufferStrideTest())
2093 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
2094 else
2095 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed.");
2096 }
2097
2098 m_iteration++;
2099 return STOP;
2100 }
2101 else
2102 {
2103 DE_ASSERT(false);
2104 return STOP;
2105 }
2106 }
2107
isUnalignedBufferOffsetTest(void) const2108 bool MultiVertexArrayTest::isUnalignedBufferOffsetTest (void) const
2109 {
2110 // Buffer offsets should be data type size aligned
2111 for (size_t i = 0; i < m_spec.arrays.size(); ++i)
2112 {
2113 if (m_spec.arrays[i].storage == Array::STORAGE_BUFFER)
2114 {
2115 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;
2116
2117 int dataTypeSize = Array::inputTypeSize(m_spec.arrays[i].inputType);
2118 if (inputTypePacked)
2119 dataTypeSize = 4;
2120
2121 if (m_spec.arrays[i].offset % dataTypeSize != 0)
2122 return true;
2123 }
2124 }
2125
2126 return false;
2127 }
2128
isUnalignedBufferStrideTest(void) const2129 bool MultiVertexArrayTest::isUnalignedBufferStrideTest (void) const
2130 {
2131 // Buffer strides should be data type size aligned
2132 for (size_t i = 0; i < m_spec.arrays.size(); ++i)
2133 {
2134 if (m_spec.arrays[i].storage == Array::STORAGE_BUFFER)
2135 {
2136 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;
2137
2138 int dataTypeSize = Array::inputTypeSize(m_spec.arrays[i].inputType);
2139 if (inputTypePacked)
2140 dataTypeSize = 4;
2141
2142 if (m_spec.arrays[i].stride % dataTypeSize != 0)
2143 return true;
2144 }
2145 }
2146
2147 return false;
2148 }
2149
2150 } // gls
2151 } // deqp
2152