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