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 // AttributeArray 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 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); 898 void bindAttribute (deUint32 loc); 899 void bindIndexArray (DrawTestSpec::Target storage); 900 901 int getComponentCount (void) const { return m_componentCount; } 902 DrawTestSpec::Target getTarget (void) const { return m_target; } 903 DrawTestSpec::InputType getInputType (void) const { return m_inputType; } 904 DrawTestSpec::OutputType getOutputType (void) const { return m_outputType; } 905 DrawTestSpec::Storage getStorageType (void) const { return m_storage; } 906 bool getNormalized (void) const { return m_normalize; } 907 int getStride (void) const { return m_stride; } 908 bool isBound (void) const { return m_bound; } 909 bool isPositionAttribute (void) const { return m_isPositionAttr; } 910 911 private: 912 DrawTestSpec::Storage m_storage; 913 sglr::Context& m_ctx; 914 deUint32 m_glBuffer; 915 916 int m_size; 917 char* m_data; 918 int m_componentCount; 919 bool m_bound; 920 DrawTestSpec::Target m_target; 921 DrawTestSpec::InputType m_inputType; 922 DrawTestSpec::OutputType m_outputType; 923 bool m_normalize; 924 int m_stride; 925 int m_offset; 926 rr::GenericVec4 m_defaultAttrib; 927 int m_instanceDivisor; 928 bool m_isPositionAttr; 929 bool m_bgraOrder; 930 }; 931 932 AttributeArray::AttributeArray (DrawTestSpec::Storage storage, sglr::Context& context) 933 : m_storage (storage) 934 , m_ctx (context) 935 , m_glBuffer (0) 936 , m_size (0) 937 , m_data (DE_NULL) 938 , m_componentCount (1) 939 , m_bound (false) 940 , m_target (DrawTestSpec::TARGET_ARRAY) 941 , m_inputType (DrawTestSpec::INPUTTYPE_FLOAT) 942 , m_outputType (DrawTestSpec::OUTPUTTYPE_VEC4) 943 , m_normalize (false) 944 , m_stride (0) 945 , m_offset (0) 946 , m_instanceDivisor (0) 947 , m_isPositionAttr (false) 948 , m_bgraOrder (false) 949 { 950 if (m_storage == DrawTestSpec::STORAGE_BUFFER) 951 { 952 m_ctx.genBuffers(1, &m_glBuffer); 953 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glGenBuffers()"); 954 } 955 } 956 957 AttributeArray::~AttributeArray (void) 958 { 959 if (m_storage == DrawTestSpec::STORAGE_BUFFER) 960 { 961 m_ctx.deleteBuffers(1, &m_glBuffer); 962 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDeleteBuffers()"); 963 } 964 else if (m_storage == DrawTestSpec::STORAGE_USER) 965 delete[] m_data; 966 else 967 DE_ASSERT(false); 968 } 969 970 void AttributeArray::data (DrawTestSpec::Target target, size_t size, const char* ptr, DrawTestSpec::Usage usage) 971 { 972 m_size = (int)size; 973 m_target = target; 974 975 if (m_storage == DrawTestSpec::STORAGE_BUFFER) 976 { 977 m_ctx.bindBuffer(targetToGL(target), m_glBuffer); 978 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()"); 979 980 m_ctx.bufferData(targetToGL(target), size, ptr, usageToGL(usage)); 981 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferData()"); 982 } 983 else if (m_storage == DrawTestSpec::STORAGE_USER) 984 { 985 if (m_data) 986 delete[] m_data; 987 988 m_data = new char[size]; 989 std::memcpy(m_data, ptr, size); 990 } 991 else 992 DE_ASSERT(false); 993 } 994 995 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) 996 { 997 m_componentCount = size; 998 m_bound = bound; 999 m_inputType = inputType; 1000 m_outputType = outType; 1001 m_normalize = normalized; 1002 m_stride = stride; 1003 m_offset = offset; 1004 m_defaultAttrib = defaultAttrib; 1005 m_instanceDivisor = instanceDivisor; 1006 m_isPositionAttr = isPositionAttr; 1007 m_bgraOrder = bgraComponentOrder; 1008 } 1009 1010 void AttributeArray::bindAttribute (deUint32 loc) 1011 { 1012 if (!isBound()) 1013 { 1014 switch (m_inputType) 1015 { 1016 case DrawTestSpec::INPUTTYPE_FLOAT: 1017 { 1018 tcu::Vec4 attr = m_defaultAttrib.get<float>(); 1019 1020 switch (m_componentCount) 1021 { 1022 case 1: m_ctx.vertexAttrib1f(loc, attr.x()); break; 1023 case 2: m_ctx.vertexAttrib2f(loc, attr.x(), attr.y()); break; 1024 case 3: m_ctx.vertexAttrib3f(loc, attr.x(), attr.y(), attr.z()); break; 1025 case 4: m_ctx.vertexAttrib4f(loc, attr.x(), attr.y(), attr.z(), attr.w()); break; 1026 default: DE_ASSERT(DE_FALSE); break; 1027 } 1028 break; 1029 } 1030 case DrawTestSpec::INPUTTYPE_INT: 1031 { 1032 tcu::IVec4 attr = m_defaultAttrib.get<deInt32>(); 1033 m_ctx.vertexAttribI4i(loc, attr.x(), attr.y(), attr.z(), attr.w()); 1034 break; 1035 } 1036 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT: 1037 { 1038 tcu::UVec4 attr = m_defaultAttrib.get<deUint32>(); 1039 m_ctx.vertexAttribI4ui(loc, attr.x(), attr.y(), attr.z(), attr.w()); 1040 break; 1041 } 1042 default: 1043 DE_ASSERT(DE_FALSE); 1044 break; 1045 } 1046 } 1047 else 1048 { 1049 const deUint8* basePtr = DE_NULL; 1050 1051 if (m_storage == DrawTestSpec::STORAGE_BUFFER) 1052 { 1053 m_ctx.bindBuffer(targetToGL(m_target), m_glBuffer); 1054 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()"); 1055 1056 basePtr = DE_NULL; 1057 } 1058 else if (m_storage == DrawTestSpec::STORAGE_USER) 1059 { 1060 m_ctx.bindBuffer(targetToGL(m_target), 0); 1061 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()"); 1062 1063 basePtr = (const deUint8*)m_data; 1064 } 1065 else 1066 DE_ASSERT(DE_FALSE); 1067 1068 if (!inputTypeIsFloatType(m_inputType)) 1069 { 1070 // Input is not float type 1071 1072 if (outputTypeIsFloatType(m_outputType)) 1073 { 1074 const int size = (m_bgraOrder) ? (GL_BGRA) : (m_componentCount); 1075 1076 DE_ASSERT(!(m_bgraOrder && m_componentCount != 4)); 1077 1078 // Output type is float type 1079 m_ctx.vertexAttribPointer(loc, size, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset); 1080 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()"); 1081 } 1082 else 1083 { 1084 // Output type is int type 1085 m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, basePtr + m_offset); 1086 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()"); 1087 } 1088 } 1089 else 1090 { 1091 // Input type is float type 1092 1093 // Output type must be float type 1094 DE_ASSERT(outputTypeIsFloatType(m_outputType)); 1095 1096 m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset); 1097 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()"); 1098 } 1099 1100 if (m_instanceDivisor) 1101 m_ctx.vertexAttribDivisor(loc, m_instanceDivisor); 1102 } 1103 } 1104 1105 void AttributeArray::bindIndexArray (DrawTestSpec::Target target) 1106 { 1107 if (m_storage == DrawTestSpec::STORAGE_USER) 1108 { 1109 } 1110 else if (m_storage == DrawTestSpec::STORAGE_BUFFER) 1111 { 1112 m_ctx.bindBuffer(targetToGL(target), m_glBuffer); 1113 } 1114 } 1115 1116 // DrawTestShaderProgram 1117 1118 class DrawTestShaderProgram : public sglr::ShaderProgram 1119 { 1120 public: 1121 DrawTestShaderProgram (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays); 1122 1123 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const; 1124 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const; 1125 1126 private: 1127 static std::string genVertexSource (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays); 1128 static std::string genFragmentSource (const glu::RenderContext& ctx); 1129 static void generateShaderParams (std::map<std::string, std::string>& params, glu::ContextType type); 1130 static rr::GenericVecType mapOutputType (const DrawTestSpec::OutputType& type); 1131 static int getComponentCount (const DrawTestSpec::OutputType& type); 1132 1133 static sglr::pdec::ShaderProgramDeclaration createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays); 1134 1135 std::vector<int> m_componentCount; 1136 std::vector<bool> m_isCoord; 1137 std::vector<rr::GenericVecType> m_attrType; 1138 }; 1139 1140 DrawTestShaderProgram::DrawTestShaderProgram (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays) 1141 : sglr::ShaderProgram (createProgramDeclaration(ctx, arrays)) 1142 , m_componentCount (arrays.size()) 1143 , m_isCoord (arrays.size()) 1144 , m_attrType (arrays.size()) 1145 { 1146 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++) 1147 { 1148 m_componentCount[arrayNdx] = getComponentCount(arrays[arrayNdx]->getOutputType()); 1149 m_isCoord[arrayNdx] = arrays[arrayNdx]->isPositionAttribute(); 1150 m_attrType[arrayNdx] = mapOutputType(arrays[arrayNdx]->getOutputType()); 1151 } 1152 } 1153 1154 template <typename T> 1155 void calcShaderColorCoord (tcu::Vec2& coord, tcu::Vec3& color, const tcu::Vector<T, 4>& attribValue, bool isCoordinate, int numComponents) 1156 { 1157 if (isCoordinate) 1158 switch (numComponents) 1159 { 1160 case 1: coord += tcu::Vec2((float)attribValue.x(), (float)attribValue.x()); break; 1161 case 2: coord += tcu::Vec2((float)attribValue.x(), (float)attribValue.y()); break; 1162 case 3: coord += tcu::Vec2((float)attribValue.x() + (float)attribValue.z(), (float)attribValue.y()); break; 1163 case 4: coord += tcu::Vec2((float)attribValue.x() + (float)attribValue.z(), (float)attribValue.y() + (float)attribValue.w()); break; 1164 1165 default: 1166 DE_ASSERT(false); 1167 } 1168 else 1169 { 1170 switch (numComponents) 1171 { 1172 case 1: 1173 color = color * (float)attribValue.x(); 1174 break; 1175 1176 case 2: 1177 color.x() = color.x() * (float)attribValue.x(); 1178 color.y() = color.y() * (float)attribValue.y(); 1179 break; 1180 1181 case 3: 1182 color.x() = color.x() * (float)attribValue.x(); 1183 color.y() = color.y() * (float)attribValue.y(); 1184 color.z() = color.z() * (float)attribValue.z(); 1185 break; 1186 1187 case 4: 1188 color.x() = color.x() * (float)attribValue.x() * (float)attribValue.w(); 1189 color.y() = color.y() * (float)attribValue.y() * (float)attribValue.w(); 1190 color.z() = color.z() * (float)attribValue.z() * (float)attribValue.w(); 1191 break; 1192 1193 default: 1194 DE_ASSERT(false); 1195 } 1196 } 1197 } 1198 1199 void DrawTestShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const 1200 { 1201 const float u_coordScale = getUniformByName("u_coordScale").value.f; 1202 const float u_colorScale = getUniformByName("u_colorScale").value.f; 1203 1204 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 1205 { 1206 const size_t varyingLocColor = 0; 1207 1208 rr::VertexPacket& packet = *packets[packetNdx]; 1209 1210 // Calc output color 1211 tcu::Vec2 coord = tcu::Vec2(0.0, 0.0); 1212 tcu::Vec3 color = tcu::Vec3(1.0, 1.0, 1.0); 1213 1214 for (int attribNdx = 0; attribNdx < (int)m_attrType.size(); attribNdx++) 1215 { 1216 const int numComponents = m_componentCount[attribNdx]; 1217 const bool isCoord = m_isCoord[attribNdx]; 1218 1219 switch (m_attrType[attribNdx]) 1220 { 1221 case rr::GENERICVECTYPE_FLOAT: calcShaderColorCoord(coord, color, rr::readVertexAttribFloat(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents); break; 1222 case rr::GENERICVECTYPE_INT32: calcShaderColorCoord(coord, color, rr::readVertexAttribInt (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents); break; 1223 case rr::GENERICVECTYPE_UINT32: calcShaderColorCoord(coord, color, rr::readVertexAttribUint (inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents); break; 1224 default: 1225 DE_ASSERT(false); 1226 } 1227 } 1228 1229 // Transform position 1230 { 1231 packet.position = tcu::Vec4(u_coordScale * coord.x(), u_coordScale * coord.y(), 1.0f, 1.0f); 1232 packet.pointSize = 1.0f; 1233 } 1234 1235 // Pass color to FS 1236 { 1237 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); 1238 } 1239 } 1240 } 1241 1242 void DrawTestShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const 1243 { 1244 const size_t varyingLocColor = 0; 1245 1246 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 1247 { 1248 rr::FragmentPacket& packet = packets[packetNdx]; 1249 1250 for (int fragNdx = 0; fragNdx < 4; ++fragNdx) 1251 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, varyingLocColor, fragNdx)); 1252 } 1253 } 1254 1255 std::string DrawTestShaderProgram::genVertexSource (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays) 1256 { 1257 std::map<std::string, std::string> params; 1258 std::stringstream vertexShaderTmpl; 1259 1260 generateShaderParams(params, ctx.getType()); 1261 1262 vertexShaderTmpl << "${VTX_HDR}"; 1263 1264 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++) 1265 { 1266 vertexShaderTmpl 1267 << "${VTX_IN} highp " << outputTypeToGLType(arrays[arrayNdx]->getOutputType()) << " a_" << arrayNdx << ";\n"; 1268 } 1269 1270 vertexShaderTmpl << 1271 "uniform highp float u_coordScale;\n" 1272 "uniform highp float u_colorScale;\n" 1273 "${VTX_OUT} ${COL_PRECISION} vec4 v_color;\n" 1274 "void main(void)\n" 1275 "{\n" 1276 "\tgl_PointSize = 1.0;\n" 1277 "\thighp vec2 coord = vec2(0.0, 0.0);\n" 1278 "\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n"; 1279 1280 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++) 1281 { 1282 const bool isPositionAttr = arrays[arrayNdx]->isPositionAttribute(); 1283 1284 if (isPositionAttr) 1285 { 1286 switch (arrays[arrayNdx]->getOutputType()) 1287 { 1288 case (DrawTestSpec::OUTPUTTYPE_FLOAT): 1289 case (DrawTestSpec::OUTPUTTYPE_INT): 1290 case (DrawTestSpec::OUTPUTTYPE_UINT): 1291 vertexShaderTmpl << 1292 "\tcoord += vec2(float(a_" << arrayNdx << "), float(a_" << arrayNdx << "));\n"; 1293 break; 1294 1295 case (DrawTestSpec::OUTPUTTYPE_VEC2): 1296 case (DrawTestSpec::OUTPUTTYPE_IVEC2): 1297 case (DrawTestSpec::OUTPUTTYPE_UVEC2): 1298 vertexShaderTmpl << 1299 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n"; 1300 break; 1301 1302 case (DrawTestSpec::OUTPUTTYPE_VEC3): 1303 case (DrawTestSpec::OUTPUTTYPE_IVEC3): 1304 case (DrawTestSpec::OUTPUTTYPE_UVEC3): 1305 vertexShaderTmpl << 1306 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n" 1307 "\tcoord.x += float(a_" << arrayNdx << ".z);\n"; 1308 break; 1309 1310 case (DrawTestSpec::OUTPUTTYPE_VEC4): 1311 case (DrawTestSpec::OUTPUTTYPE_IVEC4): 1312 case (DrawTestSpec::OUTPUTTYPE_UVEC4): 1313 vertexShaderTmpl << 1314 "\tcoord += vec2(a_" << arrayNdx << ".xy);\n" 1315 "\tcoord += vec2(a_" << arrayNdx << ".zw);\n"; 1316 break; 1317 1318 default: 1319 DE_ASSERT(false); 1320 break; 1321 } 1322 } 1323 else 1324 { 1325 switch (arrays[arrayNdx]->getOutputType()) 1326 { 1327 case (DrawTestSpec::OUTPUTTYPE_FLOAT): 1328 case (DrawTestSpec::OUTPUTTYPE_INT): 1329 case (DrawTestSpec::OUTPUTTYPE_UINT): 1330 vertexShaderTmpl << 1331 "\tcolor = color * float(a_" << arrayNdx << ");\n"; 1332 break; 1333 1334 case (DrawTestSpec::OUTPUTTYPE_VEC2): 1335 case (DrawTestSpec::OUTPUTTYPE_IVEC2): 1336 case (DrawTestSpec::OUTPUTTYPE_UVEC2): 1337 vertexShaderTmpl << 1338 "\tcolor.rg = color.rg * vec2(a_" << arrayNdx << ".xy);\n"; 1339 break; 1340 1341 case (DrawTestSpec::OUTPUTTYPE_VEC3): 1342 case (DrawTestSpec::OUTPUTTYPE_IVEC3): 1343 case (DrawTestSpec::OUTPUTTYPE_UVEC3): 1344 vertexShaderTmpl << 1345 "\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz);\n"; 1346 break; 1347 1348 case (DrawTestSpec::OUTPUTTYPE_VEC4): 1349 case (DrawTestSpec::OUTPUTTYPE_IVEC4): 1350 case (DrawTestSpec::OUTPUTTYPE_UVEC4): 1351 vertexShaderTmpl << 1352 "\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz) * float(a_" << arrayNdx << ".w);\n"; 1353 break; 1354 1355 default: 1356 DE_ASSERT(false); 1357 break; 1358 } 1359 } 1360 } 1361 1362 vertexShaderTmpl << 1363 "\tv_color = vec4(u_colorScale * color, 1.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);\n" 1364 "\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n" 1365 "}\n"; 1366 1367 return tcu::StringTemplate(vertexShaderTmpl.str().c_str()).specialize(params); 1368 } 1369 1370 std::string DrawTestShaderProgram::genFragmentSource (const glu::RenderContext& ctx) 1371 { 1372 std::map<std::string, std::string> params; 1373 1374 generateShaderParams(params, ctx.getType()); 1375 1376 static const char* fragmentShaderTmpl = 1377 "${FRAG_HDR}" 1378 "${FRAG_IN} ${COL_PRECISION} vec4 v_color;\n" 1379 "void main(void)\n" 1380 "{\n" 1381 "\t${FRAG_COLOR} = v_color;\n" 1382 "}\n"; 1383 1384 return tcu::StringTemplate(fragmentShaderTmpl).specialize(params); 1385 } 1386 1387 void DrawTestShaderProgram::generateShaderParams (std::map<std::string, std::string>& params, glu::ContextType type) 1388 { 1389 if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_300_ES)) 1390 { 1391 params["VTX_IN"] = "in"; 1392 params["VTX_OUT"] = "out"; 1393 params["FRAG_IN"] = "in"; 1394 params["FRAG_COLOR"] = "dEQP_FragColor"; 1395 params["VTX_HDR"] = "#version 300 es\n"; 1396 params["FRAG_HDR"] = "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 1397 params["COL_PRECISION"] = "mediump"; 1398 } 1399 else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_100_ES)) 1400 { 1401 params["VTX_IN"] = "attribute"; 1402 params["VTX_OUT"] = "varying"; 1403 params["FRAG_IN"] = "varying"; 1404 params["FRAG_COLOR"] = "gl_FragColor"; 1405 params["VTX_HDR"] = ""; 1406 params["FRAG_HDR"] = ""; 1407 params["COL_PRECISION"] = "mediump"; 1408 } 1409 else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_430)) 1410 { 1411 params["VTX_IN"] = "in"; 1412 params["VTX_OUT"] = "out"; 1413 params["FRAG_IN"] = "in"; 1414 params["FRAG_COLOR"] = "dEQP_FragColor"; 1415 params["VTX_HDR"] = "#version 430\n"; 1416 params["FRAG_HDR"] = "#version 430\nlayout(location = 0) out highp vec4 dEQP_FragColor;\n"; 1417 params["COL_PRECISION"] = "highp"; 1418 } 1419 else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_330)) 1420 { 1421 params["VTX_IN"] = "in"; 1422 params["VTX_OUT"] = "out"; 1423 params["FRAG_IN"] = "in"; 1424 params["FRAG_COLOR"] = "dEQP_FragColor"; 1425 params["VTX_HDR"] = "#version 330\n"; 1426 params["FRAG_HDR"] = "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 1427 params["COL_PRECISION"] = "mediump"; 1428 } 1429 else 1430 DE_ASSERT(DE_FALSE); 1431 } 1432 1433 rr::GenericVecType DrawTestShaderProgram::mapOutputType (const DrawTestSpec::OutputType& type) 1434 { 1435 switch (type) 1436 { 1437 case (DrawTestSpec::OUTPUTTYPE_FLOAT): 1438 case (DrawTestSpec::OUTPUTTYPE_VEC2): 1439 case (DrawTestSpec::OUTPUTTYPE_VEC3): 1440 case (DrawTestSpec::OUTPUTTYPE_VEC4): 1441 return rr::GENERICVECTYPE_FLOAT; 1442 1443 case (DrawTestSpec::OUTPUTTYPE_INT): 1444 case (DrawTestSpec::OUTPUTTYPE_IVEC2): 1445 case (DrawTestSpec::OUTPUTTYPE_IVEC3): 1446 case (DrawTestSpec::OUTPUTTYPE_IVEC4): 1447 return rr::GENERICVECTYPE_INT32; 1448 1449 case (DrawTestSpec::OUTPUTTYPE_UINT): 1450 case (DrawTestSpec::OUTPUTTYPE_UVEC2): 1451 case (DrawTestSpec::OUTPUTTYPE_UVEC3): 1452 case (DrawTestSpec::OUTPUTTYPE_UVEC4): 1453 return rr::GENERICVECTYPE_UINT32; 1454 1455 default: 1456 DE_ASSERT(false); 1457 return rr::GENERICVECTYPE_LAST; 1458 } 1459 } 1460 1461 int DrawTestShaderProgram::getComponentCount (const DrawTestSpec::OutputType& type) 1462 { 1463 switch (type) 1464 { 1465 case (DrawTestSpec::OUTPUTTYPE_FLOAT): 1466 case (DrawTestSpec::OUTPUTTYPE_INT): 1467 case (DrawTestSpec::OUTPUTTYPE_UINT): 1468 return 1; 1469 1470 case (DrawTestSpec::OUTPUTTYPE_VEC2): 1471 case (DrawTestSpec::OUTPUTTYPE_IVEC2): 1472 case (DrawTestSpec::OUTPUTTYPE_UVEC2): 1473 return 2; 1474 1475 case (DrawTestSpec::OUTPUTTYPE_VEC3): 1476 case (DrawTestSpec::OUTPUTTYPE_IVEC3): 1477 case (DrawTestSpec::OUTPUTTYPE_UVEC3): 1478 return 3; 1479 1480 case (DrawTestSpec::OUTPUTTYPE_VEC4): 1481 case (DrawTestSpec::OUTPUTTYPE_IVEC4): 1482 case (DrawTestSpec::OUTPUTTYPE_UVEC4): 1483 return 4; 1484 1485 default: 1486 DE_ASSERT(false); 1487 return 0; 1488 } 1489 } 1490 1491 sglr::pdec::ShaderProgramDeclaration DrawTestShaderProgram::createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays) 1492 { 1493 sglr::pdec::ShaderProgramDeclaration decl; 1494 1495 for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++) 1496 decl << sglr::pdec::VertexAttribute(std::string("a_") + de::toString(arrayNdx), mapOutputType(arrays[arrayNdx]->getOutputType())); 1497 1498 decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT); 1499 decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT); 1500 1501 decl << sglr::pdec::VertexSource(genVertexSource(ctx, arrays)); 1502 decl << sglr::pdec::FragmentSource(genFragmentSource(ctx)); 1503 1504 decl << sglr::pdec::Uniform("u_coordScale", glu::TYPE_FLOAT); 1505 decl << sglr::pdec::Uniform("u_colorScale", glu::TYPE_FLOAT); 1506 1507 return decl; 1508 } 1509 1510 class RandomArrayGenerator 1511 { 1512 public: 1513 static char* generateArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type); 1514 static char* generateIndices (int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase); 1515 static rr::GenericVec4 generateAttributeValue (int seed, DrawTestSpec::InputType type); 1516 1517 private: 1518 template<typename T> 1519 static char* createIndices (int seed, int elementCount, int offset, int min, int max, int indexBase); 1520 1521 static char* generateBasicArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type); 1522 template<typename T, typename GLType> 1523 static char* createBasicArray (int seed, int elementCount, int componentCount, int offset, int stride); 1524 static char* generatePackedArray (int seed, int elementCount, int componentCount, int offset, int stride); 1525 }; 1526 1527 char* RandomArrayGenerator::generateArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type) 1528 { 1529 if (type == DrawTestSpec::INPUTTYPE_INT_2_10_10_10 || type == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10) 1530 return generatePackedArray(seed, elementCount, componentCount, offset, stride); 1531 else 1532 return generateBasicArray(seed, elementCount, componentCount, offset, stride, type); 1533 } 1534 1535 char* RandomArrayGenerator::generateBasicArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type) 1536 { 1537 switch (type) 1538 { 1539 case DrawTestSpec::INPUTTYPE_FLOAT: return createBasicArray<float, GLValue::Float> (seed, elementCount, componentCount, offset, stride); 1540 case DrawTestSpec::INPUTTYPE_DOUBLE: return createBasicArray<double, GLValue::Double>(seed, elementCount, componentCount, offset, stride); 1541 case DrawTestSpec::INPUTTYPE_SHORT: return createBasicArray<deInt16, GLValue::Short> (seed, elementCount, componentCount, offset, stride); 1542 case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT: return createBasicArray<deUint16, GLValue::Ushort>(seed, elementCount, componentCount, offset, stride); 1543 case DrawTestSpec::INPUTTYPE_BYTE: return createBasicArray<deInt8, GLValue::Byte> (seed, elementCount, componentCount, offset, stride); 1544 case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE: return createBasicArray<deUint8, GLValue::Ubyte> (seed, elementCount, componentCount, offset, stride); 1545 case DrawTestSpec::INPUTTYPE_FIXED: return createBasicArray<deInt32, GLValue::Fixed> (seed, elementCount, componentCount, offset, stride); 1546 case DrawTestSpec::INPUTTYPE_INT: return createBasicArray<deInt32, GLValue::Int> (seed, elementCount, componentCount, offset, stride); 1547 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT: return createBasicArray<deUint32, GLValue::Uint> (seed, elementCount, componentCount, offset, stride); 1548 case DrawTestSpec::INPUTTYPE_HALF: return createBasicArray<deFloat16, GLValue::Half> (seed, elementCount, componentCount, offset, stride); 1549 default: 1550 DE_ASSERT(false); 1551 break; 1552 } 1553 return DE_NULL; 1554 } 1555 1556 #if (DE_COMPILER == DE_COMPILER_GCC) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) 1557 // GCC 4.8/4.9 incorrectly emits array-bounds warning from createBasicArray() 1558 # define GCC_ARRAY_BOUNDS_FALSE_NEGATIVE 1 1559 #endif 1560 1561 #if defined(GCC_ARRAY_BOUNDS_FALSE_NEGATIVE) 1562 # pragma GCC diagnostic push 1563 # pragma GCC diagnostic ignored "-Warray-bounds" 1564 #endif 1565 1566 template<typename T, typename GLType> 1567 char* RandomArrayGenerator::createBasicArray (int seed, int elementCount, int componentCount, int offset, int stride) 1568 { 1569 DE_ASSERT(componentCount >= 1 && componentCount <= 4); 1570 1571 const GLType min = extractGLValue<GLType>(GLValue::getMinValue(GLValueTypeTraits<GLType>::Type)); 1572 const GLType max = extractGLValue<GLType>(GLValue::getMaxValue(GLValueTypeTraits<GLType>::Type)); 1573 1574 const size_t componentSize = sizeof(T); 1575 const size_t elementSize = componentSize * componentCount; 1576 const size_t bufferSize = offset + (elementCount - 1) * stride + elementSize; 1577 1578 char* data = new char[bufferSize]; 1579 char* writePtr = data + offset; 1580 1581 GLType previousComponents[4]; 1582 1583 deRandom rnd; 1584 deRandom_init(&rnd, seed); 1585 1586 for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++) 1587 { 1588 GLType components[4]; 1589 1590 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++) 1591 { 1592 components[componentNdx] = getRandom<GLType>(rnd, min, max); 1593 1594 // Try to not create vertex near previous 1595 if (vertexNdx != 0 && abs(components[componentNdx] - previousComponents[componentNdx]) < minValue<GLType>()) 1596 { 1597 // Too close, try again (but only once) 1598 components[componentNdx] = getRandom<GLType>(rnd, min, max); 1599 } 1600 } 1601 1602 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++) 1603 previousComponents[componentNdx] = components[componentNdx]; 1604 1605 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++) 1606 alignmentSafeAssignment(writePtr + componentNdx*componentSize, components[componentNdx].getValue()); 1607 1608 writePtr += stride; 1609 } 1610 1611 return data; 1612 } 1613 1614 #if defined(GCC_ARRAY_BOUNDS_FALSE_NEGATIVE) 1615 # pragma GCC diagnostic pop 1616 #endif 1617 1618 char* RandomArrayGenerator::generatePackedArray (int seed, int elementCount, int componentCount, int offset, int stride) 1619 { 1620 DE_ASSERT(componentCount == 4); 1621 DE_UNREF(componentCount); 1622 1623 const deUint32 limit10 = (1 << 10); 1624 const deUint32 limit2 = (1 << 2); 1625 const size_t elementSize = 4; 1626 const size_t bufferSize = offset + (elementCount - 1) * stride + elementSize; 1627 1628 char* data = new char[bufferSize]; 1629 char* writePtr = data + offset; 1630 1631 deRandom rnd; 1632 deRandom_init(&rnd, seed); 1633 1634 for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++) 1635 { 1636 const deUint32 x = deRandom_getUint32(&rnd) % limit10; 1637 const deUint32 y = deRandom_getUint32(&rnd) % limit10; 1638 const deUint32 z = deRandom_getUint32(&rnd) % limit10; 1639 const deUint32 w = deRandom_getUint32(&rnd) % limit2; 1640 const deUint32 packedValue = (w << 30) | (z << 20) | (y << 10) | (x); 1641 1642 alignmentSafeAssignment(writePtr, packedValue); 1643 writePtr += stride; 1644 } 1645 1646 return data; 1647 } 1648 1649 char* RandomArrayGenerator::generateIndices (int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase) 1650 { 1651 char* data = DE_NULL; 1652 1653 switch (type) 1654 { 1655 case DrawTestSpec::INDEXTYPE_BYTE: 1656 data = createIndices<deUint8>(seed, elementCount, offset, min, max, indexBase); 1657 break; 1658 1659 case DrawTestSpec::INDEXTYPE_SHORT: 1660 data = createIndices<deUint16>(seed, elementCount, offset, min, max, indexBase); 1661 break; 1662 1663 case DrawTestSpec::INDEXTYPE_INT: 1664 data = createIndices<deUint32>(seed, elementCount, offset, min, max, indexBase); 1665 break; 1666 1667 default: 1668 DE_ASSERT(false); 1669 break; 1670 } 1671 1672 return data; 1673 } 1674 1675 template<typename T> 1676 char* RandomArrayGenerator::createIndices (int seed, int elementCount, int offset, int min, int max, int indexBase) 1677 { 1678 const size_t elementSize = sizeof(T); 1679 const size_t bufferSize = offset + elementCount * elementSize; 1680 1681 char* data = new char[bufferSize]; 1682 char* writePtr = data + offset; 1683 1684 deUint32 oldNdx1 = deUint32(-1); 1685 deUint32 oldNdx2 = deUint32(-1); 1686 1687 deRandom rnd; 1688 deRandom_init(&rnd, seed); 1689 1690 DE_ASSERT(indexBase >= 0); // watch for underflows 1691 1692 if (min < 0 || (size_t)min > std::numeric_limits<T>::max() || 1693 max < 0 || (size_t)max > std::numeric_limits<T>::max() || 1694 min > max) 1695 DE_FATAL("Invalid range"); 1696 1697 for (int elementNdx = 0; elementNdx < elementCount; ++elementNdx) 1698 { 1699 deUint32 ndx = getRandom(rnd, GLValue::Uint::create(min), GLValue::Uint::create(max)).getValue(); 1700 1701 // Try not to generate same index as any of previous two. This prevents 1702 // generation of degenerate triangles and lines. If [min, max] is too 1703 // small this cannot be guaranteed. 1704 1705 if (ndx == oldNdx1) ++ndx; 1706 if (ndx > (deUint32)max) ndx = min; 1707 if (ndx == oldNdx2) ++ndx; 1708 if (ndx > (deUint32)max) ndx = min; 1709 if (ndx == oldNdx1) ++ndx; 1710 if (ndx > (deUint32)max) ndx = min; 1711 1712 oldNdx2 = oldNdx1; 1713 oldNdx1 = ndx; 1714 1715 ndx += indexBase; 1716 1717 alignmentSafeAssignment<T>(writePtr + elementSize * elementNdx, T(ndx)); 1718 } 1719 1720 return data; 1721 } 1722 1723 rr::GenericVec4 RandomArrayGenerator::generateAttributeValue (int seed, DrawTestSpec::InputType type) 1724 { 1725 de::Random random(seed); 1726 1727 switch (type) 1728 { 1729 case DrawTestSpec::INPUTTYPE_FLOAT: 1730 return rr::GenericVec4(generateRandomVec4(random)); 1731 1732 case DrawTestSpec::INPUTTYPE_INT: 1733 return rr::GenericVec4(generateRandomIVec4(random)); 1734 1735 case DrawTestSpec::INPUTTYPE_UNSIGNED_INT: 1736 return rr::GenericVec4(generateRandomUVec4(random)); 1737 1738 default: 1739 DE_ASSERT(false); 1740 return rr::GenericVec4(tcu::Vec4(1, 1, 1, 1)); 1741 } 1742 } 1743 1744 } // anonymous 1745 1746 // AttributePack 1747 1748 class AttributePack 1749 { 1750 public: 1751 1752 AttributePack (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled); 1753 ~AttributePack (void); 1754 1755 AttributeArray* getArray (int i); 1756 int getArrayCount (void); 1757 1758 void newArray (DrawTestSpec::Storage storage); 1759 void clearArrays (void); 1760 void updateProgram (void); 1761 1762 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); 1763 1764 const tcu::Surface& getSurface (void) const { return m_screen; } 1765 private: 1766 tcu::TestContext& m_testCtx; 1767 glu::RenderContext& m_renderCtx; 1768 sglr::Context& m_ctx; 1769 1770 std::vector<AttributeArray*>m_arrays; 1771 sglr::ShaderProgram* m_program; 1772 tcu::Surface m_screen; 1773 const bool m_useVao; 1774 const bool m_logEnabled; 1775 deUint32 m_programID; 1776 deUint32 m_vaoID; 1777 }; 1778 1779 AttributePack::AttributePack (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled) 1780 : m_testCtx (testCtx) 1781 , m_renderCtx (renderCtx) 1782 , m_ctx (drawContext) 1783 , m_program (DE_NULL) 1784 , m_screen (screenSize.x(), screenSize.y()) 1785 , m_useVao (useVao) 1786 , m_logEnabled (logEnabled) 1787 , m_programID (0) 1788 , m_vaoID (0) 1789 { 1790 if (m_useVao) 1791 m_ctx.genVertexArrays(1, &m_vaoID); 1792 } 1793 1794 AttributePack::~AttributePack (void) 1795 { 1796 clearArrays(); 1797 1798 if (m_programID) 1799 m_ctx.deleteProgram(m_programID); 1800 1801 if (m_program) 1802 delete m_program; 1803 1804 if (m_useVao) 1805 m_ctx.deleteVertexArrays(1, &m_vaoID); 1806 } 1807 1808 AttributeArray* AttributePack::getArray (int i) 1809 { 1810 return m_arrays.at(i); 1811 } 1812 1813 int AttributePack::getArrayCount (void) 1814 { 1815 return (int)m_arrays.size(); 1816 } 1817 1818 void AttributePack::newArray (DrawTestSpec::Storage storage) 1819 { 1820 m_arrays.push_back(new AttributeArray(storage, m_ctx)); 1821 } 1822 1823 void AttributePack::clearArrays (void) 1824 { 1825 for (std::vector<AttributeArray*>::iterator itr = m_arrays.begin(); itr != m_arrays.end(); itr++) 1826 delete *itr; 1827 m_arrays.clear(); 1828 } 1829 1830 void AttributePack::updateProgram (void) 1831 { 1832 if (m_programID) 1833 m_ctx.deleteProgram(m_programID); 1834 if (m_program) 1835 delete m_program; 1836 1837 m_program = new DrawTestShaderProgram(m_renderCtx, m_arrays); 1838 m_programID = m_ctx.createProgram(m_program); 1839 } 1840 1841 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) 1842 { 1843 DE_ASSERT(m_program != DE_NULL); 1844 DE_ASSERT(m_programID != 0); 1845 1846 m_ctx.viewport(0, 0, m_screen.getWidth(), m_screen.getHeight()); 1847 m_ctx.clearColor(0.0, 0.0, 0.0, 1.0); 1848 m_ctx.clear(GL_COLOR_BUFFER_BIT); 1849 1850 m_ctx.useProgram(m_programID); 1851 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glUseProgram()"); 1852 1853 m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_coordScale"), coordScale); 1854 m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_colorScale"), colorScale); 1855 1856 if (m_useVao) 1857 m_ctx.bindVertexArray(m_vaoID); 1858 1859 if (indexArray) 1860 indexArray->bindIndexArray(DrawTestSpec::TARGET_ELEMENT_ARRAY); 1861 1862 for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++) 1863 { 1864 std::stringstream attribName; 1865 attribName << "a_" << arrayNdx; 1866 1867 deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str()); 1868 1869 if (m_arrays[arrayNdx]->isBound()) 1870 { 1871 m_ctx.enableVertexAttribArray(loc); 1872 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glEnableVertexAttribArray()"); 1873 } 1874 1875 m_arrays[arrayNdx]->bindAttribute(loc); 1876 } 1877 1878 if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS) 1879 { 1880 m_ctx.drawArrays(primitiveToGL(primitive), firstVertex, vertexCount); 1881 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArrays()"); 1882 } 1883 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED) 1884 { 1885 m_ctx.drawArraysInstanced(primitiveToGL(primitive), firstVertex, vertexCount, instanceCount); 1886 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysInstanced()"); 1887 } 1888 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS) 1889 { 1890 m_ctx.drawElements(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset); 1891 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElements()"); 1892 } 1893 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED) 1894 { 1895 m_ctx.drawRangeElements(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset); 1896 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElements()"); 1897 } 1898 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED) 1899 { 1900 m_ctx.drawElementsInstanced(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount); 1901 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstanced()"); 1902 } 1903 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT) 1904 { 1905 struct DrawCommand 1906 { 1907 GLuint count; 1908 GLuint primCount; 1909 GLuint first; 1910 GLuint reservedMustBeZero; 1911 }; 1912 deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset]; 1913 1914 { 1915 DrawCommand command; 1916 1917 command.count = vertexCount; 1918 command.primCount = instanceCount; 1919 command.first = firstVertex; 1920 command.reservedMustBeZero = 0; 1921 1922 memcpy(buffer + indirectOffset, &command, sizeof(command)); 1923 1924 if (m_logEnabled) 1925 m_testCtx.getLog() 1926 << tcu::TestLog::Message 1927 << "DrawArraysIndirectCommand:\n" 1928 << "\tcount: " << command.count << "\n" 1929 << "\tprimCount: " << command.primCount << "\n" 1930 << "\tfirst: " << command.first << "\n" 1931 << "\treservedMustBeZero: " << command.reservedMustBeZero << "\n" 1932 << tcu::TestLog::EndMessage; 1933 } 1934 1935 GLuint indirectBuf = 0; 1936 m_ctx.genBuffers(1, &indirectBuf); 1937 m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf); 1938 m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW); 1939 delete [] buffer; 1940 1941 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer"); 1942 1943 m_ctx.drawArraysIndirect(primitiveToGL(primitive), (const deInt8*)DE_NULL + indirectOffset); 1944 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()"); 1945 1946 m_ctx.deleteBuffers(1, &indirectBuf); 1947 } 1948 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT) 1949 { 1950 struct DrawCommand 1951 { 1952 GLuint count; 1953 GLuint primCount; 1954 GLuint firstIndex; 1955 GLint baseVertex; 1956 GLuint reservedMustBeZero; 1957 }; 1958 deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset]; 1959 1960 { 1961 DrawCommand command; 1962 1963 // index offset must be converted to firstIndex by dividing with the index element size 1964 DE_ASSERT(((const deUint8*)indexOffset - (const deUint8*)DE_NULL) % gls::DrawTestSpec::indexTypeSize(indexType) == 0); // \note This is checked in spec validation 1965 1966 command.count = vertexCount; 1967 command.primCount = instanceCount; 1968 command.firstIndex = (glw::GLuint)(((const deUint8*)indexOffset - (const deUint8*)DE_NULL) / gls::DrawTestSpec::indexTypeSize(indexType)); 1969 command.baseVertex = baseVertex; 1970 command.reservedMustBeZero = 0; 1971 1972 memcpy(buffer + indirectOffset, &command, sizeof(command)); 1973 1974 if (m_logEnabled) 1975 m_testCtx.getLog() 1976 << tcu::TestLog::Message 1977 << "DrawElementsIndirectCommand:\n" 1978 << "\tcount: " << command.count << "\n" 1979 << "\tprimCount: " << command.primCount << "\n" 1980 << "\tfirstIndex: " << command.firstIndex << "\n" 1981 << "\tbaseVertex: " << command.baseVertex << "\n" 1982 << "\treservedMustBeZero: " << command.reservedMustBeZero << "\n" 1983 << tcu::TestLog::EndMessage; 1984 } 1985 1986 GLuint indirectBuf = 0; 1987 m_ctx.genBuffers(1, &indirectBuf); 1988 m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf); 1989 m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW); 1990 delete [] buffer; 1991 1992 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer"); 1993 1994 m_ctx.drawElementsIndirect(primitiveToGL(primitive), indexTypeToGL(indexType), (const deInt8*)DE_NULL + indirectOffset); 1995 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()"); 1996 1997 m_ctx.deleteBuffers(1, &indirectBuf); 1998 } 1999 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX) 2000 { 2001 m_ctx.drawElementsBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex); 2002 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsBaseVertex()"); 2003 } 2004 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX) 2005 { 2006 m_ctx.drawElementsInstancedBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount, baseVertex); 2007 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstancedBaseVertex()"); 2008 } 2009 else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX) 2010 { 2011 m_ctx.drawRangeElementsBaseVertex(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex); 2012 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElementsBaseVertex()"); 2013 } 2014 else 2015 DE_ASSERT(DE_FALSE); 2016 2017 for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++) 2018 { 2019 if (m_arrays[arrayNdx]->isBound()) 2020 { 2021 std::stringstream attribName; 2022 attribName << "a_" << arrayNdx; 2023 2024 deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str()); 2025 2026 m_ctx.disableVertexAttribArray(loc); 2027 GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDisableVertexAttribArray()"); 2028 } 2029 } 2030 2031 if (m_useVao) 2032 m_ctx.bindVertexArray(0); 2033 2034 m_ctx.useProgram(0); 2035 m_ctx.readPixels(m_screen, 0, 0, m_screen.getWidth(), m_screen.getHeight()); 2036 } 2037 2038 // DrawTestSpec 2039 2040 DrawTestSpec::AttributeSpec DrawTestSpec::AttributeSpec::createAttributeArray (InputType inputType, OutputType outputType, Storage storage, Usage usage, int componentCount, int offset, int stride, bool normalize, int instanceDivisor) 2041 { 2042 DrawTestSpec::AttributeSpec spec; 2043 2044 spec.inputType = inputType; 2045 spec.outputType = outputType; 2046 spec.storage = storage; 2047 spec.usage = usage; 2048 spec.componentCount = componentCount; 2049 spec.offset = offset; 2050 spec.stride = stride; 2051 spec.normalize = normalize; 2052 spec.instanceDivisor = instanceDivisor; 2053 2054 spec.useDefaultAttribute= false; 2055 2056 return spec; 2057 } 2058 2059 DrawTestSpec::AttributeSpec DrawTestSpec::AttributeSpec::createDefaultAttribute (InputType inputType, OutputType outputType, int componentCount) 2060 { 2061 DE_ASSERT(inputType == INPUTTYPE_INT || inputType == INPUTTYPE_UNSIGNED_INT || inputType == INPUTTYPE_FLOAT); 2062 DE_ASSERT(inputType == INPUTTYPE_FLOAT || componentCount == 4); 2063 2064 DrawTestSpec::AttributeSpec spec; 2065 2066 spec.inputType = inputType; 2067 spec.outputType = outputType; 2068 spec.storage = DrawTestSpec::STORAGE_LAST; 2069 spec.usage = DrawTestSpec::USAGE_LAST; 2070 spec.componentCount = componentCount; 2071 spec.offset = 0; 2072 spec.stride = 0; 2073 spec.normalize = 0; 2074 spec.instanceDivisor = 0; 2075 2076 spec.useDefaultAttribute = true; 2077 2078 return spec; 2079 } 2080 2081 DrawTestSpec::AttributeSpec::AttributeSpec (void) 2082 { 2083 inputType = DrawTestSpec::INPUTTYPE_LAST; 2084 outputType = DrawTestSpec::OUTPUTTYPE_LAST; 2085 storage = DrawTestSpec::STORAGE_LAST; 2086 usage = DrawTestSpec::USAGE_LAST; 2087 componentCount = 0; 2088 offset = 0; 2089 stride = 0; 2090 normalize = false; 2091 instanceDivisor = 0; 2092 useDefaultAttribute = false; 2093 additionalPositionAttribute = false; 2094 bgraComponentOrder = false; 2095 } 2096 2097 int DrawTestSpec::AttributeSpec::hash (void) const 2098 { 2099 if (useDefaultAttribute) 2100 { 2101 return 1 * int(inputType) + 7 * int(outputType) + 13 * componentCount; 2102 } 2103 else 2104 { 2105 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; 2106 } 2107 } 2108 2109 bool DrawTestSpec::AttributeSpec::valid (glu::ApiType ctxType) const 2110 { 2111 const bool inputTypeFloat = inputType == DrawTestSpec::INPUTTYPE_FLOAT || inputType == DrawTestSpec::INPUTTYPE_FIXED || inputType == DrawTestSpec::INPUTTYPE_HALF; 2112 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; 2113 const bool inputTypeSignedInteger = inputType == DrawTestSpec::INPUTTYPE_BYTE || inputType == DrawTestSpec::INPUTTYPE_SHORT || inputType == DrawTestSpec::INPUTTYPE_INT || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10; 2114 const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10; 2115 2116 const bool outputTypeFloat = outputType == DrawTestSpec::OUTPUTTYPE_FLOAT || outputType == DrawTestSpec::OUTPUTTYPE_VEC2 || outputType == DrawTestSpec::OUTPUTTYPE_VEC3 || outputType == DrawTestSpec::OUTPUTTYPE_VEC4; 2117 const bool outputTypeSignedInteger = outputType == DrawTestSpec::OUTPUTTYPE_INT || outputType == DrawTestSpec::OUTPUTTYPE_IVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC4; 2118 const bool outputTypeUnsignedInteger = outputType == DrawTestSpec::OUTPUTTYPE_UINT || outputType == DrawTestSpec::OUTPUTTYPE_UVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC4; 2119 2120 if (useDefaultAttribute) 2121 { 2122 if (inputType != DrawTestSpec::INPUTTYPE_INT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT && inputType != DrawTestSpec::INPUTTYPE_FLOAT) 2123 return false; 2124 2125 if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && componentCount != 4) 2126 return false; 2127 2128 // no casting allowed (undefined results) 2129 if (inputType == DrawTestSpec::INPUTTYPE_INT && !outputTypeSignedInteger) 2130 return false; 2131 if (inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT && !outputTypeUnsignedInteger) 2132 return false; 2133 } 2134 2135 if (inputTypePacked && componentCount != 4) 2136 return false; 2137 2138 // Invalid conversions: 2139 2140 // float -> [u]int 2141 if (inputTypeFloat && !outputTypeFloat) 2142 return false; 2143 2144 // uint -> int (undefined results) 2145 if (inputTypeUnsignedInteger && outputTypeSignedInteger) 2146 return false; 2147 2148 // int -> uint (undefined results) 2149 if (inputTypeSignedInteger && outputTypeUnsignedInteger) 2150 return false; 2151 2152 // packed -> non-float (packed formats are converted to floats) 2153 if (inputTypePacked && !outputTypeFloat) 2154 return false; 2155 2156 // Invalid normalize. Normalize is only valid if output type is float 2157 if (normalize && !outputTypeFloat) 2158 return false; 2159 2160 // Allow reverse order (GL_BGRA) only for packed and 4-component ubyte 2161 if (bgraComponentOrder && componentCount != 4) 2162 return false; 2163 if (bgraComponentOrder && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE) 2164 return false; 2165 if (bgraComponentOrder && normalize != true) 2166 return false; 2167 2168 // GLES2 limits 2169 if (ctxType == glu::ApiType::es(2,0)) 2170 { 2171 if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && inputType != DrawTestSpec::INPUTTYPE_FIXED && 2172 inputType != DrawTestSpec::INPUTTYPE_BYTE && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE && 2173 inputType != DrawTestSpec::INPUTTYPE_SHORT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT) 2174 return false; 2175 2176 if (!outputTypeFloat) 2177 return false; 2178 2179 if (bgraComponentOrder) 2180 return false; 2181 } 2182 2183 // GLES3 limits 2184 if (ctxType.getProfile() == glu::PROFILE_ES && ctxType.getMajorVersion() == 3) 2185 { 2186 if (bgraComponentOrder) 2187 return false; 2188 } 2189 2190 // No user pointers in GL core 2191 if (ctxType.getProfile() == glu::PROFILE_CORE) 2192 { 2193 if (!useDefaultAttribute && storage == DrawTestSpec::STORAGE_USER) 2194 return false; 2195 } 2196 2197 return true; 2198 } 2199 2200 bool DrawTestSpec::AttributeSpec::isBufferAligned (void) const 2201 { 2202 const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10; 2203 2204 // Buffer alignment, offset is a multiple of underlying data type size? 2205 if (storage == STORAGE_BUFFER) 2206 { 2207 int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType); 2208 if (inputTypePacked) 2209 dataTypeSize = 4; 2210 2211 if (offset % dataTypeSize != 0) 2212 return false; 2213 } 2214 2215 return true; 2216 } 2217 2218 bool DrawTestSpec::AttributeSpec::isBufferStrideAligned (void) const 2219 { 2220 const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10; 2221 2222 // Buffer alignment, offset is a multiple of underlying data type size? 2223 if (storage == STORAGE_BUFFER) 2224 { 2225 int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType); 2226 if (inputTypePacked) 2227 dataTypeSize = 4; 2228 2229 if (stride % dataTypeSize != 0) 2230 return false; 2231 } 2232 2233 return true; 2234 } 2235 2236 std::string DrawTestSpec::targetToString(Target target) 2237 { 2238 static const char* targets[] = 2239 { 2240 "element_array", // TARGET_ELEMENT_ARRAY = 0, 2241 "array" // TARGET_ARRAY, 2242 }; 2243 2244 return de::getSizedArrayElement<DrawTestSpec::TARGET_LAST>(targets, (int)target); 2245 } 2246 2247 std::string DrawTestSpec::inputTypeToString(InputType type) 2248 { 2249 static const char* types[] = 2250 { 2251 "float", // INPUTTYPE_FLOAT = 0, 2252 "fixed", // INPUTTYPE_FIXED, 2253 "double", // INPUTTYPE_DOUBLE 2254 2255 "byte", // INPUTTYPE_BYTE, 2256 "short", // INPUTTYPE_SHORT, 2257 2258 "unsigned_byte", // INPUTTYPE_UNSIGNED_BYTE, 2259 "unsigned_short", // INPUTTYPE_UNSIGNED_SHORT, 2260 2261 "int", // INPUTTYPE_INT, 2262 "unsigned_int", // INPUTTYPE_UNSIGNED_INT, 2263 "half", // INPUTTYPE_HALF, 2264 "unsigned_int2_10_10_10", // INPUTTYPE_UNSIGNED_INT_2_10_10_10, 2265 "int2_10_10_10" // INPUTTYPE_INT_2_10_10_10, 2266 }; 2267 2268 return de::getSizedArrayElement<DrawTestSpec::INPUTTYPE_LAST>(types, (int)type); 2269 } 2270 2271 std::string DrawTestSpec::outputTypeToString(OutputType type) 2272 { 2273 static const char* types[] = 2274 { 2275 "float", // OUTPUTTYPE_FLOAT = 0, 2276 "vec2", // OUTPUTTYPE_VEC2, 2277 "vec3", // OUTPUTTYPE_VEC3, 2278 "vec4", // OUTPUTTYPE_VEC4, 2279 2280 "int", // OUTPUTTYPE_INT, 2281 "uint", // OUTPUTTYPE_UINT, 2282 2283 "ivec2", // OUTPUTTYPE_IVEC2, 2284 "ivec3", // OUTPUTTYPE_IVEC3, 2285 "ivec4", // OUTPUTTYPE_IVEC4, 2286 2287 "uvec2", // OUTPUTTYPE_UVEC2, 2288 "uvec3", // OUTPUTTYPE_UVEC3, 2289 "uvec4", // OUTPUTTYPE_UVEC4, 2290 }; 2291 2292 return de::getSizedArrayElement<DrawTestSpec::OUTPUTTYPE_LAST>(types, (int)type); 2293 } 2294 2295 std::string DrawTestSpec::usageTypeToString(Usage usage) 2296 { 2297 static const char* usages[] = 2298 { 2299 "dynamic_draw", // USAGE_DYNAMIC_DRAW = 0, 2300 "static_draw", // USAGE_STATIC_DRAW, 2301 "stream_draw", // USAGE_STREAM_DRAW, 2302 2303 "stream_read", // USAGE_STREAM_READ, 2304 "stream_copy", // USAGE_STREAM_COPY, 2305 2306 "static_read", // USAGE_STATIC_READ, 2307 "static_copy", // USAGE_STATIC_COPY, 2308 2309 "dynamic_read", // USAGE_DYNAMIC_READ, 2310 "dynamic_copy", // USAGE_DYNAMIC_COPY, 2311 }; 2312 2313 return de::getSizedArrayElement<DrawTestSpec::USAGE_LAST>(usages, (int)usage); 2314 } 2315 2316 std::string DrawTestSpec::storageToString (Storage storage) 2317 { 2318 static const char* storages[] = 2319 { 2320 "user_ptr", // STORAGE_USER = 0, 2321 "buffer" // STORAGE_BUFFER, 2322 }; 2323 2324 return de::getSizedArrayElement<DrawTestSpec::STORAGE_LAST>(storages, (int)storage); 2325 } 2326 2327 std::string DrawTestSpec::primitiveToString (Primitive primitive) 2328 { 2329 static const char* primitives[] = 2330 { 2331 "points", // PRIMITIVE_POINTS , 2332 "triangles", // PRIMITIVE_TRIANGLES, 2333 "triangle_fan", // PRIMITIVE_TRIANGLE_FAN, 2334 "triangle_strip", // PRIMITIVE_TRIANGLE_STRIP, 2335 "lines", // PRIMITIVE_LINES 2336 "line_strip", // PRIMITIVE_LINE_STRIP 2337 "line_loop", // PRIMITIVE_LINE_LOOP 2338 "lines_adjacency", // PRIMITIVE_LINES_ADJACENCY 2339 "line_strip_adjacency", // PRIMITIVE_LINE_STRIP_ADJACENCY 2340 "triangles_adjacency", // PRIMITIVE_TRIANGLES_ADJACENCY 2341 "triangle_strip_adjacency", // PRIMITIVE_TRIANGLE_STRIP_ADJACENCY 2342 }; 2343 2344 return de::getSizedArrayElement<DrawTestSpec::PRIMITIVE_LAST>(primitives, (int)primitive); 2345 } 2346 2347 std::string DrawTestSpec::indexTypeToString (IndexType type) 2348 { 2349 static const char* indexTypes[] = 2350 { 2351 "byte", // INDEXTYPE_BYTE = 0, 2352 "short", // INDEXTYPE_SHORT, 2353 "int", // INDEXTYPE_INT, 2354 }; 2355 2356 return de::getSizedArrayElement<DrawTestSpec::INDEXTYPE_LAST>(indexTypes, (int)type); 2357 } 2358 2359 std::string DrawTestSpec::drawMethodToString (DrawTestSpec::DrawMethod method) 2360 { 2361 static const char* methods[] = 2362 { 2363 "draw_arrays", //!< DRAWMETHOD_DRAWARRAYS 2364 "draw_arrays_instanced", //!< DRAWMETHOD_DRAWARRAYS_INSTANCED 2365 "draw_arrays_indirect", //!< DRAWMETHOD_DRAWARRAYS_INDIRECT 2366 "draw_elements", //!< DRAWMETHOD_DRAWELEMENTS 2367 "draw_range_elements", //!< DRAWMETHOD_DRAWELEMENTS_RANGED 2368 "draw_elements_instanced", //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED 2369 "draw_elements_indirect", //!< DRAWMETHOD_DRAWELEMENTS_INDIRECT 2370 "draw_elements_base_vertex", //!< DRAWMETHOD_DRAWELEMENTS_BASEVERTEX, 2371 "draw_elements_instanced_base_vertex", //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX, 2372 "draw_range_elements_base_vertex", //!< DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX, 2373 }; 2374 2375 return de::getSizedArrayElement<DrawTestSpec::DRAWMETHOD_LAST>(methods, (int)method); 2376 } 2377 2378 int DrawTestSpec::inputTypeSize (InputType type) 2379 { 2380 static const int size[] = 2381 { 2382 (int)sizeof(float), // INPUTTYPE_FLOAT = 0, 2383 (int)sizeof(deInt32), // INPUTTYPE_FIXED, 2384 (int)sizeof(double), // INPUTTYPE_DOUBLE 2385 2386 (int)sizeof(deInt8), // INPUTTYPE_BYTE, 2387 (int)sizeof(deInt16), // INPUTTYPE_SHORT, 2388 2389 (int)sizeof(deUint8), // INPUTTYPE_UNSIGNED_BYTE, 2390 (int)sizeof(deUint16), // INPUTTYPE_UNSIGNED_SHORT, 2391 2392 (int)sizeof(deInt32), // INPUTTYPE_INT, 2393 (int)sizeof(deUint32), // INPUTTYPE_UNSIGNED_INT, 2394 (int)sizeof(deFloat16), // INPUTTYPE_HALF, 2395 (int)sizeof(deUint32) / 4, // INPUTTYPE_UNSIGNED_INT_2_10_10_10, 2396 (int)sizeof(deUint32) / 4 // INPUTTYPE_INT_2_10_10_10, 2397 }; 2398 2399 return de::getSizedArrayElement<DrawTestSpec::INPUTTYPE_LAST>(size, (int)type); 2400 } 2401 2402 int DrawTestSpec::indexTypeSize (IndexType type) 2403 { 2404 static const int size[] = 2405 { 2406 sizeof(deUint8), // INDEXTYPE_BYTE, 2407 sizeof(deUint16), // INDEXTYPE_SHORT, 2408 sizeof(deUint32), // INDEXTYPE_INT, 2409 }; 2410 2411 return de::getSizedArrayElement<DrawTestSpec::INDEXTYPE_LAST>(size, (int)type); 2412 } 2413 2414 std::string DrawTestSpec::getName (void) const 2415 { 2416 const MethodInfo methodInfo = getMethodInfo(drawMethod); 2417 const bool hasFirst = methodInfo.first; 2418 const bool instanced = methodInfo.instanced; 2419 const bool ranged = methodInfo.ranged; 2420 const bool indexed = methodInfo.indexed; 2421 2422 std::stringstream name; 2423 2424 for (size_t ndx = 0; ndx < attribs.size(); ++ndx) 2425 { 2426 const AttributeSpec& attrib = attribs[ndx]; 2427 2428 if (attribs.size() > 1) 2429 name << "attrib" << ndx << "_"; 2430 2431 if (ndx == 0|| attrib.additionalPositionAttribute) 2432 name << "pos_"; 2433 else 2434 name << "col_"; 2435 2436 if (attrib.useDefaultAttribute) 2437 { 2438 name 2439 << "non_array_" 2440 << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "_" 2441 << attrib.componentCount << "_" 2442 << DrawTestSpec::outputTypeToString(attrib.outputType) << "_"; 2443 } 2444 else 2445 { 2446 name 2447 << DrawTestSpec::storageToString(attrib.storage) << "_" 2448 << attrib.offset << "_" 2449 << attrib.stride << "_" 2450 << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType); 2451 if (attrib.inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && attrib.inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10) 2452 name << attrib.componentCount; 2453 name 2454 << "_" 2455 << (attrib.normalize ? "normalized_" : "") 2456 << DrawTestSpec::outputTypeToString(attrib.outputType) << "_" 2457 << DrawTestSpec::usageTypeToString(attrib.usage) << "_" 2458 << attrib.instanceDivisor << "_"; 2459 } 2460 } 2461 2462 if (indexed) 2463 name 2464 << "index_" << DrawTestSpec::indexTypeToString(indexType) << "_" 2465 << DrawTestSpec::storageToString(indexStorage) << "_" 2466 << "offset" << indexPointerOffset << "_"; 2467 if (hasFirst) 2468 name << "first" << first << "_"; 2469 if (ranged) 2470 name << "ranged_" << indexMin << "_" << indexMax << "_"; 2471 if (instanced) 2472 name << "instances" << instanceCount << "_"; 2473 2474 switch (primitive) 2475 { 2476 case DrawTestSpec::PRIMITIVE_POINTS: 2477 name << "points_"; 2478 break; 2479 case DrawTestSpec::PRIMITIVE_TRIANGLES: 2480 name << "triangles_"; 2481 break; 2482 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN: 2483 name << "triangle_fan_"; 2484 break; 2485 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP: 2486 name << "triangle_strip_"; 2487 break; 2488 case DrawTestSpec::PRIMITIVE_LINES: 2489 name << "lines_"; 2490 break; 2491 case DrawTestSpec::PRIMITIVE_LINE_STRIP: 2492 name << "line_strip_"; 2493 break; 2494 case DrawTestSpec::PRIMITIVE_LINE_LOOP: 2495 name << "line_loop_"; 2496 break; 2497 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY: 2498 name << "line_adjancency"; 2499 break; 2500 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY: 2501 name << "line_strip_adjancency"; 2502 break; 2503 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY: 2504 name << "triangles_adjancency"; 2505 break; 2506 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY: 2507 name << "triangle_strip_adjancency"; 2508 break; 2509 default: 2510 DE_ASSERT(false); 2511 break; 2512 } 2513 2514 name << primitiveCount; 2515 2516 return name.str(); 2517 } 2518 2519 std::string DrawTestSpec::getDesc (void) const 2520 { 2521 std::stringstream desc; 2522 2523 for (size_t ndx = 0; ndx < attribs.size(); ++ndx) 2524 { 2525 const AttributeSpec& attrib = attribs[ndx]; 2526 2527 if (attrib.useDefaultAttribute) 2528 { 2529 desc 2530 << "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,")) 2531 << "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", " 2532 << "input component count " << attrib.componentCount << ", " 2533 << "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", "; 2534 } 2535 else 2536 { 2537 desc 2538 << "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,")) 2539 << "Storage in " << DrawTestSpec::storageToString(attrib.storage) << ", " 2540 << "stride " << attrib.stride << ", " 2541 << "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", " 2542 << "input component count " << attrib.componentCount << ", " 2543 << (attrib.normalize ? "normalized, " : "") 2544 << "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", " 2545 << "instance divisor " << attrib.instanceDivisor << ", "; 2546 } 2547 } 2548 2549 if (drawMethod == DRAWMETHOD_DRAWARRAYS) 2550 { 2551 desc 2552 << "drawArrays(), " 2553 << "first " << first << ", "; 2554 } 2555 else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED) 2556 { 2557 desc 2558 << "drawArraysInstanced(), " 2559 << "first " << first << ", " 2560 << "instance count " << instanceCount << ", "; 2561 } 2562 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS) 2563 { 2564 desc 2565 << "drawElements(), " 2566 << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", " 2567 << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", " 2568 << "index offset " << indexPointerOffset << ", "; 2569 } 2570 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED) 2571 { 2572 desc 2573 << "drawElementsRanged(), " 2574 << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", " 2575 << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", " 2576 << "index offset " << indexPointerOffset << ", " 2577 << "range start " << indexMin << ", " 2578 << "range end " << indexMax << ", "; 2579 } 2580 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED) 2581 { 2582 desc 2583 << "drawElementsInstanced(), " 2584 << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", " 2585 << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", " 2586 << "index offset " << indexPointerOffset << ", " 2587 << "instance count " << instanceCount << ", "; 2588 } 2589 else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT) 2590 { 2591 desc 2592 << "drawArraysIndirect(), " 2593 << "first " << first << ", " 2594 << "instance count " << instanceCount << ", " 2595 << "indirect offset " << indirectOffset << ", "; 2596 } 2597 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT) 2598 { 2599 desc 2600 << "drawElementsIndirect(), " 2601 << "index type " << DrawTestSpec::indexTypeToString(indexType) << ", " 2602 << "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", " 2603 << "index offset " << indexPointerOffset << ", " 2604 << "instance count " << instanceCount << ", " 2605 << "indirect offset " << indirectOffset << ", " 2606 << "base vertex " << baseVertex << ", "; 2607 } 2608 else 2609 DE_ASSERT(DE_FALSE); 2610 2611 desc << primitiveCount; 2612 2613 switch (primitive) 2614 { 2615 case DrawTestSpec::PRIMITIVE_POINTS: 2616 desc << "points"; 2617 break; 2618 case DrawTestSpec::PRIMITIVE_TRIANGLES: 2619 desc << "triangles"; 2620 break; 2621 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN: 2622 desc << "triangles (fan)"; 2623 break; 2624 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP: 2625 desc << "triangles (strip)"; 2626 break; 2627 case DrawTestSpec::PRIMITIVE_LINES: 2628 desc << "lines"; 2629 break; 2630 case DrawTestSpec::PRIMITIVE_LINE_STRIP: 2631 desc << "lines (strip)"; 2632 break; 2633 case DrawTestSpec::PRIMITIVE_LINE_LOOP: 2634 desc << "lines (loop)"; 2635 break; 2636 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY: 2637 desc << "lines (adjancency)"; 2638 break; 2639 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY: 2640 desc << "lines (strip, adjancency)"; 2641 break; 2642 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY: 2643 desc << "triangles (adjancency)"; 2644 break; 2645 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY: 2646 desc << "triangles (strip, adjancency)"; 2647 break; 2648 default: 2649 DE_ASSERT(false); 2650 break; 2651 } 2652 2653 return desc.str(); 2654 } 2655 2656 std::string DrawTestSpec::getMultilineDesc (void) const 2657 { 2658 std::stringstream desc; 2659 2660 for (size_t ndx = 0; ndx < attribs.size(); ++ndx) 2661 { 2662 const AttributeSpec& attrib = attribs[ndx]; 2663 2664 if (attrib.useDefaultAttribute) 2665 { 2666 desc 2667 << "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n")) 2668 << "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n" 2669 << "\tinput component count " << attrib.componentCount << "\n" 2670 << "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n"; 2671 } 2672 else 2673 { 2674 desc 2675 << "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n")) 2676 << "\tStorage in " << DrawTestSpec::storageToString(attrib.storage) << "\n" 2677 << "\tstride " << attrib.stride << "\n" 2678 << "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n" 2679 << "\tinput component count " << attrib.componentCount << "\n" 2680 << (attrib.normalize ? "\tnormalized\n" : "") 2681 << "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n" 2682 << "\tinstance divisor " << attrib.instanceDivisor << "\n"; 2683 } 2684 } 2685 2686 if (drawMethod == DRAWMETHOD_DRAWARRAYS) 2687 { 2688 desc 2689 << "drawArrays()\n" 2690 << "\tfirst " << first << "\n"; 2691 } 2692 else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED) 2693 { 2694 desc 2695 << "drawArraysInstanced()\n" 2696 << "\tfirst " << first << "\n" 2697 << "\tinstance count " << instanceCount << "\n"; 2698 } 2699 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS) 2700 { 2701 desc 2702 << "drawElements()\n" 2703 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2704 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2705 << "\tindex offset " << indexPointerOffset << "\n"; 2706 } 2707 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED) 2708 { 2709 desc 2710 << "drawElementsRanged()\n" 2711 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2712 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2713 << "\tindex offset " << indexPointerOffset << "\n" 2714 << "\trange start " << indexMin << "\n" 2715 << "\trange end " << indexMax << "\n"; 2716 } 2717 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED) 2718 { 2719 desc 2720 << "drawElementsInstanced()\n" 2721 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2722 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2723 << "\tindex offset " << indexPointerOffset << "\n" 2724 << "\tinstance count " << instanceCount << "\n"; 2725 } 2726 else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT) 2727 { 2728 desc 2729 << "drawArraysIndirect()\n" 2730 << "\tfirst " << first << "\n" 2731 << "\tinstance count " << instanceCount << "\n" 2732 << "\tindirect offset " << indirectOffset << "\n"; 2733 } 2734 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT) 2735 { 2736 desc 2737 << "drawElementsIndirect()\n" 2738 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2739 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2740 << "\tindex offset " << indexPointerOffset << "\n" 2741 << "\tinstance count " << instanceCount << "\n" 2742 << "\tindirect offset " << indirectOffset << "\n" 2743 << "\tbase vertex " << baseVertex << "\n"; 2744 } 2745 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_BASEVERTEX) 2746 { 2747 desc 2748 << "drawElementsBaseVertex()\n" 2749 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2750 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2751 << "\tindex offset " << indexPointerOffset << "\n" 2752 << "\tbase vertex " << baseVertex << "\n"; 2753 } 2754 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX) 2755 { 2756 desc 2757 << "drawElementsInstancedBaseVertex()\n" 2758 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2759 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2760 << "\tindex offset " << indexPointerOffset << "\n" 2761 << "\tinstance count " << instanceCount << "\n" 2762 << "\tbase vertex " << baseVertex << "\n"; 2763 } 2764 else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX) 2765 { 2766 desc 2767 << "drawRangeElementsBaseVertex()\n" 2768 << "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n" 2769 << "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n" 2770 << "\tindex offset " << indexPointerOffset << "\n" 2771 << "\tbase vertex " << baseVertex << "\n" 2772 << "\trange start " << indexMin << "\n" 2773 << "\trange end " << indexMax << "\n"; 2774 } 2775 else 2776 DE_ASSERT(DE_FALSE); 2777 2778 desc << "\t" << primitiveCount << " "; 2779 2780 switch (primitive) 2781 { 2782 case DrawTestSpec::PRIMITIVE_POINTS: 2783 desc << "points"; 2784 break; 2785 case DrawTestSpec::PRIMITIVE_TRIANGLES: 2786 desc << "triangles"; 2787 break; 2788 case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN: 2789 desc << "triangles (fan)"; 2790 break; 2791 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP: 2792 desc << "triangles (strip)"; 2793 break; 2794 case DrawTestSpec::PRIMITIVE_LINES: 2795 desc << "lines"; 2796 break; 2797 case DrawTestSpec::PRIMITIVE_LINE_STRIP: 2798 desc << "lines (strip)"; 2799 break; 2800 case DrawTestSpec::PRIMITIVE_LINE_LOOP: 2801 desc << "lines (loop)"; 2802 break; 2803 case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY: 2804 desc << "lines (adjancency)"; 2805 break; 2806 case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY: 2807 desc << "lines (strip, adjancency)"; 2808 break; 2809 case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY: 2810 desc << "triangles (adjancency)"; 2811 break; 2812 case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY: 2813 desc << "triangles (strip, adjancency)"; 2814 break; 2815 default: 2816 DE_ASSERT(false); 2817 break; 2818 } 2819 2820 desc << "\n"; 2821 2822 return desc.str(); 2823 } 2824 2825 DrawTestSpec::DrawTestSpec (void) 2826 { 2827 primitive = PRIMITIVE_LAST; 2828 primitiveCount = 0; 2829 drawMethod = DRAWMETHOD_LAST; 2830 indexType = INDEXTYPE_LAST; 2831 indexPointerOffset = 0; 2832 indexStorage = STORAGE_LAST; 2833 first = 0; 2834 indexMin = 0; 2835 indexMax = 0; 2836 instanceCount = 0; 2837 indirectOffset = 0; 2838 baseVertex = 0; 2839 } 2840 2841 int DrawTestSpec::hash (void) const 2842 { 2843 // Use only drawmode-relevant values in "hashing" as the unrelevant values might not be set (causing non-deterministic behavior). 2844 const MethodInfo methodInfo = getMethodInfo(drawMethod); 2845 const bool arrayed = methodInfo.first; 2846 const bool instanced = methodInfo.instanced; 2847 const bool ranged = methodInfo.ranged; 2848 const bool indexed = methodInfo.indexed; 2849 const bool indirect = methodInfo.indirect; 2850 const bool hasBaseVtx = methodInfo.baseVertex; 2851 2852 const int indexHash = (!indexed) ? (0) : (int(indexType) + 10 * indexPointerOffset + 100 * int(indexStorage)); 2853 const int arrayHash = (!arrayed) ? (0) : (first); 2854 const int indexRangeHash = (!ranged) ? (0) : (indexMin + 10 * indexMax); 2855 const int instanceHash = (!instanced) ? (0) : (instanceCount); 2856 const int indirectHash = (!indirect) ? (0) : (indirectOffset); 2857 const int baseVtxHash = (!hasBaseVtx) ? (0) : (baseVertex); 2858 const int basicHash = int(primitive) + 10 * primitiveCount + 100 * int(drawMethod); 2859 2860 return indexHash + 3 * arrayHash + 5 * indexRangeHash + 7 * instanceHash + 13 * basicHash + 17 * (int)attribs.size() + 19 * primitiveCount + 23 * indirectHash + 27 * baseVtxHash; 2861 } 2862 2863 bool DrawTestSpec::valid (void) const 2864 { 2865 DE_ASSERT(apiType.getProfile() != glu::PROFILE_LAST); 2866 DE_ASSERT(primitive != PRIMITIVE_LAST); 2867 DE_ASSERT(drawMethod != DRAWMETHOD_LAST); 2868 2869 const MethodInfo methodInfo = getMethodInfo(drawMethod); 2870 2871 for (int ndx = 0; ndx < (int)attribs.size(); ++ndx) 2872 if (!attribs[ndx].valid(apiType)) 2873 return false; 2874 2875 if (methodInfo.ranged) 2876 { 2877 deUint32 maxIndexValue = 0; 2878 if (indexType == INDEXTYPE_BYTE) 2879 maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_BYTE).ub.getValue(); 2880 else if (indexType == INDEXTYPE_SHORT) 2881 maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_SHORT).us.getValue(); 2882 else if (indexType == INDEXTYPE_INT) 2883 maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_INT).ui.getValue(); 2884 else 2885 DE_ASSERT(DE_FALSE); 2886 2887 if (indexMin > indexMax) 2888 return false; 2889 if (indexMin < 0 || indexMax < 0) 2890 return false; 2891 if ((deUint32)indexMin > maxIndexValue || (deUint32)indexMax > maxIndexValue) 2892 return false; 2893 } 2894 2895 if (methodInfo.first && first < 0) 2896 return false; 2897 2898 // GLES2 limits 2899 if (apiType == glu::ApiType::es(2,0)) 2900 { 2901 if (drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS && drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS) 2902 return false; 2903 if (drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS && (indexType != INDEXTYPE_BYTE && indexType != INDEXTYPE_SHORT)) 2904 return false; 2905 } 2906 2907 // Indirect limitations 2908 if (methodInfo.indirect) 2909 { 2910 // Indirect offset alignment 2911 if (indirectOffset % 4 != 0) 2912 return false; 2913 2914 // All attribute arrays must be stored in a buffer 2915 for (int ndx = 0; ndx < (int)attribs.size(); ++ndx) 2916 if (!attribs[ndx].useDefaultAttribute && attribs[ndx].storage == gls::DrawTestSpec::STORAGE_USER) 2917 return false; 2918 } 2919 if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT) 2920 { 2921 // index offset must be convertable to firstIndex 2922 if (indexPointerOffset % gls::DrawTestSpec::indexTypeSize(indexType) != 0) 2923 return false; 2924 2925 // Indices must be in a buffer 2926 if (indexStorage != STORAGE_BUFFER) 2927 return false; 2928 } 2929 2930 // Do not allow user pointer in GL core 2931 if (apiType.getProfile() == glu::PROFILE_CORE) 2932 { 2933 if (methodInfo.indexed && indexStorage == DrawTestSpec::STORAGE_USER) 2934 return false; 2935 } 2936 2937 return true; 2938 } 2939 2940 DrawTestSpec::CompatibilityTestType DrawTestSpec::isCompatibilityTest (void) const 2941 { 2942 const MethodInfo methodInfo = getMethodInfo(drawMethod); 2943 2944 bool bufferAlignmentBad = false; 2945 bool strideAlignmentBad = false; 2946 2947 // Attribute buffer alignment 2948 for (int ndx = 0; ndx < (int)attribs.size(); ++ndx) 2949 if (!attribs[ndx].isBufferAligned()) 2950 bufferAlignmentBad = true; 2951 2952 // Attribute stride alignment 2953 for (int ndx = 0; ndx < (int)attribs.size(); ++ndx) 2954 if (!attribs[ndx].isBufferStrideAligned()) 2955 strideAlignmentBad = true; 2956 2957 // Index buffer alignment 2958 if (methodInfo.indexed) 2959 { 2960 if (indexStorage == STORAGE_BUFFER) 2961 { 2962 int indexSize = 0; 2963 if (indexType == INDEXTYPE_BYTE) 2964 indexSize = 1; 2965 else if (indexType == INDEXTYPE_SHORT) 2966 indexSize = 2; 2967 else if (indexType == INDEXTYPE_INT) 2968 indexSize = 4; 2969 else 2970 DE_ASSERT(DE_FALSE); 2971 2972 if (indexPointerOffset % indexSize != 0) 2973 bufferAlignmentBad = true; 2974 } 2975 } 2976 2977 // \note combination bad alignment & stride is treated as bad offset 2978 if (bufferAlignmentBad) 2979 return COMPATIBILITY_UNALIGNED_OFFSET; 2980 else if (strideAlignmentBad) 2981 return COMPATIBILITY_UNALIGNED_STRIDE; 2982 else 2983 return COMPATIBILITY_NONE; 2984 } 2985 2986 enum PrimitiveClass 2987 { 2988 PRIMITIVECLASS_POINT = 0, 2989 PRIMITIVECLASS_LINE, 2990 PRIMITIVECLASS_TRIANGLE, 2991 2992 PRIMITIVECLASS_LAST 2993 }; 2994 2995 static PrimitiveClass getDrawPrimitiveClass (gls::DrawTestSpec::Primitive primitiveType) 2996 { 2997 switch (primitiveType) 2998 { 2999 case gls::DrawTestSpec::PRIMITIVE_POINTS: 3000 return PRIMITIVECLASS_POINT; 3001 3002 case gls::DrawTestSpec::PRIMITIVE_LINES: 3003 case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP: 3004 case gls::DrawTestSpec::PRIMITIVE_LINE_LOOP: 3005 case gls::DrawTestSpec::PRIMITIVE_LINES_ADJACENCY: 3006 case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY: 3007 return PRIMITIVECLASS_LINE; 3008 3009 case gls::DrawTestSpec::PRIMITIVE_TRIANGLES: 3010 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN: 3011 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP: 3012 case gls::DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY: 3013 case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY: 3014 return PRIMITIVECLASS_TRIANGLE; 3015 3016 default: 3017 DE_ASSERT(false); 3018 return PRIMITIVECLASS_LAST; 3019 } 3020 } 3021 3022 static bool containsLineCases (const std::vector<DrawTestSpec>& m_specs) 3023 { 3024 for (int ndx = 0; ndx < (int)m_specs.size(); ++ndx) 3025 { 3026 if (getDrawPrimitiveClass(m_specs[ndx].primitive) == PRIMITIVECLASS_LINE) 3027 return true; 3028 } 3029 return false; 3030 } 3031 3032 // DrawTest 3033 3034 DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const DrawTestSpec& spec, const char* name, const char* desc) 3035 : TestCase (testCtx, name, desc) 3036 , m_renderCtx (renderCtx) 3037 , m_refBuffers (DE_NULL) 3038 , m_refContext (DE_NULL) 3039 , m_glesContext (DE_NULL) 3040 , m_glArrayPack (DE_NULL) 3041 , m_rrArrayPack (DE_NULL) 3042 , m_maxDiffRed (-1) 3043 , m_maxDiffGreen (-1) 3044 , m_maxDiffBlue (-1) 3045 , m_iteration (0) 3046 , m_result () // \note no per-iteration result logging (only one iteration) 3047 { 3048 addIteration(spec); 3049 } 3050 3051 DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc) 3052 : TestCase (testCtx, name, desc) 3053 , m_renderCtx (renderCtx) 3054 , m_refBuffers (DE_NULL) 3055 , m_refContext (DE_NULL) 3056 , m_glesContext (DE_NULL) 3057 , m_glArrayPack (DE_NULL) 3058 , m_rrArrayPack (DE_NULL) 3059 , m_maxDiffRed (-1) 3060 , m_maxDiffGreen (-1) 3061 , m_maxDiffBlue (-1) 3062 , m_iteration (0) 3063 , m_result (testCtx.getLog(), "Iteration result: ") 3064 { 3065 } 3066 3067 DrawTest::~DrawTest (void) 3068 { 3069 deinit(); 3070 } 3071 3072 void DrawTest::addIteration (const DrawTestSpec& spec, const char* description) 3073 { 3074 // Validate spec 3075 const bool validSpec = spec.valid(); 3076 DE_ASSERT(validSpec); 3077 3078 if (!validSpec) 3079 return; 3080 3081 // Check the context type is the same with other iterations 3082 if (!m_specs.empty()) 3083 { 3084 const bool validContext = m_specs[0].apiType == spec.apiType; 3085 DE_ASSERT(validContext); 3086 3087 if (!validContext) 3088 return; 3089 } 3090 3091 m_specs.push_back(spec); 3092 3093 if (description) 3094 m_iteration_descriptions.push_back(std::string(description)); 3095 else 3096 m_iteration_descriptions.push_back(std::string()); 3097 } 3098 3099 void DrawTest::init (void) 3100 { 3101 DE_ASSERT(!m_specs.empty()); 3102 DE_ASSERT(contextSupports(m_renderCtx.getType(), m_specs[0].apiType)); 3103 3104 const int renderTargetWidth = de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getWidth()); 3105 const int renderTargetHeight = de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getHeight()); 3106 3107 // lines have significantly different rasterization in MSAA mode 3108 const bool isLineCase = containsLineCases(m_specs); 3109 const bool isMSAACase = m_renderCtx.getRenderTarget().getNumSamples() > 1; 3110 const int renderTargetSamples = (isMSAACase && isLineCase) ? (4) : (1); 3111 3112 sglr::ReferenceContextLimits limits (m_renderCtx); 3113 bool useVao = false; 3114 3115 m_glesContext = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight)); 3116 3117 if (m_renderCtx.getType().getAPI() == glu::ApiType::es(2,0) || m_renderCtx.getType().getAPI() == glu::ApiType::es(3,0)) 3118 useVao = false; 3119 else if (contextSupports(m_renderCtx.getType(), glu::ApiType::es(3,1)) || glu::isContextTypeGLCore(m_renderCtx.getType())) 3120 useVao = true; 3121 else 3122 DE_FATAL("Unknown context type"); 3123 3124 m_refBuffers = new sglr::ReferenceContextBuffers(m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, renderTargetWidth, renderTargetHeight, renderTargetSamples); 3125 m_refContext = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer()); 3126 3127 m_glArrayPack = new AttributePack(m_testCtx, m_renderCtx, *m_glesContext, tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, true); 3128 m_rrArrayPack = new AttributePack(m_testCtx, m_renderCtx, *m_refContext, tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, false); 3129 3130 m_maxDiffRed = deCeilFloatToInt32(256.0f * (6.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().redBits))); 3131 m_maxDiffGreen = deCeilFloatToInt32(256.0f * (6.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().greenBits))); 3132 m_maxDiffBlue = deCeilFloatToInt32(256.0f * (6.0f / (float)(1 << m_renderCtx.getRenderTarget().getPixelFormat().blueBits))); 3133 } 3134 3135 void DrawTest::deinit (void) 3136 { 3137 delete m_glArrayPack; 3138 delete m_rrArrayPack; 3139 delete m_refBuffers; 3140 delete m_refContext; 3141 delete m_glesContext; 3142 3143 m_glArrayPack = DE_NULL; 3144 m_rrArrayPack = DE_NULL; 3145 m_refBuffers = DE_NULL; 3146 m_refContext = DE_NULL; 3147 m_glesContext = DE_NULL; 3148 } 3149 3150 DrawTest::IterateResult DrawTest::iterate (void) 3151 { 3152 const int specNdx = (m_iteration / 2); 3153 const bool drawStep = (m_iteration % 2) == 0; 3154 const bool compareStep = (m_iteration % 2) == 1; 3155 const IterateResult iterateResult = ((size_t)m_iteration + 1 == m_specs.size()*2) ? (STOP) : (CONTINUE); 3156 const DrawTestSpec& spec = m_specs[specNdx]; 3157 const bool updateProgram = (m_iteration == 0) || (drawStep && !checkSpecsShaderCompatible(m_specs[specNdx], m_specs[specNdx-1])); // try to use the same shader in all iterations 3158 IterationLogSectionEmitter sectionEmitter (m_testCtx.getLog(), specNdx, m_specs.size(), m_iteration_descriptions[specNdx], drawStep && m_specs.size()!=1); 3159 3160 if (drawStep) 3161 { 3162 const MethodInfo methodInfo = getMethodInfo(spec.drawMethod); 3163 const bool indexed = methodInfo.indexed; 3164 const bool instanced = methodInfo.instanced; 3165 const bool ranged = methodInfo.ranged; 3166 const bool hasFirst = methodInfo.first; 3167 const bool hasBaseVtx = methodInfo.baseVertex; 3168 3169 const size_t primitiveElementCount = getElementCount(spec.primitive, spec.primitiveCount); // !< elements to be drawn 3170 const int indexMin = (ranged) ? (spec.indexMin) : (0); 3171 const int firstAddition = (hasFirst) ? (spec.first) : (0); 3172 const int baseVertexAddition = (hasBaseVtx && spec.baseVertex > 0) ? ( spec.baseVertex) : (0); // spec.baseVertex > 0 => Create bigger attribute buffer 3173 const int indexBase = (hasBaseVtx && spec.baseVertex < 0) ? (-spec.baseVertex) : (0); // spec.baseVertex < 0 => Create bigger indices 3174 const size_t elementCount = primitiveElementCount + indexMin + firstAddition + baseVertexAddition; // !< elements in buffer (buffer should have at least primitiveElementCount ACCESSIBLE (index range, first) elements) 3175 const int maxElementIndex = (int)primitiveElementCount + indexMin + firstAddition - 1; 3176 const int indexMax = de::max(0, (ranged) ? (de::clamp<int>(spec.indexMax, 0, maxElementIndex)) : (maxElementIndex)); 3177 float coordScale = getCoordScale(spec); 3178 float colorScale = getColorScale(spec); 3179 3180 rr::GenericVec4 nullAttribValue; 3181 3182 // Log info 3183 m_testCtx.getLog() << TestLog::Message << spec.getMultilineDesc() << TestLog::EndMessage; 3184 m_testCtx.getLog() << TestLog::Message << TestLog::EndMessage; // extra line for clarity 3185 3186 // Data 3187 3188 m_glArrayPack->clearArrays(); 3189 m_rrArrayPack->clearArrays(); 3190 3191 for (int attribNdx = 0; attribNdx < (int)spec.attribs.size(); attribNdx++) 3192 { 3193 DrawTestSpec::AttributeSpec attribSpec = spec.attribs[attribNdx]; 3194 const bool isPositionAttr = (attribNdx == 0) || (attribSpec.additionalPositionAttribute); 3195 3196 if (attribSpec.useDefaultAttribute) 3197 { 3198 const int seed = 10 * attribSpec.hash() + 100 * spec.hash() + attribNdx; 3199 rr::GenericVec4 attribValue = RandomArrayGenerator::generateAttributeValue(seed, attribSpec.inputType); 3200 3201 m_glArrayPack->newArray(DrawTestSpec::STORAGE_USER); 3202 m_rrArrayPack->newArray(DrawTestSpec::STORAGE_USER); 3203 3204 m_glArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false); 3205 m_rrArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false); 3206 } 3207 else 3208 { 3209 const int seed = attribSpec.hash() + 100 * spec.hash() + attribNdx; 3210 const size_t elementSize = attribSpec.componentCount * DrawTestSpec::inputTypeSize(attribSpec.inputType); 3211 const size_t stride = (attribSpec.stride == 0) ? (elementSize) : (attribSpec.stride); 3212 const size_t evaluatedElementCount = (instanced && attribSpec.instanceDivisor > 0) ? (spec.instanceCount / attribSpec.instanceDivisor + 1) : (elementCount); 3213 const size_t referencedElementCount = (ranged) ? (de::max<size_t>(evaluatedElementCount, spec.indexMax + 1)) : (evaluatedElementCount); 3214 const size_t bufferSize = attribSpec.offset + stride * (referencedElementCount - 1) + elementSize; 3215 const char* data = RandomArrayGenerator::generateArray(seed, (int)referencedElementCount, attribSpec.componentCount, attribSpec.offset, (int)stride, attribSpec.inputType); 3216 3217 try 3218 { 3219 m_glArrayPack->newArray(attribSpec.storage); 3220 m_rrArrayPack->newArray(attribSpec.storage); 3221 3222 m_glArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage); 3223 m_rrArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage); 3224 3225 m_glArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder); 3226 m_rrArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder); 3227 3228 delete [] data; 3229 data = NULL; 3230 } 3231 catch (...) 3232 { 3233 delete [] data; 3234 throw; 3235 } 3236 } 3237 } 3238 3239 // Shader program 3240 if (updateProgram) 3241 { 3242 m_glArrayPack->updateProgram(); 3243 m_rrArrayPack->updateProgram(); 3244 } 3245 3246 // Draw 3247 try 3248 { 3249 // indices 3250 if (indexed) 3251 { 3252 const int seed = spec.hash(); 3253 const size_t indexElementSize = DrawTestSpec::indexTypeSize(spec.indexType); 3254 const size_t indexArraySize = spec.indexPointerOffset + indexElementSize * elementCount; 3255 const char* indexArray = RandomArrayGenerator::generateIndices(seed, (int)elementCount, spec.indexType, spec.indexPointerOffset, indexMin, indexMax, indexBase); 3256 const char* indexPointerBase = (spec.indexStorage == DrawTestSpec::STORAGE_USER) ? (indexArray) : ((char*)DE_NULL); 3257 const char* indexPointer = indexPointerBase + spec.indexPointerOffset; 3258 3259 de::UniquePtr<AttributeArray> glArray (new AttributeArray(spec.indexStorage, *m_glesContext)); 3260 de::UniquePtr<AttributeArray> rrArray (new AttributeArray(spec.indexStorage, *m_refContext)); 3261 3262 try 3263 { 3264 glArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW); 3265 rrArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW); 3266 3267 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()); 3268 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()); 3269 3270 delete [] indexArray; 3271 indexArray = NULL; 3272 } 3273 catch (...) 3274 { 3275 delete [] indexArray; 3276 throw; 3277 } 3278 } 3279 else 3280 { 3281 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); 3282 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); 3283 } 3284 } 3285 catch (glu::Error& err) 3286 { 3287 // GL Errors are ok if the mode is not properly aligned 3288 3289 const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest(); 3290 3291 m_testCtx.getLog() << TestLog::Message << "Got error: " << err.what() << TestLog::EndMessage; 3292 3293 if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET) 3294 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers."); 3295 else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE) 3296 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride."); 3297 else 3298 throw; 3299 } 3300 } 3301 else if (compareStep) 3302 { 3303 if (!compare(spec.primitive)) 3304 { 3305 const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest(); 3306 3307 if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET) 3308 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers."); 3309 else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE) 3310 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride."); 3311 else 3312 m_result.addResult(QP_TEST_RESULT_FAIL, "Image comparison failed."); 3313 } 3314 } 3315 else 3316 { 3317 DE_ASSERT(false); 3318 return STOP; 3319 } 3320 3321 m_result.setTestContextResult(m_testCtx); 3322 3323 m_iteration++; 3324 return iterateResult; 3325 } 3326 3327 static bool isBlack (const tcu::RGBA& c) 3328 { 3329 // ignore alpha channel 3330 return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0; 3331 } 3332 3333 static bool isEdgeTripletComponent (int c1, int c2, int c3, int renderTargetDifference) 3334 { 3335 const int roundingDifference = 2 * renderTargetDifference; // src and dst pixels rounded to different directions 3336 const int d1 = c2 - c1; 3337 const int d2 = c3 - c2; 3338 const int rampDiff = de::abs(d2 - d1); 3339 3340 return rampDiff > roundingDifference; 3341 } 3342 3343 static bool isEdgeTriplet (const tcu::RGBA& c1, const tcu::RGBA& c2, const tcu::RGBA& c3, const tcu::IVec3& renderTargetThreshold) 3344 { 3345 // black (background color) and non-black is always an edge 3346 { 3347 const bool b1 = isBlack(c1); 3348 const bool b2 = isBlack(c2); 3349 const bool b3 = isBlack(c3); 3350 3351 // both pixels with coverage and pixels without coverage 3352 if ((b1 && b2 && b3) == false && (b1 || b2 || b3) == true) 3353 return true; 3354 // all black 3355 if (b1 && b2 && b3) 3356 return false; 3357 // all with coverage 3358 DE_ASSERT(!b1 && !b2 && !b3); 3359 } 3360 3361 // Color is always linearly interpolated => component values change nearly linearly 3362 // in any constant direction on triangle hull. (df/dx ~= C). 3363 3364 // Edge detection (this function) is run against the reference image 3365 // => no dithering to worry about 3366 3367 return isEdgeTripletComponent(c1.getRed(), c2.getRed(), c3.getRed(), renderTargetThreshold.x()) || 3368 isEdgeTripletComponent(c1.getGreen(), c2.getGreen(), c3.getGreen(), renderTargetThreshold.y()) || 3369 isEdgeTripletComponent(c1.getBlue(), c2.getBlue(), c3.getBlue(), renderTargetThreshold.z()); 3370 } 3371 3372 static bool pixelNearEdge (int x, int y, const tcu::Surface& ref, const tcu::IVec3& renderTargetThreshold) 3373 { 3374 // should not be called for edge pixels 3375 DE_ASSERT(x >= 1 && x <= ref.getWidth()-2); 3376 DE_ASSERT(y >= 1 && y <= ref.getHeight()-2); 3377 3378 // horizontal 3379 3380 for (int dy = -1; dy < 2; ++dy) 3381 { 3382 const tcu::RGBA c1 = ref.getPixel(x-1, y+dy); 3383 const tcu::RGBA c2 = ref.getPixel(x, y+dy); 3384 const tcu::RGBA c3 = ref.getPixel(x+1, y+dy); 3385 if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold)) 3386 return true; 3387 } 3388 3389 // vertical 3390 3391 for (int dx = -1; dx < 2; ++dx) 3392 { 3393 const tcu::RGBA c1 = ref.getPixel(x+dx, y-1); 3394 const tcu::RGBA c2 = ref.getPixel(x+dx, y); 3395 const tcu::RGBA c3 = ref.getPixel(x+dx, y+1); 3396 if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold)) 3397 return true; 3398 } 3399 3400 return false; 3401 } 3402 3403 static deUint32 getVisualizationGrayscaleColor (const tcu::RGBA& c) 3404 { 3405 // make triangle coverage and error pixels obvious by converting coverage to grayscale 3406 if (isBlack(c)) 3407 return 0; 3408 else 3409 return 50u + (deUint32)(c.getRed() + c.getBlue() + c.getGreen()) / 8u; 3410 } 3411 3412 static bool pixelNearLineIntersection (int x, int y, const tcu::Surface& target) 3413 { 3414 // should not be called for edge pixels 3415 DE_ASSERT(x >= 1 && x <= target.getWidth()-2); 3416 DE_ASSERT(y >= 1 && y <= target.getHeight()-2); 3417 3418 int coveredPixels = 0; 3419 3420 for (int dy = -1; dy < 2; dy++) 3421 for (int dx = -1; dx < 2; dx++) 3422 { 3423 const bool targetCoverage = !isBlack(target.getPixel(x+dx, y+dy)); 3424 if (targetCoverage) 3425 { 3426 ++coveredPixels; 3427 3428 // A single thin line cannot have more than 3 covered pixels in a 3x3 area 3429 if (coveredPixels >= 4) 3430 return true; 3431 } 3432 } 3433 3434 return false; 3435 } 3436 3437 static inline bool colorsEqual (const tcu::RGBA& colorA, const tcu::RGBA& colorB, const tcu::IVec3& compareThreshold) 3438 { 3439 enum 3440 { 3441 TCU_RGBA_RGB_MASK = tcu::RGBA::RED_MASK | tcu::RGBA::GREEN_MASK | tcu::RGBA::BLUE_MASK 3442 }; 3443 3444 return tcu::compareThresholdMasked(colorA, colorB, tcu::RGBA(compareThreshold.x(), compareThreshold.y(), compareThreshold.z(), 0), TCU_RGBA_RGB_MASK); 3445 } 3446 3447 // search 3x3 are for matching color 3448 static bool pixelNeighborhoodContainsColor (const tcu::Surface& target, int x, int y, const tcu::RGBA& color, const tcu::IVec3& compareThreshold) 3449 { 3450 // should not be called for edge pixels 3451 DE_ASSERT(x >= 1 && x <= target.getWidth()-2); 3452 DE_ASSERT(y >= 1 && y <= target.getHeight()-2); 3453 3454 for (int dy = -1; dy < 2; dy++) 3455 for (int dx = -1; dx < 2; dx++) 3456 { 3457 const tcu::RGBA targetCmpPixel = target.getPixel(x+dx, y+dy); 3458 if (colorsEqual(color, targetCmpPixel, compareThreshold)) 3459 return true; 3460 } 3461 3462 return false; 3463 } 3464 3465 // search 3x3 are for matching coverage (coverage == (color != background color)) 3466 static bool pixelNeighborhoodContainsCoverage (const tcu::Surface& target, int x, int y, bool coverage) 3467 { 3468 // should not be called for edge pixels 3469 DE_ASSERT(x >= 1 && x <= target.getWidth()-2); 3470 DE_ASSERT(y >= 1 && y <= target.getHeight()-2); 3471 3472 for (int dy = -1; dy < 2; dy++) 3473 for (int dx = -1; dx < 2; dx++) 3474 { 3475 const bool targetCmpCoverage = !isBlack(target.getPixel(x+dx, y+dy)); 3476 if (targetCmpCoverage == coverage) 3477 return true; 3478 } 3479 3480 return false; 3481 } 3482 3483 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) 3484 { 3485 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 3486 3487 const tcu::IVec4 green (0, 255, 0, 255); 3488 const tcu::IVec4 red (255, 0, 0, 255); 3489 const int width = reference.getWidth(); 3490 const int height = reference.getHeight(); 3491 tcu::TextureLevel errorMask (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height); 3492 const tcu::PixelBufferAccess errorAccess = errorMask.getAccess(); 3493 int numFailingPixels = 0; 3494 3495 // clear errormask edges which would otherwise be transparent 3496 3497 tcu::clear(tcu::getSubregion(errorAccess, 0, 0, width, 1), green); 3498 tcu::clear(tcu::getSubregion(errorAccess, 0, height-1, width, 1), green); 3499 tcu::clear(tcu::getSubregion(errorAccess, 0, 0, 1, height), green); 3500 tcu::clear(tcu::getSubregion(errorAccess, width-1, 0, 1, height), green); 3501 3502 // skip edge pixels since coverage on edge cannot be verified 3503 3504 for (int y = 1; y < height - 1; ++y) 3505 for (int x = 1; x < width - 1; ++x) 3506 { 3507 const tcu::RGBA refPixel = reference.getPixel(x, y); 3508 const tcu::RGBA screenPixel = result.getPixel(x, y); 3509 const bool directMatch = colorsEqual(refPixel, screenPixel, compareThreshold); 3510 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.) 3511 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.) 3512 3513 if (isOkScreenPixel && isOkReferencePixel) 3514 { 3515 // pixel valid, write greenish pixels to make the result image easier to read 3516 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel); 3517 errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y); 3518 } 3519 else if (!pixelNearEdge(x, y, reference, renderTargetThreshold)) 3520 { 3521 // non-edge pixel values must be within threshold of the reference values 3522 errorAccess.setPixel(red, x, y); 3523 ++numFailingPixels; 3524 } 3525 else 3526 { 3527 // we are on/near an edge, verify only coverage (coverage == not background colored) 3528 const bool referenceCoverage = !isBlack(refPixel); 3529 const bool screenCoverage = !isBlack(screenPixel); 3530 const bool isOkReferenceCoverage = pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage); // Check reference pixel against screen pixel 3531 const bool isOkScreenCoverage = pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage); // Check screen pixels against reference pixel 3532 3533 if (isOkScreenCoverage && isOkReferenceCoverage) 3534 { 3535 // pixel valid, write greenish pixels to make the result image easier to read 3536 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel); 3537 errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y); 3538 } 3539 else 3540 { 3541 // coverage does not match 3542 errorAccess.setPixel(red, x, y); 3543 ++numFailingPixels; 3544 } 3545 } 3546 } 3547 3548 log << TestLog::Message 3549 << "Comparing images:\n" 3550 << "\tallowed deviation in pixel positions = 1\n" 3551 << "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n" 3552 << "\tnumber of invalid pixels = " << numFailingPixels 3553 << TestLog::EndMessage; 3554 3555 if (numFailingPixels > maxAllowedInvalidPixels) 3556 { 3557 log << TestLog::Message 3558 << "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")" 3559 << TestLog::EndMessage 3560 << TestLog::ImageSet(imageSetName, imageSetDesc) 3561 << TestLog::Image("Result", "Result", result) 3562 << TestLog::Image("Reference", "Reference", reference) 3563 << TestLog::Image("ErrorMask", "Error mask", errorMask) 3564 << TestLog::EndImageSet; 3565 3566 return false; 3567 } 3568 else 3569 { 3570 log << TestLog::ImageSet(imageSetName, imageSetDesc) 3571 << TestLog::Image("Result", "Result", result) 3572 << TestLog::EndImageSet; 3573 3574 return true; 3575 } 3576 } 3577 3578 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) 3579 { 3580 DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight()); 3581 3582 const tcu::IVec4 green (0, 255, 0, 255); 3583 const tcu::IVec4 red (255, 0, 0, 255); 3584 const int width = reference.getWidth(); 3585 const int height = reference.getHeight(); 3586 tcu::TextureLevel errorMask (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height); 3587 const tcu::PixelBufferAccess errorAccess = errorMask.getAccess(); 3588 int numFailingPixels = 0; 3589 3590 // clear errormask edges which would otherwise be transparent 3591 3592 tcu::clear(tcu::getSubregion(errorAccess, 0, 0, width, 1), green); 3593 tcu::clear(tcu::getSubregion(errorAccess, 0, height-1, width, 1), green); 3594 tcu::clear(tcu::getSubregion(errorAccess, 0, 0, 1, height), green); 3595 tcu::clear(tcu::getSubregion(errorAccess, width-1, 0, 1, height), green); 3596 3597 // skip edge pixels since coverage on edge cannot be verified 3598 3599 for (int y = 1; y < height - 1; ++y) 3600 for (int x = 1; x < width - 1; ++x) 3601 { 3602 const tcu::RGBA refPixel = reference.getPixel(x, y); 3603 const tcu::RGBA screenPixel = result.getPixel(x, y); 3604 const bool directMatch = colorsEqual(refPixel, screenPixel, compareThreshold); 3605 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.) 3606 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.) 3607 3608 if (isOkScreenPixel && isOkReferencePixel) 3609 { 3610 // pixel valid, write greenish pixels to make the result image easier to read 3611 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel); 3612 errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y); 3613 } 3614 else if (!pixelNearLineIntersection(x, y, reference) && 3615 !pixelNearLineIntersection(x, y, result)) 3616 { 3617 // non-intersection pixel values must be within threshold of the reference values 3618 errorAccess.setPixel(red, x, y); 3619 ++numFailingPixels; 3620 } 3621 else 3622 { 3623 // pixel is near a line intersection 3624 // we are on/near an edge, verify only coverage (coverage == not background colored) 3625 const bool referenceCoverage = !isBlack(refPixel); 3626 const bool screenCoverage = !isBlack(screenPixel); 3627 const bool isOkScreenCoverage = pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage); // Check screen pixels against reference pixel 3628 const bool isOkReferenceCoverage = pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage); // Check reference pixel against screen pixel 3629 3630 if (isOkScreenCoverage && isOkReferenceCoverage) 3631 { 3632 // pixel valid, write greenish pixels to make the result image easier to read 3633 const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel); 3634 errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y); 3635 } 3636 else 3637 { 3638 // coverage does not match 3639 errorAccess.setPixel(red, x, y); 3640 ++numFailingPixels; 3641 } 3642 } 3643 } 3644 3645 log << TestLog::Message 3646 << "Comparing images:\n" 3647 << "\tallowed deviation in pixel positions = 1\n" 3648 << "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n" 3649 << "\tnumber of invalid pixels = " << numFailingPixels 3650 << TestLog::EndMessage; 3651 3652 if (numFailingPixels > maxAllowedInvalidPixels) 3653 { 3654 log << TestLog::Message 3655 << "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")" 3656 << TestLog::EndMessage 3657 << TestLog::ImageSet(imageSetName, imageSetDesc) 3658 << TestLog::Image("Result", "Result", result) 3659 << TestLog::Image("Reference", "Reference", reference) 3660 << TestLog::Image("ErrorMask", "Error mask", errorMask) 3661 << TestLog::EndImageSet; 3662 3663 return false; 3664 } 3665 else 3666 { 3667 log << TestLog::ImageSet(imageSetName, imageSetDesc) 3668 << TestLog::Image("Result", "Result", result) 3669 << TestLog::EndImageSet; 3670 3671 return true; 3672 } 3673 } 3674 3675 bool DrawTest::compare (gls::DrawTestSpec::Primitive primitiveType) 3676 { 3677 const tcu::Surface& ref = m_rrArrayPack->getSurface(); 3678 const tcu::Surface& screen = m_glArrayPack->getSurface(); 3679 3680 if (m_renderCtx.getRenderTarget().getNumSamples() > 1) 3681 { 3682 // \todo [mika] Improve compare when using multisampling 3683 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; 3684 return tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", ref.getAccess(), screen.getAccess(), 0.3f, tcu::COMPARE_LOG_RESULT); 3685 } 3686 else 3687 { 3688 const PrimitiveClass primitiveClass = getDrawPrimitiveClass(primitiveType); 3689 const int maxAllowedInvalidPixelsWithPoints = 0; //!< points are unlikely to have overlapping fragments 3690 const int maxAllowedInvalidPixelsWithLines = 5; //!< line are allowed to have a few bad pixels 3691 const int maxAllowedInvalidPixelsWithTriangles = 10; 3692 3693 switch (primitiveClass) 3694 { 3695 case PRIMITIVECLASS_POINT: 3696 { 3697 // Point are extremely unlikely to have overlapping regions, don't allow any no extra / missing pixels 3698 return tcu::intThresholdPositionDeviationErrorThresholdCompare(m_testCtx.getLog(), 3699 "CompareResult", 3700 "Result of rendering", 3701 ref.getAccess(), 3702 screen.getAccess(), 3703 tcu::UVec4(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue, 256), 3704 tcu::IVec3(1, 1, 0), //!< 3x3 search kernel 3705 true, //!< relax comparison on the image boundary 3706 maxAllowedInvalidPixelsWithPoints, //!< error threshold 3707 tcu::COMPARE_LOG_RESULT); 3708 } 3709 3710 case PRIMITIVECLASS_LINE: 3711 { 3712 // Lines can potentially have a large number of overlapping pixels. Pixel comparison may potentially produce 3713 // false negatives in such pixels if for example the pixel in question is overdrawn by another line in the 3714 // reference image but not in the resultin image. Relax comparison near line intersection points (areas) and 3715 // compare only coverage, not color, in such pixels 3716 return intersectionRelaxedLineImageCompare(m_testCtx.getLog(), 3717 "CompareResult", 3718 "Result of rendering", 3719 ref, 3720 screen, 3721 tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue), 3722 maxAllowedInvalidPixelsWithLines); 3723 } 3724 3725 case PRIMITIVECLASS_TRIANGLE: 3726 { 3727 // Triangles are likely to partially or fully overlap. Pixel difference comparison is fragile in pixels 3728 // where there could be potential overlapping since the pixels might be covered by one triangle in the 3729 // reference image and by the other in the result image. Relax comparsion near primitive edges and 3730 // compare only coverage, not color, in such pixels. 3731 const tcu::IVec3 renderTargetThreshold = m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold().toIVec().xyz(); 3732 3733 return edgeRelaxedImageCompare(m_testCtx.getLog(), 3734 "CompareResult", 3735 "Result of rendering", 3736 ref, 3737 screen, 3738 tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue), 3739 renderTargetThreshold, 3740 maxAllowedInvalidPixelsWithTriangles); 3741 } 3742 3743 default: 3744 DE_ASSERT(false); 3745 return false; 3746 } 3747 } 3748 } 3749 3750 float DrawTest::getCoordScale (const DrawTestSpec& spec) const 3751 { 3752 float maxValue = 1.0f; 3753 3754 for (int arrayNdx = 0; arrayNdx < (int)spec.attribs.size(); arrayNdx++) 3755 { 3756 DrawTestSpec::AttributeSpec attribSpec = spec.attribs[arrayNdx]; 3757 const bool isPositionAttr = (arrayNdx == 0) || (attribSpec.additionalPositionAttribute); 3758 float attrMaxValue = 0; 3759 3760 if (!isPositionAttr) 3761 continue; 3762 3763 if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10) 3764 { 3765 if (attribSpec.normalize) 3766 attrMaxValue += 1.0f; 3767 else 3768 attrMaxValue += 1024.0f; 3769 } 3770 else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10) 3771 { 3772 if (attribSpec.normalize) 3773 attrMaxValue += 1.0f; 3774 else 3775 attrMaxValue += 512.0f; 3776 } 3777 else 3778 { 3779 const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat(); 3780 3781 attrMaxValue += (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType)) ? (1.0f) : (max * 1.1f); 3782 } 3783 3784 if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4 3785 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4 3786 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4) 3787 attrMaxValue *= 2; 3788 3789 maxValue += attrMaxValue; 3790 } 3791 3792 return 1.0f / maxValue; 3793 } 3794 3795 float DrawTest::getColorScale (const DrawTestSpec& spec) const 3796 { 3797 float colorScale = 1.0f; 3798 3799 for (int arrayNdx = 1; arrayNdx < (int)spec.attribs.size(); arrayNdx++) 3800 { 3801 DrawTestSpec::AttributeSpec attribSpec = spec.attribs[arrayNdx]; 3802 const bool isPositionAttr = (arrayNdx == 0) || (attribSpec.additionalPositionAttribute); 3803 3804 if (isPositionAttr) 3805 continue; 3806 3807 if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10) 3808 { 3809 if (!attribSpec.normalize) 3810 colorScale *= 1.0f / 1024.0f; 3811 } 3812 else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10) 3813 { 3814 if (!attribSpec.normalize) 3815 colorScale *= 1.0f / 512.0f; 3816 } 3817 else 3818 { 3819 const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat(); 3820 3821 colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max))); 3822 if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4 || 3823 attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4 || 3824 attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4) 3825 colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max))); 3826 } 3827 } 3828 3829 return colorScale; 3830 } 3831 3832 } // gls 3833 } // deqp 3834