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