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