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