xref: /aosp_15_r20/external/deqp/modules/glshared/glsMemoryStressCase.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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