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