Merge "DO NOT MERGE: Add cube gather tests that avoid corners; remove D32F from...
[platform/upstream/VK-GL-CTS.git] / modules / glshared / glsMemoryStressCase.cpp
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
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
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
213 TextureRenderer::~TextureRenderer (void)
214 {
215         delete m_program;
216         glDeleteBuffers(1, &m_coordBuffer);
217         glDeleteBuffers(1, &m_indexBuffer);
218 }
219
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
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
375 BufferRenderer::~BufferRenderer (void)
376 {
377         delete m_program;
378         glDeleteBuffers(1, &m_coordBuffer);
379         glDeleteBuffers(1, &m_indexBuffer);
380 }
381
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);
442         Result                          getResult                       (void) const { return m_result; }
443         deUint32                        getGLError                      (void) const { return m_glError; }
444         int                                     getObjectCount          (void) const { return m_objectCount; }
445         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
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
490 MemObjectAllocator::~MemObjectAllocator (void)
491 {
492 }
493
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
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
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
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
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
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
838 MemoryStressCase::~MemoryStressCase (void)
839 {
840 }
841
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
851 void MemoryStressCase::deinit (void)
852 {
853         TCU_CHECK(!m_zeroAlloc);
854 }
855
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 = (float)(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