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