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(deUint32 error)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
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[] =
75 {
76 -1.0f, -1.0f,
77 1.0f, -1.0f,
78 1.0f, 1.0f,
79 -1.0f, 1.0f
80 };
81
82 static const GLubyte s_quadIndices[] =
83 {
84 0, 1, 2,
85 2, 3, 0
86 };
87
88 class TextureRenderer
89 {
90 public:
91 TextureRenderer (tcu::TestLog& log, glu::RenderContext& renderContext);
92 ~TextureRenderer (void);
93 void render (deUint32 texture);
94
95 private:
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
113 const 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
122 const 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
130 const 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
140 const 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
150 const 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
160 const 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
TextureRenderer(tcu::TestLog & log,glu::RenderContext & renderContext)170 TextureRenderer::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
~TextureRenderer(void)206 TextureRenderer::~TextureRenderer (void)
207 {
208 delete m_program;
209 glDeleteBuffers(1, &m_coordBuffer);
210 glDeleteBuffers(1, &m_indexBuffer);
211 }
212
render(deUint32 texture)213 void 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
250 class BufferRenderer
251 {
252 public:
253 BufferRenderer (tcu::TestLog& log, glu::RenderContext& renderContext);
254 ~BufferRenderer (void);
255 void render (deUint32 buffer, int size);
256
257 private:
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
275 const 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
285 const 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
292 const 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
303 const 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
312 const 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
323 const 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
BufferRenderer(tcu::TestLog & log,glu::RenderContext & renderContext)332 BufferRenderer::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
~BufferRenderer(void)368 BufferRenderer::~BufferRenderer (void)
369 {
370 delete m_program;
371 glDeleteBuffers(1, &m_coordBuffer);
372 glDeleteBuffers(1, &m_indexBuffer);
373 }
374
render(deUint32 buffer,int size)375 void 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
410 class MemObjectAllocator
411 {
412 public:
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);
getResult(void) const435 Result getResult (void) const { return m_result; }
getGLError(void) const436 deUint32 getGLError (void) const { return m_glError; }
getObjectCount(void) const437 int getObjectCount (void) const { return m_objectCount; }
getBytes(void) const438 deUint32 getBytes (void) const { return m_bytesRequired; }
439
440 static const char* resultToString (Result result);
441
442 private:
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_dummyData;
457 BufferRenderer m_bufferRenderer;
458 TextureRenderer m_textureRenderer;
459 };
460
MemObjectAllocator(tcu::TestLog & log,glu::RenderContext & renderContext,MemObjectType objectTypes,const MemObjectConfig & config,int seed)461 MemObjectAllocator::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.useDummyData)
475 {
476 int dummySize = deMax32(m_config.maxBufferSize, m_config.maxTextureSize*m_config.maxTextureSize*4);
477 m_dummyData = vector<deUint8>(dummySize);
478 }
479 else if (m_config.write)
480 m_dummyData = vector<deUint8>(128);
481 }
482
~MemObjectAllocator(void)483 MemObjectAllocator::~MemObjectAllocator (void)
484 {
485 }
486
allocUntilFailure(void)487 bool 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
clearObjects(void)542 void 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
allocateTexture(de::Random & rnd)573 void 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.useDummyData)
605 {
606 DE_ASSERT((int)m_dummyData.size() >= width*height*4);
607 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &(m_dummyData[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_dummyData[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
allocateBuffer(de::Random & rnd)664 void 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.useDummyData)
695 {
696 DE_ASSERT((int)m_dummyData.size() >= size);
697 glBufferData(GL_ARRAY_BUFFER, size, &(m_dummyData[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_dummyData[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
resultToString(Result result)754 const 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
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)800 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)
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.useDummyData = useDummyData;
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() << 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
deinit(void)832 void MemoryStressCase::deinit (void)
833 {
834 TCU_CHECK(!m_zeroAlloc);
835 }
836
iterate(void)837 tcu::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