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