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 Memory object stress test 22 *//*--------------------------------------------------------------------*/ 23 24 #include "glsMemoryStressCase.hpp" 25 #include "gluShaderProgram.hpp" 26 #include "tcuTestLog.hpp" 27 #include "tcuCommandLine.hpp" 28 #include "deRandom.hpp" 29 #include "deClock.h" 30 #include "deString.h" 31 32 #include "glw.h" 33 34 #include <vector> 35 #include <iostream> 36 37 using std::vector; 38 using tcu::TestLog; 39 40 namespace deqp 41 { 42 namespace gls 43 { 44 45 static const char* glErrorToString (deUint32 error) 46 { 47 switch (error) 48 { 49 case GL_OUT_OF_MEMORY: 50 return "GL_OUT_OF_MEMORY"; 51 break; 52 53 case GL_INVALID_ENUM: 54 return "GL_INVALID_ENUM"; 55 break; 56 57 case GL_INVALID_FRAMEBUFFER_OPERATION: 58 return "GL_INVALID_FRAMEBUFFER_OPERATION"; 59 break; 60 61 case GL_INVALID_OPERATION: 62 return "GL_INVALID_OPERATION"; 63 break; 64 65 case GL_INVALID_VALUE: 66 return "GL_INVALID_VALUE"; 67 break; 68 69 case 0: 70 return "<none>"; 71 break; 72 73 default: 74 // \todo [mika] Handle uknown errors? 75 DE_ASSERT(false); 76 return NULL; 77 break; 78 } 79 } 80 81 static const float s_quadCoords[] = 82 { 83 -1.0f, -1.0f, 84 1.0f, -1.0f, 85 1.0f, 1.0f, 86 -1.0f, 1.0f 87 }; 88 89 static const GLubyte s_quadIndices[] = 90 { 91 0, 1, 2, 92 2, 3, 0 93 }; 94 95 class TextureRenderer 96 { 97 public: 98 TextureRenderer (tcu::TestLog& log, glu::RenderContext& renderContext); 99 ~TextureRenderer (void); 100 void render (deUint32 texture); 101 102 private: 103 glu::ShaderProgram* m_program; 104 glu::RenderContext& m_renderCtx; 105 106 deUint32 m_coordBuffer; 107 deUint32 m_indexBuffer; 108 deUint32 m_vao; 109 110 static const char* s_vertexShaderGLES2; 111 static const char* s_fragmentShaderGLES2; 112 113 static const char* s_vertexShaderGLES3; 114 static const char* s_fragmentShaderGLES3; 115 116 static const char* s_vertexShaderGL3; 117 static const char* s_fragmentShaderGL3; 118 }; 119 120 const char* TextureRenderer::s_vertexShaderGLES2 = 121 "attribute mediump vec2 a_coord;\n" 122 "varying mediump vec2 v_texCoord;\n" 123 "void main (void)\n" 124 "{\n" 125 "\tv_texCoord = 0.5 * (a_coord + vec2(1.0));\n" 126 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n" 127 "}\n"; 128 129 const char* TextureRenderer::s_fragmentShaderGLES2 = 130 "varying mediump vec2 v_texCoord;\n" 131 "uniform sampler2D u_texture;\n" 132 "void main (void)\n" 133 "{\n" 134 "\tgl_FragColor = texture2D(u_texture, v_texCoord);\n" 135 "}\n"; 136 137 const char* TextureRenderer::s_vertexShaderGLES3 = 138 "#version 300 es\n" 139 "in mediump vec2 a_coord;\n" 140 "out mediump vec2 v_texCoord;\n" 141 "void main (void)\n" 142 "{\n" 143 "\tv_texCoord = 0.5 * (a_coord + vec2(1.0));\n" 144 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n" 145 "}\n"; 146 147 const char* TextureRenderer::s_fragmentShaderGLES3 = 148 "#version 300 es\n" 149 "in mediump vec2 v_texCoord;\n" 150 "uniform sampler2D u_texture;\n" 151 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" 152 "void main (void)\n" 153 "{\n" 154 "\tdEQP_FragColor = texture(u_texture, v_texCoord);\n" 155 "}\n"; 156 157 const char* TextureRenderer::s_vertexShaderGL3 = 158 "#version 330\n" 159 "in mediump vec2 a_coord;\n" 160 "out mediump vec2 v_texCoord;\n" 161 "void main (void)\n" 162 "{\n" 163 "\tv_texCoord = 0.5 * (a_coord + vec2(1.0));\n" 164 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n" 165 "}\n"; 166 167 const char* TextureRenderer::s_fragmentShaderGL3 = 168 "#version 330\n" 169 "in mediump vec2 v_texCoord;\n" 170 "uniform sampler2D u_texture;\n" 171 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" 172 "void main (void)\n" 173 "{\n" 174 "\tdEQP_FragColor = texture(u_texture, v_texCoord);\n" 175 "}\n"; 176 177 TextureRenderer::TextureRenderer (tcu::TestLog& log, glu::RenderContext& renderContext) 178 : m_program (NULL) 179 , m_renderCtx (renderContext) 180 , m_coordBuffer (0) 181 , m_indexBuffer (0) 182 , m_vao (0) 183 { 184 const glu::ContextType ctxType = renderContext.getType(); 185 186 if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_300_ES)) 187 m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES3, s_fragmentShaderGLES3)); 188 else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_100_ES)) 189 m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES2, s_fragmentShaderGLES2)); 190 else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_330)) 191 m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGL3, s_fragmentShaderGL3)); 192 else 193 DE_ASSERT(false); 194 195 if (ctxType.getProfile() == glu::PROFILE_CORE) 196 GLU_CHECK_CALL(glGenVertexArrays(1, &m_vao)); 197 198 GLU_CHECK_CALL(glGenBuffers(1, &m_coordBuffer)); 199 GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer)); 200 GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(s_quadCoords), s_quadCoords, GL_STATIC_DRAW)); 201 202 GLU_CHECK_CALL(glGenBuffers(1, &m_indexBuffer)); 203 GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer)); 204 GLU_CHECK_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(s_quadIndices), s_quadIndices, GL_STATIC_DRAW)); 205 206 if (!m_program->isOk()) 207 { 208 log << *m_program; 209 TCU_CHECK_MSG(m_program->isOk(), "Shader compilation failed"); 210 } 211 } 212 213 TextureRenderer::~TextureRenderer (void) 214 { 215 delete m_program; 216 glDeleteBuffers(1, &m_coordBuffer); 217 glDeleteBuffers(1, &m_indexBuffer); 218 } 219 220 void TextureRenderer::render (deUint32 texture) 221 { 222 deUint32 coordLoc = -1; 223 deUint32 texLoc = -1; 224 225 GLU_CHECK_CALL(glUseProgram(m_program->getProgram())); 226 227 coordLoc = glGetAttribLocation(m_program->getProgram(), "a_coord"); 228 GLU_CHECK(); 229 TCU_CHECK(coordLoc != (deUint32)-1); 230 231 if (m_vao != 0) 232 GLU_CHECK_CALL(glBindVertexArray(m_vao)); 233 234 GLU_CHECK_CALL(glEnableVertexAttribArray(coordLoc)); 235 236 GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer)); 237 GLU_CHECK_CALL(glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL)); 238 239 GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0)); 240 GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, texture)); 241 242 texLoc = glGetUniformLocation(m_program->getProgram(), "u_texture"); 243 GLU_CHECK(); 244 TCU_CHECK(texLoc != (deUint32)-1); 245 246 GLU_CHECK_CALL(glUniform1i(texLoc, 0)); 247 248 GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer)); 249 GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL)); 250 251 GLU_CHECK_CALL(glDisableVertexAttribArray(coordLoc)); 252 253 if (m_vao != 0) 254 GLU_CHECK_CALL(glBindVertexArray(0)); 255 } 256 257 class BufferRenderer 258 { 259 public: 260 BufferRenderer (tcu::TestLog& log, glu::RenderContext& renderContext); 261 ~BufferRenderer (void); 262 void render (deUint32 buffer, int size); 263 264 private: 265 glu::ShaderProgram* m_program; 266 glu::RenderContext& m_renderCtx; 267 268 deUint32 m_coordBuffer; 269 deUint32 m_indexBuffer; 270 deUint32 m_vao; 271 272 static const char* s_vertexShaderGLES2; 273 static const char* s_fragmentShaderGLES2; 274 275 static const char* s_vertexShaderGLES3; 276 static const char* s_fragmentShaderGLES3; 277 278 static const char* s_vertexShaderGL3; 279 static const char* s_fragmentShaderGL3; 280 }; 281 282 const char* BufferRenderer::s_vertexShaderGLES2 = 283 "attribute mediump vec2 a_coord;\n" 284 "attribute mediump vec4 a_buffer;\n" 285 "varying mediump vec4 v_buffer;\n" 286 "void main (void)\n" 287 "{\n" 288 "\tv_buffer = a_buffer;\n" 289 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n" 290 "}\n"; 291 292 const char* BufferRenderer::s_fragmentShaderGLES2 = 293 "varying mediump vec4 v_buffer;\n" 294 "void main (void)\n" 295 "{\n" 296 "\tgl_FragColor = v_buffer;\n" 297 "}\n"; 298 299 const char* BufferRenderer::s_vertexShaderGLES3 = 300 "#version 300 es\n" 301 "in mediump vec2 a_coord;\n" 302 "in mediump vec4 a_buffer;\n" 303 "out mediump vec4 v_buffer;\n" 304 "void main (void)\n" 305 "{\n" 306 "\tv_buffer = a_buffer;\n" 307 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n" 308 "}\n"; 309 310 const char* BufferRenderer::s_fragmentShaderGLES3 = 311 "#version 300 es\n" 312 "in mediump vec4 v_buffer;\n" 313 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" 314 "void main (void)\n" 315 "{\n" 316 "\tdEQP_FragColor = v_buffer;\n" 317 "}\n"; 318 319 const char* BufferRenderer::s_vertexShaderGL3 = 320 "#version 330\n" 321 "in mediump vec2 a_coord;\n" 322 "in mediump vec4 a_buffer;\n" 323 "out mediump vec4 v_buffer;\n" 324 "void main (void)\n" 325 "{\n" 326 "\tv_buffer = a_buffer;\n" 327 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n" 328 "}\n"; 329 330 const char* BufferRenderer::s_fragmentShaderGL3 = 331 "#version 330\n" 332 "in mediump vec4 v_buffer;\n" 333 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n" 334 "void main (void)\n" 335 "{\n" 336 "\tdEQP_FragColor = v_buffer;\n" 337 "}\n"; 338 339 BufferRenderer::BufferRenderer (tcu::TestLog& log, glu::RenderContext& renderContext) 340 : m_program (NULL) 341 , m_renderCtx (renderContext) 342 , m_coordBuffer (0) 343 , m_indexBuffer (0) 344 , m_vao (0) 345 { 346 const glu::ContextType ctxType = renderContext.getType(); 347 348 if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_300_ES)) 349 m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES3, s_fragmentShaderGLES3)); 350 else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_100_ES)) 351 m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES2, s_fragmentShaderGLES2)); 352 else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_330)) 353 m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGL3, s_fragmentShaderGL3)); 354 else 355 DE_ASSERT(false); 356 357 if (ctxType.getProfile() == glu::PROFILE_CORE) 358 GLU_CHECK_CALL(glGenVertexArrays(1, &m_vao)); 359 360 GLU_CHECK_CALL(glGenBuffers(1, &m_coordBuffer)); 361 GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer)); 362 GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(s_quadCoords), s_quadCoords, GL_STATIC_DRAW)); 363 364 GLU_CHECK_CALL(glGenBuffers(1, &m_indexBuffer)); 365 GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer)); 366 GLU_CHECK_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(s_quadIndices), s_quadIndices, GL_STATIC_DRAW)); 367 368 if (!m_program->isOk()) 369 { 370 log << *m_program; 371 TCU_CHECK_MSG(m_program->isOk(), "Shader compilation failed"); 372 } 373 } 374 375 BufferRenderer::~BufferRenderer (void) 376 { 377 delete m_program; 378 glDeleteBuffers(1, &m_coordBuffer); 379 glDeleteBuffers(1, &m_indexBuffer); 380 } 381 382 void BufferRenderer::render (deUint32 buffer, int size) 383 { 384 DE_UNREF(size); 385 DE_ASSERT((size_t)size >= sizeof(GLubyte) * 4 * 6); 386 GLU_CHECK_CALL(glUseProgram(m_program->getProgram())); 387 388 deUint32 bufferLoc = glGetAttribLocation(m_program->getProgram(), "a_buffer"); 389 TCU_CHECK(bufferLoc != (deUint32)-1); 390 391 deUint32 coordLoc = glGetAttribLocation(m_program->getProgram(), "a_coord"); 392 TCU_CHECK(coordLoc != (deUint32)-1); 393 394 if (m_vao != 0) 395 GLU_CHECK_CALL(glBindVertexArray(m_vao)); 396 397 GLU_CHECK_CALL(glEnableVertexAttribArray(bufferLoc)); 398 GLU_CHECK_CALL(glEnableVertexAttribArray(coordLoc)); 399 400 GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer)); 401 GLU_CHECK_CALL(glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL)); 402 403 GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffer)); 404 GLU_CHECK_CALL(glVertexAttribPointer(bufferLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0)); 405 GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0)); 406 407 GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer)); 408 GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL)); 409 410 GLU_CHECK_CALL(glDisableVertexAttribArray(bufferLoc)); 411 GLU_CHECK_CALL(glDisableVertexAttribArray(coordLoc)); 412 413 if (m_vao != 0) 414 GLU_CHECK_CALL(glBindVertexArray(0)); 415 } 416 417 class MemObjectAllocator 418 { 419 public: 420 enum Result 421 { 422 RESULT_GOT_BAD_ALLOC = 0, 423 RESULT_GEN_TEXTURES_FAILED, 424 RESULT_GEN_BUFFERS_FAILED, 425 RESULT_BUFFER_DATA_FAILED, 426 RESULT_BUFFER_SUB_DATA_FAILED, 427 RESULT_TEXTURE_IMAGE_FAILED, 428 RESULT_TEXTURE_SUB_IMAGE_FAILED, 429 RESULT_BIND_TEXTURE_FAILED, 430 RESULT_BIND_BUFFER_FAILED, 431 RESULT_DELETE_TEXTURES_FAILED, 432 RESULT_DELETE_BUFFERS_FAILED, 433 RESULT_RENDER_FAILED, 434 435 RESULT_LAST 436 }; 437 438 MemObjectAllocator (tcu::TestLog& log, glu::RenderContext& renderContext, MemObjectType objectTypes, const MemObjectConfig& config, int seed); 439 ~MemObjectAllocator (void); 440 bool allocUntilFailure (void); 441 void clearObjects (void); 442 Result getResult (void) const { return m_result; } 443 deUint32 getGLError (void) const { return m_glError; } 444 int getObjectCount (void) const { return m_objectCount; } 445 deUint32 getBytes (void) const { return m_bytesRequired; } 446 447 static const char* resultToString (Result result); 448 449 private: 450 451 void allocateTexture (de::Random& rnd); 452 void allocateBuffer (de::Random& rnd); 453 454 vector<deUint32> m_buffers; 455 vector<deUint32> m_textures; 456 int m_seed; 457 int m_objectCount; 458 deUint32 m_bytesRequired; 459 MemObjectType m_objectTypes; 460 Result m_result; 461 MemObjectConfig m_config; 462 deUint32 m_glError; 463 vector<deUint8> m_dummyData; 464 BufferRenderer m_bufferRenderer; 465 TextureRenderer m_textureRenderer; 466 }; 467 468 MemObjectAllocator::MemObjectAllocator (tcu::TestLog& log, glu::RenderContext& renderContext, MemObjectType objectTypes, const MemObjectConfig& config, int seed) 469 : m_seed (seed) 470 , m_objectCount (0) 471 , m_bytesRequired (0) 472 , m_objectTypes (objectTypes) 473 , m_result (RESULT_LAST) 474 , m_config (config) 475 , m_glError (0) 476 , m_bufferRenderer (log, renderContext) 477 , m_textureRenderer (log, renderContext) 478 { 479 DE_UNREF(renderContext); 480 481 if (m_config.useDummyData) 482 { 483 int dummySize = deMax32(m_config.maxBufferSize, m_config.maxTextureSize*m_config.maxTextureSize*4); 484 m_dummyData = vector<deUint8>(dummySize); 485 } 486 else if (m_config.write) 487 m_dummyData = vector<deUint8>(128); 488 } 489 490 MemObjectAllocator::~MemObjectAllocator (void) 491 { 492 } 493 494 bool MemObjectAllocator::allocUntilFailure (void) 495 { 496 de::Random rnd(m_seed); 497 GLU_CHECK_MSG("Error in init"); 498 try 499 { 500 const deUint64 timeoutUs = 10000000; // 10s 501 deUint64 beginTimeUs = deGetMicroseconds(); 502 deUint64 currentTimeUs; 503 504 do 505 { 506 GLU_CHECK_MSG("Unkown Error"); 507 switch (m_objectTypes) 508 { 509 case MEMOBJECTTYPE_TEXTURE: 510 allocateTexture(rnd); 511 break; 512 513 case MEMOBJECTTYPE_BUFFER: 514 allocateBuffer(rnd); 515 break; 516 517 default: 518 { 519 if (rnd.getBool()) 520 allocateBuffer(rnd); 521 else 522 allocateTexture(rnd); 523 break; 524 } 525 } 526 527 if (m_result != RESULT_LAST) 528 { 529 glFinish(); 530 return true; 531 } 532 533 currentTimeUs = deGetMicroseconds(); 534 } while (currentTimeUs - beginTimeUs < timeoutUs); 535 536 // Timeout 537 if (currentTimeUs - beginTimeUs >= timeoutUs) 538 return false; 539 else 540 return true; 541 } 542 catch (const std::bad_alloc&) 543 { 544 m_result = RESULT_GOT_BAD_ALLOC; 545 return true; 546 } 547 } 548 549 void MemObjectAllocator::clearObjects (void) 550 { 551 deUint32 error = 0; 552 553 if (!m_textures.empty()) 554 { 555 glDeleteTextures((GLsizei)m_textures.size(), &(m_textures[0])); 556 error = glGetError(); 557 if (error != 0) 558 { 559 m_result = RESULT_DELETE_TEXTURES_FAILED; 560 m_glError = error; 561 } 562 563 m_textures.clear(); 564 } 565 566 if (!m_buffers.empty()) 567 { 568 glDeleteBuffers((GLsizei)m_buffers.size(), &(m_buffers[0])); 569 error = glGetError(); 570 if (error != 0) 571 { 572 m_result = RESULT_DELETE_BUFFERS_FAILED; 573 m_glError = error; 574 } 575 576 m_buffers.clear(); 577 } 578 } 579 580 void MemObjectAllocator::allocateTexture (de::Random& rnd) 581 { 582 const int vectorBlockSize = 128; 583 deUint32 tex = 0; 584 deUint32 error = 0; 585 int width = rnd.getInt(m_config.minTextureSize, m_config.maxTextureSize); 586 int height = rnd.getInt(m_config.minTextureSize, m_config.maxTextureSize); 587 588 glGenTextures(1, &tex); 589 error = glGetError(); 590 if (error != 0) 591 { 592 m_result = RESULT_GEN_TEXTURES_FAILED; 593 m_glError = error; 594 return; 595 } 596 597 if (m_textures.size() % vectorBlockSize == 0) 598 m_textures.reserve(m_textures.size() + vectorBlockSize); 599 600 m_textures.push_back(tex); 601 602 glBindTexture(GL_TEXTURE_2D, tex); 603 error = glGetError(); 604 if (error != 0) 605 { 606 m_result = RESULT_BIND_TEXTURE_FAILED; 607 m_glError = error; 608 return; 609 } 610 611 if (m_config.useDummyData) 612 { 613 DE_ASSERT((int)m_dummyData.size() >= width*height*4); 614 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &(m_dummyData[0])); 615 } 616 else 617 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 618 619 error = glGetError(); 620 if (error != 0) 621 { 622 m_result = RESULT_TEXTURE_IMAGE_FAILED; 623 m_glError = error; 624 return; 625 } 626 627 if (m_config.write) 628 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &(m_dummyData[0])); 629 630 error = glGetError(); 631 if (error != 0) 632 { 633 m_result = RESULT_TEXTURE_SUB_IMAGE_FAILED; 634 m_glError = error; 635 return; 636 } 637 638 if (m_config.use) 639 { 640 try 641 { 642 m_textureRenderer.render(tex); 643 } 644 catch (const glu::Error& err) 645 { 646 m_result = RESULT_RENDER_FAILED; 647 m_glError = err.getError(); 648 return; 649 } 650 catch (const glu::OutOfMemoryError&) 651 { 652 m_result = RESULT_RENDER_FAILED; 653 m_glError = GL_OUT_OF_MEMORY; 654 return; 655 } 656 } 657 658 glBindTexture(GL_TEXTURE_2D, 0); 659 error = glGetError(); 660 if (error != 0) 661 { 662 m_result = RESULT_BIND_TEXTURE_FAILED; 663 m_glError = error; 664 return; 665 } 666 667 m_objectCount++; 668 m_bytesRequired += width*height*4; 669 } 670 671 void MemObjectAllocator::allocateBuffer (de::Random& rnd) 672 { 673 const int vectorBlockSize = 128; 674 deUint32 buffer = 0; 675 deUint32 error = 0; 676 int size = rnd.getInt(m_config.minBufferSize, m_config.maxBufferSize); 677 678 glGenBuffers(1, &buffer); 679 error = glGetError(); 680 if (error != 0) 681 { 682 m_result = RESULT_GEN_BUFFERS_FAILED; 683 m_glError = error; 684 return; 685 } 686 687 glBindBuffer(GL_ARRAY_BUFFER, buffer); 688 error = glGetError(); 689 if (error != 0) 690 { 691 m_result = RESULT_BIND_BUFFER_FAILED; 692 m_glError = error; 693 return; 694 } 695 696 if (m_buffers.size() % vectorBlockSize == 0) 697 m_buffers.reserve(m_buffers.size() + vectorBlockSize); 698 699 m_buffers.push_back(buffer); 700 701 if (m_config.useDummyData) 702 { 703 DE_ASSERT((int)m_dummyData.size() >= size); 704 glBufferData(GL_ARRAY_BUFFER, size, &(m_dummyData[0]), GL_DYNAMIC_DRAW); 705 } 706 else 707 glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_DYNAMIC_DRAW); 708 709 error = glGetError(); 710 if (error != 0) 711 { 712 m_result = RESULT_BUFFER_DATA_FAILED; 713 m_glError = error; 714 return; 715 } 716 717 if (m_config.write) 718 glBufferSubData(GL_ARRAY_BUFFER, 0, 1, &(m_dummyData[0])); 719 720 error = glGetError(); 721 if (error != 0) 722 { 723 m_result = RESULT_BUFFER_SUB_DATA_FAILED; 724 m_glError = error; 725 return; 726 } 727 728 if (m_config.use) 729 { 730 try 731 { 732 m_bufferRenderer.render(buffer, size); 733 } 734 catch (const glu::Error& err) 735 { 736 m_result = RESULT_RENDER_FAILED; 737 m_glError = err.getError(); 738 return; 739 } 740 catch (const glu::OutOfMemoryError&) 741 { 742 m_result = RESULT_RENDER_FAILED; 743 m_glError = GL_OUT_OF_MEMORY; 744 return; 745 } 746 } 747 748 glBindBuffer(GL_ARRAY_BUFFER, 0); 749 error = glGetError(); 750 if (error != 0) 751 { 752 m_result = RESULT_BIND_BUFFER_FAILED; 753 m_glError = error; 754 return; 755 } 756 757 m_objectCount++; 758 m_bytesRequired += size; 759 } 760 761 const char* MemObjectAllocator::resultToString (Result result) 762 { 763 switch (result) 764 { 765 case RESULT_GOT_BAD_ALLOC: 766 return "Caught std::bad_alloc"; 767 break; 768 769 case RESULT_GEN_TEXTURES_FAILED: 770 return "glGenTextures failed"; 771 break; 772 773 case RESULT_GEN_BUFFERS_FAILED: 774 return "glGenBuffers failed"; 775 break; 776 777 case RESULT_BUFFER_DATA_FAILED: 778 return "glBufferData failed"; 779 break; 780 781 case RESULT_BUFFER_SUB_DATA_FAILED: 782 return "glBufferSubData failed"; 783 break; 784 785 case RESULT_TEXTURE_IMAGE_FAILED: 786 return "glTexImage2D failed"; 787 break; 788 789 case RESULT_TEXTURE_SUB_IMAGE_FAILED: 790 return "glTexSubImage2D failed"; 791 break; 792 793 case RESULT_BIND_TEXTURE_FAILED: 794 return "glBindTexture failed"; 795 break; 796 797 case RESULT_BIND_BUFFER_FAILED: 798 return "glBindBuffer failed"; 799 break; 800 801 case RESULT_DELETE_TEXTURES_FAILED: 802 return "glDeleteTextures failed"; 803 break; 804 805 case RESULT_DELETE_BUFFERS_FAILED: 806 return "glDeleteBuffers failed"; 807 break; 808 809 case RESULT_RENDER_FAILED: 810 return "Rendering result failed"; 811 break; 812 813 default: 814 DE_ASSERT(false); 815 return NULL; 816 } 817 } 818 819 MemoryStressCase::MemoryStressCase (tcu::TestContext& ctx, glu::RenderContext& renderContext, deUint32 objectTypes, int minTextureSize, int maxTextureSize, int minBufferSize, int maxBufferSize, bool write, bool use, bool useDummyData, bool clearAfterOOM, const char* name, const char* desc) 820 : tcu::TestCase (ctx, name, desc) 821 , m_iteration (0) 822 , m_iterationCount (5) 823 , m_objectTypes ((MemObjectType)objectTypes) 824 , m_zeroAlloc (false) 825 , m_clearAfterOOM (clearAfterOOM) 826 , m_renderCtx (renderContext) 827 { 828 m_allocated.reserve(m_iterationCount); 829 m_config.maxTextureSize = maxTextureSize; 830 m_config.minTextureSize = minTextureSize; 831 m_config.maxBufferSize = maxBufferSize; 832 m_config.minBufferSize = minBufferSize; 833 m_config.useDummyData = useDummyData; 834 m_config.write = write; 835 m_config.use = use; 836 } 837 838 MemoryStressCase::~MemoryStressCase (void) 839 { 840 } 841 842 void MemoryStressCase::init (void) 843 { 844 if (!m_testCtx.getCommandLine().isOutOfMemoryTestEnabled()) 845 { 846 m_testCtx.getLog() << TestLog::Message << "Tests that exhaust memory are disabled, use --deqp-test-oom=enable command line option to enable." << TestLog::EndMessage; 847 throw tcu::NotSupportedError("OOM tests disabled"); 848 } 849 } 850 851 void MemoryStressCase::deinit (void) 852 { 853 TCU_CHECK(!m_zeroAlloc); 854 } 855 856 tcu::TestCase::IterateResult MemoryStressCase::iterate (void) 857 { 858 bool end = false; 859 tcu::TestLog& log = m_testCtx.getLog(); 860 861 MemObjectAllocator allocator(log, m_renderCtx, m_objectTypes, m_config, deStringHash(getName())); 862 863 if (!allocator.allocUntilFailure()) 864 { 865 // Allocation timed out 866 allocator.clearObjects(); 867 868 log << TestLog::Message << "Timeout. Couldn't exhaust memory in timelimit. Allocated " << allocator.getObjectCount() << " objects." << TestLog::EndMessage; 869 870 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 871 return STOP; 872 } 873 874 // Try to cancel rendering operations 875 if (m_clearAfterOOM) 876 GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT)); 877 878 allocator.clearObjects(); 879 880 m_allocated.push_back(allocator.getObjectCount()); 881 882 if (m_iteration != 0 && allocator.getObjectCount() == 0) 883 m_zeroAlloc = true; 884 885 log << TestLog::Message << "Got error when allocation object count: " << allocator.getObjectCount() << " bytes: " << allocator.getBytes() << TestLog::EndMessage; 886 887 if ((allocator.getGLError() == 0) && (allocator.getResult() == MemObjectAllocator::RESULT_GOT_BAD_ALLOC)) 888 { 889 log << TestLog::Message << "std::bad_alloc" << TestLog::EndMessage; 890 end = true; 891 m_testCtx.setTestResult(QP_TEST_RESULT_RESOURCE_ERROR, "Memory allocation failed"); 892 } 893 else if (allocator.getGLError() != GL_OUT_OF_MEMORY) 894 { 895 log << TestLog::Message << "Invalid Error " << MemObjectAllocator::resultToString(allocator.getResult()) 896 << " GLError: " << glErrorToString(allocator.getGLError()) << 897 TestLog::EndMessage; 898 899 end = true; 900 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 901 } 902 903 if ((m_iteration+1) == m_iterationCount) 904 { 905 int min = m_allocated[0]; 906 int max = m_allocated[0]; 907 908 float threshold = 50.0f; 909 910 for (int allocNdx = 0; allocNdx < (int)m_allocated.size(); allocNdx++) 911 { 912 min = deMin32(m_allocated[allocNdx], min); 913 max = deMax32(m_allocated[allocNdx], max); 914 } 915 916 if (min == 0 && max != 0) 917 { 918 log << TestLog::Message << "Allocation count zero" << TestLog::EndMessage; 919 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 920 } 921 else 922 { 923 const float change = (min - max) / ((float)(max)); 924 if (change > threshold) 925 { 926 log << TestLog::Message << "Allocated objects max: " << max << ", min: " << min << ", difference: " << change << "% threshold: " << threshold << "%" << TestLog::EndMessage; 927 m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation count variation"); 928 } 929 else 930 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 931 } 932 end = true; 933 } 934 935 GLU_CHECK_CALL(glFinish()); 936 937 m_iteration++; 938 if (end) 939 return STOP; 940 else 941 return CONTINUE; 942 } 943 944 } // gls 945 } // deqp 946