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