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