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 Parametrized, long-running stress case. 22 * 23 * \todo [2013-06-27 nuutti] Do certain things in a cleaner and less 24 * confusing way, such as the "redundant buffer 25 * factor" thing in LongStressCase. 26 *//*--------------------------------------------------------------------*/ 27 28 #include "glsLongStressCase.hpp" 29 #include "tcuTestLog.hpp" 30 #include "tcuCommandLine.hpp" 31 #include "tcuTextureUtil.hpp" 32 #include "tcuVector.hpp" 33 #include "tcuVectorUtil.hpp" 34 #include "glsTextureTestUtil.hpp" 35 #include "gluPixelTransfer.hpp" 36 #include "gluTextureUtil.hpp" 37 #include "tcuStringTemplate.hpp" 38 #include "gluStrUtil.hpp" 39 #include "gluShaderProgram.hpp" 40 #include "deRandom.hpp" 41 #include "deStringUtil.hpp" 42 #include "deString.h" 43 #include "deSharedPtr.hpp" 44 #include "deClock.h" 45 46 #include "glw.h" 47 48 #include <limits> 49 #include <vector> 50 #include <iomanip> 51 #include <map> 52 #include <iomanip> 53 54 using tcu::TestLog; 55 using tcu::Vec2; 56 using tcu::Vec3; 57 using tcu::Vec4; 58 using tcu::IVec2; 59 using tcu::IVec3; 60 using tcu::IVec4; 61 using tcu::TextureLevel; 62 using tcu::TextureFormat; 63 using tcu::ConstPixelBufferAccess; 64 using tcu::CubeFace; 65 using de::SharedPtr; 66 using de::Random; 67 using de::toString; 68 69 using std::vector; 70 using std::string; 71 using std::map; 72 73 namespace deqp 74 { 75 namespace gls 76 { 77 78 using TextureTestUtil::TextureType; 79 using TextureTestUtil::TEXTURETYPE_2D; 80 using TextureTestUtil::TEXTURETYPE_CUBE; 81 82 static const float Mi = (float)(1<<20); 83 84 static const deUint32 bufferUsages[] = 85 { 86 GL_STATIC_DRAW, 87 GL_STREAM_DRAW, 88 GL_DYNAMIC_DRAW, 89 90 GL_STATIC_READ, 91 GL_STREAM_READ, 92 GL_DYNAMIC_READ, 93 94 GL_STATIC_COPY, 95 GL_STREAM_COPY, 96 GL_DYNAMIC_COPY 97 }; 98 99 static const deUint32 bufferUsagesGLES2[] = 100 { 101 GL_STATIC_DRAW, 102 GL_DYNAMIC_DRAW, 103 GL_STREAM_DRAW 104 }; 105 106 static const deUint32 bufferTargets[] = 107 { 108 GL_ARRAY_BUFFER, 109 GL_ELEMENT_ARRAY_BUFFER, 110 111 GL_COPY_READ_BUFFER, 112 GL_COPY_WRITE_BUFFER, 113 GL_PIXEL_PACK_BUFFER, 114 GL_PIXEL_UNPACK_BUFFER, 115 GL_TRANSFORM_FEEDBACK_BUFFER, 116 GL_UNIFORM_BUFFER 117 }; 118 119 static const deUint32 bufferTargetsGLES2[] = 120 { 121 GL_ARRAY_BUFFER, 122 GL_ELEMENT_ARRAY_BUFFER 123 }; 124 125 static inline int computePixelStore (const TextureFormat& format) 126 { 127 const int pixelSize = format.getPixelSize(); 128 if (deIsPowerOfTwo32(pixelSize)) 129 return de::min(pixelSize, 8); 130 else 131 return 1; 132 } 133 134 static inline int getNumIterations (const tcu::TestContext& testCtx, const int defaultNumIterations) 135 { 136 const int cmdLineVal = testCtx.getCommandLine().getTestIterationCount(); 137 return cmdLineVal == 0 ? defaultNumIterations : cmdLineVal; 138 } 139 140 static inline float triangleArea (const Vec2& a, const Vec2& b, const Vec2& c) 141 { 142 const Vec2 ab = b-a; 143 const Vec2 ac = c-a; 144 return 0.5f * tcu::length(ab.x()*ac.y() - ab.y()*ac.x()); 145 } 146 147 static inline string mangleShaderNames (const string& source, const string& manglingSuffix) 148 { 149 map<string, string> m; 150 m["NS"] = manglingSuffix; 151 return tcu::StringTemplate(source.c_str()).specialize(m); 152 } 153 154 template <typename T, int N> 155 static inline T randomChoose (Random& rnd, const T (&arr)[N]) 156 { 157 return rnd.choose<T>(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr)); 158 } 159 160 static inline int nextDivisible (const int x, const int div) 161 { 162 DE_ASSERT(x >= 0); 163 DE_ASSERT(div >= 1); 164 return x == 0 ? 0 : x-1 + div - (x-1) % div; 165 } 166 167 static inline string getTimeStr (const deUint64 seconds) 168 { 169 const deUint64 m = seconds / 60; 170 const deUint64 h = m / 60; 171 const deUint64 d = h / 24; 172 std::ostringstream res; 173 174 res << d << "d " << h%24 << "h " << m%60 << "m " << seconds%60 << "s"; 175 return res.str(); 176 } 177 178 static inline string probabilityStr (const float prob) 179 { 180 return prob == 0.0f ? "never" : 181 prob == 1.0f ? "ALWAYS" : 182 de::floatToString(prob*100.0f, 0) + "%"; 183 } 184 185 static inline deUint32 randomBufferTarget (Random& rnd, const bool isGLES3) 186 { 187 return isGLES3 ? randomChoose(rnd, bufferTargets) : randomChoose(rnd, bufferTargetsGLES2); 188 } 189 190 static inline deUint32 randomBufferUsage (Random& rnd, const bool isGLES3) 191 { 192 return isGLES3 ? randomChoose(rnd, bufferUsages) : randomChoose(rnd, bufferUsagesGLES2); 193 } 194 195 static inline deUint32 cubeFaceToGLFace (tcu::CubeFace face) 196 { 197 switch (face) 198 { 199 case tcu::CUBEFACE_NEGATIVE_X: return GL_TEXTURE_CUBE_MAP_NEGATIVE_X; 200 case tcu::CUBEFACE_POSITIVE_X: return GL_TEXTURE_CUBE_MAP_POSITIVE_X; 201 case tcu::CUBEFACE_NEGATIVE_Y: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; 202 case tcu::CUBEFACE_POSITIVE_Y: return GL_TEXTURE_CUBE_MAP_POSITIVE_Y; 203 case tcu::CUBEFACE_NEGATIVE_Z: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; 204 case tcu::CUBEFACE_POSITIVE_Z: return GL_TEXTURE_CUBE_MAP_POSITIVE_Z; 205 default: 206 DE_ASSERT(false); 207 return GL_NONE; 208 } 209 } 210 211 #if defined(DE_DEBUG) 212 static inline bool isMatchingGLInternalFormat (const deUint32 internalFormat, const TextureFormat& texFormat) 213 { 214 switch (internalFormat) 215 { 216 // Unsized formats. 217 218 case GL_RGBA: return texFormat.order == TextureFormat::RGBA && 219 (texFormat.type == TextureFormat::UNORM_INT8 || 220 texFormat.type == TextureFormat::UNORM_SHORT_4444 || 221 texFormat.type == TextureFormat::UNORM_SHORT_5551); 222 223 case GL_RGB: return texFormat.order == TextureFormat::RGB && 224 (texFormat.type == TextureFormat::UNORM_INT8 || 225 texFormat.type == TextureFormat::UNORM_SHORT_565); 226 227 case GL_LUMINANCE_ALPHA: return texFormat.order == TextureFormat::LA && texFormat.type == TextureFormat::UNORM_INT8; 228 case GL_LUMINANCE: return texFormat.order == TextureFormat::L && texFormat.type == TextureFormat::UNORM_INT8; 229 case GL_ALPHA: return texFormat.order == TextureFormat::A && texFormat.type == TextureFormat::UNORM_INT8; 230 231 // Sized formats. 232 233 default: return glu::mapGLInternalFormat(internalFormat) == texFormat; 234 } 235 } 236 #endif // DE_DEBUG 237 238 static inline bool compileShader (const deUint32 shaderGL) 239 { 240 glCompileShader(shaderGL); 241 242 int success = GL_FALSE; 243 glGetShaderiv(shaderGL, GL_COMPILE_STATUS, &success); 244 245 return success == GL_TRUE; 246 } 247 248 static inline bool linkProgram (const deUint32 programGL) 249 { 250 glLinkProgram(programGL); 251 252 int success = GL_FALSE; 253 glGetProgramiv(programGL, GL_LINK_STATUS, &success); 254 255 return success == GL_TRUE; 256 } 257 258 static inline string getShaderInfoLog (const deUint32 shaderGL) 259 { 260 int infoLogLen = 0; 261 vector<char> infoLog; 262 glGetShaderiv(shaderGL, GL_INFO_LOG_LENGTH, &infoLogLen); 263 infoLog.resize(infoLogLen+1); 264 glGetShaderInfoLog(shaderGL, (int)infoLog.size(), DE_NULL, &infoLog[0]); 265 return &infoLog[0]; 266 } 267 268 static inline string getProgramInfoLog (const deUint32 programGL) 269 { 270 int infoLogLen = 0; 271 vector<char> infoLog; 272 glGetProgramiv(programGL, GL_INFO_LOG_LENGTH, &infoLogLen); 273 infoLog.resize(infoLogLen+1); 274 glGetProgramInfoLog(programGL, (int)infoLog.size(), DE_NULL, &infoLog[0]); 275 return &infoLog[0]; 276 } 277 278 namespace LongStressCaseInternal 279 { 280 281 // A hacky-ish class for drawing text on screen as GL quads. 282 class DebugInfoRenderer 283 { 284 public: 285 DebugInfoRenderer (const glu::RenderContext& ctx); 286 ~DebugInfoRenderer (void) { delete m_prog; } 287 288 void drawInfo (deUint64 secondsElapsed, int texMem, int maxTexMem, int bufMem, int maxBufMem, int iterNdx); 289 290 private: 291 DebugInfoRenderer (const DebugInfoRenderer&); 292 DebugInfoRenderer& operator= (const DebugInfoRenderer&); 293 294 void render (void); 295 void addTextToBuffer (const string& text, int yOffset); 296 297 const glu::RenderContext& m_ctx; 298 const glu::ShaderProgram* m_prog; 299 vector<float> m_posBuf; 300 vector<deUint16> m_ndxBuf; 301 }; 302 303 void DebugInfoRenderer::drawInfo (const deUint64 secondsElapsed, const int texMem, const int maxTexMem, const int bufMem, const int maxBufMem, const int iterNdx) 304 { 305 const deUint64 m = secondsElapsed / 60; 306 const deUint64 h = m / 60; 307 const deUint64 d = h / 24; 308 309 { 310 std::ostringstream text; 311 312 text << std::setw(2) << std::setfill('0') << d << ":" 313 << std::setw(2) << std::setfill('0') << h % 24 << ":" 314 << std::setw(2) << std::setfill('0') << m % 60 << ":" 315 << std::setw(2) << std::setfill('0') << secondsElapsed % 60; 316 addTextToBuffer(text.str(), 0); 317 text.str(""); 318 319 text << std::fixed << std::setprecision(2) << (float)texMem/Mi << "/" << (float)maxTexMem/Mi; 320 addTextToBuffer(text.str(), 1); 321 text.str(""); 322 323 text << std::fixed << std::setprecision(2) << (float)bufMem/Mi << "/" << (float)maxBufMem/Mi; 324 addTextToBuffer(text.str(), 2); 325 text.str(""); 326 327 text << std::setw(0) << iterNdx; 328 addTextToBuffer(text.str(), 3); 329 } 330 331 render(); 332 } 333 334 DebugInfoRenderer::DebugInfoRenderer (const glu::RenderContext& ctx) 335 : m_ctx (ctx) 336 , m_prog (DE_NULL) 337 { 338 DE_ASSERT(!m_prog); 339 m_prog = new glu::ShaderProgram(ctx, glu::makeVtxFragSources( 340 "attribute highp vec2 a_pos;\n" 341 "void main (void)\n" 342 "{\n" 343 " gl_Position = vec4(a_pos, -1.0, 1.0);\n" 344 "}\n", 345 346 "void main(void)\n" 347 "{\n" 348 " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 349 "}\n")); 350 } 351 352 void DebugInfoRenderer::addTextToBuffer (const string& text, const int yOffset) 353 { 354 static const char characters[] = "0123456789.:/"; 355 const int numCharacters = DE_LENGTH_OF_ARRAY(characters)-1; // \note -1 for null byte. 356 const int charWid = 6; 357 const int charHei = 6; 358 static const string charsStr (characters); 359 360 static const char font[numCharacters*charWid*charHei + 1]= 361 " #### "" # "" #### ""##### "" # ""######"" #####""######"" #### "" #### "" "" ## "" #" 362 "# #"" ## ""# #"" #"" # ""# ""# "" # ""# #""# #"" "" ## "" # " 363 "# #"" # "" # "" ### "" # # "" #### ""# ### "" # "" #### "" #####"" "" "" # " 364 "# #"" # "" # "" #""######"" #""## #"" # ""# #"" #"" "" ## "" # " 365 "# #"" # "" # ""# #"" # ""# #""# #"" # ""# #"" ## "" ## "" ## "" # " 366 " #### "" ### ""######"" #### "" # "" #### "" #### ""# "" #### ""### "" ## "" ""# "; 367 368 for (int ndxInText = 0; ndxInText < (int)text.size(); ndxInText++) 369 { 370 const int ndxInCharset = (int)charsStr.find(text[ndxInText]); 371 DE_ASSERT(ndxInCharset < numCharacters); 372 const int fontXStart = ndxInCharset*charWid; 373 374 for (int y = 0; y < charHei; y++) 375 { 376 float ay = -1.0f + (float)(y + 0 + yOffset*(charHei+2))*0.1f/(float)(charHei+2); 377 float by = -1.0f + (float)(y + 1 + yOffset*(charHei+2))*0.1f/(float)(charHei+2); 378 for (int x = 0; x < charWid; x++) 379 { 380 // \note Text is mirrored in x direction since on most(?) mobile devices the image is mirrored(?). 381 float ax = 1.0f - (float)(x + 0 + ndxInText*(charWid+2))*0.1f/(float)(charWid+2); 382 float bx = 1.0f - (float)(x + 1 + ndxInText*(charWid+2))*0.1f/(float)(charWid+2); 383 384 if (font[y*numCharacters*charWid + fontXStart + x] != ' ') 385 { 386 const int vtxNdx = (int)m_posBuf.size()/2; 387 388 m_ndxBuf.push_back(deUint16(vtxNdx+0)); 389 m_ndxBuf.push_back(deUint16(vtxNdx+1)); 390 m_ndxBuf.push_back(deUint16(vtxNdx+2)); 391 392 m_ndxBuf.push_back(deUint16(vtxNdx+2)); 393 m_ndxBuf.push_back(deUint16(vtxNdx+1)); 394 m_ndxBuf.push_back(deUint16(vtxNdx+3)); 395 396 m_posBuf.push_back(ax); 397 m_posBuf.push_back(ay); 398 399 m_posBuf.push_back(bx); 400 m_posBuf.push_back(ay); 401 402 m_posBuf.push_back(ax); 403 m_posBuf.push_back(by); 404 405 m_posBuf.push_back(bx); 406 m_posBuf.push_back(by); 407 } 408 } 409 } 410 } 411 } 412 413 void DebugInfoRenderer::render (void) 414 { 415 const int prog = m_prog->getProgram(); 416 const int posloc = glGetAttribLocation(prog, "a_pos"); 417 418 glUseProgram(prog); 419 glBindBuffer(GL_ARRAY_BUFFER, 0); 420 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 421 glEnableVertexAttribArray(posloc); 422 glVertexAttribPointer(posloc, 2, GL_FLOAT, 0, 0, &m_posBuf[0]); 423 glDrawElements(GL_TRIANGLES, (int)m_ndxBuf.size(), GL_UNSIGNED_SHORT, &m_ndxBuf[0]); 424 glDisableVertexAttribArray(posloc); 425 426 m_posBuf.clear(); 427 m_ndxBuf.clear(); 428 } 429 430 /*--------------------------------------------------------------------*//*! 431 * \brief Texture object helper class 432 * 433 * Each Texture owns a GL texture object that is created when the Texture 434 * is constructed and deleted when it's destructed. The class provides some 435 * convenience interface functions to e.g. upload texture data to the GL. 436 * 437 * In addition, the class tracks the approximate amount of GL memory likely 438 * used by the corresponding GL texture object; get this with 439 * getApproxMemUsage(). Also, getApproxMemUsageDiff() returns N-M, where N 440 * is the value that getApproxMemUsage() would return after a call to 441 * setData() with arguments corresponding to those given to 442 * getApproxMemUsageDiff(), and M is the value currently returned by 443 * getApproxMemUsage(). This can be used to check if we need to free some 444 * other memory before performing the setData() call, in case we have an 445 * upper limit on the amount of memory we want to use. 446 *//*--------------------------------------------------------------------*/ 447 class Texture 448 { 449 public: 450 Texture (TextureType type); 451 ~Texture (void); 452 453 // Functions that may change the value returned by getApproxMemUsage(). 454 void setData (const ConstPixelBufferAccess& src, int width, int height, deUint32 internalFormat, bool useMipmap); 455 456 // Functions that don't change the value returned by getApproxMemUsage(). 457 void setSubData (const ConstPixelBufferAccess& src, int xOff, int yOff, int width, int height) const; 458 void toUnit (int unit) const; 459 void setFilter (deUint32 min, deUint32 mag) const; 460 void setWrap (deUint32 s, deUint32 t) const; 461 462 int getApproxMemUsage (void) const { return m_dataSizeApprox; } 463 int getApproxMemUsageDiff (int width, int height, deUint32 internalFormat, bool useMipmap) const; 464 465 private: 466 Texture (const Texture&); // Not allowed. 467 Texture& operator= (const Texture&); // Not allowed. 468 469 static deUint32 genTexture (void) { deUint32 tex = 0; glGenTextures(1, &tex); return tex; } 470 471 deUint32 getGLBindTarget (void) const { DE_ASSERT(m_type == TEXTURETYPE_2D || m_type == TEXTURETYPE_CUBE); return m_type == TEXTURETYPE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP; } 472 473 const TextureType m_type; 474 const deUint32 m_textureGL; 475 476 int m_numMipLevels; 477 deUint32 m_internalFormat; 478 int m_dataSizeApprox; 479 }; 480 481 Texture::Texture (const TextureType type) 482 : m_type (type) 483 , m_textureGL (genTexture()) 484 , m_numMipLevels (0) 485 , m_internalFormat (0) 486 , m_dataSizeApprox (0) 487 { 488 } 489 490 Texture::~Texture (void) 491 { 492 glDeleteTextures(1, &m_textureGL); 493 } 494 495 int Texture::getApproxMemUsageDiff (const int width, const int height, const deUint32 internalFormat, const bool useMipmap) const 496 { 497 const int numLevels = useMipmap ? deLog2Floor32(de::max(width, height))+1 : 1; 498 const int pixelSize = internalFormat == GL_RGBA ? 4 499 : internalFormat == GL_RGB ? 3 500 : internalFormat == GL_ALPHA ? 1 501 : glu::mapGLInternalFormat(internalFormat).getPixelSize(); 502 int memUsageApproxAfter = 0; 503 504 for (int level = 0; level < numLevels; level++) 505 memUsageApproxAfter += de::max(1, width>>level) * de::max(1, height>>level) * pixelSize * (m_type == TEXTURETYPE_CUBE ? 6 : 1); 506 507 return memUsageApproxAfter - getApproxMemUsage(); 508 } 509 510 void Texture::setData (const ConstPixelBufferAccess& src, const int width, const int height, const deUint32 internalFormat, const bool useMipmap) 511 { 512 DE_ASSERT(m_type != TEXTURETYPE_CUBE || width == height); 513 DE_ASSERT(!useMipmap || (deIsPowerOfTwo32(width) && deIsPowerOfTwo32(height))); 514 515 const TextureFormat& format = src.getFormat(); 516 const glu::TransferFormat transfer = glu::getTransferFormat(format); 517 518 m_numMipLevels = useMipmap ? deLog2Floor32(de::max(width, height))+1 : 1; 519 520 m_internalFormat = internalFormat; 521 m_dataSizeApprox = width * height * format.getPixelSize() * (m_type == TEXTURETYPE_CUBE ? 6 : 1); 522 523 DE_ASSERT(src.getRowPitch() == format.getPixelSize()*src.getWidth()); 524 DE_ASSERT(isMatchingGLInternalFormat(internalFormat, format)); 525 DE_ASSERT(width <= src.getWidth() && height <= src.getHeight()); 526 527 glPixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(format)); 528 529 if (m_type == TEXTURETYPE_2D) 530 { 531 m_dataSizeApprox = 0; 532 533 glBindTexture(GL_TEXTURE_2D, m_textureGL); 534 for (int level = 0; level < m_numMipLevels; level++) 535 { 536 const int levelWid = de::max(1, width>>level); 537 const int levelHei = de::max(1, height>>level); 538 m_dataSizeApprox += levelWid * levelHei * format.getPixelSize(); 539 glTexImage2D(GL_TEXTURE_2D, level, internalFormat, levelWid, levelHei, 0, transfer.format, transfer.dataType, src.getDataPtr()); 540 } 541 } 542 else if (m_type == TEXTURETYPE_CUBE) 543 { 544 m_dataSizeApprox = 0; 545 546 glBindTexture(GL_TEXTURE_CUBE_MAP, m_textureGL); 547 for (int level = 0; level < m_numMipLevels; level++) 548 { 549 const int levelWid = de::max(1, width>>level); 550 const int levelHei = de::max(1, height>>level); 551 m_dataSizeApprox += 6 * levelWid * levelHei * format.getPixelSize(); 552 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 553 glTexImage2D(cubeFaceToGLFace((CubeFace)face), level, internalFormat, levelWid, levelHei, 0, transfer.format, transfer.dataType, src.getDataPtr()); 554 } 555 } 556 else 557 DE_ASSERT(false); 558 } 559 560 void Texture::setSubData (const ConstPixelBufferAccess& src, const int xOff, const int yOff, const int width, const int height) const 561 { 562 const TextureFormat& format = src.getFormat(); 563 const glu::TransferFormat transfer = glu::getTransferFormat(format); 564 565 DE_ASSERT(src.getRowPitch() == format.getPixelSize()*src.getWidth()); 566 DE_ASSERT(isMatchingGLInternalFormat(m_internalFormat, format)); 567 DE_ASSERT(width <= src.getWidth() && height <= src.getHeight()); 568 569 glPixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(format)); 570 571 if (m_type == TEXTURETYPE_2D) 572 { 573 glBindTexture(GL_TEXTURE_2D, m_textureGL); 574 for (int level = 0; level < m_numMipLevels; level++) 575 glTexSubImage2D(GL_TEXTURE_2D, level, xOff>>level, yOff>>level, de::max(1, width>>level), de::max(1, height>>level), transfer.format, transfer.dataType, src.getDataPtr()); 576 } 577 else if (m_type == TEXTURETYPE_CUBE) 578 { 579 glBindTexture(GL_TEXTURE_CUBE_MAP, m_textureGL); 580 for (int level = 0; level < m_numMipLevels; level++) 581 { 582 for (int face = 0; face < tcu::CUBEFACE_LAST; face++) 583 glTexSubImage2D(cubeFaceToGLFace((CubeFace)face), level, xOff>>level, yOff>>level, de::max(1, width>>level), de::max(1, height>>level), transfer.format, transfer.dataType, src.getDataPtr()); 584 } 585 } 586 else 587 DE_ASSERT(false); 588 } 589 590 void Texture::setFilter (const deUint32 min, const deUint32 mag) const 591 { 592 glBindTexture(getGLBindTarget(), m_textureGL); 593 glTexParameteri(getGLBindTarget(), GL_TEXTURE_MIN_FILTER, min); 594 glTexParameteri(getGLBindTarget(), GL_TEXTURE_MAG_FILTER, mag); 595 } 596 597 void Texture::setWrap (const deUint32 s, const deUint32 t) const 598 { 599 glBindTexture(getGLBindTarget(), m_textureGL); 600 glTexParameteri(getGLBindTarget(), GL_TEXTURE_WRAP_S, s); 601 glTexParameteri(getGLBindTarget(), GL_TEXTURE_WRAP_T, t); 602 } 603 604 void Texture::toUnit (const int unit) const 605 { 606 glActiveTexture(GL_TEXTURE0 + unit); 607 glBindTexture(getGLBindTarget(), m_textureGL); 608 } 609 610 /*--------------------------------------------------------------------*//*! 611 * \brief Buffer object helper class 612 * 613 * Each Buffer owns a GL buffer object that is created when the Buffer 614 * is constructed and deleted when it's destructed. The class provides some 615 * convenience interface functions to e.g. upload buffer data to the GL. 616 * 617 * In addition, the class tracks the approximate amount of GL memory, 618 * similarly to the Texture class (see above). The getApproxMemUsageDiff() 619 * is also analoguous. 620 *//*--------------------------------------------------------------------*/ 621 class Buffer 622 { 623 public: 624 Buffer (void); 625 ~Buffer (void); 626 627 // Functions that may change the value returned by getApproxMemUsage(). 628 template <typename T> 629 void setData (const vector<T>& src, const deUint32 target, const deUint32 usage) { setData(&src[0], (int)(src.size()*sizeof(T)), target, usage); } 630 void setData (const void* src, int size, deUint32 target, deUint32 usage); 631 632 // Functions that don't change the value returned by getApproxMemUsage(). 633 template <typename T> 634 void setSubData (const vector<T>& src, const int offsetElems, const int numElems, const deUint32 target) { setSubData(&src[offsetElems], offsetElems*(int)sizeof(T), numElems*(int)sizeof(T), target); } 635 void setSubData (const void* src, int offsetBytes, int sizeBytes, deUint32 target) const; 636 void bind (const deUint32 target) const { glBindBuffer(target, m_bufferGL); } 637 638 int getApproxMemUsage (void) const { return m_dataSizeApprox; } 639 template <typename T> 640 int getApproxMemUsageDiff (const vector<T>& src) const { return getApproxMemUsageDiff((int)(src.size()*sizeof(T))); } 641 int getApproxMemUsageDiff (const int sizeBytes) const { return sizeBytes - getApproxMemUsage(); } 642 643 private: 644 Buffer (const Buffer&); // Not allowed. 645 Buffer& operator= (const Buffer&); // Not allowed. 646 647 static deUint32 genBuffer (void) { deUint32 buf = 0; glGenBuffers(1, &buf); return buf; } 648 649 const deUint32 m_bufferGL; 650 int m_dataSizeApprox; 651 }; 652 653 Buffer::Buffer (void) 654 : m_bufferGL (genBuffer()) 655 , m_dataSizeApprox (0) 656 { 657 } 658 659 Buffer::~Buffer (void) 660 { 661 glDeleteBuffers(1, &m_bufferGL); 662 } 663 664 void Buffer::setData (const void* const src, const int size, const deUint32 target, const deUint32 usage) 665 { 666 bind(target); 667 glBufferData(target, size, src, usage); 668 glBindBuffer(target, 0); 669 670 m_dataSizeApprox = size; 671 } 672 673 void Buffer::setSubData (const void* const src, const int offsetBytes, const int sizeBytes, const deUint32 target) const 674 { 675 bind(target); 676 glBufferSubData(target, offsetBytes, sizeBytes, src); 677 glBindBuffer(target, 0); 678 } 679 680 class Program 681 { 682 public: 683 Program (void); 684 ~Program (void); 685 686 void setSources (const string& vertSource, const string& fragSource); 687 void build (TestLog& log); 688 void use (void) const { DE_ASSERT(m_isBuilt); glUseProgram(m_programGL); } 689 void setRandomUniforms (const vector<VarSpec>& uniforms, const string& shaderNameManglingSuffix, Random& rnd) const; 690 void setAttribute (const Buffer& attrBuf, int attrBufOffset, const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const; 691 void setAttributeClientMem (const void* attrData, const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const; 692 void disableAttributeArray (const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const; 693 694 private: 695 Program (const Program&); // Not allowed. 696 Program& operator= (const Program&); // Not allowed. 697 698 string m_vertSource; 699 string m_fragSource; 700 701 const deUint32 m_vertShaderGL; 702 const deUint32 m_fragShaderGL; 703 const deUint32 m_programGL; 704 bool m_hasSources; 705 bool m_isBuilt; 706 }; 707 708 Program::Program (void) 709 : m_vertShaderGL (glCreateShader(GL_VERTEX_SHADER)) 710 , m_fragShaderGL (glCreateShader(GL_FRAGMENT_SHADER)) 711 , m_programGL (glCreateProgram()) 712 , m_hasSources (false) 713 , m_isBuilt (false) 714 { 715 glAttachShader(m_programGL, m_vertShaderGL); 716 glAttachShader(m_programGL, m_fragShaderGL); 717 } 718 719 Program::~Program (void) 720 { 721 glDeleteShader(m_vertShaderGL); 722 glDeleteShader(m_fragShaderGL); 723 glDeleteProgram(m_programGL); 724 } 725 726 void Program::setSources (const string& vertSource, const string& fragSource) 727 { 728 const char* const vertSourceCstr = vertSource.c_str(); 729 const char* const fragSourceCstr = fragSource.c_str(); 730 731 m_vertSource = vertSource; 732 m_fragSource = fragSource; 733 734 // \note In GLES2 api the source parameter type lacks one const. 735 glShaderSource(m_vertShaderGL, 1, (const char**)&vertSourceCstr, DE_NULL); 736 glShaderSource(m_fragShaderGL, 1, (const char**)&fragSourceCstr, DE_NULL); 737 738 m_hasSources = true; 739 } 740 741 void Program::build (TestLog& log) 742 { 743 DE_ASSERT(m_hasSources); 744 745 const bool vertCompileOk = compileShader(m_vertShaderGL); 746 const bool fragCompileOk = compileShader(m_fragShaderGL); 747 const bool attemptLink = vertCompileOk && fragCompileOk; 748 const bool linkOk = attemptLink && linkProgram(m_programGL); 749 750 if (!(vertCompileOk && fragCompileOk && linkOk)) 751 { 752 log << TestLog::ShaderProgram(linkOk, attemptLink ? getProgramInfoLog(m_programGL) : string("")) 753 << TestLog::Shader(QP_SHADER_TYPE_VERTEX, m_vertSource, vertCompileOk, getShaderInfoLog(m_vertShaderGL)) 754 << TestLog::Shader(QP_SHADER_TYPE_FRAGMENT, m_fragSource, fragCompileOk, getShaderInfoLog(m_fragShaderGL)) 755 << TestLog::EndShaderProgram; 756 757 throw tcu::TestError("Program build failed"); 758 } 759 760 m_isBuilt = true; 761 } 762 763 void Program::setRandomUniforms (const vector<VarSpec>& uniforms, const string& shaderNameManglingSuffix, Random& rnd) const 764 { 765 use(); 766 767 for (int unifNdx = 0; unifNdx < (int)uniforms.size(); unifNdx++) 768 { 769 const VarSpec& spec = uniforms[unifNdx]; 770 const int typeScalarSize = glu::getDataTypeScalarSize(spec.type); 771 const int location = glGetUniformLocation(m_programGL, mangleShaderNames(spec.name, shaderNameManglingSuffix).c_str()); 772 if (location < 0) 773 continue; 774 775 if (glu::isDataTypeFloatOrVec(spec.type)) 776 { 777 float val[4]; 778 for (int i = 0; i < typeScalarSize; i++) 779 val[i] = rnd.getFloat(spec.minValue.f[i], spec.maxValue.f[i]); 780 781 switch (spec.type) 782 { 783 case glu::TYPE_FLOAT: glUniform1f(location, val[0]); break; 784 case glu::TYPE_FLOAT_VEC2: glUniform2f(location, val[0], val[1]); break; 785 case glu::TYPE_FLOAT_VEC3: glUniform3f(location, val[0], val[1], val[2]); break; 786 case glu::TYPE_FLOAT_VEC4: glUniform4f(location, val[0], val[1], val[2], val[3]); break; 787 default: DE_ASSERT(false); 788 } 789 } 790 else if (glu::isDataTypeMatrix(spec.type)) 791 { 792 float val[4*4]; 793 for (int i = 0; i < typeScalarSize; i++) 794 val[i] = rnd.getFloat(spec.minValue.f[i], spec.maxValue.f[i]); 795 796 switch (spec.type) 797 { 798 case glu::TYPE_FLOAT_MAT2: glUniformMatrix2fv (location, 1, GL_FALSE, &val[0]); break; 799 case glu::TYPE_FLOAT_MAT3: glUniformMatrix3fv (location, 1, GL_FALSE, &val[0]); break; 800 case glu::TYPE_FLOAT_MAT4: glUniformMatrix4fv (location, 1, GL_FALSE, &val[0]); break; 801 case glu::TYPE_FLOAT_MAT2X3: glUniformMatrix2x3fv (location, 1, GL_FALSE, &val[0]); break; 802 case glu::TYPE_FLOAT_MAT2X4: glUniformMatrix2x4fv (location, 1, GL_FALSE, &val[0]); break; 803 case glu::TYPE_FLOAT_MAT3X2: glUniformMatrix3x2fv (location, 1, GL_FALSE, &val[0]); break; 804 case glu::TYPE_FLOAT_MAT3X4: glUniformMatrix3x4fv (location, 1, GL_FALSE, &val[0]); break; 805 case glu::TYPE_FLOAT_MAT4X2: glUniformMatrix4x2fv (location, 1, GL_FALSE, &val[0]); break; 806 case glu::TYPE_FLOAT_MAT4X3: glUniformMatrix4x3fv (location, 1, GL_FALSE, &val[0]); break; 807 default: DE_ASSERT(false); 808 } 809 } 810 else if (glu::isDataTypeIntOrIVec(spec.type)) 811 { 812 int val[4]; 813 for (int i = 0; i < typeScalarSize; i++) 814 val[i] = rnd.getInt(spec.minValue.i[i], spec.maxValue.i[i]); 815 816 switch (spec.type) 817 { 818 case glu::TYPE_INT: glUniform1i(location, val[0]); break; 819 case glu::TYPE_INT_VEC2: glUniform2i(location, val[0], val[1]); break; 820 case glu::TYPE_INT_VEC3: glUniform3i(location, val[0], val[1], val[2]); break; 821 case glu::TYPE_INT_VEC4: glUniform4i(location, val[0], val[1], val[2], val[3]); break; 822 default: DE_ASSERT(false); 823 } 824 } 825 else if (glu::isDataTypeUintOrUVec(spec.type)) 826 { 827 deUint32 val[4]; 828 for (int i = 0; i < typeScalarSize; i++) 829 { 830 DE_ASSERT(spec.minValue.i[i] >= 0 && spec.maxValue.i[i] >= 0); 831 val[i] = (deUint32)rnd.getInt(spec.minValue.i[i], spec.maxValue.i[i]); 832 } 833 834 switch (spec.type) 835 { 836 case glu::TYPE_UINT: glUniform1ui(location, val[0]); break; 837 case glu::TYPE_UINT_VEC2: glUniform2ui(location, val[0], val[1]); break; 838 case glu::TYPE_UINT_VEC3: glUniform3ui(location, val[0], val[1], val[2]); break; 839 case glu::TYPE_UINT_VEC4: glUniform4ui(location, val[0], val[1], val[2], val[3]); break; 840 default: DE_ASSERT(false); 841 } 842 } 843 else 844 DE_ASSERT(false); 845 } 846 } 847 848 void Program::setAttribute (const Buffer& attrBuf, const int attrBufOffset, const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const 849 { 850 const int attrLoc = glGetAttribLocation(m_programGL, mangleShaderNames(attrSpec.name, shaderNameManglingSuffix).c_str()); 851 852 glEnableVertexAttribArray(attrLoc); 853 attrBuf.bind(GL_ARRAY_BUFFER); 854 855 if (glu::isDataTypeFloatOrVec(attrSpec.type)) 856 glVertexAttribPointer(attrLoc, glu::getDataTypeScalarSize(attrSpec.type), GL_FLOAT, GL_FALSE, 0, (GLvoid*)(deIntptr)attrBufOffset); 857 else 858 DE_ASSERT(false); 859 } 860 861 void Program::setAttributeClientMem (const void* const attrData, const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const 862 { 863 const int attrLoc = glGetAttribLocation(m_programGL, mangleShaderNames(attrSpec.name, shaderNameManglingSuffix).c_str()); 864 865 glEnableVertexAttribArray(attrLoc); 866 glBindBuffer(GL_ARRAY_BUFFER, 0); 867 868 if (glu::isDataTypeFloatOrVec(attrSpec.type)) 869 glVertexAttribPointer(attrLoc, glu::getDataTypeScalarSize(attrSpec.type), GL_FLOAT, GL_FALSE, 0, attrData); 870 else 871 DE_ASSERT(false); 872 } 873 874 void Program::disableAttributeArray (const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const 875 { 876 const int attrLoc = glGetAttribLocation(m_programGL, mangleShaderNames(attrSpec.name, shaderNameManglingSuffix).c_str()); 877 878 glDisableVertexAttribArray(attrLoc); 879 } 880 881 /*--------------------------------------------------------------------*//*! 882 * \brief Container class for managing GL objects 883 * 884 * GLObjectManager can be used for objects of class Program, Buffer or 885 * Texture. In the manager, each such object is associated with a name that 886 * is used to access it. 887 * 888 * In addition to the making, getting and removing functions, the manager 889 * supports marking objects as "garbage", meaning they're not yet 890 * destroyed, but can be later destroyed with removeRandomGarbage(). The 891 * idea is that if we want to stress test with high memory usage, we can 892 * continuously move objects to garbage after using them, and when a memory 893 * limit is reached, we can call removeGarbageUntilUnder(limit, rnd). This 894 * way we can approximately keep our memory usage at just under the wanted 895 * limit. 896 * 897 * The manager also supports querying the approximate amount of GL memory 898 * used by its objects. 899 * 900 * \note The memory usage related functions are not currently supported 901 * for Program objects. 902 *//*--------------------------------------------------------------------*/ 903 template <typename T> 904 class GLObjectManager 905 { 906 public: 907 void make (const string& name) { DE_ASSERT(!has(name)); m_objects[name] = SharedPtr<T>(new T); } 908 void make (const string& name, gls::TextureType texType) { DE_ASSERT(!has(name)); m_objects[name] = SharedPtr<T>(new T(texType)); } 909 bool has (const string& name) const { return m_objects.find(name) != m_objects.end(); } 910 const T& get (const string& name) const; 911 T& get (const string& name) { return const_cast<T&>(((const GLObjectManager<T>*)this)->get(name)); } 912 void remove (const string& name) { const int removed = (int)m_objects.erase(name); DE_ASSERT(removed); DE_UNREF(removed); } 913 int computeApproxMemUsage (void) const; 914 void markAsGarbage (const string& name); 915 int removeRandomGarbage (Random& rnd); 916 void removeGarbageUntilUnder (int limit, Random& rnd); 917 918 private: 919 static const char* objTypeName (void); 920 921 map<string, SharedPtr<T> > m_objects; 922 vector<SharedPtr<T> > m_garbageObjects; 923 }; 924 925 template <> const char* GLObjectManager<Buffer>::objTypeName (void) { return "buffer"; } 926 template <> const char* GLObjectManager<Texture>::objTypeName (void) { return "texture"; } 927 template <> const char* GLObjectManager<Program>::objTypeName (void) { return "program"; } 928 929 template <typename T> 930 const T& GLObjectManager<T>::get (const string& name) const 931 { 932 const typename map<string, SharedPtr<T> >::const_iterator it = m_objects.find(name); 933 DE_ASSERT(it != m_objects.end()); 934 return *it->second; 935 } 936 937 template <typename T> 938 int GLObjectManager<T>::computeApproxMemUsage (void) const 939 { 940 int result = 0; 941 942 for (typename map<string, SharedPtr<T> >::const_iterator it = m_objects.begin(); it != m_objects.end(); ++it) 943 result += it->second->getApproxMemUsage(); 944 945 for (typename vector<SharedPtr<T> >::const_iterator it = m_garbageObjects.begin(); it != m_garbageObjects.end(); ++it) 946 result += (*it)->getApproxMemUsage(); 947 948 return result; 949 } 950 951 template <typename T> 952 void GLObjectManager<T>::markAsGarbage (const string& name) 953 { 954 const typename map<string, SharedPtr<T> >::iterator it = m_objects.find(name); 955 DE_ASSERT(it != m_objects.end()); 956 m_garbageObjects.push_back(it->second); 957 m_objects.erase(it); 958 } 959 960 template <typename T> 961 int GLObjectManager<T>::removeRandomGarbage (Random& rnd) 962 { 963 if (m_garbageObjects.empty()) 964 return -1; 965 966 const int removeNdx = rnd.getInt(0, (int)m_garbageObjects.size()-1); 967 const int memoryFreed = m_garbageObjects[removeNdx]->getApproxMemUsage(); 968 m_garbageObjects.erase(m_garbageObjects.begin() + removeNdx); 969 return memoryFreed; 970 } 971 972 template <typename T> 973 void GLObjectManager<T>::removeGarbageUntilUnder (const int limit, Random& rnd) 974 { 975 int memUsage = computeApproxMemUsage(); 976 977 while (memUsage > limit) 978 { 979 const int memReleased = removeRandomGarbage(rnd); 980 if (memReleased < 0) 981 throw tcu::InternalError(string("") + "Given " + objTypeName() + " memory usage limit exceeded, and no unneeded " + objTypeName() + " resources available to release"); 982 memUsage -= memReleased; 983 DE_ASSERT(memUsage == computeApproxMemUsage()); 984 } 985 } 986 987 } // LongStressCaseInternal 988 989 using namespace LongStressCaseInternal; 990 991 static int generateRandomAttribData (vector<deUint8>& attrDataBuf, int& dataSizeBytesDst, const VarSpec& attrSpec, const int numVertices, Random& rnd) 992 { 993 const bool isFloat = glu::isDataTypeFloatOrVec(attrSpec.type); 994 const int numComponents = glu::getDataTypeScalarSize(attrSpec.type); 995 const int componentSize = (int)(isFloat ? sizeof(GLfloat) : sizeof(GLint)); 996 const int offsetInBuf = nextDivisible((int)attrDataBuf.size(), componentSize); // Round up for alignment. 997 998 DE_STATIC_ASSERT(sizeof(GLint) == sizeof(int)); 999 DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(float)); 1000 1001 dataSizeBytesDst = numComponents*componentSize*numVertices; 1002 1003 attrDataBuf.resize(offsetInBuf + dataSizeBytesDst); 1004 1005 if (isFloat) 1006 { 1007 float* const data = (float*)&attrDataBuf[offsetInBuf]; 1008 1009 for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx++) 1010 for (int compNdx = 0; compNdx < numComponents; compNdx++) 1011 data[vtxNdx*numComponents + compNdx] = rnd.getFloat(attrSpec.minValue.f[compNdx], attrSpec.maxValue.f[compNdx]); 1012 } 1013 else 1014 { 1015 DE_ASSERT(glu::isDataTypeIntOrIVec(attrSpec.type)); 1016 1017 int* const data = (int*)&attrDataBuf[offsetInBuf]; 1018 1019 for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx++) 1020 for (int compNdx = 0; compNdx < numComponents; compNdx++) 1021 data[vtxNdx*numComponents + compNdx] = rnd.getInt(attrSpec.minValue.i[compNdx], attrSpec.maxValue.i[compNdx]); 1022 } 1023 1024 return offsetInBuf; 1025 } 1026 1027 static int generateRandomPositionAttribData (vector<deUint8>& attrDataBuf, int& dataSizeBytesDst, const VarSpec& attrSpec, const int numVertices, Random& rnd) 1028 { 1029 DE_ASSERT(glu::isDataTypeFloatOrVec(attrSpec.type)); 1030 1031 const int numComponents = glu::getDataTypeScalarSize(attrSpec.type); 1032 DE_ASSERT(numComponents >= 2); 1033 const int offsetInBuf = generateRandomAttribData(attrDataBuf, dataSizeBytesDst, attrSpec, numVertices, rnd); 1034 1035 if (numComponents > 2) 1036 { 1037 float* const data = (float*)&attrDataBuf[offsetInBuf]; 1038 1039 for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx++) 1040 data[vtxNdx*numComponents + 2] = -1.0f; 1041 1042 for (int triNdx = 0; triNdx < numVertices-2; triNdx++) 1043 { 1044 float* const vtxAComps = &data[(triNdx+0)*numComponents]; 1045 float* const vtxBComps = &data[(triNdx+1)*numComponents]; 1046 float* const vtxCComps = &data[(triNdx+2)*numComponents]; 1047 1048 const float triArea = triangleArea(Vec2(vtxAComps[0], vtxAComps[1]), 1049 Vec2(vtxBComps[0], vtxBComps[1]), 1050 Vec2(vtxCComps[0], vtxCComps[1])); 1051 const float t = triArea / (triArea + 1.0f); 1052 const float z = (1.0f-t)*attrSpec.minValue.f[2] + t*attrSpec.maxValue.f[2]; 1053 1054 vtxAComps[2] = de::max(vtxAComps[2], z); 1055 vtxBComps[2] = de::max(vtxBComps[2], z); 1056 vtxCComps[2] = de::max(vtxCComps[2], z); 1057 } 1058 } 1059 1060 return offsetInBuf; 1061 } 1062 1063 static void generateAttribs (vector<deUint8>& attrDataBuf, vector<int>& attrDataOffsets, vector<int>& attrDataSizes, const vector<VarSpec>& attrSpecs, const string& posAttrName, const int numVertices, Random& rnd) 1064 { 1065 attrDataBuf.clear(); 1066 attrDataOffsets.clear(); 1067 attrDataSizes.resize(attrSpecs.size()); 1068 1069 for (int i = 0; i < (int)attrSpecs.size(); i++) 1070 { 1071 if (attrSpecs[i].name == posAttrName) 1072 attrDataOffsets.push_back(generateRandomPositionAttribData(attrDataBuf, attrDataSizes[i], attrSpecs[i], numVertices, rnd)); 1073 else 1074 attrDataOffsets.push_back(generateRandomAttribData(attrDataBuf, attrDataSizes[i], attrSpecs[i], numVertices, rnd)); 1075 } 1076 } 1077 1078 LongStressCase::LongStressCase (tcu::TestContext& testCtx, 1079 const glu::RenderContext& renderCtx, 1080 const char* const name, 1081 const char* const desc, 1082 const int maxTexMemoryUsageBytes, 1083 const int maxBufMemoryUsageBytes, 1084 const int numDrawCallsPerIteration, 1085 const int numTrianglesPerDrawCall, 1086 const vector<ProgramContext>& programContexts, 1087 const FeatureProbabilities& probabilities, 1088 const deUint32 indexBufferUsage, 1089 const deUint32 attrBufferUsage, 1090 const int redundantBufferFactor, 1091 const bool showDebugInfo) 1092 : tcu::TestCase (testCtx, name, desc) 1093 , m_renderCtx (renderCtx) 1094 , m_maxTexMemoryUsageBytes (maxTexMemoryUsageBytes) 1095 , m_maxBufMemoryUsageBytes (maxBufMemoryUsageBytes) 1096 , m_numDrawCallsPerIteration (numDrawCallsPerIteration) 1097 , m_numTrianglesPerDrawCall (numTrianglesPerDrawCall) 1098 , m_numVerticesPerDrawCall (numTrianglesPerDrawCall+2) // \note Triangle strips are used. 1099 , m_programContexts (programContexts) 1100 , m_probabilities (probabilities) 1101 , m_indexBufferUsage (indexBufferUsage) 1102 , m_attrBufferUsage (attrBufferUsage) 1103 , m_redundantBufferFactor (redundantBufferFactor) 1104 , m_showDebugInfo (showDebugInfo) 1105 , m_numIterations (getNumIterations(testCtx, 5)) 1106 , m_isGLES3 (contextSupports(renderCtx.getType(), glu::ApiType::es(3,0))) 1107 , m_currentIteration (0) 1108 , m_startTimeSeconds ((deUint64)-1) 1109 , m_lastLogTime ((deUint64)-1) 1110 , m_lastLogIteration (0) 1111 , m_currentLogEntryNdx (0) 1112 , m_rnd (deStringHash(getName()) ^ testCtx.getCommandLine().getBaseSeed()) 1113 , m_programs (DE_NULL) 1114 , m_buffers (DE_NULL) 1115 , m_textures (DE_NULL) 1116 , m_debugInfoRenderer (DE_NULL) 1117 { 1118 DE_ASSERT(m_numVerticesPerDrawCall <= (int)std::numeric_limits<deUint16>::max()+1); // \note Vertices are referred to with 16-bit indices. 1119 DE_ASSERT(m_redundantBufferFactor > 0); 1120 } 1121 1122 LongStressCase::~LongStressCase (void) 1123 { 1124 LongStressCase::deinit(); 1125 } 1126 1127 void LongStressCase::init (void) 1128 { 1129 // Generate dummy texture data for each texture spec in m_programContexts. 1130 1131 DE_ASSERT(!m_programContexts.empty()); 1132 DE_ASSERT(m_programResources.empty()); 1133 m_programResources.resize(m_programContexts.size()); 1134 1135 for (int progCtxNdx = 0; progCtxNdx < (int)m_programContexts.size(); progCtxNdx++) 1136 { 1137 const ProgramContext& progCtx = m_programContexts[progCtxNdx]; 1138 ProgramResources& progRes = m_programResources[progCtxNdx]; 1139 1140 for (int texSpecNdx = 0; texSpecNdx < (int)progCtx.textureSpecs.size(); texSpecNdx++) 1141 { 1142 const TextureSpec& spec = progCtx.textureSpecs[texSpecNdx]; 1143 const TextureFormat format = glu::mapGLTransferFormat(spec.format, spec.dataType); 1144 1145 // If texture data with the same format has already been generated, re-use that (don't care much about contents). 1146 1147 SharedPtr<TextureLevel> dummyTex; 1148 1149 for (int prevProgCtxNdx = 0; prevProgCtxNdx < (int)m_programResources.size(); prevProgCtxNdx++) 1150 { 1151 const vector<SharedPtr<TextureLevel> >& prevProgCtxTextures = m_programResources[prevProgCtxNdx].dummyTextures; 1152 1153 for (int texNdx = 0; texNdx < (int)prevProgCtxTextures.size(); texNdx++) 1154 { 1155 if (prevProgCtxTextures[texNdx]->getFormat() == format) 1156 { 1157 dummyTex = prevProgCtxTextures[texNdx]; 1158 break; 1159 } 1160 } 1161 } 1162 1163 if (!dummyTex) 1164 dummyTex = SharedPtr<TextureLevel>(new TextureLevel(format)); 1165 1166 if (dummyTex->getWidth() < spec.width || dummyTex->getHeight() < spec.height) 1167 { 1168 dummyTex->setSize(spec.width, spec.height); 1169 tcu::fillWithComponentGradients(dummyTex->getAccess(), spec.minValue, spec.maxValue); 1170 } 1171 1172 progRes.dummyTextures.push_back(dummyTex); 1173 } 1174 } 1175 1176 m_vertexIndices.clear(); 1177 for (int i = 0; i < m_numVerticesPerDrawCall; i++) 1178 m_vertexIndices.push_back((deUint16)i); 1179 m_rnd.shuffle(m_vertexIndices.begin(), m_vertexIndices.end()); 1180 1181 DE_ASSERT(!m_programs && !m_buffers && !m_textures); 1182 m_programs = new GLObjectManager<Program>; 1183 m_buffers = new GLObjectManager<Buffer>; 1184 m_textures = new GLObjectManager<Texture>; 1185 1186 m_currentIteration = 0; 1187 1188 { 1189 TestLog& log = m_testCtx.getLog(); 1190 1191 log << TestLog::Message << "Number of iterations: " << (m_numIterations > 0 ? toString(m_numIterations) : "infinite") << TestLog::EndMessage 1192 << TestLog::Message << "Number of draw calls per iteration: " << m_numDrawCallsPerIteration << TestLog::EndMessage 1193 << TestLog::Message << "Number of triangles per draw call: " << m_numTrianglesPerDrawCall << TestLog::EndMessage 1194 << TestLog::Message << "Using triangle strips" << TestLog::EndMessage 1195 << TestLog::Message << "Approximate texture memory usage limit: " << de::floatToString((float)m_maxTexMemoryUsageBytes / Mi, 2) << " MiB" << TestLog::EndMessage 1196 << TestLog::Message << "Approximate buffer memory usage limit: " << de::floatToString((float)m_maxBufMemoryUsageBytes / Mi, 2) << " MiB" << TestLog::EndMessage 1197 << TestLog::Message << "Default vertex attribute data buffer usage parameter: " << glu::getUsageName(m_attrBufferUsage) << TestLog::EndMessage 1198 << TestLog::Message << "Default vertex index data buffer usage parameter: " << glu::getUsageName(m_indexBufferUsage) << TestLog::EndMessage 1199 1200 << TestLog::Section("ProbabilityParams", "Per-iteration probability parameters") 1201 << TestLog::Message << "Program re-build: " << probabilityStr(m_probabilities.rebuildProgram) << TestLog::EndMessage 1202 << TestLog::Message << "Texture re-upload: " << probabilityStr(m_probabilities.reuploadTexture) << TestLog::EndMessage 1203 << TestLog::Message << "Buffer re-upload: " << probabilityStr(m_probabilities.reuploadBuffer) << TestLog::EndMessage 1204 << TestLog::Message << "Use glTexImage* instead of glTexSubImage* when uploading texture: " << probabilityStr(m_probabilities.reuploadWithTexImage) << TestLog::EndMessage 1205 << TestLog::Message << "Use glBufferData* instead of glBufferSubData* when uploading buffer: " << probabilityStr(m_probabilities.reuploadWithBufferData) << TestLog::EndMessage 1206 << TestLog::Message << "Delete texture after using it, even if could re-use it: " << probabilityStr(m_probabilities.deleteTexture) << TestLog::EndMessage 1207 << TestLog::Message << "Delete buffer after using it, even if could re-use it: " << probabilityStr(m_probabilities.deleteBuffer) << TestLog::EndMessage 1208 << TestLog::Message << "Don't re-use texture, and only delete if memory limit is hit: " << probabilityStr(m_probabilities.wastefulTextureMemoryUsage) << TestLog::EndMessage 1209 << TestLog::Message << "Don't re-use buffer, and only delete if memory limit is hit: " << probabilityStr(m_probabilities.wastefulBufferMemoryUsage) << TestLog::EndMessage 1210 << TestLog::Message << "Use client memory (instead of GL buffers) for vertex attribute data: " << probabilityStr(m_probabilities.clientMemoryAttributeData) << TestLog::EndMessage 1211 << TestLog::Message << "Use client memory (instead of GL buffers) for vertex index data: " << probabilityStr(m_probabilities.clientMemoryIndexData) << TestLog::EndMessage 1212 << TestLog::Message << "Use random target parameter when uploading buffer data: " << probabilityStr(m_probabilities.randomBufferUploadTarget) << TestLog::EndMessage 1213 << TestLog::Message << "Use random usage parameter when uploading buffer data: " << probabilityStr(m_probabilities.randomBufferUsage) << TestLog::EndMessage 1214 << TestLog::Message << "Use glDrawArrays instead of glDrawElements: " << probabilityStr(m_probabilities.useDrawArrays) << TestLog::EndMessage 1215 << TestLog::Message << "Use separate buffers for each attribute, instead of one array for all: " << probabilityStr(m_probabilities.separateAttributeBuffers) << TestLog::EndMessage 1216 << TestLog::EndSection 1217 << TestLog::Message << "Using " << m_programContexts.size() << " program(s)" << TestLog::EndMessage; 1218 1219 bool anyProgramsFailed = false; 1220 for (int progCtxNdx = 0; progCtxNdx < (int)m_programContexts.size(); progCtxNdx++) 1221 { 1222 const ProgramContext& progCtx = m_programContexts[progCtxNdx]; 1223 glu::ShaderProgram prog(m_renderCtx, glu::makeVtxFragSources(mangleShaderNames(progCtx.vertexSource, ""), mangleShaderNames(progCtx.fragmentSource, ""))); 1224 log << TestLog::Section("ShaderProgram" + toString(progCtxNdx), "Shader program " + toString(progCtxNdx)) << prog << TestLog::EndSection; 1225 if (!prog.isOk()) 1226 anyProgramsFailed = true; 1227 } 1228 1229 if (anyProgramsFailed) 1230 throw tcu::TestError("One or more shader programs failed to compile"); 1231 } 1232 1233 DE_ASSERT(!m_debugInfoRenderer); 1234 if (m_showDebugInfo) 1235 m_debugInfoRenderer = new DebugInfoRenderer(m_renderCtx); 1236 } 1237 1238 void LongStressCase::deinit (void) 1239 { 1240 m_programResources.clear(); 1241 1242 delete m_programs; 1243 m_programs = DE_NULL; 1244 1245 delete m_buffers; 1246 m_buffers = DE_NULL; 1247 1248 delete m_textures; 1249 m_textures = DE_NULL; 1250 1251 delete m_debugInfoRenderer; 1252 m_debugInfoRenderer = DE_NULL; 1253 } 1254 1255 LongStressCase::IterateResult LongStressCase::iterate (void) 1256 { 1257 TestLog& log = m_testCtx.getLog(); 1258 const int renderWidth = m_renderCtx.getRenderTarget().getWidth(); 1259 const int renderHeight = m_renderCtx.getRenderTarget().getHeight(); 1260 const bool useClientMemoryIndexData = m_rnd.getFloat() < m_probabilities.clientMemoryIndexData; 1261 const bool useDrawArrays = m_rnd.getFloat() < m_probabilities.useDrawArrays; 1262 const bool separateAttributeBuffers = m_rnd.getFloat() < m_probabilities.separateAttributeBuffers; 1263 const int progContextNdx = m_rnd.getInt(0, (int)m_programContexts.size()-1); 1264 const ProgramContext& programContext = m_programContexts[progContextNdx]; 1265 ProgramResources& programResources = m_programResources[progContextNdx]; 1266 const string programName = "prog" + toString(progContextNdx); 1267 const string textureNamePrefix = "tex" + toString(progContextNdx) + "_"; 1268 const string unitedAttrBufferNamePrefix = "attrBuf" + toString(progContextNdx) + "_"; 1269 const string indexBufferName = "indexBuf" + toString(progContextNdx); 1270 const string separateAttrBufNamePrefix = "attrBuf" + toString(progContextNdx) + "_"; 1271 1272 if (m_currentIteration == 0) 1273 m_lastLogTime = m_startTimeSeconds = deGetTime(); 1274 1275 // Make or re-compile programs. 1276 { 1277 const bool hadProgram = m_programs->has(programName); 1278 1279 if (!hadProgram) 1280 m_programs->make(programName); 1281 1282 Program& prog = m_programs->get(programName); 1283 1284 if (!hadProgram || m_rnd.getFloat() < m_probabilities.rebuildProgram) 1285 { 1286 programResources.shaderNameManglingSuffix = toString((deUint16)deUint64Hash((deUint64)m_currentIteration ^ deGetTime())); 1287 1288 prog.setSources(mangleShaderNames(programContext.vertexSource, programResources.shaderNameManglingSuffix), 1289 mangleShaderNames(programContext.fragmentSource, programResources.shaderNameManglingSuffix)); 1290 1291 prog.build(log); 1292 } 1293 1294 prog.use(); 1295 } 1296 1297 Program& program = m_programs->get(programName); 1298 1299 // Make or re-upload textures. 1300 1301 for (int texNdx = 0; texNdx < (int)programContext.textureSpecs.size(); texNdx++) 1302 { 1303 const string texName = textureNamePrefix + toString(texNdx); 1304 const bool hadTexture = m_textures->has(texName); 1305 const TextureSpec& spec = programContext.textureSpecs[texNdx]; 1306 1307 if (!hadTexture) 1308 m_textures->make(texName, spec.textureType); 1309 1310 if (!hadTexture || m_rnd.getFloat() < m_probabilities.reuploadTexture) 1311 { 1312 Texture& texture = m_textures->get(texName); 1313 1314 m_textures->removeGarbageUntilUnder(m_maxTexMemoryUsageBytes - texture.getApproxMemUsageDiff(spec.width, spec.height, spec.internalFormat, spec.useMipmap), m_rnd); 1315 1316 if (!hadTexture || m_rnd.getFloat() < m_probabilities.reuploadWithTexImage) 1317 texture.setData(programResources.dummyTextures[texNdx]->getAccess(), spec.width, spec.height, spec.internalFormat, spec.useMipmap); 1318 else 1319 texture.setSubData(programResources.dummyTextures[texNdx]->getAccess(), 0, 0, spec.width, spec.height); 1320 1321 texture.toUnit(0); 1322 texture.setWrap(spec.sWrap, spec.tWrap); 1323 texture.setFilter(spec.minFilter, spec.magFilter); 1324 } 1325 } 1326 1327 // Bind textures to units, in random order (because when multiple texture specs have same unit, we want to pick one randomly). 1328 1329 { 1330 vector<int> texSpecIndices(programContext.textureSpecs.size()); 1331 for (int i = 0; i < (int)texSpecIndices.size(); i++) 1332 texSpecIndices[i] = i; 1333 m_rnd.shuffle(texSpecIndices.begin(), texSpecIndices.end()); 1334 for (int i = 0; i < (int)texSpecIndices.size(); i++) 1335 m_textures->get(textureNamePrefix + toString(texSpecIndices[i])).toUnit(programContext.textureSpecs[i].textureUnit); 1336 } 1337 1338 // Make or re-upload index buffer. 1339 1340 if (!useDrawArrays) 1341 { 1342 m_rnd.shuffle(m_vertexIndices.begin(), m_vertexIndices.end()); 1343 1344 if (!useClientMemoryIndexData) 1345 { 1346 const bool hadIndexBuffer = m_buffers->has(indexBufferName); 1347 1348 if (!hadIndexBuffer) 1349 m_buffers->make(indexBufferName); 1350 1351 Buffer& indexBuf = m_buffers->get(indexBufferName); 1352 1353 if (!hadIndexBuffer || m_rnd.getFloat() < m_probabilities.reuploadBuffer) 1354 { 1355 m_buffers->removeGarbageUntilUnder(m_maxBufMemoryUsageBytes - indexBuf.getApproxMemUsageDiff(m_vertexIndices), m_rnd); 1356 const deUint32 target = m_rnd.getFloat() < m_probabilities.randomBufferUploadTarget ? randomBufferTarget(m_rnd, m_isGLES3) : GL_ELEMENT_ARRAY_BUFFER; 1357 1358 if (!hadIndexBuffer || m_rnd.getFloat() < m_probabilities.reuploadWithBufferData) 1359 indexBuf.setData(m_vertexIndices, target, m_rnd.getFloat() < m_probabilities.randomBufferUsage ? randomBufferUsage(m_rnd, m_isGLES3) : m_indexBufferUsage); 1360 else 1361 indexBuf.setSubData(m_vertexIndices, 0, m_numVerticesPerDrawCall, target); 1362 } 1363 } 1364 } 1365 1366 // Set vertex attributes. If not using client-memory data, make or re-upload attribute buffers. 1367 1368 generateAttribs(programResources.attrDataBuf, programResources.attrDataOffsets, programResources.attrDataSizes, 1369 programContext.attributes, programContext.positionAttrName, m_numVerticesPerDrawCall, m_rnd); 1370 1371 if (!(m_rnd.getFloat() < m_probabilities.clientMemoryAttributeData)) 1372 { 1373 if (separateAttributeBuffers) 1374 { 1375 for (int attrNdx = 0; attrNdx < (int)programContext.attributes.size(); attrNdx++) 1376 { 1377 const int usedRedundantBufferNdx = m_rnd.getInt(0, m_redundantBufferFactor-1); 1378 1379 for (int redundantBufferNdx = 0; redundantBufferNdx < m_redundantBufferFactor; redundantBufferNdx++) 1380 { 1381 const string curAttrBufName = separateAttrBufNamePrefix + toString(attrNdx) + "_" + toString(redundantBufferNdx); 1382 const bool hadCurAttrBuffer = m_buffers->has(curAttrBufName); 1383 1384 if (!hadCurAttrBuffer) 1385 m_buffers->make(curAttrBufName); 1386 1387 Buffer& curAttrBuf = m_buffers->get(curAttrBufName); 1388 1389 if (!hadCurAttrBuffer || m_rnd.getFloat() < m_probabilities.reuploadBuffer) 1390 { 1391 m_buffers->removeGarbageUntilUnder(m_maxBufMemoryUsageBytes - curAttrBuf.getApproxMemUsageDiff(programResources.attrDataSizes[attrNdx]), m_rnd); 1392 const deUint32 target = m_rnd.getFloat() < m_probabilities.randomBufferUploadTarget ? randomBufferTarget(m_rnd, m_isGLES3) : GL_ARRAY_BUFFER; 1393 1394 if (!hadCurAttrBuffer || m_rnd.getFloat() < m_probabilities.reuploadWithBufferData) 1395 curAttrBuf.setData(&programResources.attrDataBuf[programResources.attrDataOffsets[attrNdx]], programResources.attrDataSizes[attrNdx], target, 1396 m_rnd.getFloat() < m_probabilities.randomBufferUsage ? randomBufferUsage(m_rnd, m_isGLES3) : m_attrBufferUsage); 1397 else 1398 curAttrBuf.setSubData(&programResources.attrDataBuf[programResources.attrDataOffsets[attrNdx]], 0, programResources.attrDataSizes[attrNdx], target); 1399 } 1400 1401 if (redundantBufferNdx == usedRedundantBufferNdx) 1402 program.setAttribute(curAttrBuf, 0, programContext.attributes[attrNdx], programResources.shaderNameManglingSuffix); 1403 } 1404 } 1405 } 1406 else 1407 { 1408 const int usedRedundantBufferNdx = m_rnd.getInt(0, m_redundantBufferFactor-1); 1409 1410 for (int redundantBufferNdx = 0; redundantBufferNdx < m_redundantBufferFactor; redundantBufferNdx++) 1411 { 1412 const string attrBufName = unitedAttrBufferNamePrefix + toString(redundantBufferNdx); 1413 const bool hadAttrBuffer = m_buffers->has(attrBufName); 1414 1415 if (!hadAttrBuffer) 1416 m_buffers->make(attrBufName); 1417 1418 Buffer& attrBuf = m_buffers->get(attrBufName); 1419 1420 if (!hadAttrBuffer || m_rnd.getFloat() < m_probabilities.reuploadBuffer) 1421 { 1422 m_buffers->removeGarbageUntilUnder(m_maxBufMemoryUsageBytes - attrBuf.getApproxMemUsageDiff(programResources.attrDataBuf), m_rnd); 1423 const deUint32 target = m_rnd.getFloat() < m_probabilities.randomBufferUploadTarget ? randomBufferTarget(m_rnd, m_isGLES3) : GL_ARRAY_BUFFER; 1424 1425 if (!hadAttrBuffer || m_rnd.getFloat() < m_probabilities.reuploadWithBufferData) 1426 attrBuf.setData(programResources.attrDataBuf, target, m_rnd.getFloat() < m_probabilities.randomBufferUsage ? randomBufferUsage(m_rnd, m_isGLES3) : m_attrBufferUsage); 1427 else 1428 attrBuf.setSubData(programResources.attrDataBuf, 0, (int)programResources.attrDataBuf.size(), target); 1429 } 1430 1431 if (redundantBufferNdx == usedRedundantBufferNdx) 1432 { 1433 for (int i = 0; i < (int)programContext.attributes.size(); i++) 1434 program.setAttribute(attrBuf, programResources.attrDataOffsets[i], programContext.attributes[i], programResources.shaderNameManglingSuffix); 1435 } 1436 } 1437 } 1438 } 1439 else 1440 { 1441 for (int i = 0; i < (int)programContext.attributes.size(); i++) 1442 program.setAttributeClientMem(&programResources.attrDataBuf[programResources.attrDataOffsets[i]], programContext.attributes[i], programResources.shaderNameManglingSuffix); 1443 } 1444 1445 // Draw. 1446 1447 glViewport(0, 0, renderWidth, renderHeight); 1448 1449 glClearDepthf(1.0f); 1450 glClear(GL_DEPTH_BUFFER_BIT); 1451 glEnable(GL_DEPTH_TEST); 1452 1453 for (int i = 0; i < m_numDrawCallsPerIteration; i++) 1454 { 1455 program.use(); 1456 program.setRandomUniforms(programContext.uniforms, programResources.shaderNameManglingSuffix, m_rnd); 1457 1458 if (useDrawArrays) 1459 glDrawArrays(GL_TRIANGLE_STRIP, 0, m_numVerticesPerDrawCall); 1460 else 1461 { 1462 if (useClientMemoryIndexData) 1463 { 1464 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 1465 glDrawElements(GL_TRIANGLE_STRIP, m_numVerticesPerDrawCall, GL_UNSIGNED_SHORT, &m_vertexIndices[0]); 1466 } 1467 else 1468 { 1469 m_buffers->get(indexBufferName).bind(GL_ELEMENT_ARRAY_BUFFER); 1470 glDrawElements(GL_TRIANGLE_STRIP, m_numVerticesPerDrawCall, GL_UNSIGNED_SHORT, DE_NULL); 1471 } 1472 } 1473 } 1474 1475 for(int i = 0; i < (int)programContext.attributes.size(); i++) 1476 program.disableAttributeArray(programContext.attributes[i], programResources.shaderNameManglingSuffix); 1477 1478 if (m_showDebugInfo) 1479 m_debugInfoRenderer->drawInfo(deGetTime()-m_startTimeSeconds, m_textures->computeApproxMemUsage(), m_maxTexMemoryUsageBytes, m_buffers->computeApproxMemUsage(), m_maxBufMemoryUsageBytes, m_currentIteration); 1480 1481 if (m_currentIteration > 0) 1482 { 1483 // Log if a certain amount of time has passed since last log entry (or if this is the last iteration). 1484 1485 const deUint64 loggingIntervalSeconds = 10; 1486 const deUint64 time = deGetTime(); 1487 const deUint64 timeDiff = time - m_lastLogTime; 1488 const int iterDiff = m_currentIteration - m_lastLogIteration; 1489 1490 if (timeDiff >= loggingIntervalSeconds || m_currentIteration == m_numIterations-1) 1491 { 1492 log << TestLog::Section("LogEntry" + toString(m_currentLogEntryNdx), "Log entry " + toString(m_currentLogEntryNdx)) 1493 << TestLog::Message << "Time elapsed: " << getTimeStr(time - m_startTimeSeconds) << TestLog::EndMessage 1494 << TestLog::Message << "Frame number: " << m_currentIteration << TestLog::EndMessage 1495 << TestLog::Message << "Time since last log entry: " << timeDiff << "s" << TestLog::EndMessage 1496 << TestLog::Message << "Frames since last log entry: " << iterDiff << TestLog::EndMessage 1497 << TestLog::Message << "Average frame time since last log entry: " << de::floatToString((float)timeDiff / (float)iterDiff, 2) << "s" << TestLog::EndMessage 1498 << TestLog::Message << "Approximate texture memory usage: " 1499 << de::floatToString((float)m_textures->computeApproxMemUsage() / Mi, 2) << " MiB / " 1500 << de::floatToString((float)m_maxTexMemoryUsageBytes / Mi, 2) << " MiB" 1501 << TestLog::EndMessage 1502 << TestLog::Message << "Approximate buffer memory usage: " 1503 << de::floatToString((float)m_buffers->computeApproxMemUsage() / Mi, 2) << " MiB / " 1504 << de::floatToString((float)m_maxBufMemoryUsageBytes / Mi, 2) << " MiB" 1505 << TestLog::EndMessage 1506 << TestLog::EndSection; 1507 1508 m_lastLogTime = time; 1509 m_lastLogIteration = m_currentIteration; 1510 m_currentLogEntryNdx++; 1511 } 1512 } 1513 1514 // Possibly remove or set-as-garbage some objects, depending on given probabilities. 1515 1516 for (int texNdx = 0; texNdx < (int)programContext.textureSpecs.size(); texNdx++) 1517 { 1518 const string texName = textureNamePrefix + toString(texNdx); 1519 if (m_rnd.getFloat() < m_probabilities.deleteTexture) 1520 m_textures->remove(texName); 1521 else if (m_rnd.getFloat() < m_probabilities.wastefulTextureMemoryUsage) 1522 m_textures->markAsGarbage(texName); 1523 1524 } 1525 1526 if (m_buffers->has(indexBufferName)) 1527 { 1528 if (m_rnd.getFloat() < m_probabilities.deleteBuffer) 1529 m_buffers->remove(indexBufferName); 1530 else if (m_rnd.getFloat() < m_probabilities.wastefulBufferMemoryUsage) 1531 m_buffers->markAsGarbage(indexBufferName); 1532 1533 } 1534 1535 if (separateAttributeBuffers) 1536 { 1537 for (int attrNdx = 0; attrNdx < (int)programContext.attributes.size(); attrNdx++) 1538 { 1539 const string curAttrBufNamePrefix = separateAttrBufNamePrefix + toString(attrNdx) + "_"; 1540 1541 if (m_buffers->has(curAttrBufNamePrefix + "0")) 1542 { 1543 if (m_rnd.getFloat() < m_probabilities.deleteBuffer) 1544 { 1545 for (int i = 0; i < m_redundantBufferFactor; i++) 1546 m_buffers->remove(curAttrBufNamePrefix + toString(i)); 1547 } 1548 else if (m_rnd.getFloat() < m_probabilities.wastefulBufferMemoryUsage) 1549 { 1550 for (int i = 0; i < m_redundantBufferFactor; i++) 1551 m_buffers->markAsGarbage(curAttrBufNamePrefix + toString(i)); 1552 } 1553 } 1554 } 1555 } 1556 else 1557 { 1558 if (m_buffers->has(unitedAttrBufferNamePrefix + "0")) 1559 { 1560 if (m_rnd.getFloat() < m_probabilities.deleteBuffer) 1561 { 1562 for (int i = 0; i < m_redundantBufferFactor; i++) 1563 m_buffers->remove(unitedAttrBufferNamePrefix + toString(i)); 1564 } 1565 else if (m_rnd.getFloat() < m_probabilities.wastefulBufferMemoryUsage) 1566 { 1567 for (int i = 0; i < m_redundantBufferFactor; i++) 1568 m_buffers->markAsGarbage(unitedAttrBufferNamePrefix + toString(i)); 1569 } 1570 } 1571 } 1572 1573 GLU_CHECK_MSG("End of LongStressCase::iterate()"); 1574 1575 m_currentIteration++; 1576 if (m_currentIteration == m_numIterations) 1577 { 1578 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Passed"); 1579 return STOP; 1580 } 1581 else 1582 return CONTINUE; 1583 } 1584 1585 } // gls 1586 } // deqp 1587