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