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 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
TextureRenderer(tcu::TestLog & log,glu::RenderContext & renderContext)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
~TextureRenderer(void)213 TextureRenderer::~TextureRenderer (void)
214 {
215 delete m_program;
216 glDeleteBuffers(1, &m_coordBuffer);
217 glDeleteBuffers(1, &m_indexBuffer);
218 }
219
render(deUint32 texture)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
BufferRenderer(tcu::TestLog & log,glu::RenderContext & renderContext)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
~BufferRenderer(void)375 BufferRenderer::~BufferRenderer (void)
376 {
377 delete m_program;
378 glDeleteBuffers(1, &m_coordBuffer);
379 glDeleteBuffers(1, &m_indexBuffer);
380 }
381
render(deUint32 buffer,int size)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);
getResult(void) const442 Result getResult (void) const { return m_result; }
getGLError(void) const443 deUint32 getGLError (void) const { return m_glError; }
getObjectCount(void) const444 int getObjectCount (void) const { return m_objectCount; }
getBytes(void) const445 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
MemObjectAllocator(tcu::TestLog & log,glu::RenderContext & renderContext,MemObjectType objectTypes,const MemObjectConfig & config,int seed)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
~MemObjectAllocator(void)490 MemObjectAllocator::~MemObjectAllocator (void)
491 {
492 }
493
allocUntilFailure(void)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
clearObjects(void)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
allocateTexture(de::Random & rnd)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
allocateBuffer(de::Random & rnd)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
resultToString(Result result)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
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)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
~MemoryStressCase(void)838 MemoryStressCase::~MemoryStressCase (void)
839 {
840 }
841
init(void)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
deinit(void)851 void MemoryStressCase::deinit (void)
852 {
853 TCU_CHECK(!m_zeroAlloc);
854 }
855
iterate(void)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