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 Draw tests 22 *//*--------------------------------------------------------------------*/ 23 24#include "glsDrawTest.hpp" 25 26#include "deRandom.h" 27#include "deRandom.hpp" 28#include "deMath.h" 29#include "deStringUtil.hpp" 30#include "deFloat16.h" 31#include "deUniquePtr.hpp" 32 33#include "tcuTestLog.hpp" 34#include "tcuPixelFormat.hpp" 35#include "tcuRGBA.hpp" 36#include "tcuSurface.hpp" 37#include "tcuVector.hpp" 38#include "tcuTestLog.hpp" 39#include "tcuRenderTarget.hpp" 40#include "tcuStringTemplate.hpp" 41#include "tcuImageCompare.hpp" 42#include "tcuFloat.hpp" 43#include "tcuTextureUtil.hpp" 44 45#include "gluPixelTransfer.hpp" 46#include "gluCallLogWrapper.hpp" 47 48#include "sglrContext.hpp" 49#include "sglrReferenceContext.hpp" 50#include "sglrGLContext.hpp" 51 52#include "rrGenericVector.hpp" 53 54#include <cstring> 55#include <cmath> 56#include <vector> 57#include <sstream> 58#include <limits> 59 60#include "glwDefs.hpp" 61#include "glwEnums.hpp" 62 63namespace deqp 64{ 65namespace gls 66{ 67namespace 68{ 69 70using tcu::TestLog; 71using namespace glw; // GL types 72 73const int MAX_RENDER_TARGET_SIZE = 512; 74 75// Utils 76 77static GLenum targetToGL (DrawTestSpec::Target target) 78{ 79 DE_ASSERT(target < DrawTestSpec::TARGET_LAST); 80 81 static const GLenum targets[] = 82 { 83 GL_ELEMENT_ARRAY_BUFFER, // TARGET_ELEMENT_ARRAY = 0, 84 GL_ARRAY_BUFFER // TARGET_ARRAY, 85 }; 86 87 return targets[(int)target]; 88} 89 90static GLenum usageToGL (DrawTestSpec::Usage usage) 91{ 92 DE_ASSERT(usage < DrawTestSpec::USAGE_LAST); 93 94 static const GLenum usages[] = 95 { 96 GL_DYNAMIC_DRAW, // USAGE_DYNAMIC_DRAW = 0, 97 GL_STATIC_DRAW, // USAGE_STATIC_DRAW, 98 GL_STREAM_DRAW, // USAGE_STREAM_DRAW, 99 100 GL_STREAM_READ, // USAGE_STREAM_READ, 101 GL_STREAM_COPY, // USAGE_STREAM_COPY, 102 103 GL_STATIC_READ, // USAGE_STATIC_READ, 104 GL_STATIC_COPY, // USAGE_STATIC_COPY, 105 106 GL_DYNAMIC_READ, // USAGE_DYNAMIC_READ, 107 GL_DYNAMIC_COPY // USAGE_DYNAMIC_COPY, 108 }; 109 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(usages) == DrawTestSpec::USAGE_LAST); 110 111 return usages[(int)usage]; 112} 113 114static GLenum inputTypeToGL (DrawTestSpec::InputType type) 115{ 116 DE_ASSERT(type < DrawTestSpec::INPUTTYPE_LAST); 117 118 static const GLenum types[] = 119 { 120 GL_FLOAT, // INPUTTYPE_FLOAT = 0, 121 GL_FIXED, // INPUTTYPE_FIXED, 122 GL_DOUBLE, // INPUTTYPE_DOUBLE 123 GL_BYTE, // INPUTTYPE_BYTE, 124 GL_SHORT, // INPUTTYPE_SHORT, 125 GL_UNSIGNED_BYTE, // INPUTTYPE_UNSIGNED_BYTE, 126 GL_UNSIGNED_SHORT, // INPUTTYPE_UNSIGNED_SHORT, 127 128 GL_INT, // INPUTTYPE_INT, 129 GL_UNSIGNED_INT, // INPUTTYPE_UNSIGNED_INT, 130 GL_HALF_FLOAT, // INPUTTYPE_HALF, 131 GL_UNSIGNED_INT_2_10_10_10_REV, // INPUTTYPE_UNSIGNED_INT_2_10_10_10, 132 GL_INT_2_10_10_10_REV // INPUTTYPE_INT_2_10_10_10, 133 }; 134 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types) == DrawTestSpec::INPUTTYPE_LAST); 135 136 return types[(int)type]; 137} 138 139static std::string outputTypeToGLType (DrawTestSpec::OutputType type) 140{ 141 DE_ASSERT(type < DrawTestSpec::OUTPUTTYPE_LAST); 142 143 static const char* types[] = 144 { 145 "float", // OUTPUTTYPE_FLOAT = 0, 146 "vec2", // OUTPUTTYPE_VEC2, 147 "vec3", // OUTPUTTYPE_VEC3, 148 "vec4", // OUTPUTTYPE_VEC4, 149 150 "int", // OUTPUTTYPE_INT, 151 "uint", // OUTPUTTYPE_UINT, 152 153 "ivec2", // OUTPUTTYPE_IVEC2, 154 "ivec3", // OUTPUTTYPE_IVEC3, 155 "ivec4", // OUTPUTTYPE_IVEC4, 156 157 "uvec2", // OUTPUTTYPE_UVEC2, 158 "uvec3", // OUTPUTTYPE_UVEC3, 159 "uvec4", // OUTPUTTYPE_UVEC4, 160 }; 161 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types) == DrawTestSpec::OUTPUTTYPE_LAST); 162 163 return types[type]; 164} 165 166static GLenum primitiveToGL (DrawTestSpec::Primitive primitive) 167{ 168 GLenum primitives[] = 169 { 170 GL_POINTS, // PRIMITIVE_POINTS = 0, 171 GL_TRIANGLES, // PRIMITIVE_TRIANGLES, 172 GL_TRIANGLE_FAN, // PRIMITIVE_TRIANGLE_FAN, 173 GL_TRIANGLE_STRIP, // PRIMITIVE_TRIANGLE_STRIP, 174 GL_LINES, // PRIMITIVE_LINES 175 GL_LINE_STRIP, // PRIMITIVE_LINE_STRIP 176 GL_LINE_LOOP, // PRIMITIVE_LINE_LOOP 177 GL_LINES_ADJACENCY, // PRIMITIVE_LINES_ADJACENCY 178 GL_LINE_STRIP_ADJACENCY, // PRIMITIVE_LINE_STRIP_ADJACENCY 179 GL_TRIANGLES_ADJACENCY, // PRIMITIVE_TRIANGLES_ADJACENCY 180 GL_TRIANGLE_STRIP_ADJACENCY, // PRIMITIVE_TRIANGLE_STRIP_ADJACENCY 181 }; 182 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(primitives) == DrawTestSpec::PRIMITIVE_LAST); 183 184 return primitives[(int)primitive]; 185} 186 187static deUint32 indexTypeToGL (DrawTestSpec::IndexType indexType) 188{ 189 GLenum indexTypes[] = 190 { 191 GL_UNSIGNED_BYTE, // INDEXTYPE_BYTE = 0, 192 GL_UNSIGNED_SHORT, // INDEXTYPE_SHORT, 193 GL_UNSIGNED_INT, // INDEXTYPE_INT, 194 }; 195 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(indexTypes) == DrawTestSpec::INDEXTYPE_LAST); 196 197 return indexTypes[(int)indexType]; 198} 199 200static bool inputTypeIsFloatType (DrawTestSpec::InputType type) 201{ 202 if (type == DrawTestSpec::INPUTTYPE_FLOAT) 203 return true; 204 if (type == DrawTestSpec::INPUTTYPE_FIXED) 205 return true; 206 if (type == DrawTestSpec::INPUTTYPE_HALF) 207 return true; 208 if (type == DrawTestSpec::INPUTTYPE_DOUBLE) 209 return true; 210 return false; 211} 212 213static bool outputTypeIsFloatType (DrawTestSpec::OutputType type) 214{ 215 if (type == DrawTestSpec::OUTPUTTYPE_FLOAT 216 || type == DrawTestSpec::OUTPUTTYPE_VEC2 217 || type == DrawTestSpec::OUTPUTTYPE_VEC3 218 || type == DrawTestSpec::OUTPUTTYPE_VEC4) 219 return true; 220 221 return false; 222} 223 224static bool outputTypeIsIntType (DrawTestSpec::OutputType type) 225{ 226 if (type == DrawTestSpec::OUTPUTTYPE_INT 227 || type == DrawTestSpec::OUTPUTTYPE_IVEC2 228 || type == DrawTestSpec::OUTPUTTYPE_IVEC3 229 || type == DrawTestSpec::OUTPUTTYPE_IVEC4) 230 return true; 231 232 return false; 233} 234 235static bool outputTypeIsUintType (DrawTestSpec::OutputType type) 236{ 237 if (type == DrawTestSpec::OUTPUTTYPE_UINT 238 || type == DrawTestSpec::OUTPUTTYPE_UVEC2 239 || type == DrawTestSpec::OUTPUTTYPE_UVEC3 240 || type == DrawTestSpec::OUTPUTTYPE_UVEC4) 241 return true; 242 243 return false; 244} 245 246static size_t getElementCount (DrawTestSpec::Primitive primitive, size_t primitiveCount) 247{ 248 switch (primitive) 249 { 250 case DrawTestSpec::PRIMITIVE_POINTS: return primitiveCount; 251 case DrawTestSpec::PRIMITIVE_TRIANGLES: return primitiveCount * 3; 252 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN: return primitiveCount + 2; 253 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP: return primitiveCount + 2; 254 case DrawTestSpec::PRIMITIVE_LINES: return primitiveCount * 2; 255 case DrawTestSpec::PRIMITIVE_LINE_STRIP: return primitiveCount + 1; 256 case DrawTestSpec::PRIMITIVE_LINE_LOOP: return (primitiveCount==1) ? (2) : (primitiveCount); 257 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY: return primitiveCount * 4; 258 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY: return primitiveCount + 3; 259 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY: return primitiveCount * 6; 260 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY: return primitiveCount * 2 + 4; 261 default: 262 DE_ASSERT(false); 263 return 0; 264 } 265} 266 267struct MethodInfo 268{ 269 bool indexed; 270 bool instanced; 271 bool ranged; 272 bool first; 273 bool baseVertex; 274 bool indirect; 275}; 276 277static MethodInfo getMethodInfo (gls::DrawTestSpec::DrawMethod method) 278{ 279 static const MethodInfo infos[] = 280 { 281 // indexed instanced ranged first baseVertex indirect 282 { false, false, false, true, false, false }, //!< DRAWMETHOD_DRAWARRAYS, 283 { false, true, false, true, false, false }, //!< DRAWMETHOD_DRAWARRAYS_INSTANCED, 284 { false, true, false, true, false, true }, //!< DRAWMETHOD_DRAWARRAYS_INDIRECT, 285 { true, false, false, false, false, false }, //!< DRAWMETHOD_DRAWELEMENTS, 286 { true, false, true, false, false, false }, //!< DRAWMETHOD_DRAWELEMENTS_RANGED, 287 { true, true, false, false, false, false }, //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED, 288 { true, true, false, false, true, true }, //!< DRAWMETHOD_DRAWELEMENTS_INDIRECT, 289 { true, false, false, false, true, false }, //!< DRAWMETHOD_DRAWELEMENTS_BASEVERTEX, 290 { true, true, false, false, true, false }, //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX, 291 { true, false, true, false, true, false }, //!< DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX, 292 }; 293 294 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(infos) == DrawTestSpec::DRAWMETHOD_LAST); 295 DE_ASSERT((int)method < DE_LENGTH_OF_ARRAY(infos)); 296 return infos[(int)method]; 297} 298 299template<class T> 300inline static void alignmentSafeAssignment (char* dst, T val) 301{ 302 std::memcpy(dst, &val, sizeof(T)); 303} 304 305static bool checkSpecsShaderCompatible (const DrawTestSpec& a, const DrawTestSpec& b) 306{ 307 // Only the attributes matter 308 if (a.attribs.size() != b.attribs.size()) 309 return false; 310 311 for (size_t ndx = 0; ndx < a.attribs.size(); ++ndx) 312 { 313 // Only the output type (== shader input type) matters and the usage in the shader. 314 315 if (a.attribs[ndx].additionalPositionAttribute != b.attribs[ndx].additionalPositionAttribute) 316 return false; 317 318 // component counts need not to match 319 if (outputTypeIsFloatType(a.attribs[ndx].outputType) && outputTypeIsFloatType(b.attribs[ndx].outputType)) 320 continue; 321 if (outputTypeIsIntType(a.attribs[ndx].outputType) && outputTypeIsIntType(b.attribs[ndx].outputType)) 322 continue; 323 if (outputTypeIsUintType(a.attribs[ndx].outputType) && outputTypeIsUintType(b.attribs[ndx].outputType)) 324 continue; 325 326 return false; 327 } 328 329 return true; 330} 331 332// generate random vectors in a way that does not depend on argument evaluation order 333 334tcu::Vec4 generateRandomVec4 (de::Random& random) 335{ 336 tcu::Vec4 retVal; 337 338 for (int i = 0; i < 4; ++i) 339 retVal[i] = random.getFloat(); 340 341 return retVal; 342} 343 344tcu::IVec4 generateRandomIVec4 (de::Random& random) 345{ 346 tcu::IVec4 retVal; 347 348 for (int i = 0; i < 4; ++i) 349 retVal[i] = random.getUint32(); 350 351 return retVal; 352} 353 354tcu::UVec4 generateRandomUVec4 (de::Random& random) 355{ 356 tcu::UVec4 retVal; 357 358 for (int i = 0; i < 4; ++i) 359 retVal[i] = random.getUint32(); 360 361 return retVal; 362} 363 364// IterationLogSectionEmitter 365 366class IterationLogSectionEmitter 367{ 368public: 369 IterationLogSectionEmitter (tcu::TestLog& log, size_t testIteration, size_t testIterations, const std::string& description, bool enabled); 370 ~IterationLogSectionEmitter (void); 371private: 372 IterationLogSectionEmitter (const IterationLogSectionEmitter&); // delete 373 IterationLogSectionEmitter& operator= (const IterationLogSectionEmitter&); // delete 374 375 tcu::TestLog& m_log; 376 bool m_enabled; 377}; 378 379IterationLogSectionEmitter::IterationLogSectionEmitter (tcu::TestLog& log, size_t testIteration, size_t testIterations, const std::string& description, bool enabled) 380 : m_log (log) 381 , m_enabled (enabled) 382{ 383 if (m_enabled) 384 { 385 std::ostringstream buf; 386 buf << "Iteration " << (testIteration+1) << "/" << testIterations; 387 388 if (!description.empty()) 389 buf << " - " << description; 390 391 m_log << tcu::TestLog::Section(buf.str(), buf.str()); 392 } 393} 394 395IterationLogSectionEmitter::~IterationLogSectionEmitter (void) 396{ 397 if (m_enabled) 398 m_log << tcu::TestLog::EndSection; 399} 400 401// GLValue 402 403class GLValue 404{ 405public: 406 407 template<class Type> 408 class WrappedType 409 { 410 public: 411 static WrappedType<Type> create (Type value) { WrappedType<Type> v; v.m_value = value; return v; } 412 inline Type getValue (void) const { return m_value; } 413 414 inline WrappedType<Type> operator+ (const WrappedType<Type>& other) const { return WrappedType<Type>::create(m_value + other.getValue()); } 415 inline WrappedType<Type> operator* (const WrappedType<Type>& other) const { return WrappedType<Type>::create(m_value * other.getValue()); } 416 inline WrappedType<Type> operator/ (const WrappedType<Type>& other) const { return WrappedType<Type>::create(m_value / other.getValue()); } 417 inline WrappedType<Type> operator- (const WrappedType<Type>& other) const { return WrappedType<Type>::create(m_value - other.getValue()); } 418 419 inline WrappedType<Type>& operator+= (const WrappedType<Type>& other) { m_value += other.getValue(); return *this; } 420 inline WrappedType<Type>& operator*= (const WrappedType<Type>& other) { m_value *= other.getValue(); return *this; } 421 inline WrappedType<Type>& operator/= (const WrappedType<Type>& other) { m_value /= other.getValue(); return *this; } 422 inline WrappedType<Type>& operator-= (const WrappedType<Type>& other) { m_value -= other.getValue(); return *this; } 423 424 inline bool operator== (const WrappedType<Type>& other) const { return m_value == other.m_value; } 425 inline bool operator!= (const WrappedType<Type>& other) const { return m_value != other.m_value; } 426 inline bool operator< (const WrappedType<Type>& other) const { return m_value < other.m_value; } 427 inline bool operator> (const WrappedType<Type>& other) const { return m_value > other.m_value; } 428 inline bool operator<= (const WrappedType<Type>& other) const { return m_value <= other.m_value; } 429 inline bool operator>= (const WrappedType<Type>& other) const { return m_value >= other.m_value; } 430 431 inline operator Type (void) const { return m_value; } 432 template<class T> 433 inline T to (void) const { return (T)m_value; } 434 private: 435 Type m_value; 436 }; 437 438 typedef WrappedType<deInt16> Short; 439 typedef WrappedType<deUint16> Ushort; 440 441 typedef WrappedType<deInt8> Byte; 442 typedef WrappedType<deUint8> Ubyte; 443 444 typedef WrappedType<float> Float; 445 typedef WrappedType<double> Double; 446 447 typedef WrappedType<deInt32> Int; 448 typedef WrappedType<deUint32> Uint; 449 450 class Half 451 { 452 public: 453 static Half create (float value) { Half h; h.m_value = floatToHalf(value); return h; } 454 inline deFloat16 getValue (void) const { return m_value; } 455 456 inline Half operator+ (const Half& other) const { return create(halfToFloat(m_value) + halfToFloat(other.getValue())); } 457 inline Half operator* (const Half& other) const { return create(halfToFloat(m_value) * halfToFloat(other.getValue())); } 458 inline Half operator/ (const Half& other) const { return create(halfToFloat(m_value) / halfToFloat(other.getValue())); } 459 inline Half operator- (const Half& other) const { return create(halfToFloat(m_value) - halfToFloat(other.getValue())); } 460 461 inline Half& operator+= (const Half& other) { m_value = floatToHalf(halfToFloat(other.getValue()) + halfToFloat(m_value)); return *this; } 462 inline Half& operator*= (const Half& other) { m_value = floatToHalf(halfToFloat(other.getValue()) * halfToFloat(m_value)); return *this; } 463 inline Half& operator/= (const Half& other) { m_value = floatToHalf(halfToFloat(other.getValue()) / halfToFloat(m_value)); return *this; } 464 inline Half& operator-= (const Half& other) { m_value = floatToHalf(halfToFloat(other.getValue()) - halfToFloat(m_value)); return *this; } 465 466 inline bool operator== (const Half& other) const { return m_value == other.m_value; } 467 inline bool operator!= (const Half& other) const { return m_value != other.m_value; } 468 inline bool operator< (const Half& other) const { return halfToFloat(m_value) < halfToFloat(other.m_value); } 469 inline bool operator> (const Half& other) const { return halfToFloat(m_value) > halfToFloat(other.m_value); } 470 inline bool operator<= (const Half& other) const { return halfToFloat(m_value) <= halfToFloat(other.m_value); } 471 inline bool operator>= (const Half& other) const { return halfToFloat(m_value) >= halfToFloat(other.m_value); } 472 473 template<class T> 474 inline T to (void) const { return (T)halfToFloat(m_value); } 475 476 inline static deFloat16 floatToHalf (float f); 477 inline static float halfToFloat (deFloat16 h); 478 private: 479 deFloat16 m_value; 480 }; 481 482 class Fixed 483 { 484 public: 485 static Fixed create (deInt32 value) { Fixed v; v.m_value = value; return v; } 486 inline deInt32 getValue (void) const { return m_value; } 487 488 inline Fixed operator+ (const Fixed& other) const { return create(m_value + other.getValue()); } 489 inline Fixed operator* (const Fixed& other) const { return create(m_value * other.getValue()); } 490 inline Fixed operator/ (const Fixed& other) const { return create(m_value / other.getValue()); } 491 inline Fixed operator- (const Fixed& other) const { return create(m_value - other.getValue()); } 492 493 inline Fixed& operator+= (const Fixed& other) { m_value += other.getValue(); return *this; } 494 inline Fixed& operator*= (const Fixed& other) { m_value *= other.getValue(); return *this; } 495 inline Fixed& operator/= (const Fixed& other) { m_value /= other.getValue(); return *this; } 496 inline Fixed& operator-= (const Fixed& other) { m_value -= other.getValue(); return *this; } 497 498 inline bool operator== (const Fixed& other) const { return m_value == other.m_value; } 499 inline bool operator!= (const Fixed& other) const { return m_value != other.m_value; } 500 inline bool operator< (const Fixed& other) const { return m_value < other.m_value; } 501 inline bool operator> (const Fixed& other) const { return m_value > other.m_value; } 502 inline bool operator<= (const Fixed& other) const { return m_value <= other.m_value; } 503 inline bool operator>= (const Fixed& other) const { return m_value >= other.m_value; } 504 505 inline operator deInt32 (void) const { return m_value; } 506 template<class T> 507 inline T to (void) const { return (T)m_value; } 508 private: 509 deInt32 m_value; 510 }; 511 512 // \todo [mika] This is pretty messy 513 GLValue (void) : type(DrawTestSpec::INPUTTYPE_LAST) {} 514 explicit GLValue (Float value) : type(DrawTestSpec::INPUTTYPE_FLOAT), fl(value) {} 515 explicit GLValue (Fixed value) : type(DrawTestSpec::INPUTTYPE_FIXED), fi(value) {} 516 explicit GLValue (Byte value) : type(DrawTestSpec::INPUTTYPE_BYTE), b(value) {} 517 explicit GLValue (Ubyte value) : type(DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE), ub(value) {} 518 explicit GLValue (Short value) : type(DrawTestSpec::INPUTTYPE_SHORT), s(value) {} 519 explicit GLValue (Ushort value) : type(DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT), us(value) {} 520 explicit GLValue (Int value) : type(DrawTestSpec::INPUTTYPE_INT), i(value) {} 521 explicit GLValue (Uint value) : type(DrawTestSpec::INPUTTYPE_UNSIGNED_INT), ui(value) {} 522 explicit GLValue (Half value) : type(DrawTestSpec::INPUTTYPE_HALF), h(value) {} 523 explicit GLValue (Double value) : type(DrawTestSpec::INPUTTYPE_DOUBLE), d(value) {} 524 525 float toFloat (void) const; 526 527 static GLValue getMaxValue (DrawTestSpec::InputType type); 528 static GLValue getMinValue (DrawTestSpec::InputType type); 529 530 DrawTestSpec::InputType type; 531 532 union 533 { 534 Float fl; 535 Fixed fi; 536 Double d; 537 Byte b; 538 Ubyte ub; 539 Short s; 540 Ushort us; 541 Int i; 542 Uint ui; 543 Half h; 544 }; 545}; 546 547inline deFloat16 GLValue::Half::floatToHalf (float f) 548{ 549 // No denorm support. 550 tcu::Float<deUint16, 5, 10, 15, tcu::FLOAT_HAS_SIGN> v(f); 551 DE_ASSERT(!v.isNaN() && !v.isInf()); 552 return v.bits(); 553} 554 555inline float GLValue::Half::halfToFloat (deFloat16 h) 556{ 557 return tcu::Float16((deUint16)h).asFloat(); 558} 559 560float GLValue::toFloat (void) const 561{ 562 switch (type) 563 { 564 case DrawTestSpec::INPUTTYPE_FLOAT: 565 return fl.getValue(); 566 break; 567 568 case DrawTestSpec::INPUTTYPE_BYTE: 569 return b.getValue(); 570 break; 571 572 case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE: 573 return ub.getValue(); 574 break; 575 576 case DrawTestSpec::INPUTTYPE_SHORT: 577 return s.getValue(); 578 break; 579 580 case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT: 581 return us.getValue(); 582 break; 583 584 case DrawTestSpec::INPUTTYPE_FIXED: 585 { 586 int maxValue = 65536; 587 return (float)(double(2 * fi.getValue() + 1) / (maxValue - 1)); 588 589 break; 590 } 591 592 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT: 593 return (float)ui.getValue(); 594 break; 595 596 case DrawTestSpec::INPUTTYPE_INT: 597 return (float)i.getValue(); 598 break; 599 600 case DrawTestSpec::INPUTTYPE_HALF: 601 return h.to<float>(); 602 break; 603 604 case DrawTestSpec::INPUTTYPE_DOUBLE: 605 return d.to<float>(); 606 break; 607 608 default: 609 DE_ASSERT(false); 610 return 0.0f; 611 break; 612 }; 613} 614 615GLValue GLValue::getMaxValue (DrawTestSpec::InputType type) 616{ 617 GLValue rangesHi[(int)DrawTestSpec::INPUTTYPE_LAST]; 618 619 rangesHi[(int)DrawTestSpec::INPUTTYPE_FLOAT] = GLValue(Float::create(127.0f)); 620 rangesHi[(int)DrawTestSpec::INPUTTYPE_DOUBLE] = GLValue(Double::create(127.0f)); 621 rangesHi[(int)DrawTestSpec::INPUTTYPE_BYTE] = GLValue(Byte::create(127)); 622 rangesHi[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE] = GLValue(Ubyte::create(255)); 623 rangesHi[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT] = GLValue(Ushort::create(65530)); 624 rangesHi[(int)DrawTestSpec::INPUTTYPE_SHORT] = GLValue(Short::create(32760)); 625 rangesHi[(int)DrawTestSpec::INPUTTYPE_FIXED] = GLValue(Fixed::create(32760)); 626 rangesHi[(int)DrawTestSpec::INPUTTYPE_INT] = GLValue(Int::create(2147483647)); 627 rangesHi[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_INT] = GLValue(Uint::create(4294967295u)); 628 rangesHi[(int)DrawTestSpec::INPUTTYPE_HALF] = GLValue(Half::create(256.0f)); 629 630 return rangesHi[(int)type]; 631} 632 633GLValue GLValue::getMinValue (DrawTestSpec::InputType type) 634{ 635 GLValue rangesLo[(int)DrawTestSpec::INPUTTYPE_LAST]; 636 637 rangesLo[(int)DrawTestSpec::INPUTTYPE_FLOAT] = GLValue(Float::create(-127.0f)); 638 rangesLo[(int)DrawTestSpec::INPUTTYPE_DOUBLE] = GLValue(Double::create(-127.0f)); 639 rangesLo[(int)DrawTestSpec::INPUTTYPE_BYTE] = GLValue(Byte::create(-127)); 640 rangesLo[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE] = GLValue(Ubyte::create(0)); 641 rangesLo[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT] = GLValue(Ushort::create(0)); 642 rangesLo[(int)DrawTestSpec::INPUTTYPE_SHORT] = GLValue(Short::create(-32760)); 643 rangesLo[(int)DrawTestSpec::INPUTTYPE_FIXED] = GLValue(Fixed::create(-32760)); 644 rangesLo[(int)DrawTestSpec::INPUTTYPE_INT] = GLValue(Int::create(-2147483647)); 645 rangesLo[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_INT] = GLValue(Uint::create(0)); 646 rangesLo[(int)DrawTestSpec::INPUTTYPE_HALF] = GLValue(Half::create(-256.0f)); 647 648 return rangesLo[(int)type]; 649} 650 651template<typename T> 652struct GLValueTypeTraits; 653 654template<> struct GLValueTypeTraits<GLValue::Float> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_FLOAT; }; 655template<> struct GLValueTypeTraits<GLValue::Double> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_DOUBLE; }; 656template<> struct GLValueTypeTraits<GLValue::Byte> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_BYTE; }; 657template<> struct GLValueTypeTraits<GLValue::Ubyte> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE; }; 658template<> struct GLValueTypeTraits<GLValue::Ushort> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT; }; 659template<> struct GLValueTypeTraits<GLValue::Short> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_SHORT; }; 660template<> struct GLValueTypeTraits<GLValue::Fixed> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_FIXED; }; 661template<> struct GLValueTypeTraits<GLValue::Int> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_INT; }; 662template<> struct GLValueTypeTraits<GLValue::Uint> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_UNSIGNED_INT; }; 663template<> struct GLValueTypeTraits<GLValue::Half> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_HALF; }; 664 665template<typename T> 666inline T extractGLValue (const GLValue& v); 667 668template<> GLValue::Float inline extractGLValue<GLValue::Float> (const GLValue& v) { return v.fl; }; 669template<> GLValue::Double inline extractGLValue<GLValue::Double> (const GLValue& v) { return v.d; }; 670template<> GLValue::Byte inline extractGLValue<GLValue::Byte> (const GLValue& v) { return v.b; }; 671template<> GLValue::Ubyte inline extractGLValue<GLValue::Ubyte> (const GLValue& v) { return v.ub; }; 672template<> GLValue::Ushort inline extractGLValue<GLValue::Ushort> (const GLValue& v) { return v.us; }; 673template<> GLValue::Short inline extractGLValue<GLValue::Short> (const GLValue& v) { return v.s; }; 674template<> GLValue::Fixed inline extractGLValue<GLValue::Fixed> (const GLValue& v) { return v.fi; }; 675template<> GLValue::Int inline extractGLValue<GLValue::Int> (const GLValue& v) { return v.i; }; 676template<> GLValue::Uint inline extractGLValue<GLValue::Uint> (const GLValue& v) { return v.ui; }; 677template<> GLValue::Half inline extractGLValue<GLValue::Half> (const GLValue& v) { return v.h; }; 678 679template<class T> 680inline T getRandom (deRandom& rnd, T min, T max); 681 682template<> 683inline GLValue::Float getRandom (deRandom& rnd, GLValue::Float min, GLValue::Float max) 684{ 685 if (max < min) 686 return min; 687 688 return GLValue::Float::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>())); 689} 690 691template<> 692inline GLValue::Double getRandom (deRandom& rnd, GLValue::Double min, GLValue::Double max) 693{ 694 if (max < min) 695 return min; 696 697 return GLValue::Double::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>())); 698} 699 700template<> 701inline GLValue::Short getRandom (deRandom& rnd, GLValue::Short min, GLValue::Short max) 702{ 703 if (max < min) 704 return min; 705 706 return GLValue::Short::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))); 707} 708 709template<> 710inline GLValue::Ushort getRandom (deRandom& rnd, GLValue::Ushort min, GLValue::Ushort max) 711{ 712 if (max < min) 713 return min; 714 715 return GLValue::Ushort::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))); 716} 717 718template<> 719inline GLValue::Byte getRandom (deRandom& rnd, GLValue::Byte min, GLValue::Byte max) 720{ 721 if (max < min) 722 return min; 723 724 return GLValue::Byte::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))); 725} 726 727template<> 728inline GLValue::Ubyte getRandom (deRandom& rnd, GLValue::Ubyte min, GLValue::Ubyte max) 729{ 730 if (max < min) 731 return min; 732 733 return GLValue::Ubyte::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>())))); 734} 735 736template<> 737inline GLValue::Fixed getRandom (deRandom& rnd, GLValue::Fixed min, GLValue::Fixed max) 738{ 739 if (max < min) 740 return min; 741 742 return GLValue::Fixed::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>())))); 743} 744 745template<> 746inline GLValue::Half getRandom (deRandom& rnd, GLValue::Half min, GLValue::Half max) 747{ 748 if (max < min) 749 return min; 750 751 float fMax = max.to<float>(); 752 float fMin = min.to<float>(); 753 GLValue::Half h = GLValue::Half::create(fMin + deRandom_getFloat(&rnd) * (fMax - fMin)); 754 return h; 755} 756 757template<> 758inline GLValue::Int getRandom (deRandom& rnd, GLValue::Int min, GLValue::Int max) 759{ 760 if (max < min) 761 return min; 762 763 return GLValue::Int::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>())))); 764} 765 766template<> 767inline GLValue::Uint getRandom (deRandom& rnd, GLValue::Uint min, GLValue::Uint max) 768{ 769 if (max < min) 770 return min; 771 772 return GLValue::Uint::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>())))); 773} 774 775// Minimum difference required between coordinates 776template<class T> 777inline T minValue (void); 778 779template<> 780inline GLValue::Float minValue (void) 781{ 782 return GLValue::Float::create(4 * 1.0f); 783} 784 785template<> 786inline GLValue::Double minValue (void) 787{ 788 return GLValue::Double::create(4 * 1.0f); 789} 790 791template<> 792inline GLValue::Short minValue (void) 793{ 794 return GLValue::Short::create(4 * 256); 795} 796 797template<> 798inline GLValue::Ushort minValue (void) 799{ 800 return GLValue::Ushort::create(4 * 256); 801} 802 803template<> 804inline GLValue::Byte minValue (void) 805{ 806 return GLValue::Byte::create(4 * 1); 807} 808 809template<> 810inline GLValue::Ubyte minValue (void) 811{ 812 return GLValue::Ubyte::create(4 * 2); 813} 814 815template<> 816inline GLValue::Fixed minValue (void) 817{ 818 return GLValue::Fixed::create(4 * 1); 819} 820 821template<> 822inline GLValue::Int minValue (void) 823{ 824 return GLValue::Int::create(4 * 16777216); 825} 826 827template<> 828inline GLValue::Uint minValue (void) 829{ 830 return GLValue::Uint::create(4 * 16777216); 831} 832 833template<> 834inline GLValue::Half minValue (void) 835{ 836 return GLValue::Half::create(4 * 1.0f); 837} 838 839template<class T> 840inline T abs (T val); 841 842template<> 843inline GLValue::Fixed abs (GLValue::Fixed val) 844{ 845 return GLValue::Fixed::create(0x7FFFu & val.getValue()); 846} 847 848template<> 849inline GLValue::Ubyte abs (GLValue::Ubyte val) 850{ 851 return val; 852} 853 854template<> 855inline GLValue::Byte abs (GLValue::Byte val) 856{ 857 return GLValue::Byte::create(0x7Fu & val.getValue()); 858} 859 860template<> 861inline GLValue::Ushort abs (GLValue::Ushort val) 862{ 863 return val; 864} 865 866template<> 867inline GLValue::Short abs (GLValue::Short val) 868{ 869 return GLValue::Short::create(0x7FFFu & val.getValue()); 870} 871 872template<> 873inline GLValue::Float abs (GLValue::Float val) 874{ 875 return GLValue::Float::create(std::fabs(val.to<float>())); 876} 877 878template<> 879inline GLValue::Double abs (GLValue::Double val) 880{ 881 return GLValue::Double::create(std::fabs(val.to<float>())); 882} 883 884template<> 885inline GLValue::Uint abs (GLValue::Uint val) 886{ 887 return val; 888} 889 890template<> 891inline GLValue::Int abs (GLValue::Int val) 892{ 893 return GLValue::Int::create(0x7FFFFFFFu & val.getValue()); 894} 895 896template<> 897inline GLValue::Half abs (GLValue::Half val) 898{ 899 return GLValue::Half::create(std::fabs(val.to<float>())); 900} 901 902// AttriuteArray 903 904class AttributeArray 905{ 906public: 907 AttributeArray (DrawTestSpec::Storage storage, sglr::Context& context); 908 ~AttributeArray (void); 909 910 void data (DrawTestSpec::Target target, size_t size, const char* data, DrawTestSpec::Usage usage); 911 void subdata (DrawTestSpec::Target target, int offset, int size, const char* data); 912 void setupArray (bool bound, int offset, int size, DrawTestSpec::InputType inType, DrawTestSpec::OutputType outType, bool normalized, int stride, int instanceDivisor, const rr::GenericVec4& defaultAttrib, bool isPositionAttr, bool bgraComponentOrder); 913 void bindAttribute (deUint32 loc); 914 void bindIndexArray (DrawTestSpec::Target storage); 915 916 int getComponentCount (void) const { return m_componentCount; } 917 DrawTestSpec::Target getTarget (void) const { return m_target; } 918 DrawTestSpec::InputType getInputType (void) const { return m_inputType; } 919 DrawTestSpec::OutputType getOutputType (void) const { return m_outputType; } 920 DrawTestSpec::Storage getStorageType (void) const { return m_storage; } 921 bool getNormalized (void) const { return m_normalize; } 922 int getStride (void) const { return m_stride; } 923 bool isBound (void) const { return m_bound; } 924 bool isPositionAttribute (void) const { return m_isPositionAttr; } 925 926private: 927 DrawTestSpec::Storage m_storage; 928 sglr::Context& m_ctx; 929 deUint32 m_glBuffer; 930 931 int m_size; 932 char* m_data; 933 int m_componentCount; 934 bool m_bound; 935 DrawTestSpec::Target m_target; 936 DrawTestSpec::InputType m_inputType; 937 DrawTestSpec::OutputType m_outputType; 938 bool m_normalize; 939 int m_stride; 940 int m_offset; 941 rr::GenericVec4 m_defaultAttrib; 942 int m_instanceDivisor; 943 bool m_isPositionAttr; 944 bool m_bgraOrder; 945}; 946 947AttributeArray::AttributeArray (DrawTestSpec::Storage storage, sglr::Context& context) 948 : m_storage (storage) 949 , m_ctx (context) 950 , m_glBuffer (0) 951 , m_size (0) 952 , m_data (DE_NULL) 953 , m_componentCount (1) 954 , m_bound (false) 955 , m_target (DrawTestSpec::TARGET_ARRAY) 956 , m_inputType (DrawTestSpec::INPUTTYPE_FLOAT) 957 , m_outputType (DrawTestSpec::OUTPUTTYPE_VEC4) 958 , m_normalize (false) 959 , m_stride (0) 960 , m_offset (0) 961 , m_instanceDivisor (0) 962 , m_isPositionAttr (false) 963 , m_bgraOrder (false) 964{ 965 if (m_storage == DrawTestSpec::STORAGE_BUFFER) 966 { 967 m_ctx.genBuffers(1, &m_glBuffer); 968 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glGenBuffers()"); 969 } 970} 971 972AttributeArray::~AttributeArray (void) 973{ 974 if (m_storage == DrawTestSpec::STORAGE_BUFFER) 975 { 976 m_ctx.deleteBuffers(1, &m_glBuffer); 977 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDeleteBuffers()"); 978 } 979 else if (m_storage == DrawTestSpec::STORAGE_USER) 980 delete[] m_data; 981 else 982 DE_ASSERT(false); 983} 984 985void AttributeArray::data (DrawTestSpec::Target target, size_t size, const char* ptr, DrawTestSpec::Usage usage) 986{ 987 m_size = (int)size; 988 m_target = target; 989 990 if (m_storage == DrawTestSpec::STORAGE_BUFFER) 991 { 992 m_ctx.bindBuffer(targetToGL(target), m_glBuffer); 993 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()"); 994 995 m_ctx.bufferData(targetToGL(target), size, ptr, usageToGL(usage)); 996 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferData()"); 997 } 998 else if (m_storage == DrawTestSpec::STORAGE_USER) 999 { 1000 if (m_data) 1001 delete[] m_data; 1002 1003 m_data = new char[size]; 1004 std::memcpy(m_data, ptr, size); 1005 } 1006 else 1007 DE_ASSERT(false); 1008} 1009 1010void AttributeArray::subdata (DrawTestSpec::Target target, int offset, int size, const char* ptr) 1011{ 1012 m_target = target; 1013 1014 if (m_storage == DrawTestSpec::STORAGE_BUFFER) 1015 { 1016 m_ctx.bindBuffer(targetToGL(target), m_glBuffer); 1017 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()"); 1018 1019 m_ctx.bufferSubData(targetToGL(target), offset, size, ptr); 1020 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferSubData()"); 1021 } 1022 else if (m_storage == DrawTestSpec::STORAGE_USER) 1023 std::memcpy(m_data + offset, ptr, size); 1024 else 1025 DE_ASSERT(false); 1026} 1027 1028void AttributeArray::setupArray (bool bound, int offset, int size, DrawTestSpec::InputType inputType, DrawTestSpec::OutputType outType, bool normalized, int stride, int instanceDivisor, const rr::GenericVec4& defaultAttrib, bool isPositionAttr, bool bgraComponentOrder) 1029{ 1030 m_componentCount = size; 1031 m_bound = bound; 1032 m_inputType = inputType; 1033 m_outputType = outType; 1034 m_normalize = normalized; 1035 m_stride = stride; 1036 m_offset = offset; 1037 m_defaultAttrib = defaultAttrib; 1038 m_instanceDivisor = instanceDivisor; 1039 m_isPositionAttr = isPositionAttr; 1040 m_bgraOrder = bgraComponentOrder; 1041} 1042 1043void AttributeArray::bindAttribute (deUint32 loc) 1044{ 1045 if (!isBound()) 1046 { 1047 switch (m_inputType) 1048 { 1049 case DrawTestSpec::INPUTTYPE_FLOAT: 1050 { 1051 tcu::Vec4 attr = m_defaultAttrib.get<float>(); 1052 1053 switch (m_componentCount) 1054 { 1055 case 1: m_ctx.vertexAttrib1f(loc, attr.x()); break; 1056 case 2: m_ctx.vertexAttrib2f(loc, attr.x(), attr.y()); break; 1057 case 3: m_ctx.vertexAttrib3f(loc, attr.x(), attr.y(), attr.z()); break; 1058 case 4: m_ctx.vertexAttrib4f(loc, attr.x(), attr.y(), attr.z(), attr.w()); break; 1059 default: DE_ASSERT(DE_FALSE); break; 1060 } 1061 break; 1062 } 1063 case DrawTestSpec::INPUTTYPE_INT: 1064 { 1065 tcu::IVec4 attr = m_defaultAttrib.get<deInt32>(); 1066 m_ctx.vertexAttribI4i(loc, attr.x(), attr.y(), attr.z(), attr.w()); 1067 break; 1068 } 1069 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT: 1070 { 1071 tcu::UVec4 attr = m_defaultAttrib.get<deUint32>(); 1072 m_ctx.vertexAttribI4ui(loc, attr.x(), attr.y(), attr.z(), attr.w()); 1073 break; 1074 } 1075 default: 1076 DE_ASSERT(DE_FALSE); 1077 break; 1078 } 1079 } 1080 else 1081 { 1082 const deUint8* basePtr = DE_NULL; 1083 1084 if (m_storage == DrawTestSpec::STORAGE_BUFFER) 1085 { 1086 m_ctx.bindBuffer(targetToGL(m_target), m_glBuffer); 1087 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()"); 1088 1089 basePtr = DE_NULL; 1090 } 1091 else if (m_storage == DrawTestSpec::STORAGE_USER) 1092 { 1093 m_ctx.bindBuffer(targetToGL(m_target), 0); 1094 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()"); 1095 1096 basePtr = (const deUint8*)m_data; 1097 } 1098 else 1099 DE_ASSERT(DE_FALSE); 1100 1101 if (!inputTypeIsFloatType(m_inputType)) 1102 { 1103 // Input is not float type 1104 1105 if (outputTypeIsFloatType(m_outputType)) 1106 { 1107 const int size = (m_bgraOrder) ? (GL_BGRA) : (m_componentCount); 1108 1109 DE_ASSERT(!(m_bgraOrder && m_componentCount != 4)); 1110 1111 // Output type is float type 1112 m_ctx.vertexAttribPointer(loc, size, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset); 1113 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()"); 1114 } 1115 else 1116 { 1117 // Output type is int type 1118 m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, basePtr + m_offset); 1119 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()"); 1120 } 1121 } 1122 else 1123 { 1124 // Input type is float type 1125 1126 // Output type must be float type 1127 DE_ASSERT(outputTypeIsFloatType(m_outputType)); 1128 1129 m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset); 1130 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()"); 1131 } 1132 1133 if (m_instanceDivisor) 1134 m_ctx.vertexAttribDivisor(loc, m_instanceDivisor); 1135 } 1136} 1137 1138void AttributeArray::bindIndexArray (DrawTestSpec::Target target) 1139{ 1140 if (m_storage == DrawTestSpec::STORAGE_USER) 1141 { 1142 } 1143 else if (m_storage == DrawTestSpec::STORAGE_BUFFER) 1144 { 1145 m_ctx.bindBuffer(targetToGL(target), m_glBuffer); 1146 } 1147} 1148 1149// DrawTestShaderProgram 1150 1151class DrawTestShaderProgram : public sglr::ShaderProgram 1152{ 1153public: 1154 DrawTestShaderProgram (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays); 1155 1156 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const; 1157 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const; 1158 1159private: 1160 static std::string genVertexSource (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays); 1161 static std::string genFragmentSource (const glu::RenderContext& ctx); 1162 static void generateShaderParams (std::map<std::string, std::string>& params, glu::ContextType type); 1163 static rr::GenericVecType mapOutputType (const DrawTestSpec::OutputType& type); 1164 static int getComponentCount (const DrawTestSpec::OutputType& type); 1165 1166 static sglr::pdec::ShaderProgramDeclaration createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays); 1167 1168 std::vector<int> m_componentCount; 1169 std::vector<bool> m_isCoord; 1170 std::vector<rr::GenericVecType> m_attrType; 1171}; 1172 1173DrawTestShaderProgram::DrawTestShaderProgram (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays) 1174 : sglr::ShaderProgram (createProgramDeclaration(ctx, arrays)) 1175 , m_componentCount (arrays.size()) 1176 , m_isCoord (arrays.size()) 1177 , m_attrType (arrays.size()) 1178{ 1179 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++) 1180 { 1181 m_componentCount[arrayNdx] = getComponentCount(arrays[arrayNdx]->getOutputType()); 1182 m_isCoord[arrayNdx] = arrays[arrayNdx]->isPositionAttribute(); 1183 m_attrType[arrayNdx] = mapOutputType(arrays[arrayNdx]->getOutputType()); 1184 } 1185} 1186 1187template <typename T> 1188void calcShaderColorCoord (tcu::Vec2& coord, tcu::Vec3& color, const tcu::Vector<T, 4>& attribValue, bool isCoordinate, int numComponents) 1189{ 1190 if (isCoordinate) 1191 switch (numComponents) 1192 { 1193 case 1: coord += tcu::Vec2((float)attribValue.x(), (float)attribValue.x()); break; 1194 case 2: coord += tcu::Vec2((float)attribValue.x(), (float)attribValue.y()); break; 1195 case 3: coord += tcu::Vec2((float)attribValue.x() + attribValue.z(), (float)attribValue.y()); break; 1196 case 4: coord += tcu::Vec2((float)attribValue.x() + attribValue.z(), (float)attribValue.y() + attribValue.w()); break; 1197 1198 default: 1199 DE_ASSERT(false); 1200 } 1201 else 1202 { 1203 switch (numComponents) 1204 { 1205 case 1: 1206 color = color * (float)attribValue.x(); 1207 break; 1208 1209 case 2: 1210 color.x() = color.x() * attribValue.x(); 1211 color.y() = color.y() * attribValue.y(); 1212 break; 1213 1214 case 3: 1215 color.x() = color.x() * attribValue.x(); 1216 color.y() = color.y() * attribValue.y(); 1217 color.z() = color.z() * attribValue.z(); 1218 break; 1219 1220 case 4: 1221 color.x() = color.x() * attribValue.x() * attribValue.w(); 1222 color.y() = color.y() * attribValue.y() * attribValue.w(); 1223 color.z() = color.z() * attribValue.z() * attribValue.w(); 1224 break; 1225 1226 default: 1227 DE_ASSERT(false); 1228 } 1229 } 1230} 1231 1232void DrawTestShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const 1233{ 1234 const float u_coordScale = getUniformByName("u_coordScale").value.f; 1235 const float u_colorScale = getUniformByName("u_colorScale").value.f; 1236 1237 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 1238 { 1239 const size_t varyingLocColor = 0; 1240 1241 rr::VertexPacket& packet = *packets[packetNdx]; 1242 1243 // Calc output color 1244 tcu::Vec2 coord = tcu::Vec2(0.0, 0.0); 1245 tcu::Vec3 color = tcu::Vec3(1.0, 1.0, 1.0); 1246 1247 for (int attribNdx = 0; attribNdx < (int)m_attrType.size(); attribNdx++) 1248 { 1249 const int numComponents = m_componentCount[attribNdx]; 1250 const bool isCoord = m_isCoord[attribNdx]; 1251 1252 switch (m_attrType[attribNdx]) 1253 { 1254 case rr::GENERICVECTYPE_FLOAT: calcShaderColorCoord(coord, color, rr::readVertexAttribFloat(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents); break; 1255 case rr::GENERICVECTYPE_INT32: calcShaderColorCoord(coord, color, rr::readVertexAttribInt (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents); break; 1256 case rr::GENERICVECTYPE_UINT32: calcShaderColorCoord(coord, color, rr::readVertexAttribUint (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents); break; 1257 default: 1258 DE_ASSERT(false); 1259 } 1260 } 1261 1262 // Transform position 1263 { 1264 packet.position = tcu::Vec4(u_coordScale * coord.x(), u_coordScale * coord.y(), 1.0f, 1.0f); 1265 packet.pointSize = 1.0f; 1266 } 1267 1268 // Pass color to FS 1269 { 1270 packet.outputs[varyingLocColor] = tcu::Vec4(u_colorScale * color.x(), u_colorScale * color.y(), u_colorScale * color.z(), 1.0f) * 0.5f + tcu::Vec4(0.5f, 0.5f, 0.5f, 0.5f); 1271 } 1272 } 1273} 1274 1275void DrawTestShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const 1276{ 1277 const size_t varyingLocColor = 0; 1278 1279 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 1280 { 1281 rr::FragmentPacket& packet = packets[packetNdx]; 1282 1283 for (int fragNdx = 0; fragNdx < 4; ++fragNdx) 1284 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, varyingLocColor, fragNdx)); 1285 } 1286} 1287 1288std::string DrawTestShaderProgram::genVertexSource (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays) 1289{ 1290 std::map<std::string, std::string> params; 1291 std::stringstream vertexShaderTmpl; 1292 1293 generateShaderParams(params, ctx.getType()); 1294 1295 vertexShaderTmpl << "${VTX_HDR}"; 1296 1297 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++) 1298 { 1299 vertexShaderTmpl 1300 << "${VTX_IN} highp " << outputTypeToGLType(arrays[arrayNdx]->getOutputType()) << " a_" << arrayNdx << ";\n"; 1301 } 1302 1303 vertexShaderTmpl << 1304 "uniform highp float u_coordScale;\n" 1305 "uniform highp float u_colorScale;\n" 1306 "${VTX_OUT} ${COL_PRECISION} vec4 v_color;\n" 1307 "void main(void)\n" 1308 "{\n" 1309 "\tgl_PointSize = 1.0;\n" 1310 "\thighp vec2 coord = vec2(0.0, 0.0);\n" 1311 "\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n"; 1312 1313 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++) 1314 { 1315 const bool isPositionAttr = arrays[arrayNdx]->isPositionAttribute(); 1316 1317 if (isPositionAttr) 1318 { 1319 switch (arrays[arrayNdx]->getOutputType()) 1320 { 1321 case (DrawTestSpec::OUTPUTTYPE_FLOAT): 1322 case (DrawTestSpec::OUTPUTTYPE_INT): 1323 case (DrawTestSpec::OUTPUTTYPE_UINT): 1324 vertexShaderTmpl << 1325 "\tcoord += vec2(float(a_" << arrayNdx << "), float(a_" << arrayNdx << "));\n"; 1326 break; 1327 1328 case (DrawTestSpec::OUTPUTTYPE_VEC2): 1329 case (DrawTestSpec::OUTPUTTYPE_IVEC2): 1330 case (DrawTestSpec::OUTPUTTYPE_UVEC2): 1331 vertexShaderTmpl << 1332 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n"; 1333 break; 1334 1335 case (DrawTestSpec::OUTPUTTYPE_VEC3): 1336 case (DrawTestSpec::OUTPUTTYPE_IVEC3): 1337 case (DrawTestSpec::OUTPUTTYPE_UVEC3): 1338 vertexShaderTmpl << 1339 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n" 1340 "\tcoord.x += float(a_" << arrayNdx << ".z);\n"; 1341 break; 1342 1343 case (DrawTestSpec::OUTPUTTYPE_VEC4): 1344 case (DrawTestSpec::OUTPUTTYPE_IVEC4): 1345 case (DrawTestSpec::OUTPUTTYPE_UVEC4): 1346 vertexShaderTmpl << 1347 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n" 1348 "\tcoord += vec2(a_" << arrayNdx << ".zw);\n"; 1349 break; 1350 1351 default: 1352 DE_ASSERT(false); 1353 break; 1354 } 1355 } 1356 else 1357 { 1358 switch (arrays[arrayNdx]->getOutputType()) 1359 { 1360 case (DrawTestSpec::OUTPUTTYPE_FLOAT): 1361 case (DrawTestSpec::OUTPUTTYPE_INT): 1362 case (DrawTestSpec::OUTPUTTYPE_UINT): 1363 vertexShaderTmpl << 1364 "\tcolor = color * float(a_" << arrayNdx << ");\n"; 1365 break; 1366 1367 case (DrawTestSpec::OUTPUTTYPE_VEC2): 1368 case (DrawTestSpec::OUTPUTTYPE_IVEC2): 1369 case (DrawTestSpec::OUTPUTTYPE_UVEC2): 1370 vertexShaderTmpl << 1371 "\tcolor.rg = color.rg * vec2(a_" << arrayNdx << ".xy);\n"; 1372 break; 1373 1374 case (DrawTestSpec::OUTPUTTYPE_VEC3): 1375 case (DrawTestSpec::OUTPUTTYPE_IVEC3): 1376 case (DrawTestSpec::OUTPUTTYPE_UVEC3): 1377 vertexShaderTmpl << 1378 "\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz);\n"; 1379 break; 1380 1381 case (DrawTestSpec::OUTPUTTYPE_VEC4): 1382 case (DrawTestSpec::OUTPUTTYPE_IVEC4): 1383 case (DrawTestSpec::OUTPUTTYPE_UVEC4): 1384 vertexShaderTmpl << 1385 "\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz) * float(a_" << arrayNdx << ".w);\n"; 1386 break; 1387 1388 default: 1389 DE_ASSERT(false); 1390 break; 1391 } 1392 } 1393 } 1394 1395 vertexShaderTmpl << 1396 "\tv_color = vec4(u_colorScale * color, 1.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);\n" 1397 "\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n" 1398 "}\n"; 1399 1400 return tcu::StringTemplate(vertexShaderTmpl.str().c_str()).specialize(params); 1401} 1402 1403std::string DrawTestShaderProgram::genFragmentSource (const glu::RenderContext& ctx) 1404{ 1405 std::map<std::string, std::string> params; 1406 1407 generateShaderParams(params, ctx.getType()); 1408 1409 static const char* fragmentShaderTmpl = 1410 "${FRAG_HDR}" 1411 "${FRAG_IN} ${COL_PRECISION} vec4 v_color;\n" 1412 "void main(void)\n" 1413 "{\n" 1414 "\t${FRAG_COLOR} = v_color;\n" 1415 "}\n"; 1416 1417 return tcu::StringTemplate(fragmentShaderTmpl).specialize(params); 1418} 1419 1420void DrawTestShaderProgram::generateShaderParams (std::map<std::string, std::string>& params, glu::ContextType type) 1421{ 1422 if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_300_ES)) 1423 { 1424 params["VTX_IN"] = "in"; 1425 params["VTX_OUT"] = "out"; 1426 params["FRAG_IN"] = "in"; 1427 params["FRAG_COLOR"] = "dEQP_FragColor"; 1428 params["VTX_HDR"] = "#version 300 es\n"; 1429 params["FRAG_HDR"] = "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 1430 params["COL_PRECISION"] = "mediump"; 1431 } 1432 else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_100_ES)) 1433 { 1434 params["VTX_IN"] = "attribute"; 1435 params["VTX_OUT"] = "varying"; 1436 params["FRAG_IN"] = "varying"; 1437 params["FRAG_COLOR"] = "gl_FragColor"; 1438 params["VTX_HDR"] = ""; 1439 params["FRAG_HDR"] = ""; 1440 params["COL_PRECISION"] = "mediump"; 1441 } 1442 else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_430)) 1443 { 1444 params["VTX_IN"] = "in"; 1445 params["VTX_OUT"] = "out"; 1446 params["FRAG_IN"] = "in"; 1447 params["FRAG_COLOR"] = "dEQP_FragColor"; 1448 params["VTX_HDR"] = "#version 430\n"; 1449 params["FRAG_HDR"] = "#version 430\nlayout(location = 0) out highp vec4 dEQP_FragColor;\n"; 1450 params["COL_PRECISION"] = "highp"; 1451 } 1452 else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_330)) 1453 { 1454 params["VTX_IN"] = "in"; 1455 params["VTX_OUT"] = "out"; 1456 params["FRAG_IN"] = "in"; 1457 params["FRAG_COLOR"] = "dEQP_FragColor"; 1458 params["VTX_HDR"] = "#version 330\n"; 1459 params["FRAG_HDR"] = "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 1460 params["COL_PRECISION"] = "mediump"; 1461 } 1462 else 1463 DE_ASSERT(DE_FALSE); 1464} 1465 1466rr::GenericVecType DrawTestShaderProgram::mapOutputType (const DrawTestSpec::OutputType& type) 1467{ 1468 switch (type) 1469 { 1470 case (DrawTestSpec::OUTPUTTYPE_FLOAT): 1471 case (DrawTestSpec::OUTPUTTYPE_VEC2): 1472 case (DrawTestSpec::OUTPUTTYPE_VEC3): 1473 case (DrawTestSpec::OUTPUTTYPE_VEC4): 1474 return rr::GENERICVECTYPE_FLOAT; 1475 1476 case (DrawTestSpec::OUTPUTTYPE_INT): 1477 case (DrawTestSpec::OUTPUTTYPE_IVEC2): 1478 case (DrawTestSpec::OUTPUTTYPE_IVEC3): 1479 case (DrawTestSpec::OUTPUTTYPE_IVEC4): 1480 return rr::GENERICVECTYPE_INT32; 1481 1482 case (DrawTestSpec::OUTPUTTYPE_UINT): 1483 case (DrawTestSpec::OUTPUTTYPE_UVEC2): 1484 case (DrawTestSpec::OUTPUTTYPE_UVEC3): 1485 case (DrawTestSpec::OUTPUTTYPE_UVEC4): 1486 return rr::GENERICVECTYPE_UINT32; 1487 1488 default: 1489 DE_ASSERT(false); 1490 return rr::GENERICVECTYPE_LAST; 1491 } 1492} 1493 1494int DrawTestShaderProgram::getComponentCount (const DrawTestSpec::OutputType& type) 1495{ 1496 switch (type) 1497 { 1498 case (DrawTestSpec::OUTPUTTYPE_FLOAT): 1499 case (DrawTestSpec::OUTPUTTYPE_INT): 1500 case (DrawTestSpec::OUTPUTTYPE_UINT): 1501 return 1; 1502 1503 case (DrawTestSpec::OUTPUTTYPE_VEC2): 1504 case (DrawTestSpec::OUTPUTTYPE_IVEC2): 1505 case (DrawTestSpec::OUTPUTTYPE_UVEC2): 1506 return 2; 1507 1508 case (DrawTestSpec::OUTPUTTYPE_VEC3): 1509 case (DrawTestSpec::OUTPUTTYPE_IVEC3): 1510 case (DrawTestSpec::OUTPUTTYPE_UVEC3): 1511 return 3; 1512 1513 case (DrawTestSpec::OUTPUTTYPE_VEC4): 1514 case (DrawTestSpec::OUTPUTTYPE_IVEC4): 1515 case (DrawTestSpec::OUTPUTTYPE_UVEC4): 1516 return 4; 1517 1518 default: 1519 DE_ASSERT(false); 1520 return 0; 1521 } 1522} 1523 1524sglr::pdec::ShaderProgramDeclaration DrawTestShaderProgram::createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays) 1525{ 1526 sglr::pdec::ShaderProgramDeclaration decl; 1527 1528 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++) 1529 decl << sglr::pdec::VertexAttribute(std::string("a_") + de::toString(arrayNdx), mapOutputType(arrays[arrayNdx]->getOutputType())); 1530 1531 decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT); 1532 decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT); 1533 1534 decl << sglr::pdec::VertexSource(genVertexSource(ctx, arrays)); 1535 decl << sglr::pdec::FragmentSource(genFragmentSource(ctx)); 1536 1537 decl << sglr::pdec::Uniform("u_coordScale", glu::TYPE_FLOAT); 1538 decl << sglr::pdec::Uniform("u_colorScale", glu::TYPE_FLOAT); 1539 1540 return decl; 1541} 1542 1543class RandomArrayGenerator 1544{ 1545public: 1546 static char* generateArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type); 1547 static char* generateIndices (int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase); 1548 static rr::GenericVec4 generateAttributeValue (int seed, DrawTestSpec::InputType type); 1549 1550private: 1551 template<typename T> 1552 static char* createIndices (int seed, int elementCount, int offset, int min, int max, int indexBase); 1553 static void setData (char* data, DrawTestSpec::InputType type, deRandom& rnd, GLValue min, GLValue max); 1554 1555 static char* generateBasicArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type); 1556 template<typename T, typename GLType> 1557 static char* createBasicArray (int seed, int elementCount, int componentCount, int offset, int stride); 1558 static char* generatePackedArray (int seed, int elementCount, int componentCount, int offset, int stride); 1559}; 1560 1561void RandomArrayGenerator::setData (char* data, DrawTestSpec::InputType type, deRandom& rnd, GLValue min, GLValue max) 1562{ 1563 switch (type) 1564 { 1565 case DrawTestSpec::INPUTTYPE_FLOAT: 1566 { 1567 alignmentSafeAssignment<float>(data, getRandom<GLValue::Float>(rnd, min.fl, max.fl)); 1568 break; 1569 } 1570 1571 case DrawTestSpec::INPUTTYPE_SHORT: 1572 { 1573 alignmentSafeAssignment<deInt16>(data, getRandom<GLValue::Short>(rnd, min.s, max.s)); 1574 break; 1575 } 1576 1577 case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT: 1578 { 1579 alignmentSafeAssignment<deUint16>(data, getRandom<GLValue::Ushort>(rnd, min.us, max.us)); 1580 break; 1581 } 1582 1583 case DrawTestSpec::INPUTTYPE_BYTE: 1584 { 1585 alignmentSafeAssignment<deInt8>(data, getRandom<GLValue::Byte>(rnd, min.b, max.b)); 1586 break; 1587 } 1588 1589 case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE: 1590 { 1591 alignmentSafeAssignment<deUint8>(data, getRandom<GLValue::Ubyte>(rnd, min.ub, max.ub)); 1592 break; 1593 } 1594 1595 case DrawTestSpec::INPUTTYPE_FIXED: 1596 { 1597 alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Fixed>(rnd, min.fi, max.fi)); 1598 break; 1599 } 1600 1601 case DrawTestSpec::INPUTTYPE_INT: 1602 { 1603 alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Int>(rnd, min.i, max.i)); 1604 break; 1605 } 1606 1607 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT: 1608 { 1609 alignmentSafeAssignment<deUint32>(data, getRandom<GLValue::Uint>(rnd, min.ui, max.ui)); 1610 break; 1611 } 1612 1613 case DrawTestSpec::INPUTTYPE_HALF: 1614 { 1615 alignmentSafeAssignment<deFloat16>(data, getRandom<GLValue::Half>(rnd, min.h, max.h).getValue()); 1616 break; 1617 } 1618 1619 default: 1620 DE_ASSERT(false); 1621 break; 1622 } 1623} 1624 1625char* RandomArrayGenerator::generateArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type) 1626{ 1627 if (type == DrawTestSpec::INPUTTYPE_INT_2_10_10_10 || type == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10) 1628 return generatePackedArray(seed, elementCount, componentCount, offset, stride); 1629 else 1630 return generateBasicArray(seed, elementCount, componentCount, offset, stride, type); 1631} 1632 1633char* RandomArrayGenerator::generateBasicArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type) 1634{ 1635 switch (type) 1636 { 1637 case DrawTestSpec::INPUTTYPE_FLOAT: return createBasicArray<float, GLValue::Float> (seed, elementCount, componentCount, offset, stride); 1638 case DrawTestSpec::INPUTTYPE_DOUBLE: return createBasicArray<double, GLValue::Double>(seed, elementCount, componentCount, offset, stride); 1639 case DrawTestSpec::INPUTTYPE_SHORT: return createBasicArray<deInt16, GLValue::Short> (seed, elementCount, componentCount, offset, stride); 1640 case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT: return createBasicArray<deUint16, GLValue::Ushort>(seed, elementCount, componentCount, offset, stride); 1641 case DrawTestSpec::INPUTTYPE_BYTE: return createBasicArray<deInt8, GLValue::Byte> (seed, elementCount, componentCount, offset, stride); 1642 case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE: return createBasicArray<deUint8, GLValue::Ubyte> (seed, elementCount, componentCount, offset, stride); 1643 case DrawTestSpec::INPUTTYPE_FIXED: return createBasicArray<deInt32, GLValue::Fixed> (seed, elementCount, componentCount, offset, stride); 1644 case DrawTestSpec::INPUTTYPE_INT: return createBasicArray<deInt32, GLValue::Int> (seed, elementCount, componentCount, offset, stride); 1645 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT: return createBasicArray<deUint32, GLValue::Uint> (seed, elementCount, componentCount, offset, stride); 1646 case DrawTestSpec::INPUTTYPE_HALF: return createBasicArray<deFloat16, GLValue::Half> (seed, elementCount, componentCount, offset, stride); 1647 default: 1648 DE_ASSERT(false); 1649 break; 1650 } 1651 return DE_NULL; 1652} 1653 1654#if (DE_COMPILER == DE_COMPILER_GCC) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) 1655 // GCC 4.8/4.9 incorrectly emits array-bounds warning from createBasicArray() 1656# define GCC_ARRAY_BOUNDS_FALSE_NEGATIVE 1 1657#endif 1658 1659#if defined(GCC_ARRAY_BOUNDS_FALSE_NEGATIVE) 1660# pragma GCC diagnostic push 1661# pragma GCC diagnostic ignored "-Warray-bounds" 1662#endif 1663 1664template<typename T, typename GLType> 1665char* RandomArrayGenerator::createBasicArray (int seed, int elementCount, int componentCount, int offset, int stride) 1666{ 1667 DE_ASSERT(componentCount >= 1 && componentCount <= 4); 1668 1669 const GLType min = extractGLValue<GLType>(GLValue::getMinValue(GLValueTypeTraits<GLType>::Type)); 1670 const GLType max = extractGLValue<GLType>(GLValue::getMaxValue(GLValueTypeTraits<GLType>::Type)); 1671 1672 const size_t componentSize = sizeof(T); 1673 const size_t elementSize = componentSize * componentCount; 1674 const size_t bufferSize = offset + (elementCount - 1) * stride + elementSize; 1675 1676 char* data = new char[bufferSize]; 1677 char* writePtr = data + offset; 1678 1679 GLType previousComponents[4]; 1680 1681 deRandom rnd; 1682 deRandom_init(&rnd, seed); 1683 1684 for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++) 1685 { 1686 GLType components[4]; 1687 1688 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++) 1689 { 1690 components[componentNdx] = getRandom<GLType>(rnd, min, max); 1691 1692 // Try to not create vertex near previous 1693 if (vertexNdx != 0 && abs(components[componentNdx] - previousComponents[componentNdx]) < minValue<GLType>()) 1694 { 1695 // Too close, try again (but only once) 1696 components[componentNdx] = getRandom<GLType>(rnd, min, max); 1697 } 1698 } 1699 1700 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++) 1701 previousComponents[componentNdx] = components[componentNdx]; 1702 1703 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++) 1704 alignmentSafeAssignment(writePtr + componentNdx*componentSize, components[componentNdx].getValue()); 1705 1706 writePtr += stride; 1707 } 1708 1709 return data; 1710} 1711 1712#if defined(GCC_ARRAY_BOUNDS_FALSE_NEGATIVE) 1713# pragma GCC diagnostic pop 1714#endif 1715 1716char* RandomArrayGenerator::generatePackedArray (int seed, int elementCount, int componentCount, int offset, int stride) 1717{ 1718 DE_ASSERT(componentCount == 4); 1719 DE_UNREF(componentCount); 1720 1721 const deUint32 limit10 = (1 << 10); 1722 const deUint32 limit2 = (1 << 2); 1723 const size_t elementSize = 4; 1724 const size_t bufferSize = offset + (elementCount - 1) * stride + elementSize; 1725 1726 char* data = new char[bufferSize]; 1727 char* writePtr = data + offset; 1728 1729 deRandom rnd; 1730 deRandom_init(&rnd, seed); 1731 1732 for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++) 1733 { 1734 const deUint32 x = deRandom_getUint32(&rnd) % limit10; 1735 const deUint32 y = deRandom_getUint32(&rnd) % limit10; 1736 const deUint32 z = deRandom_getUint32(&rnd) % limit10; 1737 const deUint32 w = deRandom_getUint32(&rnd) % limit2; 1738 const deUint32 packedValue = (w << 30) | (z << 20) | (y << 10) | (x); 1739 1740 alignmentSafeAssignment(writePtr, packedValue); 1741 writePtr += stride; 1742 } 1743 1744 return data; 1745} 1746 1747char* RandomArrayGenerator::generateIndices (int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase) 1748{ 1749 char* data = DE_NULL; 1750 1751 switch (type) 1752 { 1753 case DrawTestSpec::INDEXTYPE_BYTE: 1754 data = createIndices<deUint8>(seed, elementCount, offset, min, max, indexBase); 1755 break; 1756 1757 case DrawTestSpec::INDEXTYPE_SHORT: 1758 data = createIndices<deUint16>(seed, elementCount, offset, min, max, indexBase); 1759 break; 1760 1761 case DrawTestSpec::INDEXTYPE_INT: 1762 data = createIndices<deUint32>(seed, elementCount, offset, min, max, indexBase); 1763 break; 1764 1765 default: 1766 DE_ASSERT(false); 1767 break; 1768 } 1769 1770 return data; 1771} 1772 1773template<typename T> 1774char* RandomArrayGenerator::createIndices (int seed, int elementCount, int offset, int min, int max, int indexBase) 1775{ 1776 const size_t elementSize = sizeof(T); 1777 const size_t bufferSize = offset + elementCount * elementSize; 1778 1779 char* data = new char[bufferSize]; 1780 char* writePtr = data + offset; 1781 1782 deUint32 oldNdx1 = deUint32(-1); 1783 deUint32 oldNdx2 = deUint32(-1); 1784 1785 deRandom rnd; 1786 deRandom_init(&rnd, seed); 1787 1788 DE_ASSERT(indexBase >= 0); // watch for underflows 1789 1790 if (min < 0 || (size_t)min > std::numeric_limits<T>::max() || 1791 max < 0 || (size_t)max > std::numeric_limits<T>::max() || 1792 min > max) 1793 DE_ASSERT(!"Invalid range"); 1794 1795 for (int elementNdx = 0; elementNdx < elementCount; ++elementNdx) 1796 { 1797 deUint32 ndx = getRandom(rnd, GLValue::Uint::create(min), GLValue::Uint::create(max)).getValue(); 1798 1799 // Try not to generate same index as any of previous two. This prevents 1800 // generation of degenerate triangles and lines. If [min, max] is too 1801 // small this cannot be guaranteed. 1802 1803 if (ndx == oldNdx1) ++ndx; 1804 if (ndx > (deUint32)max) ndx = min; 1805 if (ndx == oldNdx2) ++ndx; 1806 if (ndx > (deUint32)max) ndx = min; 1807 if (ndx == oldNdx1) ++ndx; 1808 if (ndx > (deUint32)max) ndx = min; 1809 1810 oldNdx2 = oldNdx1; 1811 oldNdx1 = ndx; 1812 1813 ndx += indexBase; 1814 1815 alignmentSafeAssignment<T>(writePtr + elementSize * elementNdx, T(ndx)); 1816 } 1817 1818 return data; 1819} 1820 1821rr::GenericVec4 RandomArrayGenerator::generateAttributeValue (int seed, DrawTestSpec::InputType type) 1822{ 1823 de::Random random(seed); 1824 1825 switch (type) 1826 { 1827 case DrawTestSpec::INPUTTYPE_FLOAT: 1828 return rr::GenericVec4(generateRandomVec4(random)); 1829 1830 case DrawTestSpec::INPUTTYPE_INT: 1831 return rr::GenericVec4(generateRandomIVec4(random)); 1832 1833 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT: 1834 return rr::GenericVec4(generateRandomUVec4(random)); 1835 1836 default: 1837 DE_ASSERT(false); 1838 return rr::GenericVec4(tcu::Vec4(1, 1, 1, 1)); 1839 } 1840} 1841 1842} // anonymous 1843 1844// AttributePack 1845 1846class AttributePack 1847{ 1848public: 1849 1850 AttributePack (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled); 1851 ~AttributePack (void); 1852 1853 AttributeArray* getArray (int i); 1854 int getArrayCount (void); 1855 1856 void newArray (DrawTestSpec::Storage storage); 1857 void clearArrays (void); 1858 void updateProgram (void); 1859 1860 void render (DrawTestSpec::Primitive primitive, DrawTestSpec::DrawMethod drawMethod, int firstVertex, int vertexCount, DrawTestSpec::IndexType indexType, const void* indexOffset, int rangeStart, int rangeEnd, int instanceCount, int indirectOffset, int baseVertex, float coordScale, float colorScale, AttributeArray* indexArray); 1861 1862 const tcu::Surface& getSurface (void) const { return m_screen; } 1863private: 1864 tcu::TestContext& m_testCtx; 1865 glu::RenderContext& m_renderCtx; 1866 sglr::Context& m_ctx; 1867 1868 std::vector<AttributeArray*>m_arrays; 1869 sglr::ShaderProgram* m_program; 1870 tcu::Surface m_screen; 1871 const bool m_useVao; 1872 const bool m_logEnabled; 1873 deUint32 m_programID; 1874 deUint32 m_vaoID; 1875}; 1876 1877AttributePack::AttributePack (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled) 1878 : m_testCtx (testCtx) 1879 , m_renderCtx (renderCtx) 1880 , m_ctx (drawContext) 1881 , m_program (DE_NULL) 1882 , m_screen (screenSize.x(), screenSize.y()) 1883 , m_useVao (useVao) 1884 , m_logEnabled (logEnabled) 1885 , m_programID (0) 1886 , m_vaoID (0) 1887{ 1888 if (m_useVao) 1889 m_ctx.genVertexArrays(1, &m_vaoID); 1890} 1891 1892AttributePack::~AttributePack (void) 1893{ 1894 clearArrays(); 1895 1896 if (m_programID) 1897 m_ctx.deleteProgram(m_programID); 1898 1899 if (m_program) 1900 delete m_program; 1901 1902 if (m_useVao) 1903 m_ctx.deleteVertexArrays(1, &m_vaoID); 1904} 1905 1906AttributeArray* AttributePack::getArray (int i) 1907{ 1908 return m_arrays.at(i); 1909} 1910 1911int AttributePack::getArrayCount (void) 1912{ 1913 return (int)m_arrays.size(); 1914} 1915 1916void AttributePack::newArray (DrawTestSpec::Storage storage) 1917{ 1918 m_arrays.push_back(new AttributeArray(storage, m_ctx)); 1919} 1920 1921void AttributePack::clearArrays (void) 1922{ 1923 for (std::vector<AttributeArray*>::iterator itr = m_arrays.begin(); itr != m_arrays.end(); itr++) 1924 delete *itr; 1925 m_arrays.clear(); 1926} 1927 1928void AttributePack::updateProgram (void) 1929{ 1930 if (m_programID) 1931 m_ctx.deleteProgram(m_programID); 1932 if (m_program) 1933 delete m_program; 1934 1935 m_program = new DrawTestShaderProgram(m_renderCtx, m_arrays); 1936 m_programID = m_ctx.createProgram(m_program); 1937} 1938 1939void AttributePack::render (DrawTestSpec::Primitive primitive, DrawTestSpec::DrawMethod drawMethod, int firstVertex, int vertexCount, DrawTestSpec::IndexType indexType, const void* indexOffset, int rangeStart, int rangeEnd, int instanceCount, int indirectOffset, int baseVertex, float coordScale, float colorScale, AttributeArray* indexArray) 1940{ 1941 DE_ASSERT(m_program != DE_NULL); 1942 DE_ASSERT(m_programID != 0); 1943 1944 m_ctx.viewport(0, 0, m_screen.getWidth(), m_screen.getHeight()); 1945 m_ctx.clearColor(0.0, 0.0, 0.0, 1.0); 1946 m_ctx.clear(GL_COLOR_BUFFER_BIT); 1947 1948 m_ctx.useProgram(m_programID); 1949 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glUseProgram()"); 1950 1951 m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_coordScale"), coordScale); 1952 m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_colorScale"), colorScale); 1953 1954 if (m_useVao) 1955 m_ctx.bindVertexArray(m_vaoID); 1956 1957 if (indexArray) 1958 indexArray->bindIndexArray(DrawTestSpec::TARGET_ELEMENT_ARRAY); 1959 1960 for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++) 1961 { 1962 std::stringstream attribName; 1963 attribName << "a_" << arrayNdx; 1964 1965 deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str()); 1966 1967 if (m_arrays[arrayNdx]->isBound()) 1968 { 1969 m_ctx.enableVertexAttribArray(loc); 1970 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glEnableVertexAttribArray()"); 1971 } 1972 1973 m_arrays[arrayNdx]->bindAttribute(loc); 1974 } 1975 1976 if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS) 1977 { 1978 m_ctx.drawArrays(primitiveToGL(primitive), firstVertex, vertexCount); 1979 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArrays()"); 1980 } 1981 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED) 1982 { 1983 m_ctx.drawArraysInstanced(primitiveToGL(primitive), firstVertex, vertexCount, instanceCount); 1984 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysInstanced()"); 1985 } 1986 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS) 1987 { 1988 m_ctx.drawElements(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset); 1989 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElements()"); 1990 } 1991 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED) 1992 { 1993 m_ctx.drawRangeElements(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset); 1994 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElements()"); 1995 } 1996 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED) 1997 { 1998 m_ctx.drawElementsInstanced(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount); 1999 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstanced()"); 2000 } 2001 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT) 2002 { 2003 struct DrawCommand 2004 { 2005 GLuint count; 2006 GLuint primCount; 2007 GLuint first; 2008 GLuint reservedMustBeZero; 2009 }; 2010 deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset]; 2011 2012 { 2013 DrawCommand command; 2014 2015 command.count = vertexCount; 2016 command.primCount = instanceCount; 2017 command.first = firstVertex; 2018 command.reservedMustBeZero = 0; 2019 2020 memcpy(buffer + indirectOffset, &command, sizeof(command)); 2021 2022 if (m_logEnabled) 2023 m_testCtx.getLog() 2024 << tcu::TestLog::Message 2025 << "DrawArraysIndirectCommand:\n" 2026 << "\tcount: " << command.count << "\n" 2027 << "\tprimCount: " << command.primCount << "\n" 2028 << "\tfirst: " << command.first << "\n" 2029 << "\treservedMustBeZero: " << command.reservedMustBeZero << "\n" 2030 << tcu::TestLog::EndMessage; 2031 } 2032 2033 GLuint indirectBuf = 0; 2034 m_ctx.genBuffers(1, &indirectBuf); 2035 m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf); 2036 m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW); 2037 delete [] buffer; 2038 2039 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer"); 2040 2041 m_ctx.drawArraysIndirect(primitiveToGL(primitive), (const deInt8*)DE_NULL + indirectOffset); 2042 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()"); 2043 2044 m_ctx.deleteBuffers(1, &indirectBuf); 2045 } 2046 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT) 2047 { 2048 struct DrawCommand 2049 { 2050 GLuint count; 2051 GLuint primCount; 2052 GLuint firstIndex; 2053 GLint baseVertex; 2054 GLuint reservedMustBeZero; 2055 }; 2056 deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset]; 2057 2058 { 2059 DrawCommand command; 2060 2061 // index offset must be converted to firstIndex by dividing with the index element size 2062 DE_ASSERT(((const deUint8*)indexOffset - (const deUint8*)DE_NULL) % gls::DrawTestSpec::indexTypeSize(indexType) == 0); // \note This is checked in spec validation 2063 2064 command.count = vertexCount; 2065 command.primCount = instanceCount; 2066 command.firstIndex = (glw::GLuint)(((const deUint8*)indexOffset - (const deUint8*)DE_NULL) / gls::DrawTestSpec::indexTypeSize(indexType)); 2067 command.baseVertex = baseVertex; 2068 command.reservedMustBeZero = 0; 2069 2070 memcpy(buffer + indirectOffset, &command, sizeof(command)); 2071 2072 if (m_logEnabled) 2073 m_testCtx.getLog() 2074 << tcu::TestLog::Message 2075 << "DrawElementsIndirectCommand:\n" 2076 << "\tcount: " << command.count << "\n" 2077 << "\tprimCount: " << command.primCount << "\n" 2078 << "\tfirstIndex: " << command.firstIndex << "\n" 2079 << "\tbaseVertex: " << command.baseVertex << "\n" 2080 << "\treservedMustBeZero: " << command.reservedMustBeZero << "\n" 2081 << tcu::TestLog::EndMessage; 2082 } 2083 2084 GLuint indirectBuf = 0; 2085 m_ctx.genBuffers(1, &indirectBuf); 2086 m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf); 2087 m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW); 2088 delete [] buffer; 2089 2090 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer"); 2091 2092 m_ctx.drawElementsIndirect(primitiveToGL(primitive), indexTypeToGL(indexType), (const deInt8*)DE_NULL + indirectOffset); 2093 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()"); 2094 2095 m_ctx.deleteBuffers(1, &indirectBuf); 2096 } 2097 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX) 2098 { 2099 m_ctx.drawElementsBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex); 2100 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsBaseVertex()"); 2101 } 2102 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX) 2103 { 2104 m_ctx.drawElementsInstancedBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount, baseVertex); 2105 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstancedBaseVertex()"); 2106 } 2107 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX) 2108 { 2109 m_ctx.drawRangeElementsBaseVertex(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex); 2110 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElementsBaseVertex()"); 2111 } 2112 else 2113 DE_ASSERT(DE_FALSE); 2114 2115 for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++) 2116 { 2117 if (m_arrays[arrayNdx]->isBound()) 2118 { 2119 std::stringstream attribName; 2120 attribName << "a_" << arrayNdx; 2121 2122 deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str()); 2123 2124 m_ctx.disableVertexAttribArray(loc); 2125 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDisableVertexAttribArray()"); 2126 } 2127 } 2128 2129 if (m_useVao) 2130 m_ctx.bindVertexArray(0); 2131 2132 m_ctx.useProgram(0); 2133 m_ctx.readPixels(m_screen, 0, 0, m_screen.getWidth(), m_screen.getHeight()); 2134} 2135 2136// DrawTestSpec 2137 2138DrawTestSpec::AttributeSpec DrawTestSpec::AttributeSpec::createAttributeArray (InputType inputType, OutputType outputType, Storage storage, Usage usage, int componentCount, int offset, int stride, bool normalize, int instanceDivisor) 2139{ 2140 DrawTestSpec::AttributeSpec spec; 2141 2142 spec.inputType = inputType; 2143 spec.outputType = outputType; 2144 spec.storage = storage; 2145 spec.usage = usage; 2146 spec.componentCount = componentCount; 2147 spec.offset = offset; 2148 spec.stride = stride; 2149 spec.normalize = normalize; 2150 spec.instanceDivisor = instanceDivisor; 2151 2152 spec.useDefaultAttribute= false; 2153 2154 return spec; 2155} 2156 2157DrawTestSpec::AttributeSpec DrawTestSpec::AttributeSpec::createDefaultAttribute (InputType inputType, OutputType outputType, int componentCount) 2158{ 2159 DE_ASSERT(inputType == INPUTTYPE_INT || inputType == INPUTTYPE_UNSIGNED_INT || inputType == INPUTTYPE_FLOAT); 2160 DE_ASSERT(inputType == INPUTTYPE_FLOAT || componentCount == 4); 2161 2162 DrawTestSpec::AttributeSpec spec; 2163 2164 spec.inputType = inputType; 2165 spec.outputType = outputType; 2166 spec.storage = DrawTestSpec::STORAGE_LAST; 2167 spec.usage = DrawTestSpec::USAGE_LAST; 2168 spec.componentCount = componentCount; 2169 spec.offset = 0; 2170 spec.stride = 0; 2171 spec.normalize = 0; 2172 spec.instanceDivisor = 0; 2173 2174 spec.useDefaultAttribute = true; 2175 2176 return spec; 2177} 2178 2179DrawTestSpec::AttributeSpec::AttributeSpec (void) 2180{ 2181 inputType = DrawTestSpec::INPUTTYPE_LAST; 2182 outputType = DrawTestSpec::OUTPUTTYPE_LAST; 2183 storage = DrawTestSpec::STORAGE_LAST; 2184 usage = DrawTestSpec::USAGE_LAST; 2185 componentCount = 0; 2186 offset = 0; 2187 stride = 0; 2188 normalize = false; 2189 instanceDivisor = 0; 2190 useDefaultAttribute = false; 2191 additionalPositionAttribute = false; 2192 bgraComponentOrder = false; 2193} 2194 2195int DrawTestSpec::AttributeSpec::hash (void) const 2196{ 2197 if (useDefaultAttribute) 2198 { 2199 return 1 * int(inputType) + 7 * int(outputType) + 13 * componentCount; 2200 } 2201 else 2202 { 2203 return 1 * int(inputType) + 2 * int(outputType) + 3 * int(storage) + 5 * int(usage) + 7 * componentCount + 11 * offset + 13 * stride + 17 * (normalize ? 0 : 1) + 19 * instanceDivisor; 2204 } 2205} 2206 2207bool DrawTestSpec::AttributeSpec::valid (glu::ApiType ctxType) const 2208{ 2209 const bool inputTypeFloat = inputType == DrawTestSpec::INPUTTYPE_FLOAT || inputType == DrawTestSpec::INPUTTYPE_FIXED || inputType == DrawTestSpec::INPUTTYPE_HALF; 2210 const bool inputTypeUnsignedInteger = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE || inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT || inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT || inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10; 2211 const bool inputTypeSignedInteger = inputType == DrawTestSpec::INPUTTYPE_BYTE || inputType == DrawTestSpec::INPUTTYPE_SHORT || inputType == DrawTestSpec::INPUTTYPE_INT || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10; 2212 const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10; 2213 2214 const bool outputTypeFloat = outputType == DrawTestSpec::OUTPUTTYPE_FLOAT || outputType == DrawTestSpec::OUTPUTTYPE_VEC2 || outputType == DrawTestSpec::OUTPUTTYPE_VEC3 || outputType == DrawTestSpec::OUTPUTTYPE_VEC4; 2215 const bool outputTypeSignedInteger = outputType == DrawTestSpec::OUTPUTTYPE_INT || outputType == DrawTestSpec::OUTPUTTYPE_IVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC4; 2216 const bool outputTypeUnsignedInteger = outputType == DrawTestSpec::OUTPUTTYPE_UINT || outputType == DrawTestSpec::OUTPUTTYPE_UVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC4; 2217 2218 if (useDefaultAttribute) 2219 { 2220 if (inputType != DrawTestSpec::INPUTTYPE_INT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT && inputType != DrawTestSpec::INPUTTYPE_FLOAT) 2221 return false; 2222 2223 if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && componentCount != 4) 2224 return false; 2225 2226 // no casting allowed (undefined results) 2227 if (inputType == DrawTestSpec::INPUTTYPE_INT && !outputTypeSignedInteger) 2228 return false; 2229 if (inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT && !outputTypeUnsignedInteger) 2230 return false; 2231 } 2232 2233 if (inputTypePacked && componentCount != 4) 2234 return false; 2235 2236 // Invalid conversions: 2237 2238 // float -> [u]int 2239 if (inputTypeFloat && !outputTypeFloat) 2240 return false; 2241 2242 // uint -> int (undefined results) 2243 if (inputTypeUnsignedInteger && outputTypeSignedInteger) 2244 return false; 2245 2246 // int -> uint (undefined results) 2247 if (inputTypeSignedInteger && outputTypeUnsignedInteger) 2248 return false; 2249 2250 // packed -> non-float (packed formats are converted to floats) 2251 if (inputTypePacked && !outputTypeFloat) 2252 return false; 2253 2254 // Invalid normalize. Normalize is only valid if output type is float 2255 if (normalize && !outputTypeFloat) 2256 return false; 2257 2258 // Allow reverse order (GL_BGRA) only for packed and 4-component ubyte 2259 if (bgraComponentOrder && componentCount != 4) 2260 return false; 2261 if (bgraComponentOrder && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE) 2262 return false; 2263 if (bgraComponentOrder && normalize != true) 2264 return false; 2265 2266 // GLES2 limits 2267 if (ctxType == glu::ApiType::es(2,0)) 2268 { 2269 if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && inputType != DrawTestSpec::INPUTTYPE_FIXED && 2270 inputType != DrawTestSpec::INPUTTYPE_BYTE && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE && 2271 inputType != DrawTestSpec::INPUTTYPE_SHORT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT) 2272 return false; 2273 2274 if (!outputTypeFloat) 2275 return false; 2276 2277 if (bgraComponentOrder) 2278 return false; 2279 } 2280 2281 // GLES3 limits 2282 if (ctxType.getProfile() == glu::PROFILE_ES && ctxType.getMajorVersion() == 3) 2283 { 2284 if (bgraComponentOrder) 2285 return false; 2286 } 2287 2288 // No user pointers in GL core 2289 if (ctxType.getProfile() == glu::PROFILE_CORE) 2290 { 2291 if (!useDefaultAttribute && storage == DrawTestSpec::STORAGE_USER) 2292 return false; 2293 } 2294 2295 return true; 2296} 2297 2298bool DrawTestSpec::AttributeSpec::isBufferAligned (void) const 2299{ 2300 const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10; 2301 2302 // Buffer alignment, offset is a multiple of underlying data type size? 2303 if (storage == STORAGE_BUFFER) 2304 { 2305 int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType); 2306 if (inputTypePacked) 2307 dataTypeSize = 4; 2308 2309 if (offset % dataTypeSize != 0) 2310 return false; 2311 } 2312 2313 return true; 2314} 2315 2316bool DrawTestSpec::AttributeSpec::isBufferStrideAligned (void) const 2317{ 2318 const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10; 2319 2320 // Buffer alignment, offset is a multiple of underlying data type size? 2321 if (storage == STORAGE_BUFFER) 2322 { 2323 int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType); 2324 if (inputTypePacked) 2325 dataTypeSize = 4; 2326 2327 if (stride % dataTypeSize != 0) 2328 return false; 2329 } 2330 2331 return true; 2332} 2333 2334std::string DrawTestSpec::targetToString(Target target) 2335{ 2336 DE_ASSERT(target < TARGET_LAST); 2337 2338 static const char* targets[] = 2339 { 2340 "element_array", // TARGET_ELEMENT_ARRAY = 0, 2341 "array" // TARGET_ARRAY, 2342 }; 2343 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(targets) == DrawTestSpec::TARGET_LAST); 2344 2345 return targets[(int)target]; 2346} 2347 2348std::string DrawTestSpec::inputTypeToString(InputType type) 2349{ 2350 DE_ASSERT(type < INPUTTYPE_LAST); 2351 2352 static const char* types[] = 2353 { 2354 "float", // INPUTTYPE_FLOAT = 0, 2355 "fixed", // INPUTTYPE_FIXED, 2356 "double", // INPUTTYPE_DOUBLE 2357 2358 "byte", // INPUTTYPE_BYTE, 2359 "short", // INPUTTYPE_SHORT, 2360 2361 "unsigned_byte", // INPUTTYPE_UNSIGNED_BYTE, 2362 "unsigned_short", // INPUTTYPE_UNSIGNED_SHORT, 2363 2364 "int", // INPUTTYPE_INT, 2365 "unsigned_int", // INPUTTYPE_UNSIGNED_INT, 2366 "half", // INPUTTYPE_HALF, 2367 "unsigned_int2_10_10_10", // INPUTTYPE_UNSIGNED_INT_2_10_10_10, 2368 "int2_10_10_10" // INPUTTYPE_INT_2_10_10_10, 2369 }; 2370 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types) == DrawTestSpec::INPUTTYPE_LAST); 2371 2372 return types[(int)type]; 2373} 2374 2375std::string DrawTestSpec::outputTypeToString(OutputType type) 2376{ 2377 DE_ASSERT(type < OUTPUTTYPE_LAST); 2378 2379 static const char* types[] = 2380 { 2381 "float", // OUTPUTTYPE_FLOAT = 0, 2382 "vec2", // OUTPUTTYPE_VEC2, 2383 "vec3", // OUTPUTTYPE_VEC3, 2384 "vec4", // OUTPUTTYPE_VEC4, 2385 2386 "int", // OUTPUTTYPE_INT, 2387 "uint", // OUTPUTTYPE_UINT, 2388 2389 "ivec2", // OUTPUTTYPE_IVEC2, 2390 "ivec3", // OUTPUTTYPE_IVEC3, 2391 "ivec4", // OUTPUTTYPE_IVEC4, 2392 2393 "uvec2", // OUTPUTTYPE_UVEC2, 2394 "uvec3", // OUTPUTTYPE_UVEC3, 2395 "uvec4", // OUTPUTTYPE_UVEC4, 2396 }; 2397 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types) == DrawTestSpec::OUTPUTTYPE_LAST); 2398 2399 return types[(int)type]; 2400} 2401 2402std::string DrawTestSpec::usageTypeToString(Usage usage) 2403{ 2404 DE_ASSERT(usage < USAGE_LAST); 2405 2406 static const char* usages[] = 2407 { 2408 "dynamic_draw", // USAGE_DYNAMIC_DRAW = 0, 2409 "static_draw", // USAGE_STATIC_DRAW, 2410 "stream_draw", // USAGE_STREAM_DRAW, 2411 2412 "stream_read", // USAGE_STREAM_READ, 2413 "stream_copy", // USAGE_STREAM_COPY, 2414 2415 "static_read", // USAGE_STATIC_READ, 2416 "static_copy", // USAGE_STATIC_COPY, 2417 2418 "dynamic_read", // USAGE_DYNAMIC_READ, 2419 "dynamic_copy", // USAGE_DYNAMIC_COPY, 2420 }; 2421 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(usages) == DrawTestSpec::USAGE_LAST); 2422 2423 return usages[(int)usage]; 2424} 2425 2426std::string DrawTestSpec::storageToString (Storage storage) 2427{ 2428 DE_ASSERT(storage < STORAGE_LAST); 2429 2430 static const char* storages[] = 2431 { 2432 "user_ptr", // STORAGE_USER = 0, 2433 "buffer" // STORAGE_BUFFER, 2434 }; 2435 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(storages) == DrawTestSpec::STORAGE_LAST); 2436 2437 return storages[(int)storage]; 2438} 2439 2440std::string DrawTestSpec::primitiveToString (Primitive primitive) 2441{ 2442 DE_ASSERT(primitive < PRIMITIVE_LAST); 2443 2444 static const char* primitives[] = 2445 { 2446 "points", // PRIMITIVE_POINTS , 2447 "triangles", // PRIMITIVE_TRIANGLES, 2448 "triangle_fan", // PRIMITIVE_TRIANGLE_FAN, 2449 "triangle_strip", // PRIMITIVE_TRIANGLE_STRIP, 2450 "lines", // PRIMITIVE_LINES 2451 "line_strip", // PRIMITIVE_LINE_STRIP 2452 "line_loop", // PRIMITIVE_LINE_LOOP 2453 "lines_adjacency", // PRIMITIVE_LINES_ADJACENCY 2454 "line_strip_adjacency", // PRIMITIVE_LINE_STRIP_ADJACENCY 2455 "triangles_adjacency", // PRIMITIVE_TRIANGLES_ADJACENCY 2456 "triangle_strip_adjacency", // PRIMITIVE_TRIANGLE_STRIP_ADJACENCY 2457 }; 2458 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(primitives) == DrawTestSpec::PRIMITIVE_LAST); 2459 2460 return primitives[(int)primitive]; 2461} 2462 2463std::string DrawTestSpec::indexTypeToString (IndexType type) 2464{ 2465 DE_ASSERT(type < DrawTestSpec::INDEXTYPE_LAST); 2466 2467 static const char* indexTypes[] = 2468 { 2469 "byte", // INDEXTYPE_BYTE = 0, 2470 "short", // INDEXTYPE_SHORT, 2471 "int", // INDEXTYPE_INT, 2472 }; 2473 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(indexTypes) == DrawTestSpec::INDEXTYPE_LAST); 2474 2475 return indexTypes[(int)type]; 2476} 2477 2478std::string DrawTestSpec::drawMethodToString (DrawTestSpec::DrawMethod method) 2479{ 2480 DE_ASSERT(method < DrawTestSpec::DRAWMETHOD_LAST); 2481 2482 static const char* methods[] = 2483 { 2484 "draw_arrays", //!< DRAWMETHOD_DRAWARRAYS 2485 "draw_arrays_instanced", //!< DRAWMETHOD_DRAWARRAYS_INSTANCED 2486 "draw_arrays_indirect", //!< DRAWMETHOD_DRAWARRAYS_INDIRECT 2487 "draw_elements", //!< DRAWMETHOD_DRAWELEMENTS 2488 "draw_range_elements", //!< DRAWMETHOD_DRAWELEMENTS_RANGED 2489 "draw_elements_instanced", //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED 2490 "draw_elements_indirect", //!< DRAWMETHOD_DRAWELEMENTS_INDIRECT 2491 "draw_elements_base_vertex", //!< DRAWMETHOD_DRAWELEMENTS_BASEVERTEX, 2492 "draw_elements_instanced_base_vertex", //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX, 2493 "draw_range_elements_base_vertex", //!< DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX, 2494 }; 2495 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(methods) == DrawTestSpec::DRAWMETHOD_LAST); 2496 2497 return methods[(int)method]; 2498} 2499 2500int DrawTestSpec::inputTypeSize (InputType type) 2501{ 2502 DE_ASSERT(type < INPUTTYPE_LAST); 2503 2504 static const int size[] = 2505 { 2506 sizeof(float), // INPUTTYPE_FLOAT = 0, 2507 sizeof(deInt32), // INPUTTYPE_FIXED, 2508 sizeof(double), // INPUTTYPE_DOUBLE 2509 2510 sizeof(deInt8), // INPUTTYPE_BYTE, 2511 sizeof(deInt16), // INPUTTYPE_SHORT, 2512 2513 sizeof(deUint8), // INPUTTYPE_UNSIGNED_BYTE, 2514 sizeof(deUint16), // INPUTTYPE_UNSIGNED_SHORT, 2515 2516 sizeof(deInt32), // INPUTTYPE_INT, 2517 sizeof(deUint32), // INPUTTYPE_UNSIGNED_INT, 2518 sizeof(deFloat16), // INPUTTYPE_HALF, 2519 sizeof(deUint32) / 4, // INPUTTYPE_UNSIGNED_INT_2_10_10_10, 2520 sizeof(deUint32) / 4 // INPUTTYPE_INT_2_10_10_10, 2521 }; 2522 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(size) == DrawTestSpec::INPUTTYPE_LAST); 2523 2524 return size[(int)type]; 2525} 2526 2527int DrawTestSpec::indexTypeSize (IndexType type) 2528{ 2529 DE_ASSERT(type < INDEXTYPE_LAST); 2530 2531 static const int size[] = 2532 { 2533 sizeof(deUint8), // INDEXTYPE_BYTE, 2534 sizeof(deUint16), // INDEXTYPE_SHORT, 2535 sizeof(deUint32), // INDEXTYPE_INT, 2536 }; 2537 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(size) == DrawTestSpec::INDEXTYPE_LAST); 2538 2539 return size[(int)type]; 2540} 2541 2542std::string DrawTestSpec::getName (void) const 2543{ 2544 const MethodInfo methodInfo = getMethodInfo(drawMethod); 2545 const bool hasFirst = methodInfo.first; 2546 const bool instanced = methodInfo.instanced; 2547 const bool ranged = methodInfo.ranged; 2548 const bool indexed = methodInfo.indexed; 2549 2550 std::stringstream name; 2551 2552 for (size_t ndx = 0; ndx < attribs.size(); ++ndx) 2553 { 2554 const AttributeSpec& attrib = attribs[ndx]; 2555 2556 if (attribs.size() > 1) 2557 name << "attrib" << ndx << "_"; 2558 2559 if (ndx == 0|| attrib.additionalPositionAttribute) 2560 name << "pos_"; 2561 else 2562 name << "col_"; 2563 2564 if (attrib.useDefaultAttribute) 2565 { 2566 name 2567 << "non_array_" 2568 << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "_" 2569 << attrib.componentCount << "_" 2570 << DrawTestSpec::outputTypeToString(attrib.outputType) << "_"; 2571 } 2572 else 2573 { 2574 name 2575 << DrawTestSpec::storageToString(attrib.storage) << "_" 2576 << attrib.offset << "_" 2577 << attrib.stride << "_" 2578 << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType); 2579 if (attrib.inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && attrib.inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10) 2580 name << attrib.componentCount; 2581 name 2582 << "_" 2583 << (attrib.normalize ? "normalized_" : "") 2584 << DrawTestSpec::outputTypeToString(attrib.outputType) << "_" 2585 << DrawTestSpec::usageTypeToString(attrib.usage) << "_" 2586 << attrib.instanceDivisor << "_"; 2587 } 2588 } 2589 2590 if (indexed) 2591 name 2592 << "index_" << DrawTestSpec::indexTypeToString(indexType) << "_" 2593 << DrawTestSpec::storageToString(indexStorage) << "_" 2594 << "offset" << indexPointerOffset << "_"; 2595 if (hasFirst) 2596 name << "first" << first << "_"; 2597 if (ranged) 2598 name << "ranged_" << indexMin << "_" << indexMax << "_"; 2599 if (instanced) 2600 name << "instances" << instanceCount << "_"; 2601 2602 switch (primitive) 2603 { 2604 case DrawTestSpec::PRIMITIVE_POINTS: 2605 name << "points_"; 2606 break; 2607 case DrawTestSpec::PRIMITIVE_TRIANGLES: 2608 name << "triangles_"; 2609 break; 2610 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN: 2611 name << "triangle_fan_"; 2612 break; 2613 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP: 2614 name << "triangle_strip_"; 2615 break; 2616 case DrawTestSpec::PRIMITIVE_LINES: 2617 name << "lines_"; 2618 break; 2619 case DrawTestSpec::PRIMITIVE_LINE_STRIP: 2620 name << "line_strip_"; 2621 break; 2622 case DrawTestSpec::PRIMITIVE_LINE_LOOP: 2623 name << "line_loop_"; 2624 break; 2625 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY: 2626 name << "line_adjancency"; 2627 break; 2628 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY: 2629 name << "line_strip_adjancency"; 2630 break; 2631 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY: 2632 name << "triangles_adjancency"; 2633 break; 2634 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY: 2635 name << "triangle_strip_adjancency"; 2636 break; 2637 default: 2638 DE_ASSERT(false); 2639 break; 2640 } 2641 2642 name << primitiveCount; 2643 2644 return name.str(); 2645} 2646 2647std::string DrawTestSpec::getDesc (void) const 2648{ 2649 std::stringstream desc; 2650 2651 for (size_t ndx = 0; ndx < attribs.size(); ++ndx) 2652 { 2653 const AttributeSpec& attrib = attribs[ndx]; 2654 2655 if (attrib.useDefaultAttribute) 2656 { 2657 desc 2658 << "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,")) 2659 << "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", " 2660 << "input component count " << attrib.componentCount << ", " 2661 << "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", "; 2662 } 2663 else 2664 { 2665 desc 2666 << "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,")) 2667 << "Storage in " << DrawTestSpec::storageToString(attrib.storage) << ", " 2668 << "stride " << attrib.stride << ", " 2669 << "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", " 2670 << "input component count " << attrib.componentCount << ", " 2671 << (attrib.normalize ? "normalized, " : "") 2672 << "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", " 2673 << "instance divisor " << attrib.instanceDivisor << ", "; 2674 } 2675 } 2676 2677 if (drawMethod == DRAWMETHOD_DRAWARRAYS) 2678 { 2679 desc 2680 << "drawArrays(), " 2681 << "first " << first << ", "; 2682 } 2683 else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED) 2684 { 2685 desc 2686 << "drawArraysInstanced(), " 2687 << "first " << first << ", " 2688 << "instance count " << instanceCount << ", "; 2689 } 2690 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS) 2691 { 2692 desc 2693 << "drawElements(), " 2694 << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", " 2695 << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", " 2696 << "index offset " << indexPointerOffset << ", "; 2697 } 2698 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED) 2699 { 2700 desc 2701 << "drawElementsRanged(), " 2702 << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", " 2703 << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", " 2704 << "index offset " << indexPointerOffset << ", " 2705 << "range start " << indexMin << ", " 2706 << "range end " << indexMax << ", "; 2707 } 2708 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED) 2709 { 2710 desc 2711 << "drawElementsInstanced(), " 2712 << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", " 2713 << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", " 2714 << "index offset " << indexPointerOffset << ", " 2715 << "instance count " << instanceCount << ", "; 2716 } 2717 else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT) 2718 { 2719 desc 2720 << "drawArraysIndirect(), " 2721 << "first " << first << ", " 2722 << "instance count " << instanceCount << ", " 2723 << "indirect offset " << indirectOffset << ", "; 2724 } 2725 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT) 2726 { 2727 desc 2728 << "drawElementsIndirect(), " 2729 << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", " 2730 << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", " 2731 << "index offset " << indexPointerOffset << ", " 2732 << "instance count " << instanceCount << ", " 2733 << "indirect offset " << indirectOffset << ", " 2734 << "base vertex " << baseVertex << ", "; 2735 } 2736 else 2737 DE_ASSERT(DE_FALSE); 2738 2739 desc << primitiveCount; 2740 2741 switch (primitive) 2742 { 2743 case DrawTestSpec::PRIMITIVE_POINTS: 2744 desc << "points"; 2745 break; 2746 case DrawTestSpec::PRIMITIVE_TRIANGLES: 2747 desc << "triangles"; 2748 break; 2749 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN: 2750 desc << "triangles (fan)"; 2751 break; 2752 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP: 2753 desc << "triangles (strip)"; 2754 break; 2755 case DrawTestSpec::PRIMITIVE_LINES: 2756 desc << "lines"; 2757 break; 2758 case DrawTestSpec::PRIMITIVE_LINE_STRIP: 2759 desc << "lines (strip)"; 2760 break; 2761 case DrawTestSpec::PRIMITIVE_LINE_LOOP: 2762 desc << "lines (loop)"; 2763 break; 2764 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY: 2765 desc << "lines (adjancency)"; 2766 break; 2767 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY: 2768 desc << "lines (strip, adjancency)"; 2769 break; 2770 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY: 2771 desc << "triangles (adjancency)"; 2772 break; 2773 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY: 2774 desc << "triangles (strip, adjancency)"; 2775 break; 2776 default: 2777 DE_ASSERT(false); 2778 break; 2779 } 2780 2781 return desc.str(); 2782} 2783 2784std::string DrawTestSpec::getMultilineDesc (void) const 2785{ 2786 std::stringstream desc; 2787 2788 for (size_t ndx = 0; ndx < attribs.size(); ++ndx) 2789 { 2790 const AttributeSpec& attrib = attribs[ndx]; 2791 2792 if (attrib.useDefaultAttribute) 2793 { 2794 desc 2795 << "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n")) 2796 << "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n" 2797 << "\tinput component count " << attrib.componentCount << "\n" 2798 << "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n"; 2799 } 2800 else 2801 { 2802 desc 2803 << "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n")) 2804 << "\tStorage in " << DrawTestSpec::storageToString(attrib.storage) << "\n" 2805 << "\tstride " << attrib.stride << "\n" 2806 << "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n" 2807 << "\tinput component count " << attrib.componentCount << "\n" 2808 << (attrib.normalize ? "\tnormalized\n" : "") 2809 << "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n" 2810 << "\tinstance divisor " << attrib.instanceDivisor << "\n"; 2811 } 2812 } 2813 2814 if (drawMethod == DRAWMETHOD_DRAWARRAYS) 2815 { 2816 desc 2817 << "drawArrays()\n" 2818 << "\tfirst " << first << "\n"; 2819 } 2820 else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED) 2821 { 2822 desc 2823 << "drawArraysInstanced()\n" 2824 << "\tfirst " << first << "\n" 2825 << "\tinstance count " << instanceCount << "\n"; 2826 } 2827 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS) 2828 { 2829 desc 2830 << "drawElements()\n" 2831 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2832 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2833 << "\tindex offset " << indexPointerOffset << "\n"; 2834 } 2835 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED) 2836 { 2837 desc 2838 << "drawElementsRanged()\n" 2839 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2840 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2841 << "\tindex offset " << indexPointerOffset << "\n" 2842 << "\trange start " << indexMin << "\n" 2843 << "\trange end " << indexMax << "\n"; 2844 } 2845 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED) 2846 { 2847 desc 2848 << "drawElementsInstanced()\n" 2849 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2850 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2851 << "\tindex offset " << indexPointerOffset << "\n" 2852 << "\tinstance count " << instanceCount << "\n"; 2853 } 2854 else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT) 2855 { 2856 desc 2857 << "drawArraysIndirect()\n" 2858 << "\tfirst " << first << "\n" 2859 << "\tinstance count " << instanceCount << "\n" 2860 << "\tindirect offset " << indirectOffset << "\n"; 2861 } 2862 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT) 2863 { 2864 desc 2865 << "drawElementsIndirect()\n" 2866 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2867 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2868 << "\tindex offset " << indexPointerOffset << "\n" 2869 << "\tinstance count " << instanceCount << "\n" 2870 << "\tindirect offset " << indirectOffset << "\n" 2871 << "\tbase vertex " << baseVertex << "\n"; 2872 } 2873 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_BASEVERTEX) 2874 { 2875 desc 2876 << "drawElementsBaseVertex()\n" 2877 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2878 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2879 << "\tindex offset " << indexPointerOffset << "\n" 2880 << "\tbase vertex " << baseVertex << "\n"; 2881 } 2882 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX) 2883 { 2884 desc 2885 << "drawElementsInstancedBaseVertex()\n" 2886 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2887 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2888 << "\tindex offset " << indexPointerOffset << "\n" 2889 << "\tinstance count " << instanceCount << "\n" 2890 << "\tbase vertex " << baseVertex << "\n"; 2891 } 2892 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX) 2893 { 2894 desc 2895 << "drawRangeElementsBaseVertex()\n" 2896 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2897 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2898 << "\tindex offset " << indexPointerOffset << "\n" 2899 << "\tbase vertex " << baseVertex << "\n" 2900 << "\trange start " << indexMin << "\n" 2901 << "\trange end " << indexMax << "\n"; 2902 } 2903 else 2904 DE_ASSERT(DE_FALSE); 2905 2906 desc << "\t" << primitiveCount << " "; 2907 2908 switch (primitive) 2909 { 2910 case DrawTestSpec::PRIMITIVE_POINTS: 2911 desc << "points"; 2912 break; 2913 case DrawTestSpec::PRIMITIVE_TRIANGLES: 2914 desc << "triangles"; 2915 break; 2916 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN: 2917 desc << "triangles (fan)"; 2918 break; 2919 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP: 2920 desc << "triangles (strip)"; 2921 break; 2922 case DrawTestSpec::PRIMITIVE_LINES: 2923 desc << "lines"; 2924 break; 2925 case DrawTestSpec::PRIMITIVE_LINE_STRIP: 2926 desc << "lines (strip)"; 2927 break; 2928 case DrawTestSpec::PRIMITIVE_LINE_LOOP: 2929 desc << "lines (loop)"; 2930 break; 2931 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY: 2932 desc << "lines (adjancency)"; 2933 break; 2934 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY: 2935 desc << "lines (strip, adjancency)"; 2936 break; 2937 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY: 2938 desc << "triangles (adjancency)"; 2939 break; 2940 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY: 2941 desc << "triangles (strip, adjancency)"; 2942 break; 2943 default: 2944 DE_ASSERT(false); 2945 break; 2946 } 2947 2948 desc << "\n"; 2949 2950 return desc.str(); 2951} 2952 2953DrawTestSpec::DrawTestSpec (void) 2954{ 2955 primitive = PRIMITIVE_LAST; 2956 primitiveCount = 0; 2957 drawMethod = DRAWMETHOD_LAST; 2958 indexType = INDEXTYPE_LAST; 2959 indexPointerOffset = 0; 2960 indexStorage = STORAGE_LAST; 2961 first = 0; 2962 indexMin = 0; 2963 indexMax = 0; 2964 instanceCount = 0; 2965 indirectOffset = 0; 2966 baseVertex = 0; 2967} 2968 2969int DrawTestSpec::hash (void) const 2970{ 2971 // Use only drawmode-relevant values in "hashing" as the unrelevant values might not be set (causing non-deterministic behavior). 2972 const MethodInfo methodInfo = getMethodInfo(drawMethod); 2973 const bool arrayed = methodInfo.first; 2974 const bool instanced = methodInfo.instanced; 2975 const bool ranged = methodInfo.ranged; 2976 const bool indexed = methodInfo.indexed; 2977 const bool indirect = methodInfo.indirect; 2978 const bool hasBaseVtx = methodInfo.baseVertex; 2979 2980 const int indexHash = (!indexed) ? (0) : (int(indexType) + 10 * indexPointerOffset + 100 * int(indexStorage)); 2981 const int arrayHash = (!arrayed) ? (0) : (first); 2982 const int indexRangeHash = (!ranged) ? (0) : (indexMin + 10 * indexMax); 2983 const int instanceHash = (!instanced) ? (0) : (instanceCount); 2984 const int indirectHash = (!indirect) ? (0) : (indirectOffset); 2985 const int baseVtxHash = (!hasBaseVtx) ? (0) : (baseVertex); 2986 const int basicHash = int(primitive) + 10 * primitiveCount + 100 * int(drawMethod); 2987 2988 return indexHash + 3 * arrayHash + 5 * indexRangeHash + 7 * instanceHash + 13 * basicHash + 17 * (int)attribs.size() + 19 * primitiveCount + 23 * indirectHash + 27 * baseVtxHash; 2989} 2990 2991bool DrawTestSpec::valid (void) const 2992{ 2993 DE_ASSERT(apiType.getProfile() != glu::PROFILE_LAST); 2994 DE_ASSERT(primitive != PRIMITIVE_LAST); 2995 DE_ASSERT(drawMethod != DRAWMETHOD_LAST); 2996 2997 const MethodInfo methodInfo = getMethodInfo(drawMethod); 2998 2999 for (int ndx = 0; ndx < (int)attribs.size(); ++ndx) 3000 if (!attribs[ndx].valid(apiType)) 3001 return false; 3002 3003 if (methodInfo.ranged) 3004 { 3005 deUint32 maxIndexValue = 0; 3006 if (indexType == INDEXTYPE_BYTE) 3007 maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_BYTE).ub.getValue(); 3008 else if (indexType == INDEXTYPE_SHORT) 3009 maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_SHORT).us.getValue(); 3010 else if (indexType == INDEXTYPE_INT) 3011 maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_INT).ui.getValue(); 3012 else 3013 DE_ASSERT(DE_FALSE); 3014 3015 if (indexMin > indexMax) 3016 return false; 3017 if (indexMin < 0 || indexMax < 0) 3018 return false; 3019 if ((deUint32)indexMin > maxIndexValue || (deUint32)indexMax > maxIndexValue) 3020 return false; 3021 } 3022 3023 if (methodInfo.first && first < 0) 3024 return false; 3025 3026 // GLES2 limits 3027 if (apiType == glu::ApiType::es(2,0)) 3028 { 3029 if (drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS && drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS) 3030 return false; 3031 if (drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS && (indexType != INDEXTYPE_BYTE && indexType != INDEXTYPE_SHORT)) 3032 return false; 3033 } 3034 3035 // Indirect limitations 3036 if (methodInfo.indirect) 3037 { 3038 // Indirect offset alignment 3039 if (indirectOffset % 4 != 0) 3040 return false; 3041 3042 // All attribute arrays must be stored in a buffer 3043 for (int ndx = 0; ndx < (int)attribs.size(); ++ndx) 3044 if (!attribs[ndx].useDefaultAttribute && attribs[ndx].storage == gls::DrawTestSpec::STORAGE_USER) 3045 return false; 3046 } 3047 if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT) 3048 { 3049 // index offset must be convertable to firstIndex 3050 if (indexPointerOffset % gls::DrawTestSpec::indexTypeSize(indexType) != 0) 3051 return false; 3052 3053 // Indices must be in a buffer 3054 if (indexStorage != STORAGE_BUFFER) 3055 return false; 3056 } 3057 3058 // Do not allow user pointer in GL core 3059 if (apiType.getProfile() == glu::PROFILE_CORE) 3060 { 3061 if (methodInfo.indexed && indexStorage == DrawTestSpec::STORAGE_USER) 3062 return false; 3063 } 3064 3065 return true; 3066} 3067 3068DrawTestSpec::CompatibilityTestType DrawTestSpec::isCompatibilityTest (void) const 3069{ 3070 const MethodInfo methodInfo = getMethodInfo(drawMethod); 3071 3072 bool bufferAlignmentBad = false; 3073 bool strideAlignmentBad = false; 3074 3075 // Attribute buffer alignment 3076 for (int ndx = 0; ndx < (int)attribs.size(); ++ndx) 3077 if (!attribs[ndx].isBufferAligned()) 3078 bufferAlignmentBad = true; 3079 3080 // Attribute stride alignment 3081 for (int ndx = 0; ndx < (int)attribs.size(); ++ndx) 3082 if (!attribs[ndx].isBufferStrideAligned()) 3083 strideAlignmentBad = true; 3084 3085 // Index buffer alignment 3086 if (methodInfo.indexed) 3087 { 3088 if (indexStorage == STORAGE_BUFFER) 3089 { 3090 int indexSize = 0; 3091 if (indexType == INDEXTYPE_BYTE) 3092 indexSize = 1; 3093 else if (indexType == INDEXTYPE_SHORT) 3094 indexSize = 2; 3095 else if (indexType == INDEXTYPE_INT) 3096 indexSize = 4; 3097 else 3098 DE_ASSERT(DE_FALSE); 3099 3100 if (indexPointerOffset % indexSize != 0) 3101 bufferAlignmentBad = true; 3102 } 3103 } 3104 3105 // \note combination bad alignment & stride is treated as bad offset 3106 if (bufferAlignmentBad) 3107 return COMPATIBILITY_UNALIGNED_OFFSET; 3108 else if (strideAlignmentBad) 3109 return COMPATIBILITY_UNALIGNED_STRIDE; 3110 else 3111 return COMPATIBILITY_NONE; 3112} 3113 3114// DrawTest 3115 3116DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const DrawTestSpec& spec, const char* name, const char* desc) 3117 : TestCase (testCtx, name, desc) 3118 , m_renderCtx (renderCtx) 3119 , m_refBuffers (DE_NULL) 3120 , m_refContext (DE_NULL) 3121 , m_glesContext (DE_NULL) 3122 , m_glArrayPack (DE_NULL) 3123 , m_rrArrayPack (DE_NULL) 3124 , m_maxDiffRed (-1) 3125 , m_maxDiffGreen (-1) 3126 , m_maxDiffBlue (-1) 3127 , m_iteration (0) 3128 , m_result () // \note no per-iteration result logging (only one iteration) 3129{ 3130 addIteration(spec); 3131} 3132 3133DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc) 3134 : TestCase (testCtx, name, desc) 3135 , m_renderCtx (renderCtx) 3136 , m_refBuffers (DE_NULL) 3137 , m_refContext (DE_NULL) 3138 , m_glesContext (DE_NULL) 3139 , m_glArrayPack (DE_NULL) 3140 , m_rrArrayPack (DE_NULL) 3141 , m_maxDiffRed (-1) 3142 , m_maxDiffGreen (-1) 3143 , m_maxDiffBlue (-1) 3144 , m_iteration (0) 3145 , m_result (testCtx.getLog(), "Iteration result: ") 3146{ 3147} 3148 3149DrawTest::~DrawTest (void) 3150{ 3151 deinit(); 3152} 3153 3154void DrawTest::addIteration (const DrawTestSpec& spec, const char* description) 3155{ 3156 // Validate spec 3157 const bool validSpec = spec.valid(); 3158 DE_ASSERT(validSpec); 3159 3160 if (!validSpec) 3161 return; 3162 3163 // Check the context type is the same with other iterations 3164 if (!m_specs.empty()) 3165 { 3166 const bool validContext = m_specs[0].apiType == spec.apiType; 3167 DE_ASSERT(validContext); 3168 3169 if (!validContext) 3170 return; 3171 } 3172 3173 m_specs.push_back(spec); 3174 3175 if (description) 3176 m_iteration_descriptions.push_back(std::string(description)); 3177 else 3178 m_iteration_descriptions.push_back(std::string()); 3179} 3180 3181void DrawTest::init (void) 3182{ 3183 const int renderTargetWidth = de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getWidth()); 3184 const int renderTargetHeight = de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getHeight()); 3185 sglr::ReferenceContextLimits limits (m_renderCtx); 3186 bool useVao = false; 3187 3188 m_glesContext = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight)); 3189 3190 if (m_renderCtx.getType().getAPI() == glu::ApiType::es(2,0) || m_renderCtx.getType().getAPI() == glu::ApiType::es(3,0)) 3191 useVao = false; 3192 else if (contextSupports(m_renderCtx.getType(), glu::ApiType::es(3,1)) || glu::isContextTypeGLCore(m_renderCtx.getType())) 3193 useVao = true; 3194 else 3195 DE_ASSERT(!"Unknown context type"); 3196 3197 DE_ASSERT(!m_specs.empty()); 3198 DE_ASSERT(contextSupports(m_renderCtx.getType(), m_specs[0].apiType)); 3199 3200 m_refBuffers = new sglr::ReferenceContextBuffers(m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, renderTargetWidth, renderTargetHeight); 3201 m_refContext = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer()); 3202 3203 m_glArrayPack = new AttributePack(m_testCtx, m_renderCtx, *m_glesContext, tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, true); 3204 m_rrArrayPack = new AttributePack(m_testCtx, m_renderCtx, *m_refContext, tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, false); 3205 3206 m_maxDiffRed = deCeilFloatToInt32(256.0f * (6.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().redBits))); 3207 m_maxDiffGreen = deCeilFloatToInt32(256.0f * (6.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().greenBits))); 3208 m_maxDiffBlue = deCeilFloatToInt32(256.0f * (6.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().blueBits))); 3209} 3210 3211void DrawTest::deinit (void) 3212{ 3213 delete m_glArrayPack; 3214 delete m_rrArrayPack; 3215 delete m_refBuffers; 3216 delete m_refContext; 3217 delete m_glesContext; 3218 3219 m_glArrayPack = DE_NULL; 3220 m_rrArrayPack = DE_NULL; 3221 m_refBuffers = DE_NULL; 3222 m_refContext = DE_NULL; 3223 m_glesContext = DE_NULL; 3224} 3225 3226DrawTest::IterateResult DrawTest::iterate (void) 3227{ 3228 const int specNdx = (m_iteration / 2); 3229 const bool drawStep = (m_iteration % 2) == 0; 3230 const bool compareStep = (m_iteration % 2) == 1; 3231 const IterateResult iterateResult = ((size_t)m_iteration + 1 == m_specs.size()*2) ? (STOP) : (CONTINUE); 3232 const DrawTestSpec& spec = m_specs[specNdx]; 3233 const bool updateProgram = (m_iteration == 0) || (drawStep && !checkSpecsShaderCompatible(m_specs[specNdx], m_specs[specNdx-1])); // try to use the same shader in all iterations 3234 IterationLogSectionEmitter sectionEmitter (m_testCtx.getLog(), specNdx, m_specs.size(), m_iteration_descriptions[specNdx], drawStep && m_specs.size()!=1); 3235 3236 if (drawStep) 3237 { 3238 const MethodInfo methodInfo = getMethodInfo(spec.drawMethod); 3239 const bool indexed = methodInfo.indexed; 3240 const bool instanced = methodInfo.instanced; 3241 const bool ranged = methodInfo.ranged; 3242 const bool hasFirst = methodInfo.first; 3243 const bool hasBaseVtx = methodInfo.baseVertex; 3244 3245 const size_t primitiveElementCount = getElementCount(spec.primitive, spec.primitiveCount); // !< elements to be drawn 3246 const int indexMin = (ranged) ? (spec.indexMin) : (0); 3247 const int firstAddition = (hasFirst) ? (spec.first) : (0); 3248 const int baseVertexAddition = (hasBaseVtx && spec.baseVertex > 0) ? ( spec.baseVertex) : (0); // spec.baseVertex > 0 => Create bigger attribute buffer 3249 const int indexBase = (hasBaseVtx && spec.baseVertex < 0) ? (-spec.baseVertex) : (0); // spec.baseVertex < 0 => Create bigger indices 3250 const size_t elementCount = primitiveElementCount + indexMin + firstAddition + baseVertexAddition; // !< elements in buffer (buffer should have at least primitiveElementCount ACCESSIBLE (index range, first) elements) 3251 const int maxElementIndex = (int)primitiveElementCount + indexMin + firstAddition - 1; 3252 const int indexMax = de::max(0, (ranged) ? (de::clamp<int>(spec.indexMax, 0, maxElementIndex)) : (maxElementIndex)); 3253 float coordScale = getCoordScale(spec); 3254 float colorScale = getColorScale(spec); 3255 3256 rr::GenericVec4 nullAttribValue; 3257 3258 // Log info 3259 m_testCtx.getLog() << TestLog::Message << spec.getMultilineDesc() << TestLog::EndMessage; 3260 m_testCtx.getLog() << TestLog::Message << TestLog::EndMessage; // extra line for clarity 3261 3262 // Data 3263 3264 m_glArrayPack->clearArrays(); 3265 m_rrArrayPack->clearArrays(); 3266 3267 for (int attribNdx = 0; attribNdx < (int)spec.attribs.size(); attribNdx++) 3268 { 3269 DrawTestSpec::AttributeSpec attribSpec = spec.attribs[attribNdx]; 3270 const bool isPositionAttr = (attribNdx == 0) || (attribSpec.additionalPositionAttribute); 3271 3272 if (attribSpec.useDefaultAttribute) 3273 { 3274 const int seed = 10 * attribSpec.hash() + 100 * spec.hash() + attribNdx; 3275 rr::GenericVec4 attribValue = RandomArrayGenerator::generateAttributeValue(seed, attribSpec.inputType); 3276 3277 m_glArrayPack->newArray(DrawTestSpec::STORAGE_USER); 3278 m_rrArrayPack->newArray(DrawTestSpec::STORAGE_USER); 3279 3280 m_glArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false); 3281 m_rrArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false); 3282 } 3283 else 3284 { 3285 const int seed = attribSpec.hash() + 100 * spec.hash() + attribNdx; 3286 const size_t elementSize = attribSpec.componentCount * DrawTestSpec::inputTypeSize(attribSpec.inputType); 3287 const size_t stride = (attribSpec.stride == 0) ? (elementSize) : (attribSpec.stride); 3288 const size_t evaluatedElementCount = (instanced && attribSpec.instanceDivisor > 0) ? (spec.instanceCount / attribSpec.instanceDivisor + 1) : (elementCount); 3289 const size_t referencedElementCount = (ranged) ? (de::max<size_t>(evaluatedElementCount, spec.indexMax + 1)) : (evaluatedElementCount); 3290 const size_t bufferSize = attribSpec.offset + stride * (referencedElementCount - 1) + elementSize; 3291 const char* data = RandomArrayGenerator::generateArray(seed, (int)referencedElementCount, attribSpec.componentCount, attribSpec.offset, (int)stride, attribSpec.inputType); 3292 3293 try 3294 { 3295 m_glArrayPack->newArray(attribSpec.storage); 3296 m_rrArrayPack->newArray(attribSpec.storage); 3297 3298 m_glArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage); 3299 m_rrArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage); 3300 3301 m_glArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder); 3302 m_rrArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder); 3303 3304 delete [] data; 3305 data = NULL; 3306 } 3307 catch (...) 3308 { 3309 delete [] data; 3310 throw; 3311 } 3312 } 3313 } 3314 3315 // Shader program 3316 if (updateProgram) 3317 { 3318 m_glArrayPack->updateProgram(); 3319 m_rrArrayPack->updateProgram(); 3320 } 3321 3322 // Draw 3323 try 3324 { 3325 // indices 3326 if (indexed) 3327 { 3328 const int seed = spec.hash(); 3329 const size_t indexElementSize = DrawTestSpec::indexTypeSize(spec.indexType); 3330 const size_t indexArraySize = spec.indexPointerOffset + indexElementSize * elementCount; 3331 const char* indexArray = RandomArrayGenerator::generateIndices(seed, (int)elementCount, spec.indexType, spec.indexPointerOffset, indexMin, indexMax, indexBase); 3332 const char* indexPointerBase = (spec.indexStorage == DrawTestSpec::STORAGE_USER) ? (indexArray) : ((char*)DE_NULL); 3333 const char* indexPointer = indexPointerBase + spec.indexPointerOffset; 3334 3335 de::UniquePtr<AttributeArray> glArray (new AttributeArray(spec.indexStorage, *m_glesContext)); 3336 de::UniquePtr<AttributeArray> rrArray (new AttributeArray(spec.indexStorage, *m_refContext)); 3337 3338 try 3339 { 3340 glArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW); 3341 rrArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW); 3342 3343 m_glArrayPack->render(spec.primitive, spec.drawMethod, 0, (int)primitiveElementCount, spec.indexType, indexPointer, spec.indexMin, spec.indexMax, spec.instanceCount, spec.indirectOffset, spec.baseVertex, coordScale, colorScale, glArray.get()); 3344 m_rrArrayPack->render(spec.primitive, spec.drawMethod, 0, (int)primitiveElementCount, spec.indexType, indexPointer, spec.indexMin, spec.indexMax, spec.instanceCount, spec.indirectOffset, spec.baseVertex, coordScale, colorScale, rrArray.get()); 3345 3346 delete [] indexArray; 3347 indexArray = NULL; 3348 } 3349 catch (...) 3350 { 3351 delete [] indexArray; 3352 throw; 3353 } 3354 } 3355 else 3356 { 3357 m_glArrayPack->render(spec.primitive, spec.drawMethod, spec.first, (int)primitiveElementCount, DrawTestSpec::INDEXTYPE_LAST, DE_NULL, 0, 0, spec.instanceCount, spec.indirectOffset, 0, coordScale, colorScale, DE_NULL); 3358 m_rrArrayPack->render(spec.primitive, spec.drawMethod, spec.first, (int)primitiveElementCount, DrawTestSpec::INDEXTYPE_LAST, DE_NULL, 0, 0, spec.instanceCount, spec.indirectOffset, 0, coordScale, colorScale, DE_NULL); 3359 } 3360 } 3361 catch (glu::Error& err) 3362 { 3363 // GL Errors are ok if the mode is not properly aligned 3364 3365 const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest(); 3366 3367 m_testCtx.getLog() << TestLog::Message << "Got error: " << err.what() << TestLog::EndMessage; 3368 3369 if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET) 3370 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers."); 3371 else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE) 3372 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride."); 3373 else 3374 throw; 3375 } 3376 } 3377 else if (compareStep) 3378 { 3379 if (!compare(spec.primitive)) 3380 { 3381 const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest(); 3382 3383 if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET) 3384 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers."); 3385 else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE) 3386 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride."); 3387 else 3388 m_result.addResult(QP_TEST_RESULT_FAIL, "Image comparison failed."); 3389 } 3390 } 3391 else 3392 { 3393 DE_ASSERT(false); 3394 return STOP; 3395 } 3396 3397 m_result.setTestContextResult(m_testCtx); 3398 3399 m_iteration++; 3400 return iterateResult; 3401} 3402 3403enum PrimitiveClass 3404{ 3405 PRIMITIVECLASS_POINT = 0, 3406 PRIMITIVECLASS_LINE, 3407 PRIMITIVECLASS_TRIANGLE, 3408 3409 PRIMITIVECLASS_LAST 3410}; 3411 3412static PrimitiveClass getDrawPrimitiveClass (gls::DrawTestSpec::Primitive primitiveType) 3413{ 3414 switch (primitiveType) 3415 { 3416 case gls::DrawTestSpec::PRIMITIVE_POINTS: 3417 return PRIMITIVECLASS_POINT; 3418 3419 case gls::DrawTestSpec::PRIMITIVE_LINES: 3420 case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP: 3421 case gls::DrawTestSpec::PRIMITIVE_LINE_LOOP: 3422 case gls::DrawTestSpec::PRIMITIVE_LINES_ADJACENCY: 3423 case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY: 3424 return PRIMITIVECLASS_LINE; 3425 3426 case gls::DrawTestSpec::PRIMITIVE_TRIANGLES: 3427 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN: 3428 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP: 3429 case gls::DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY: 3430 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY: 3431 return PRIMITIVECLASS_TRIANGLE; 3432 3433 default: 3434 DE_ASSERT(false); 3435 return PRIMITIVECLASS_LAST; 3436 } 3437} 3438 3439static bool isBlack (const tcu::RGBA& c) 3440{ 3441 // ignore alpha channel 3442 return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0; 3443} 3444 3445static bool isEdgeTripletComponent (int c1, int c2, int c3, int renderTargetDifference) 3446{ 3447 const int roundingDifference = 2 * renderTargetDifference; // src and dst pixels rounded to different directions 3448 const int d1 = c2 - c1; 3449 const int d2 = c3 - c2; 3450 const int rampDiff = de::abs(d2 - d1); 3451 3452 return rampDiff > roundingDifference; 3453} 3454 3455static bool isEdgeTriplet (const tcu::RGBA& c1, const tcu::RGBA& c2, const tcu::RGBA& c3, const tcu::IVec3& renderTargetThreshold) 3456{ 3457 // black (background color) and non-black is always an edge 3458 { 3459 const bool b1 = isBlack(c1); 3460 const bool b2 = isBlack(c2); 3461 const bool b3 = isBlack(c3); 3462 3463 // both pixels with coverage and pixels without coverage 3464 if ((b1 && b2 && b3) == false && (b1 || b2 || b3) == true) 3465 return true; 3466 // all black 3467 if (b1 && b2 && b3) 3468 return false; 3469 // all with coverage 3470 DE_ASSERT(!b1 && !b2 && !b3); 3471 } 3472 3473 // Color is always linearly interpolated => component values change nearly linearly 3474 // in any constant direction on triangle hull. (df/dx ~= C). 3475 3476 // Edge detection (this function) is run against the reference image 3477 // => no dithering to worry about 3478 3479 return isEdgeTripletComponent(c1.getRed(), c2.getRed(), c3.getRed(), renderTargetThreshold.x()) || 3480 isEdgeTripletComponent(c1.getGreen(), c2.getGreen(), c3.getGreen(), renderTargetThreshold.y()) || 3481 isEdgeTripletComponent(c1.getBlue(), c2.getBlue(), c3.getBlue(), renderTargetThreshold.z()); 3482} 3483 3484static bool pixelNearEdge (int x, int y, const tcu::Surface& ref, const tcu::IVec3& renderTargetThreshold) 3485{ 3486 // should not be called for edge pixels 3487 DE_ASSERT(x >= 1 && x <= ref.getWidth()-2); 3488 DE_ASSERT(y >= 1 && y <= ref.getHeight()-2); 3489 3490 // horizontal 3491 3492 for (int dy = -1; dy < 2; ++dy) 3493 { 3494 const tcu::RGBA c1 = ref.getPixel(x-1, y+dy); 3495 const tcu::RGBA c2 = ref.getPixel(x, y+dy); 3496 const tcu::RGBA c3 = ref.getPixel(x+1, y+dy); 3497 if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold)) 3498 return true; 3499 } 3500 3501 // vertical 3502 3503 for (int dx = -1; dx < 2; ++dx) 3504 { 3505 const tcu::RGBA c1 = ref.getPixel(x+dx, y-1); 3506 const tcu::RGBA c2 = ref.getPixel(x+dx, y); 3507 const tcu::RGBA c3 = ref.getPixel(x+dx, y+1); 3508 if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold)) 3509 return true; 3510 } 3511 3512 return false; 3513} 3514 3515static deUint32 getVisualizationGrayscaleColor (const tcu::RGBA& c) 3516{ 3517 // make triangle coverage and error pixels obvious by converting coverage to grayscale 3518 if (isBlack(c)) 3519 return 0; 3520 else 3521 return 50u + (deUint32)(c.getRed() + c.getBlue() + c.getGreen()) / 8u; 3522} 3523 3524static bool pixelNearLineIntersection (int x, int y, const tcu::Surface& target) 3525{ 3526 // should not be called for edge pixels 3527 DE_ASSERT(x >= 1 && x <= target.getWidth()-2); 3528 DE_ASSERT(y >= 1 && y <= target.getHeight()-2); 3529 3530 int coveredPixels = 0; 3531 3532 for (int dy = -1; dy < 2; dy++) 3533 for (int dx = -1; dx < 2; dx++) 3534 { 3535 const bool targetCoverage = !isBlack(target.getPixel(x+dx, y+dy)); 3536 if (targetCoverage) 3537 { 3538 ++coveredPixels; 3539 3540 // A single thin line cannot have more than 3 covered pixels in a 3x3 area 3541 if (coveredPixels >= 4) 3542 return true; 3543 } 3544 } 3545 3546 return false; 3547} 3548 3549// search 3x3 are for matching color 3550static bool pixelNeighborhoodContainsColor (const tcu::Surface& target, int x, int y, const tcu::RGBA& color, const tcu::IVec3& compareThreshold) 3551{ 3552 // should not be called for edge pixels 3553 DE_ASSERT(x >= 1 && x <= target.getWidth()-2); 3554 DE_ASSERT(y >= 1 && y <= target.getHeight()-2); 3555 3556 for (int dy = -1; dy < 2; dy++) 3557 for (int dx = -1; dx < 2; dx++) 3558 { 3559 const tcu::RGBA targetCmpPixel = target.getPixel(x+dx, y+dy); 3560 const int r = deAbs32(color.getRed() - targetCmpPixel.getRed()); 3561 const int g = deAbs32(color.getGreen() - targetCmpPixel.getGreen()); 3562 const int b = deAbs32(color.getBlue() - targetCmpPixel.getBlue()); 3563 3564 if (r <= compareThreshold.x() && g <= compareThreshold.y() && b <= compareThreshold.z()) 3565 return true; 3566 } 3567 3568 return false; 3569} 3570 3571// search 3x3 are for matching coverage (coverage == (color != background color)) 3572static bool pixelNeighborhoodContainsCoverage (const tcu::Surface& target, int x, int y, bool coverage) 3573{ 3574 // should not be called for edge pixels 3575 DE_ASSERT(x >= 1 && x <= target.getWidth()-2); 3576 DE_ASSERT(y >= 1 && y <= target.getHeight()-2); 3577 3578 for (int dy = -1; dy < 2; dy++) 3579 for (int dx = -1; dx < 2; dx++) 3580 { 3581 const bool targetCmpCoverage = !isBlack(target.getPixel(x+dx, y+dy)); 3582 if (targetCmpCoverage == coverage) 3583 return true; 3584 } 3585 3586 return false; 3587} 3588 3589static bool edgeRelaxedImageCompare (tcu::TestLog& log, const char* imageSetName, const char* imageSetDesc, const tcu::Surface& reference, const tcu::Surface& result, const tcu::IVec3& compareThreshold, const tcu::IVec3& renderTargetThreshold, int maxAllowedInvalidPixels) 3590{ 3591 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 3592 3593 const tcu::IVec4 green (0, 255, 0, 255); 3594 const tcu::IVec4 errorColor (255, 0, 0, 255); 3595 const int width = reference.getWidth(); 3596 const int height = reference.getHeight(); 3597 tcu::TextureLevel errorMask (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height); 3598 int numFailingPixels = 0; 3599 3600 // clear errormask edges which would otherwise be transparent 3601 3602 tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0, 0, width, 1), green); 3603 tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0, height-1, width, 1), green); 3604 tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0, 0, 1, height), green); 3605 tcu::clear(tcu::getSubregion(errorMask.getAccess(), width-1, 0, 1, height), green); 3606 3607 // skip edge pixels since coverage on edge cannot be verified 3608 3609 for (int y = 1; y < height - 1; ++y) 3610 for (int x = 1; x < width - 1; ++x) 3611 { 3612 const tcu::RGBA refPixel = reference.getPixel(x, y); 3613 const tcu::RGBA screenPixel = result.getPixel(x, y); 3614 const bool isOkReferencePixel = pixelNeighborhoodContainsColor(result, x, y, refPixel, compareThreshold); // screen image has a matching pixel nearby (~= If something is drawn on reference, it must be drawn to screen too.) 3615 const bool isOkScreenPixel = pixelNeighborhoodContainsColor(reference, x, y, screenPixel, compareThreshold); // reference image has a matching pixel nearby (~= If something is drawn on screen, it must be drawn to reference too.) 3616 3617 if (isOkScreenPixel && isOkReferencePixel) 3618 { 3619 // pixel valid, write greenish pixels to make the result image easier to read 3620 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel); 3621 errorMask.getAccess().setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y); 3622 } 3623 else if (!pixelNearEdge(x, y, reference, renderTargetThreshold)) 3624 { 3625 // non-edge pixel values must be within threshold of the reference values 3626 errorMask.getAccess().setPixel(errorColor, x, y); 3627 ++numFailingPixels; 3628 } 3629 else 3630 { 3631 // we are on/near an edge, verify only coverage (coverage == not background colored) 3632 const bool referenceCoverage = !isBlack(refPixel); 3633 const bool screenCoverage = !isBlack(screenPixel); 3634 const bool isOkReferenceCoverage = pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage); // Check reference pixel against screen pixel 3635 const bool isOkScreenCoverage = pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage); // Check screen pixels against reference pixel 3636 3637 if (isOkScreenCoverage && isOkReferenceCoverage) 3638 { 3639 // pixel valid, write greenish pixels to make the result image easier to read 3640 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel); 3641 errorMask.getAccess().setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y); 3642 } 3643 else 3644 { 3645 // coverage does not match 3646 errorMask.getAccess().setPixel(errorColor, x, y); 3647 ++numFailingPixels; 3648 } 3649 } 3650 } 3651 3652 log << TestLog::Message 3653 << "Comparing images:\n" 3654 << "\tallowed deviation in pixel positions = 1\n" 3655 << "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n" 3656 << "\tnumber of invalid pixels = " << numFailingPixels 3657 << TestLog::EndMessage; 3658 3659 if (numFailingPixels > maxAllowedInvalidPixels) 3660 { 3661 log << TestLog::Message 3662 << "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")" 3663 << TestLog::EndMessage 3664 << TestLog::ImageSet(imageSetName, imageSetDesc) 3665 << TestLog::Image("Result", "Result", result) 3666 << TestLog::Image("Reference", "Reference", reference) 3667 << TestLog::Image("ErrorMask", "Error mask", errorMask) 3668 << TestLog::EndImageSet; 3669 3670 return false; 3671 } 3672 else 3673 { 3674 log << TestLog::ImageSet(imageSetName, imageSetDesc) 3675 << TestLog::Image("Result", "Result", result) 3676 << TestLog::EndImageSet; 3677 3678 return true; 3679 } 3680} 3681 3682static bool intersectionRelaxedLineImageCompare (tcu::TestLog& log, const char* imageSetName, const char* imageSetDesc, const tcu::Surface& reference, const tcu::Surface& result, const tcu::IVec3& compareThreshold, int maxAllowedInvalidPixels) 3683{ 3684 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 3685 3686 const tcu::IVec4 green (0, 255, 0, 255); 3687 const tcu::IVec4 errorColor (255, 0, 0, 255); 3688 const int width = reference.getWidth(); 3689 const int height = reference.getHeight(); 3690 tcu::TextureLevel errorMask (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height); 3691 int numFailingPixels = 0; 3692 3693 // clear errormask edges which would otherwise be transparent 3694 3695 tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0, 0, width, 1), green); 3696 tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0, height-1, width, 1), green); 3697 tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0, 0, 1, height), green); 3698 tcu::clear(tcu::getSubregion(errorMask.getAccess(), width-1, 0, 1, height), green); 3699 3700 // skip edge pixels since coverage on edge cannot be verified 3701 3702 for (int y = 1; y < height - 1; ++y) 3703 for (int x = 1; x < width - 1; ++x) 3704 { 3705 const tcu::RGBA refPixel = reference.getPixel(x, y); 3706 const tcu::RGBA screenPixel = result.getPixel(x, y); 3707 const bool isOkScreenPixel = pixelNeighborhoodContainsColor(reference, x, y, screenPixel, compareThreshold); // reference image has a matching pixel nearby (~= If something is drawn on screen, it must be drawn to reference too.) 3708 const bool isOkReferencePixel = pixelNeighborhoodContainsColor(result, x, y, refPixel, compareThreshold); // screen image has a matching pixel nearby (~= If something is drawn on reference, it must be drawn to screen too.) 3709 3710 if (isOkScreenPixel && isOkReferencePixel) 3711 { 3712 // pixel valid, write greenish pixels to make the result image easier to read 3713 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel); 3714 errorMask.getAccess().setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y); 3715 } 3716 else if (!pixelNearLineIntersection(x, y, reference) && 3717 !pixelNearLineIntersection(x, y, result)) 3718 { 3719 // non-intersection pixel values must be within threshold of the reference values 3720 errorMask.getAccess().setPixel(errorColor, x, y); 3721 ++numFailingPixels; 3722 } 3723 else 3724 { 3725 // pixel is near a line intersection 3726 // we are on/near an edge, verify only coverage (coverage == not background colored) 3727 const bool referenceCoverage = !isBlack(refPixel); 3728 const bool screenCoverage = !isBlack(screenPixel); 3729 const bool isOkScreenCoverage = pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage); // Check screen pixels against reference pixel 3730 const bool isOkReferenceCoverage = pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage); // Check reference pixel against screen pixel 3731 3732 if (isOkScreenCoverage && isOkReferenceCoverage) 3733 { 3734 // pixel valid, write greenish pixels to make the result image easier to read 3735 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel); 3736 errorMask.getAccess().setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y); 3737 } 3738 else 3739 { 3740 // coverage does not match 3741 errorMask.getAccess().setPixel(errorColor, x, y); 3742 ++numFailingPixels; 3743 } 3744 } 3745 } 3746 3747 log << TestLog::Message 3748 << "Comparing images:\n" 3749 << "\tallowed deviation in pixel positions = 1\n" 3750 << "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n" 3751 << "\tnumber of invalid pixels = " << numFailingPixels 3752 << TestLog::EndMessage; 3753 3754 if (numFailingPixels > maxAllowedInvalidPixels) 3755 { 3756 log << TestLog::Message 3757 << "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")" 3758 << TestLog::EndMessage 3759 << TestLog::ImageSet(imageSetName, imageSetDesc) 3760 << TestLog::Image("Result", "Result", result) 3761 << TestLog::Image("Reference", "Reference", reference) 3762 << TestLog::Image("ErrorMask", "Error mask", errorMask) 3763 << TestLog::EndImageSet; 3764 3765 return false; 3766 } 3767 else 3768 { 3769 log << TestLog::ImageSet(imageSetName, imageSetDesc) 3770 << TestLog::Image("Result", "Result", result) 3771 << TestLog::EndImageSet; 3772 3773 return true; 3774 } 3775} 3776 3777bool DrawTest::compare (gls::DrawTestSpec::Primitive primitiveType) 3778{ 3779 const tcu::Surface& ref = m_rrArrayPack->getSurface(); 3780 const tcu::Surface& screen = m_glArrayPack->getSurface(); 3781 3782 if (m_renderCtx.getRenderTarget().getNumSamples() > 1) 3783 { 3784 // \todo [mika] Improve compare when using multisampling 3785 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; 3786 return tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", ref.getAccess(), screen.getAccess(), 0.3f, tcu::COMPARE_LOG_RESULT); 3787 } 3788 else 3789 { 3790 const PrimitiveClass primitiveClass = getDrawPrimitiveClass(primitiveType); 3791 3792 switch (primitiveClass) 3793 { 3794 case PRIMITIVECLASS_POINT: 3795 { 3796 // Point are extremely unlikely to have overlapping regions, don't allow any no extra / missing pixels 3797 const int maxAllowedInvalidPixelsWithPoints = 0; 3798 return tcu::intThresholdPositionDeviationErrorThresholdCompare(m_testCtx.getLog(), 3799 "CompareResult", 3800 "Result of rendering", 3801 ref.getAccess(), 3802 screen.getAccess(), 3803 tcu::UVec4(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue, 256), 3804 tcu::IVec3(1, 1, 0), //!< 3x3 search kernel 3805 true, //!< relax comparison on the image boundary 3806 maxAllowedInvalidPixelsWithPoints, //!< error threshold 3807 tcu::COMPARE_LOG_RESULT); 3808 } 3809 3810 case PRIMITIVECLASS_LINE: 3811 { 3812 // Lines can potentially have a large number of overlapping pixels. Pixel comparison may potentially produce 3813 // false negatives in such pixels if for example the pixel in question is overdrawn by another line in the 3814 // reference image but not in the resultin image. Relax comparison near line intersection points (areas) and 3815 // compare only coverage, not color, in such pixels 3816 const int maxAllowedInvalidPixelsWithLines = 5; // line are allowed to have a few bad pixels 3817 return intersectionRelaxedLineImageCompare(m_testCtx.getLog(), 3818 "CompareResult", 3819 "Result of rendering", 3820 ref, 3821 screen, 3822 tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue), 3823 maxAllowedInvalidPixelsWithLines); 3824 } 3825 3826 case PRIMITIVECLASS_TRIANGLE: 3827 { 3828 // Triangles are likely to partially or fully overlap. Pixel difference comparison is fragile in pixels 3829 // where there could be potential overlapping since the pixels might be covered by one triangle in the 3830 // reference image and by the other in the result image. Relax comparsion near primitive edges and 3831 // compare only coverage, not color, in such pixels. 3832 const int maxAllowedInvalidPixelsWithTriangles = 10; 3833 const tcu::IVec3 renderTargetThreshold = m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold().toIVec().xyz(); 3834 3835 return edgeRelaxedImageCompare(m_testCtx.getLog(), 3836 "CompareResult", 3837 "Result of rendering", 3838 ref, 3839 screen, 3840 tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue), 3841 renderTargetThreshold, 3842 maxAllowedInvalidPixelsWithTriangles); 3843 } 3844 3845 default: 3846 DE_ASSERT(false); 3847 return false; 3848 } 3849 } 3850} 3851 3852float DrawTest::getCoordScale (const DrawTestSpec& spec) const 3853{ 3854 float maxValue = 1.0f; 3855 3856 for (int arrayNdx = 0; arrayNdx < (int)spec.attribs.size(); arrayNdx++) 3857 { 3858 DrawTestSpec::AttributeSpec attribSpec = spec.attribs[arrayNdx]; 3859 const bool isPositionAttr = (arrayNdx == 0) || (attribSpec.additionalPositionAttribute); 3860 float attrMaxValue = 0; 3861 3862 if (!isPositionAttr) 3863 continue; 3864 3865 if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10) 3866 { 3867 if (attribSpec.normalize) 3868 attrMaxValue += 1.0f; 3869 else 3870 attrMaxValue += 1024.0; 3871 } 3872 else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10) 3873 { 3874 if (attribSpec.normalize) 3875 attrMaxValue += 1.0f; 3876 else 3877 attrMaxValue += 512.0; 3878 } 3879 else 3880 { 3881 const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat(); 3882 3883 attrMaxValue += (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType)) ? (1.0f) : (max * 1.1f); 3884 } 3885 3886 if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4 3887 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4 3888 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4) 3889 attrMaxValue *= 2; 3890 3891 maxValue += attrMaxValue; 3892 } 3893 3894 return 1.0f / maxValue; 3895} 3896 3897float DrawTest::getColorScale (const DrawTestSpec& spec) const 3898{ 3899 float colorScale = 1.0f; 3900 3901 for (int arrayNdx = 1; arrayNdx < (int)spec.attribs.size(); arrayNdx++) 3902 { 3903 DrawTestSpec::AttributeSpec attribSpec = spec.attribs[arrayNdx]; 3904 const bool isPositionAttr = (arrayNdx == 0) || (attribSpec.additionalPositionAttribute); 3905 3906 if (isPositionAttr) 3907 continue; 3908 3909 if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10) 3910 { 3911 if (!attribSpec.normalize) 3912 colorScale *= 1.0 / 1024.0; 3913 } 3914 else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10) 3915 { 3916 if (!attribSpec.normalize) 3917 colorScale *= 1.0 / 512.0; 3918 } 3919 else 3920 { 3921 const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat(); 3922 3923 colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max))); 3924 if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4 || 3925 attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4 || 3926 attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4) 3927 colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max))); 3928 } 3929 } 3930 3931 return colorScale; 3932} 3933 3934} // gls 3935} // deqp 3936