Use -std=c++03 with GCC and clang
[platform/upstream/VK-GL-CTS.git] / modules / glshared / glsLongStressCase.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 Parametrized, long-running stress case.
22  *
23  * \todo [2013-06-27 nuutti] Do certain things in a cleaner and less
24  *                                                       confusing way, such as the "redundant buffer
25  *                                                       factor" thing in LongStressCase.
26  *//*--------------------------------------------------------------------*/
27
28 #include "glsLongStressCase.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuCommandLine.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "tcuVector.hpp"
33 #include "tcuVectorUtil.hpp"
34 #include "glsTextureTestUtil.hpp"
35 #include "gluPixelTransfer.hpp"
36 #include "gluTextureUtil.hpp"
37 #include "tcuStringTemplate.hpp"
38 #include "gluStrUtil.hpp"
39 #include "gluShaderProgram.hpp"
40 #include "deRandom.hpp"
41 #include "deStringUtil.hpp"
42 #include "deString.h"
43 #include "deSharedPtr.hpp"
44 #include "deClock.h"
45
46 #include "glw.h"
47
48 #include <limits>
49 #include <vector>
50 #include <iomanip>
51 #include <map>
52 #include <iomanip>
53
54 using tcu::TestLog;
55 using tcu::Vec2;
56 using tcu::Vec3;
57 using tcu::Vec4;
58 using tcu::IVec2;
59 using tcu::IVec3;
60 using tcu::IVec4;
61 using tcu::TextureLevel;
62 using tcu::TextureFormat;
63 using tcu::ConstPixelBufferAccess;
64 using tcu::CubeFace;
65 using de::SharedPtr;
66 using de::Random;
67 using de::toString;
68
69 using std::vector;
70 using std::string;
71 using std::map;
72
73 namespace deqp
74 {
75 namespace gls
76 {
77
78 using glu::TextureTestUtil::TextureType;
79 using glu::TextureTestUtil::TEXTURETYPE_2D;
80 using glu::TextureTestUtil::TEXTURETYPE_CUBE;
81
82 static const float Mi = (float)(1<<20);
83
84 static const deUint32 bufferUsages[] =
85 {
86         GL_STATIC_DRAW,
87         GL_STREAM_DRAW,
88         GL_DYNAMIC_DRAW,
89
90         GL_STATIC_READ,
91         GL_STREAM_READ,
92         GL_DYNAMIC_READ,
93
94         GL_STATIC_COPY,
95         GL_STREAM_COPY,
96         GL_DYNAMIC_COPY
97 };
98
99 static const deUint32 bufferUsagesGLES2[] =
100 {
101         GL_STATIC_DRAW,
102         GL_DYNAMIC_DRAW,
103         GL_STREAM_DRAW
104 };
105
106 static const deUint32 bufferTargets[] =
107 {
108         GL_ARRAY_BUFFER,
109         GL_ELEMENT_ARRAY_BUFFER,
110
111         GL_COPY_READ_BUFFER,
112         GL_COPY_WRITE_BUFFER,
113         GL_PIXEL_PACK_BUFFER,
114         GL_PIXEL_UNPACK_BUFFER,
115         GL_TRANSFORM_FEEDBACK_BUFFER,
116         GL_UNIFORM_BUFFER
117 };
118
119 static const deUint32 bufferTargetsGLES2[] =
120 {
121         GL_ARRAY_BUFFER,
122         GL_ELEMENT_ARRAY_BUFFER
123 };
124
125 static inline int computePixelStore (const TextureFormat& format)
126 {
127         const int pixelSize = format.getPixelSize();
128         if (deIsPowerOfTwo32(pixelSize))
129                 return de::min(pixelSize, 8);
130         else
131                 return 1;
132 }
133
134 static inline int getNumIterations (const tcu::TestContext& testCtx, const int defaultNumIterations)
135 {
136         const int cmdLineVal = testCtx.getCommandLine().getTestIterationCount();
137         return cmdLineVal == 0 ? defaultNumIterations : cmdLineVal;
138 }
139
140 static inline float triangleArea (const Vec2& a, const Vec2& b, const Vec2& c)
141 {
142         const Vec2 ab = b-a;
143         const Vec2 ac = c-a;
144         return 0.5f * tcu::length(ab.x()*ac.y() - ab.y()*ac.x());
145 }
146
147 static inline string mangleShaderNames (const string& source, const string& manglingSuffix)
148 {
149         map<string, string> m;
150         m["NS"] = manglingSuffix;
151         return tcu::StringTemplate(source.c_str()).specialize(m);
152 }
153
154 template <typename T, int N>
155 static inline T randomChoose (Random& rnd, const T (&arr)[N])
156 {
157         return rnd.choose<T>(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr));
158 }
159
160 static inline int nextDivisible (const int x, const int div)
161 {
162         DE_ASSERT(x >= 0);
163         DE_ASSERT(div >= 1);
164         return x == 0 ? 0 : x-1 + div - (x-1) % div;
165 }
166
167 static inline string getTimeStr (const deUint64 seconds)
168 {
169         const deUint64          m = seconds / 60;
170         const deUint64          h = m / 60;
171         const deUint64          d = h / 24;
172         std::ostringstream      res;
173
174         res << d << "d " << h%24 << "h " << m%60 << "m " << seconds%60 << "s";
175         return res.str();
176 }
177
178 static inline string probabilityStr (const float prob)
179 {
180         return prob == 0.0f ? "never"   :
181                    prob == 1.0f ? "ALWAYS"      :
182                    de::floatToString(prob*100.0f, 0) + "%";
183 }
184
185 static inline deUint32 randomBufferTarget (Random& rnd, const bool isGLES3)
186 {
187         return isGLES3 ? randomChoose(rnd, bufferTargets) : randomChoose(rnd, bufferTargetsGLES2);
188 }
189
190 static inline deUint32 randomBufferUsage (Random& rnd, const bool isGLES3)
191 {
192         return isGLES3 ? randomChoose(rnd, bufferUsages) : randomChoose(rnd, bufferUsagesGLES2);
193 }
194
195 static inline deUint32 cubeFaceToGLFace (tcu::CubeFace face)
196 {
197         switch (face)
198         {
199                 case tcu::CUBEFACE_NEGATIVE_X: return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
200                 case tcu::CUBEFACE_POSITIVE_X: return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
201                 case tcu::CUBEFACE_NEGATIVE_Y: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
202                 case tcu::CUBEFACE_POSITIVE_Y: return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
203                 case tcu::CUBEFACE_NEGATIVE_Z: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
204                 case tcu::CUBEFACE_POSITIVE_Z: return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
205                 default:
206                         DE_ASSERT(false);
207                         return GL_NONE;
208         }
209 }
210
211 #if defined(DE_DEBUG)
212 static inline bool isMatchingGLInternalFormat (const deUint32 internalFormat, const TextureFormat& texFormat)
213 {
214         switch (internalFormat)
215         {
216                 // Unsized formats.
217
218                 case GL_RGBA:                           return texFormat.order == TextureFormat::RGBA &&
219                                                                                            (texFormat.type == TextureFormat::UNORM_INT8                 ||
220                                                                                                 texFormat.type == TextureFormat::UNORM_SHORT_4444       ||
221                                                                                                 texFormat.type == TextureFormat::UNORM_SHORT_5551);
222
223                 case GL_RGB:                            return texFormat.order == TextureFormat::RGB &&
224                                                                                            (texFormat.type == TextureFormat::UNORM_INT8                 ||
225                                                                                                 texFormat.type == TextureFormat::UNORM_SHORT_565);
226
227                 case GL_LUMINANCE_ALPHA:        return texFormat.order == TextureFormat::LA && texFormat.type == TextureFormat::UNORM_INT8;
228                 case GL_LUMINANCE:                      return texFormat.order == TextureFormat::L && texFormat.type == TextureFormat::UNORM_INT8;
229                 case GL_ALPHA:                          return texFormat.order == TextureFormat::A && texFormat.type == TextureFormat::UNORM_INT8;
230
231                 // Sized formats.
232
233                 default:                                        return glu::mapGLInternalFormat(internalFormat) == texFormat;
234         }
235 }
236 #endif // DE_DEBUG
237
238 static inline bool compileShader (const deUint32 shaderGL)
239 {
240         glCompileShader(shaderGL);
241
242         int success = GL_FALSE;
243         glGetShaderiv(shaderGL, GL_COMPILE_STATUS, &success);
244
245         return success == GL_TRUE;
246 }
247
248 static inline bool linkProgram (const deUint32 programGL)
249 {
250         glLinkProgram(programGL);
251
252         int success = GL_FALSE;
253         glGetProgramiv(programGL, GL_LINK_STATUS, &success);
254
255         return success == GL_TRUE;
256 }
257
258 static inline string getShaderInfoLog (const deUint32 shaderGL)
259 {
260         int                             infoLogLen = 0;
261         vector<char>    infoLog;
262         glGetShaderiv(shaderGL, GL_INFO_LOG_LENGTH, &infoLogLen);
263         infoLog.resize(infoLogLen+1);
264         glGetShaderInfoLog(shaderGL, (int)infoLog.size(), DE_NULL, &infoLog[0]);
265         return &infoLog[0];
266 }
267
268 static inline string getProgramInfoLog (const deUint32 programGL)
269 {
270         int                             infoLogLen = 0;
271         vector<char>    infoLog;
272         glGetProgramiv(programGL, GL_INFO_LOG_LENGTH, &infoLogLen);
273         infoLog.resize(infoLogLen+1);
274         glGetProgramInfoLog(programGL, (int)infoLog.size(), DE_NULL, &infoLog[0]);
275         return &infoLog[0];
276 }
277
278 namespace LongStressCaseInternal
279 {
280
281 // A hacky-ish class for drawing text on screen as GL quads.
282 class DebugInfoRenderer
283 {
284 public:
285                                                                 DebugInfoRenderer               (const glu::RenderContext& ctx);
286                                                                 ~DebugInfoRenderer              (void) { delete m_prog; }
287
288         void                                            drawInfo                                (deUint64 secondsElapsed, int texMem, int maxTexMem, int bufMem, int maxBufMem, int iterNdx);
289
290 private:
291                                                                 DebugInfoRenderer               (const DebugInfoRenderer&);
292         DebugInfoRenderer&                      operator=                               (const DebugInfoRenderer&);
293
294         void                                            render                                  (void);
295         void                                            addTextToBuffer                 (const string& text, int yOffset);
296
297         const glu::RenderContext&       m_ctx;
298         const glu::ShaderProgram*       m_prog;
299         vector<float>                           m_posBuf;
300         vector<deUint16>                        m_ndxBuf;
301 };
302
303 void DebugInfoRenderer::drawInfo (const deUint64 secondsElapsed, const int texMem, const int maxTexMem, const int bufMem, const int maxBufMem, const int iterNdx)
304 {
305         const deUint64 m = secondsElapsed / 60;
306         const deUint64 h = m / 60;
307         const deUint64 d = h / 24;
308
309         {
310                 std::ostringstream text;
311
312                 text << std::setw(2) << std::setfill('0') << d << ":"
313                          << std::setw(2) << std::setfill('0') << h % 24 << ":"
314                          << std::setw(2) << std::setfill('0') << m % 60 << ":"
315                          << std::setw(2) << std::setfill('0') << secondsElapsed % 60;
316                 addTextToBuffer(text.str(), 0);
317                 text.str("");
318
319                 text << std::fixed << std::setprecision(2) << (float)texMem/Mi << "/" << (float)maxTexMem/Mi;
320                 addTextToBuffer(text.str(), 1);
321                 text.str("");
322
323                 text << std::fixed << std::setprecision(2) << (float)bufMem/Mi << "/" << (float)maxBufMem/Mi;
324                 addTextToBuffer(text.str(), 2);
325                 text.str("");
326
327                 text << std::setw(0) << iterNdx;
328                 addTextToBuffer(text.str(), 3);
329         }
330
331         render();
332 }
333
334 DebugInfoRenderer::DebugInfoRenderer (const glu::RenderContext& ctx)
335         : m_ctx                 (ctx)
336         , m_prog                (DE_NULL)
337 {
338         DE_ASSERT(!m_prog);
339         m_prog = new glu::ShaderProgram(ctx, glu::makeVtxFragSources(
340                 "attribute highp vec2 a_pos;\n"
341                 "void main (void)\n"
342                 "{\n"
343                 "       gl_Position = vec4(a_pos, -1.0, 1.0);\n"
344                 "}\n",
345
346                 "void main(void)\n"
347                 "{\n"
348                 "       gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
349                 "}\n"));
350 }
351
352 void DebugInfoRenderer::addTextToBuffer (const string& text, const int yOffset)
353 {
354         static const char               characters[]    = "0123456789.:/";
355         const int                               numCharacters   = DE_LENGTH_OF_ARRAY(characters)-1; // \note -1 for null byte.
356         const int                               charWid                 = 6;
357         const int                               charHei                 = 6;
358         static const string             charsStr                (characters);
359
360         static const char font[numCharacters*charWid*charHei + 1]=
361                 " #### ""   #  "" #### ""##### ""   #  ""######"" #####""######"" #### "" #### ""      ""  ##  ""     #"
362                 "#    #""  ##  ""#    #""     #""  #   ""#     ""#     ""    # ""#    #""#    #""      ""  ##  ""    # "
363                 "#    #""   #  ""    # ""  ### "" #  # "" #### ""# ### ""   #  "" #### "" #####""      ""      ""   #  "
364                 "#    #""   #  ""   #  ""     #""######""     #""##   #""  #   ""#    #""     #""      ""  ##  ""  #   "
365                 "#    #""   #  ""  #   ""#    #""    # ""#    #""#    #"" #    ""#    #""   ## ""  ##  ""  ##  "" #    "
366                 " #### ""  ### ""######"" #### ""    # "" #### "" #### ""#     "" #### ""###   ""  ##  ""      ""#     ";
367
368         for (int ndxInText = 0; ndxInText < (int)text.size(); ndxInText++)
369         {
370                 const int ndxInCharset  = (int)charsStr.find(text[ndxInText]);
371                 DE_ASSERT(ndxInCharset < numCharacters);
372                 const int fontXStart    = ndxInCharset*charWid;
373
374                 for (int y = 0; y < charHei; y++)
375                 {
376                         float ay = -1.0f + (float)(y + 0 + yOffset*(charHei+2))*0.1f/(float)(charHei+2);
377                         float by = -1.0f + (float)(y + 1 + yOffset*(charHei+2))*0.1f/(float)(charHei+2);
378                         for (int x = 0; x < charWid; x++)
379                         {
380                                 // \note Text is mirrored in x direction since on most(?) mobile devices the image is mirrored(?).
381                                 float ax = 1.0f - (float)(x + 0 + ndxInText*(charWid+2))*0.1f/(float)(charWid+2);
382                                 float bx = 1.0f - (float)(x + 1 + ndxInText*(charWid+2))*0.1f/(float)(charWid+2);
383
384                                 if (font[y*numCharacters*charWid + fontXStart + x] != ' ')
385                                 {
386                                         const int vtxNdx = (int)m_posBuf.size()/2;
387
388                                         m_ndxBuf.push_back(deUint16(vtxNdx+0));
389                                         m_ndxBuf.push_back(deUint16(vtxNdx+1));
390                                         m_ndxBuf.push_back(deUint16(vtxNdx+2));
391
392                                         m_ndxBuf.push_back(deUint16(vtxNdx+2));
393                                         m_ndxBuf.push_back(deUint16(vtxNdx+1));
394                                         m_ndxBuf.push_back(deUint16(vtxNdx+3));
395
396                                         m_posBuf.push_back(ax);
397                                         m_posBuf.push_back(ay);
398
399                                         m_posBuf.push_back(bx);
400                                         m_posBuf.push_back(ay);
401
402                                         m_posBuf.push_back(ax);
403                                         m_posBuf.push_back(by);
404
405                                         m_posBuf.push_back(bx);
406                                         m_posBuf.push_back(by);
407                                 }
408                         }
409                 }
410         }
411 }
412
413 void DebugInfoRenderer::render (void)
414 {
415         const int prog          = m_prog->getProgram();
416         const int posloc        = glGetAttribLocation(prog, "a_pos");
417
418         glUseProgram(prog);
419         glBindBuffer(GL_ARRAY_BUFFER, 0);
420         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
421         glEnableVertexAttribArray(posloc);
422         glVertexAttribPointer(posloc, 2, GL_FLOAT, 0, 0, &m_posBuf[0]);
423         glDrawElements(GL_TRIANGLES, (int)m_ndxBuf.size(), GL_UNSIGNED_SHORT, &m_ndxBuf[0]);
424         glDisableVertexAttribArray(posloc);
425
426         m_posBuf.clear();
427         m_ndxBuf.clear();
428 }
429
430 /*--------------------------------------------------------------------*//*!
431  * \brief Texture object helper class
432  *
433  * Each Texture owns a GL texture object that is created when the Texture
434  * is constructed and deleted when it's destructed. The class provides some
435  * convenience interface functions to e.g. upload texture data to the GL.
436  *
437  * In addition, the class tracks the approximate amount of GL memory likely
438  * used by the corresponding GL texture object; get this with
439  * getApproxMemUsage(). Also, getApproxMemUsageDiff() returns N-M, where N
440  * is the value that getApproxMemUsage() would return after a call to
441  * setData() with arguments corresponding to those given to
442  * getApproxMemUsageDiff(), and M is the value currently returned by
443  * getApproxMemUsage(). This can be used to check if we need to free some
444  * other memory before performing the setData() call, in case we have an
445  * upper limit on the amount of memory we want to use.
446  *//*--------------------------------------------------------------------*/
447 class Texture
448 {
449 public:
450                                                 Texture                                 (TextureType type);
451                                                 ~Texture                                (void);
452
453         // Functions that may change the value returned by getApproxMemUsage().
454         void                            setData                                 (const ConstPixelBufferAccess& src, int width, int height, deUint32 internalFormat, bool useMipmap);
455
456         // Functions that don't change the value returned by getApproxMemUsage().
457         void                            setSubData                              (const ConstPixelBufferAccess& src, int xOff, int yOff, int width, int height) const;
458         void                            toUnit                                  (int unit) const;
459         void                            setFilter                               (deUint32 min, deUint32 mag) const;
460         void                            setWrap                                 (deUint32 s, deUint32 t) const;
461
462         int                                     getApproxMemUsage               (void) const { return m_dataSizeApprox; }
463         int                                     getApproxMemUsageDiff   (int width, int height, deUint32 internalFormat, bool useMipmap) const;
464
465 private:
466                                                 Texture                                 (const Texture&); // Not allowed.
467         Texture&                        operator=                               (const Texture&); // Not allowed.
468
469         static deUint32         genTexture                              (void) { deUint32 tex = 0; glGenTextures(1, &tex); return tex; }
470
471         deUint32                        getGLBindTarget                 (void) const { DE_ASSERT(m_type == TEXTURETYPE_2D || m_type == TEXTURETYPE_CUBE); return m_type == TEXTURETYPE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP; }
472
473         const TextureType       m_type;
474         const deUint32          m_textureGL;
475
476         int                                     m_numMipLevels;
477         deUint32                        m_internalFormat;
478         int                                     m_dataSizeApprox;
479 };
480
481 Texture::Texture (const TextureType type)
482         : m_type                        (type)
483         , m_textureGL           (genTexture())
484         , m_numMipLevels        (0)
485         , m_internalFormat      (0)
486         , m_dataSizeApprox      (0)
487 {
488 }
489
490 Texture::~Texture (void)
491 {
492         glDeleteTextures(1, &m_textureGL);
493 }
494
495 int Texture::getApproxMemUsageDiff (const int width, const int height, const deUint32 internalFormat, const bool useMipmap) const
496 {
497         const int       numLevels                               = useMipmap ? deLog2Floor32(de::max(width, height))+1 : 1;
498         const int       pixelSize                               = internalFormat == GL_RGBA             ? 4
499                                                                                 : internalFormat == GL_RGB              ? 3
500                                                                                 : internalFormat == GL_ALPHA    ? 1
501                                                                                 : glu::mapGLInternalFormat(internalFormat).getPixelSize();
502         int                     memUsageApproxAfter             = 0;
503
504         for (int level = 0; level < numLevels; level++)
505                 memUsageApproxAfter += de::max(1, width>>level) * de::max(1, height>>level) * pixelSize * (m_type == TEXTURETYPE_CUBE ? 6 : 1);
506
507         return memUsageApproxAfter - getApproxMemUsage();
508 }
509
510 void Texture::setData (const ConstPixelBufferAccess& src, const int width, const int height, const deUint32 internalFormat, const bool useMipmap)
511 {
512         DE_ASSERT(m_type != TEXTURETYPE_CUBE || width == height);
513         DE_ASSERT(!useMipmap || (deIsPowerOfTwo32(width) && deIsPowerOfTwo32(height)));
514
515         const TextureFormat&            format          = src.getFormat();
516         const glu::TransferFormat       transfer        = glu::getTransferFormat(format);
517
518         m_numMipLevels = useMipmap ? deLog2Floor32(de::max(width, height))+1 : 1;
519
520         m_internalFormat = internalFormat;
521         m_dataSizeApprox = width * height * format.getPixelSize() * (m_type == TEXTURETYPE_CUBE ? 6 : 1);
522
523         DE_ASSERT(src.getRowPitch() == format.getPixelSize()*src.getWidth());
524         DE_ASSERT(isMatchingGLInternalFormat(internalFormat, format));
525         DE_ASSERT(width <= src.getWidth() && height <= src.getHeight());
526
527         glPixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(format));
528
529         if (m_type == TEXTURETYPE_2D)
530         {
531                 m_dataSizeApprox = 0;
532
533                 glBindTexture(GL_TEXTURE_2D, m_textureGL);
534                 for (int level = 0; level < m_numMipLevels; level++)
535                 {
536                         const int levelWid = de::max(1, width>>level);
537                         const int levelHei = de::max(1, height>>level);
538                         m_dataSizeApprox += levelWid * levelHei * format.getPixelSize();
539                         glTexImage2D(GL_TEXTURE_2D, level, internalFormat, levelWid, levelHei, 0, transfer.format, transfer.dataType, src.getDataPtr());
540                 }
541         }
542         else if (m_type == TEXTURETYPE_CUBE)
543         {
544                 m_dataSizeApprox = 0;
545
546                 glBindTexture(GL_TEXTURE_CUBE_MAP, m_textureGL);
547                 for (int level = 0; level < m_numMipLevels; level++)
548                 {
549                         const int levelWid = de::max(1, width>>level);
550                         const int levelHei = de::max(1, height>>level);
551                         m_dataSizeApprox += 6 * levelWid * levelHei * format.getPixelSize();
552                         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
553                                 glTexImage2D(cubeFaceToGLFace((CubeFace)face), level, internalFormat, levelWid, levelHei, 0, transfer.format, transfer.dataType, src.getDataPtr());
554                 }
555         }
556         else
557                 DE_ASSERT(false);
558 }
559
560 void Texture::setSubData (const ConstPixelBufferAccess& src, const int xOff, const int yOff, const int width, const int height) const
561 {
562         const TextureFormat&            format          = src.getFormat();
563         const glu::TransferFormat       transfer        = glu::getTransferFormat(format);
564
565         DE_ASSERT(src.getRowPitch() == format.getPixelSize()*src.getWidth());
566         DE_ASSERT(isMatchingGLInternalFormat(m_internalFormat, format));
567         DE_ASSERT(width <= src.getWidth() && height <= src.getHeight());
568
569         glPixelStorei(GL_UNPACK_ALIGNMENT, computePixelStore(format));
570
571         if (m_type == TEXTURETYPE_2D)
572         {
573                 glBindTexture(GL_TEXTURE_2D, m_textureGL);
574                 for (int level = 0; level < m_numMipLevels; level++)
575                         glTexSubImage2D(GL_TEXTURE_2D, level, xOff>>level, yOff>>level, de::max(1, width>>level), de::max(1, height>>level), transfer.format, transfer.dataType, src.getDataPtr());
576         }
577         else if (m_type == TEXTURETYPE_CUBE)
578         {
579                 glBindTexture(GL_TEXTURE_CUBE_MAP, m_textureGL);
580                 for (int level = 0; level < m_numMipLevels; level++)
581                 {
582                         for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
583                                 glTexSubImage2D(cubeFaceToGLFace((CubeFace)face), level, xOff>>level, yOff>>level, de::max(1, width>>level), de::max(1, height>>level), transfer.format, transfer.dataType, src.getDataPtr());
584                 }
585         }
586         else
587                 DE_ASSERT(false);
588 }
589
590 void Texture::setFilter (const deUint32 min, const deUint32 mag) const
591 {
592         glBindTexture(getGLBindTarget(), m_textureGL);
593         glTexParameteri(getGLBindTarget(), GL_TEXTURE_MIN_FILTER, min);
594         glTexParameteri(getGLBindTarget(), GL_TEXTURE_MAG_FILTER, mag);
595 }
596
597 void Texture::setWrap (const deUint32 s, const deUint32 t) const
598 {
599         glBindTexture(getGLBindTarget(), m_textureGL);
600         glTexParameteri(getGLBindTarget(), GL_TEXTURE_WRAP_S, s);
601         glTexParameteri(getGLBindTarget(), GL_TEXTURE_WRAP_T, t);
602 }
603
604 void Texture::toUnit (const int unit) const
605 {
606         glActiveTexture(GL_TEXTURE0 + unit);
607         glBindTexture(getGLBindTarget(), m_textureGL);
608 }
609
610 /*--------------------------------------------------------------------*//*!
611  * \brief Buffer object helper class
612  *
613  * Each Buffer owns a GL buffer object that is created when the Buffer
614  * is constructed and deleted when it's destructed. The class provides some
615  * convenience interface functions to e.g. upload buffer data to the GL.
616  *
617  * In addition, the class tracks the approximate amount of GL memory,
618  * similarly to the Texture class (see above). The getApproxMemUsageDiff()
619  * is also analoguous.
620  *//*--------------------------------------------------------------------*/
621 class Buffer
622 {
623 public:
624                                                 Buffer                                  (void);
625                                                 ~Buffer                                 (void);
626
627         // Functions that may change the value returned by getApproxMemUsage().
628         template <typename T>
629         void                            setData                                 (const vector<T>& src, const deUint32 target, const deUint32 usage) { setData(&src[0], (int)(src.size()*sizeof(T)), target, usage); }
630         void                            setData                                 (const void* src, int size, deUint32 target, deUint32 usage);
631
632         // Functions that don't change the value returned by getApproxMemUsage().
633         template <typename T>
634         void                            setSubData                              (const vector<T>& src, const int offsetElems, const int numElems, const deUint32 target) { setSubData(&src[offsetElems], offsetElems*(int)sizeof(T), numElems*(int)sizeof(T), target); }
635         void                            setSubData                              (const void* src, int offsetBytes, int sizeBytes, deUint32 target) const;
636         void                            bind                                    (const deUint32 target) const { glBindBuffer(target, m_bufferGL); }
637
638         int                                     getApproxMemUsage               (void) const { return m_dataSizeApprox; }
639         template <typename T>
640         int                                     getApproxMemUsageDiff   (const vector<T>& src) const { return getApproxMemUsageDiff((int)(src.size()*sizeof(T))); }
641         int                                     getApproxMemUsageDiff   (const int sizeBytes) const { return sizeBytes - getApproxMemUsage(); }
642
643 private:
644                                                 Buffer                                  (const Buffer&); // Not allowed.
645         Buffer&                         operator=                               (const Buffer&); // Not allowed.
646
647         static deUint32         genBuffer                               (void) { deUint32 buf = 0; glGenBuffers(1, &buf); return buf; }
648
649         const deUint32          m_bufferGL;
650         int                                     m_dataSizeApprox;
651 };
652
653 Buffer::Buffer (void)
654         : m_bufferGL            (genBuffer())
655         , m_dataSizeApprox      (0)
656 {
657 }
658
659 Buffer::~Buffer (void)
660 {
661         glDeleteBuffers(1, &m_bufferGL);
662 }
663
664 void Buffer::setData (const void* const src, const int size, const deUint32 target, const deUint32 usage)
665 {
666         bind(target);
667         glBufferData(target, size, src, usage);
668         glBindBuffer(target, 0);
669
670         m_dataSizeApprox = size;
671 }
672
673 void Buffer::setSubData (const void* const src, const int offsetBytes, const int sizeBytes, const deUint32 target) const
674 {
675         bind(target);
676         glBufferSubData(target, offsetBytes, sizeBytes, src);
677         glBindBuffer(target, 0);
678 }
679
680 class Program
681 {
682 public:
683                                                 Program                                 (void);
684                                                 ~Program                                (void);
685
686         void                            setSources                              (const string& vertSource, const string& fragSource);
687         void                            build                                   (TestLog& log);
688         void                            use                                             (void) const { DE_ASSERT(m_isBuilt); glUseProgram(m_programGL); }
689         void                            setRandomUniforms               (const vector<VarSpec>& uniforms, const string& shaderNameManglingSuffix, Random& rnd) const;
690         void                            setAttribute                    (const Buffer& attrBuf, int attrBufOffset, const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const;
691         void                            setAttributeClientMem   (const void* attrData, const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const;
692         void                            disableAttributeArray   (const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const;
693
694 private:
695                                                 Program                         (const Program&); // Not allowed.
696         Program&                        operator=                       (const Program&); // Not allowed.
697
698         string                          m_vertSource;
699         string                          m_fragSource;
700
701         const deUint32          m_vertShaderGL;
702         const deUint32          m_fragShaderGL;
703         const deUint32          m_programGL;
704         bool                            m_hasSources;
705         bool                            m_isBuilt;
706 };
707
708 Program::Program (void)
709         : m_vertShaderGL        (glCreateShader(GL_VERTEX_SHADER))
710         , m_fragShaderGL        (glCreateShader(GL_FRAGMENT_SHADER))
711         , m_programGL           (glCreateProgram())
712         , m_hasSources          (false)
713         , m_isBuilt                     (false)
714 {
715         glAttachShader(m_programGL, m_vertShaderGL);
716         glAttachShader(m_programGL, m_fragShaderGL);
717 }
718
719 Program::~Program (void)
720 {
721         glDeleteShader(m_vertShaderGL);
722         glDeleteShader(m_fragShaderGL);
723         glDeleteProgram(m_programGL);
724 }
725
726 void Program::setSources (const string& vertSource, const string& fragSource)
727 {
728         const char* const vertSourceCstr = vertSource.c_str();
729         const char* const fragSourceCstr = fragSource.c_str();
730
731         m_vertSource = vertSource;
732         m_fragSource = fragSource;
733
734         // \note In GLES2 api the source parameter type lacks one const.
735         glShaderSource(m_vertShaderGL, 1, (const char**)&vertSourceCstr, DE_NULL);
736         glShaderSource(m_fragShaderGL, 1, (const char**)&fragSourceCstr, DE_NULL);
737
738         m_hasSources = true;
739 }
740
741 void Program::build (TestLog& log)
742 {
743         DE_ASSERT(m_hasSources);
744
745         const bool vertCompileOk        = compileShader(m_vertShaderGL);
746         const bool fragCompileOk        = compileShader(m_fragShaderGL);
747         const bool attemptLink          = vertCompileOk && fragCompileOk;
748         const bool linkOk                       = attemptLink && linkProgram(m_programGL);
749
750         if (!(vertCompileOk && fragCompileOk && linkOk))
751         {
752                 log << TestLog::ShaderProgram(linkOk, attemptLink ? getProgramInfoLog(m_programGL) : string(""))
753                         << TestLog::Shader(QP_SHADER_TYPE_VERTEX, m_vertSource, vertCompileOk, getShaderInfoLog(m_vertShaderGL))
754                         << TestLog::Shader(QP_SHADER_TYPE_FRAGMENT, m_fragSource, fragCompileOk, getShaderInfoLog(m_fragShaderGL))
755                         << TestLog::EndShaderProgram;
756
757                 throw tcu::TestError("Program build failed");
758         }
759
760         m_isBuilt = true;
761 }
762
763 void Program::setRandomUniforms (const vector<VarSpec>& uniforms, const string& shaderNameManglingSuffix, Random& rnd) const
764 {
765         use();
766
767         for (int unifNdx = 0; unifNdx < (int)uniforms.size(); unifNdx++)
768         {
769                 const VarSpec&  spec                    = uniforms[unifNdx];
770                 const int               typeScalarSize  = glu::getDataTypeScalarSize(spec.type);
771                 const int               location                = glGetUniformLocation(m_programGL, mangleShaderNames(spec.name, shaderNameManglingSuffix).c_str());
772                 if (location < 0)
773                         continue;
774
775                 if (glu::isDataTypeFloatOrVec(spec.type))
776                 {
777                         float val[4];
778                         for (int i = 0; i < typeScalarSize; i++)
779                                 val[i] = rnd.getFloat(spec.minValue.f[i], spec.maxValue.f[i]);
780
781                         switch (spec.type)
782                         {
783                                 case glu::TYPE_FLOAT:           glUniform1f(location, val[0]);                                                  break;
784                                 case glu::TYPE_FLOAT_VEC2:      glUniform2f(location, val[0], val[1]);                                  break;
785                                 case glu::TYPE_FLOAT_VEC3:      glUniform3f(location, val[0], val[1], val[2]);                  break;
786                                 case glu::TYPE_FLOAT_VEC4:      glUniform4f(location, val[0], val[1], val[2], val[3]);  break;
787                                 default: DE_ASSERT(false);
788                         }
789                 }
790                 else if (glu::isDataTypeMatrix(spec.type))
791                 {
792                         float val[4*4];
793                         for (int i = 0; i < typeScalarSize; i++)
794                                 val[i] = rnd.getFloat(spec.minValue.f[i], spec.maxValue.f[i]);
795
796                         switch (spec.type)
797                         {
798                                 case glu::TYPE_FLOAT_MAT2:              glUniformMatrix2fv              (location, 1, GL_FALSE, &val[0]); break;
799                                 case glu::TYPE_FLOAT_MAT3:              glUniformMatrix3fv              (location, 1, GL_FALSE, &val[0]); break;
800                                 case glu::TYPE_FLOAT_MAT4:              glUniformMatrix4fv              (location, 1, GL_FALSE, &val[0]); break;
801                                 case glu::TYPE_FLOAT_MAT2X3:    glUniformMatrix2x3fv    (location, 1, GL_FALSE, &val[0]); break;
802                                 case glu::TYPE_FLOAT_MAT2X4:    glUniformMatrix2x4fv    (location, 1, GL_FALSE, &val[0]); break;
803                                 case glu::TYPE_FLOAT_MAT3X2:    glUniformMatrix3x2fv    (location, 1, GL_FALSE, &val[0]); break;
804                                 case glu::TYPE_FLOAT_MAT3X4:    glUniformMatrix3x4fv    (location, 1, GL_FALSE, &val[0]); break;
805                                 case glu::TYPE_FLOAT_MAT4X2:    glUniformMatrix4x2fv    (location, 1, GL_FALSE, &val[0]); break;
806                                 case glu::TYPE_FLOAT_MAT4X3:    glUniformMatrix4x3fv    (location, 1, GL_FALSE, &val[0]); break;
807                                 default: DE_ASSERT(false);
808                         }
809                 }
810                 else if (glu::isDataTypeIntOrIVec(spec.type))
811                 {
812                         int val[4];
813                         for (int i = 0; i < typeScalarSize; i++)
814                                 val[i] = rnd.getInt(spec.minValue.i[i], spec.maxValue.i[i]);
815
816                         switch (spec.type)
817                         {
818                                 case glu::TYPE_INT:                     glUniform1i(location, val[0]);                                                  break;
819                                 case glu::TYPE_INT_VEC2:        glUniform2i(location, val[0], val[1]);                                  break;
820                                 case glu::TYPE_INT_VEC3:        glUniform3i(location, val[0], val[1], val[2]);                  break;
821                                 case glu::TYPE_INT_VEC4:        glUniform4i(location, val[0], val[1], val[2], val[3]);  break;
822                                 default: DE_ASSERT(false);
823                         }
824                 }
825                 else if (glu::isDataTypeUintOrUVec(spec.type))
826                 {
827                         deUint32 val[4];
828                         for (int i = 0; i < typeScalarSize; i++)
829                         {
830                                 DE_ASSERT(spec.minValue.i[i] >= 0 && spec.maxValue.i[i] >= 0);
831                                 val[i] = (deUint32)rnd.getInt(spec.minValue.i[i], spec.maxValue.i[i]);
832                         }
833
834                         switch (spec.type)
835                         {
836                                 case glu::TYPE_UINT:            glUniform1ui(location, val[0]);                                                 break;
837                                 case glu::TYPE_UINT_VEC2:       glUniform2ui(location, val[0], val[1]);                                 break;
838                                 case glu::TYPE_UINT_VEC3:       glUniform3ui(location, val[0], val[1], val[2]);                 break;
839                                 case glu::TYPE_UINT_VEC4:       glUniform4ui(location, val[0], val[1], val[2], val[3]); break;
840                                 default: DE_ASSERT(false);
841                         }
842                 }
843                 else
844                         DE_ASSERT(false);
845         }
846 }
847
848 void Program::setAttribute (const Buffer& attrBuf, const int attrBufOffset, const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const
849 {
850         const int attrLoc = glGetAttribLocation(m_programGL, mangleShaderNames(attrSpec.name, shaderNameManglingSuffix).c_str());
851
852         glEnableVertexAttribArray(attrLoc);
853         attrBuf.bind(GL_ARRAY_BUFFER);
854
855         if (glu::isDataTypeFloatOrVec(attrSpec.type))
856                 glVertexAttribPointer(attrLoc, glu::getDataTypeScalarSize(attrSpec.type), GL_FLOAT, GL_FALSE, 0, (GLvoid*)(deIntptr)attrBufOffset);
857         else
858                 DE_ASSERT(false);
859 }
860
861 void Program::setAttributeClientMem (const void* const attrData, const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const
862 {
863         const int attrLoc = glGetAttribLocation(m_programGL, mangleShaderNames(attrSpec.name, shaderNameManglingSuffix).c_str());
864
865         glEnableVertexAttribArray(attrLoc);
866         glBindBuffer(GL_ARRAY_BUFFER, 0);
867
868         if (glu::isDataTypeFloatOrVec(attrSpec.type))
869                 glVertexAttribPointer(attrLoc, glu::getDataTypeScalarSize(attrSpec.type), GL_FLOAT, GL_FALSE, 0, attrData);
870         else
871                 DE_ASSERT(false);
872 }
873
874 void Program::disableAttributeArray (const VarSpec& attrSpec, const string& shaderNameManglingSuffix) const
875 {
876         const int attrLoc = glGetAttribLocation(m_programGL, mangleShaderNames(attrSpec.name, shaderNameManglingSuffix).c_str());
877
878         glDisableVertexAttribArray(attrLoc);
879 }
880
881 /*--------------------------------------------------------------------*//*!
882  * \brief Container class for managing GL objects
883  *
884  * GLObjectManager can be used for objects of class Program, Buffer or
885  * Texture. In the manager, each such object is associated with a name that
886  * is used to access it.
887  *
888  * In addition to the making, getting and removing functions, the manager
889  * supports marking objects as "garbage", meaning they're not yet
890  * destroyed, but can be later destroyed with removeRandomGarbage(). The
891  * idea is that if we want to stress test with high memory usage, we can
892  * continuously move objects to garbage after using them, and when a memory
893  * limit is reached, we can call removeGarbageUntilUnder(limit, rnd). This
894  * way we can approximately keep our memory usage at just under the wanted
895  * limit.
896  *
897  * The manager also supports querying the approximate amount of GL memory
898  * used by its objects.
899  *
900  * \note The memory usage related functions are not currently supported
901  *               for Program objects.
902  *//*--------------------------------------------------------------------*/
903 template <typename T>
904 class GLObjectManager
905 {
906 public:
907         void                                            make                                            (const string& name)                                                            { DE_ASSERT(!has(name)); m_objects[name] = SharedPtr<T>(new T); }
908         void                                            make                                            (const string& name, gls::TextureType texType)          { DE_ASSERT(!has(name)); m_objects[name] = SharedPtr<T>(new T(texType)); }
909         bool                                            has                                                     (const string& name) const      { return m_objects.find(name) != m_objects.end(); }
910         const T&                                        get                                                     (const string& name) const;
911         T&                                                      get                                                     (const string& name)            { return const_cast<T&>(((const GLObjectManager<T>*)this)->get(name)); }
912         void                                            remove                                          (const string& name)            { const int removed = (int)m_objects.erase(name); DE_ASSERT(removed); DE_UNREF(removed); }
913         int                                                     computeApproxMemUsage           (void) const;
914         void                                            markAsGarbage                           (const string& name);
915         int                                                     removeRandomGarbage                     (Random& rnd);
916         void                                            removeGarbageUntilUnder         (int limit, Random& rnd);
917
918 private:
919         static const char*                      objTypeName                                     (void);
920
921         map<string, SharedPtr<T> >      m_objects;
922         vector<SharedPtr<T> >           m_garbageObjects;
923 };
924
925 template <> const char* GLObjectManager<Buffer>::objTypeName    (void) { return "buffer"; }
926 template <> const char* GLObjectManager<Texture>::objTypeName   (void) { return "texture"; }
927 template <> const char* GLObjectManager<Program>::objTypeName   (void) { return "program"; }
928
929 template <typename T>
930 const T& GLObjectManager<T>::get (const string& name) const
931 {
932         const typename map<string, SharedPtr<T> >::const_iterator it = m_objects.find(name);
933         DE_ASSERT(it != m_objects.end());
934         return *it->second;
935 }
936
937 template <typename T>
938 int GLObjectManager<T>::computeApproxMemUsage (void) const
939 {
940         int result = 0;
941
942         for (typename map<string, SharedPtr<T> >::const_iterator it = m_objects.begin(); it != m_objects.end(); ++it)
943                 result += it->second->getApproxMemUsage();
944
945         for (typename vector<SharedPtr<T> >::const_iterator it = m_garbageObjects.begin(); it != m_garbageObjects.end(); ++it)
946                 result += (*it)->getApproxMemUsage();
947
948         return result;
949 }
950
951 template <typename T>
952 void GLObjectManager<T>::markAsGarbage (const string& name)
953 {
954         const typename map<string, SharedPtr<T> >::iterator it = m_objects.find(name);
955         DE_ASSERT(it != m_objects.end());
956         m_garbageObjects.push_back(it->second);
957         m_objects.erase(it);
958 }
959
960 template <typename T>
961 int GLObjectManager<T>::removeRandomGarbage (Random& rnd)
962 {
963         if (m_garbageObjects.empty())
964                 return -1;
965
966         const int removeNdx             = rnd.getInt(0, (int)m_garbageObjects.size()-1);
967         const int memoryFreed   = m_garbageObjects[removeNdx]->getApproxMemUsage();
968         m_garbageObjects.erase(m_garbageObjects.begin() + removeNdx);
969         return memoryFreed;
970 }
971
972 template <typename T>
973 void GLObjectManager<T>::removeGarbageUntilUnder (const int limit, Random& rnd)
974 {
975         int memUsage = computeApproxMemUsage();
976
977         while (memUsage > limit)
978         {
979                 const int memReleased = removeRandomGarbage(rnd);
980                 if (memReleased < 0)
981                         throw tcu::InternalError(string("") + "Given " + objTypeName() + " memory usage limit exceeded, and no unneeded " + objTypeName() + " resources available to release");
982                 memUsage -= memReleased;
983                 DE_ASSERT(memUsage == computeApproxMemUsage());
984         }
985 }
986
987 } // LongStressCaseInternal
988
989 using namespace LongStressCaseInternal;
990
991 static int generateRandomAttribData (vector<deUint8>& attrDataBuf, int& dataSizeBytesDst, const VarSpec& attrSpec, const int numVertices, Random& rnd)
992 {
993         const bool      isFloat                 = glu::isDataTypeFloatOrVec(attrSpec.type);
994         const int       numComponents   = glu::getDataTypeScalarSize(attrSpec.type);
995         const int       componentSize   = (int)(isFloat ? sizeof(GLfloat) : sizeof(GLint));
996         const int       offsetInBuf             = nextDivisible((int)attrDataBuf.size(), componentSize); // Round up for alignment.
997
998         DE_STATIC_ASSERT(sizeof(GLint) == sizeof(int));
999         DE_STATIC_ASSERT(sizeof(GLfloat) == sizeof(float));
1000
1001         dataSizeBytesDst = numComponents*componentSize*numVertices;
1002
1003         attrDataBuf.resize(offsetInBuf + dataSizeBytesDst);
1004
1005         if (isFloat)
1006         {
1007                 float* const data = (float*)&attrDataBuf[offsetInBuf];
1008
1009                 for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx++)
1010                         for (int compNdx = 0; compNdx < numComponents; compNdx++)
1011                                 data[vtxNdx*numComponents + compNdx] = rnd.getFloat(attrSpec.minValue.f[compNdx], attrSpec.maxValue.f[compNdx]);
1012         }
1013         else
1014         {
1015                 DE_ASSERT(glu::isDataTypeIntOrIVec(attrSpec.type));
1016
1017                 int* const data = (int*)&attrDataBuf[offsetInBuf];
1018
1019                 for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx++)
1020                         for (int compNdx = 0; compNdx < numComponents; compNdx++)
1021                                 data[vtxNdx*numComponents + compNdx] = rnd.getInt(attrSpec.minValue.i[compNdx], attrSpec.maxValue.i[compNdx]);
1022         }
1023
1024         return offsetInBuf;
1025 }
1026
1027 static int generateRandomPositionAttribData (vector<deUint8>& attrDataBuf, int& dataSizeBytesDst, const VarSpec& attrSpec, const int numVertices, Random& rnd)
1028 {
1029         DE_ASSERT(glu::isDataTypeFloatOrVec(attrSpec.type));
1030
1031         const int numComponents = glu::getDataTypeScalarSize(attrSpec.type);
1032         DE_ASSERT(numComponents >= 2);
1033         const int offsetInBuf = generateRandomAttribData(attrDataBuf, dataSizeBytesDst, attrSpec, numVertices, rnd);
1034
1035         if (numComponents > 2)
1036         {
1037                 float* const data = (float*)&attrDataBuf[offsetInBuf];
1038
1039                 for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx++)
1040                         data[vtxNdx*numComponents + 2] = -1.0f;
1041
1042                 for (int triNdx = 0; triNdx < numVertices-2; triNdx++)
1043                 {
1044                         float* const    vtxAComps       = &data[(triNdx+0)*numComponents];
1045                         float* const    vtxBComps       = &data[(triNdx+1)*numComponents];
1046                         float* const    vtxCComps       = &data[(triNdx+2)*numComponents];
1047
1048                         const float             triArea         = triangleArea(Vec2(vtxAComps[0], vtxAComps[1]),
1049                                                                                                            Vec2(vtxBComps[0], vtxBComps[1]),
1050                                                                                                            Vec2(vtxCComps[0], vtxCComps[1]));
1051                         const float             t                       = triArea / (triArea + 1.0f);
1052                         const float             z                       = (1.0f-t)*attrSpec.minValue.f[2] + t*attrSpec.maxValue.f[2];
1053
1054                         vtxAComps[2] = de::max(vtxAComps[2], z);
1055                         vtxBComps[2] = de::max(vtxBComps[2], z);
1056                         vtxCComps[2] = de::max(vtxCComps[2], z);
1057                 }
1058         }
1059
1060         return offsetInBuf;
1061 }
1062
1063 static void generateAttribs (vector<deUint8>& attrDataBuf, vector<int>& attrDataOffsets, vector<int>& attrDataSizes, const vector<VarSpec>& attrSpecs, const string& posAttrName, const int numVertices, Random& rnd)
1064 {
1065         attrDataBuf.clear();
1066         attrDataOffsets.clear();
1067         attrDataSizes.resize(attrSpecs.size());
1068
1069         for (int i = 0; i < (int)attrSpecs.size(); i++)
1070         {
1071                 if (attrSpecs[i].name == posAttrName)
1072                         attrDataOffsets.push_back(generateRandomPositionAttribData(attrDataBuf, attrDataSizes[i], attrSpecs[i], numVertices, rnd));
1073                 else
1074                         attrDataOffsets.push_back(generateRandomAttribData(attrDataBuf, attrDataSizes[i], attrSpecs[i], numVertices, rnd));
1075         }
1076 }
1077
1078 LongStressCase::LongStressCase (tcu::TestContext&                               testCtx,
1079                                                                 const glu::RenderContext&               renderCtx,
1080                                                                 const char* const                               name,
1081                                                                 const char* const                               desc,
1082                                                                 const int                                               maxTexMemoryUsageBytes,
1083                                                                 const int                                               maxBufMemoryUsageBytes,
1084                                                                 const int                                               numDrawCallsPerIteration,
1085                                                                 const int                                               numTrianglesPerDrawCall,
1086                                                                 const vector<ProgramContext>&   programContexts,
1087                                                                 const FeatureProbabilities&             probabilities,
1088                                                                 const deUint32                                  indexBufferUsage,
1089                                                                 const deUint32                                  attrBufferUsage,
1090                                                                 const int                                               redundantBufferFactor,
1091                                                                 const bool                                              showDebugInfo)
1092         : tcu::TestCase                                 (testCtx, name, desc)
1093         , m_renderCtx                                   (renderCtx)
1094         , m_maxTexMemoryUsageBytes              (maxTexMemoryUsageBytes)
1095         , m_maxBufMemoryUsageBytes              (maxBufMemoryUsageBytes)
1096         , m_numDrawCallsPerIteration    (numDrawCallsPerIteration)
1097         , m_numTrianglesPerDrawCall             (numTrianglesPerDrawCall)
1098         , m_numVerticesPerDrawCall              (numTrianglesPerDrawCall+2) // \note Triangle strips are used.
1099         , m_programContexts                             (programContexts)
1100         , m_probabilities                               (probabilities)
1101         , m_indexBufferUsage                    (indexBufferUsage)
1102         , m_attrBufferUsage                             (attrBufferUsage)
1103         , m_redundantBufferFactor               (redundantBufferFactor)
1104         , m_showDebugInfo                               (showDebugInfo)
1105         , m_numIterations                               (getNumIterations(testCtx, 5))
1106         , m_isGLES3                                             (contextSupports(renderCtx.getType(), glu::ApiType::es(3,0)))
1107         , m_currentIteration                    (0)
1108         , m_startTimeSeconds                    ((deUint64)-1)
1109         , m_lastLogTime                                 ((deUint64)-1)
1110         , m_lastLogIteration                    (0)
1111         , m_currentLogEntryNdx                  (0)
1112         , m_rnd                                                 (deStringHash(getName()) ^ testCtx.getCommandLine().getBaseSeed())
1113         , m_programs                                    (DE_NULL)
1114         , m_buffers                                             (DE_NULL)
1115         , m_textures                                    (DE_NULL)
1116         , m_debugInfoRenderer                   (DE_NULL)
1117 {
1118         DE_ASSERT(m_numVerticesPerDrawCall <= (int)std::numeric_limits<deUint16>::max()+1); // \note Vertices are referred to with 16-bit indices.
1119         DE_ASSERT(m_redundantBufferFactor > 0);
1120 }
1121
1122 LongStressCase::~LongStressCase (void)
1123 {
1124         LongStressCase::deinit();
1125 }
1126
1127 void LongStressCase::init (void)
1128 {
1129         // Generate dummy texture data for each texture spec in m_programContexts.
1130
1131         DE_ASSERT(!m_programContexts.empty());
1132         DE_ASSERT(m_programResources.empty());
1133         m_programResources.resize(m_programContexts.size());
1134
1135         for (int progCtxNdx = 0; progCtxNdx < (int)m_programContexts.size(); progCtxNdx++)
1136         {
1137                 const ProgramContext&   progCtx = m_programContexts[progCtxNdx];
1138                 ProgramResources&               progRes = m_programResources[progCtxNdx];
1139
1140                 for (int texSpecNdx = 0; texSpecNdx < (int)progCtx.textureSpecs.size(); texSpecNdx++)
1141                 {
1142                         const TextureSpec&              spec    = progCtx.textureSpecs[texSpecNdx];
1143                         const TextureFormat             format  = glu::mapGLTransferFormat(spec.format, spec.dataType);
1144
1145                         // If texture data with the same format has already been generated, re-use that (don't care much about contents).
1146
1147                         SharedPtr<TextureLevel> dummyTex;
1148
1149                         for (int prevProgCtxNdx = 0; prevProgCtxNdx < (int)m_programResources.size(); prevProgCtxNdx++)
1150                         {
1151                                 const vector<SharedPtr<TextureLevel> >& prevProgCtxTextures = m_programResources[prevProgCtxNdx].dummyTextures;
1152
1153                                 for (int texNdx = 0; texNdx < (int)prevProgCtxTextures.size(); texNdx++)
1154                                 {
1155                                         if (prevProgCtxTextures[texNdx]->getFormat() == format)
1156                                         {
1157                                                 dummyTex = prevProgCtxTextures[texNdx];
1158                                                 break;
1159                                         }
1160                                 }
1161                         }
1162
1163                         if (!dummyTex)
1164                                 dummyTex = SharedPtr<TextureLevel>(new TextureLevel(format));
1165
1166                         if (dummyTex->getWidth() < spec.width || dummyTex->getHeight() < spec.height)
1167                         {
1168                                 dummyTex->setSize(spec.width, spec.height);
1169                                 tcu::fillWithComponentGradients(dummyTex->getAccess(), spec.minValue, spec.maxValue);
1170                         }
1171
1172                         progRes.dummyTextures.push_back(dummyTex);
1173                 }
1174         }
1175
1176         m_vertexIndices.clear();
1177         for (int i = 0; i < m_numVerticesPerDrawCall; i++)
1178                 m_vertexIndices.push_back((deUint16)i);
1179         m_rnd.shuffle(m_vertexIndices.begin(), m_vertexIndices.end());
1180
1181         DE_ASSERT(!m_programs && !m_buffers && !m_textures);
1182         m_programs = new GLObjectManager<Program>;
1183         m_buffers = new GLObjectManager<Buffer>;
1184         m_textures = new GLObjectManager<Texture>;
1185
1186         m_currentIteration = 0;
1187
1188         {
1189                 TestLog& log = m_testCtx.getLog();
1190
1191                 log << TestLog::Message << "Number of iterations: "                                                                             << (m_numIterations > 0 ? toString(m_numIterations) : "infinite")                               << TestLog::EndMessage
1192                         << TestLog::Message << "Number of draw calls per iteration: "                                           << m_numDrawCallsPerIteration                                                                                                   << TestLog::EndMessage
1193                         << TestLog::Message << "Number of triangles per draw call: "                                            << m_numTrianglesPerDrawCall                                                                                                    << TestLog::EndMessage
1194                         << TestLog::Message << "Using triangle strips"                                                                                                                                                                                                                                          << TestLog::EndMessage
1195                         << TestLog::Message << "Approximate texture memory usage limit: "                                       << de::floatToString((float)m_maxTexMemoryUsageBytes / Mi, 2) << " MiB"                 << TestLog::EndMessage
1196                         << TestLog::Message << "Approximate buffer memory usage limit: "                                        << de::floatToString((float)m_maxBufMemoryUsageBytes / Mi, 2) << " MiB"                 << TestLog::EndMessage
1197                         << TestLog::Message << "Default vertex attribute data buffer usage parameter: "         << glu::getUsageName(m_attrBufferUsage)                                                                                 << TestLog::EndMessage
1198                         << TestLog::Message << "Default vertex index data buffer usage parameter: "                     << glu::getUsageName(m_indexBufferUsage)                                                                                << TestLog::EndMessage
1199
1200                         << TestLog::Section("ProbabilityParams", "Per-iteration probability parameters")
1201                         << TestLog::Message << "Program re-build: "                                                                                                                     << probabilityStr(m_probabilities.rebuildProgram)                               << TestLog::EndMessage
1202                         << TestLog::Message << "Texture re-upload: "                                                                                                            << probabilityStr(m_probabilities.reuploadTexture)                              << TestLog::EndMessage
1203                         << TestLog::Message << "Buffer re-upload: "                                                                                                                     << probabilityStr(m_probabilities.reuploadBuffer)                               << TestLog::EndMessage
1204                         << TestLog::Message << "Use glTexImage* instead of glTexSubImage* when uploading texture: "                     << probabilityStr(m_probabilities.reuploadWithTexImage)                 << TestLog::EndMessage
1205                         << TestLog::Message << "Use glBufferData* instead of glBufferSubData* when uploading buffer: "          << probabilityStr(m_probabilities.reuploadWithBufferData)               << TestLog::EndMessage
1206                         << TestLog::Message << "Delete texture after using it, even if could re-use it: "                                       << probabilityStr(m_probabilities.deleteTexture)                                << TestLog::EndMessage
1207                         << TestLog::Message << "Delete buffer after using it, even if could re-use it: "                                        << probabilityStr(m_probabilities.deleteBuffer)                                 << TestLog::EndMessage
1208                         << TestLog::Message << "Don't re-use texture, and only delete if memory limit is hit: "                         << probabilityStr(m_probabilities.wastefulTextureMemoryUsage)   << TestLog::EndMessage
1209                         << TestLog::Message << "Don't re-use buffer, and only delete if memory limit is hit: "                          << probabilityStr(m_probabilities.wastefulBufferMemoryUsage)    << TestLog::EndMessage
1210                         << TestLog::Message << "Use client memory (instead of GL buffers) for vertex attribute data: "          << probabilityStr(m_probabilities.clientMemoryAttributeData)    << TestLog::EndMessage
1211                         << TestLog::Message << "Use client memory (instead of GL buffers) for vertex index data: "                      << probabilityStr(m_probabilities.clientMemoryIndexData)                << TestLog::EndMessage
1212                         << TestLog::Message << "Use random target parameter when uploading buffer data: "                                       << probabilityStr(m_probabilities.randomBufferUploadTarget)             << TestLog::EndMessage
1213                         << TestLog::Message << "Use random usage parameter when uploading buffer data: "                                        << probabilityStr(m_probabilities.randomBufferUsage)                    << TestLog::EndMessage
1214                         << TestLog::Message << "Use glDrawArrays instead of glDrawElements: "                                                           << probabilityStr(m_probabilities.useDrawArrays)                                << TestLog::EndMessage
1215                         << TestLog::Message << "Use separate buffers for each attribute, instead of one array for all: "        << probabilityStr(m_probabilities.separateAttributeBuffers)             << TestLog::EndMessage
1216                         << TestLog::EndSection
1217                         << TestLog::Message << "Using " << m_programContexts.size() << " program(s)" << TestLog::EndMessage;
1218
1219                 bool anyProgramsFailed = false;
1220                 for (int progCtxNdx = 0; progCtxNdx < (int)m_programContexts.size(); progCtxNdx++)
1221                 {
1222                         const ProgramContext& progCtx = m_programContexts[progCtxNdx];
1223                         glu::ShaderProgram prog(m_renderCtx, glu::makeVtxFragSources(mangleShaderNames(progCtx.vertexSource, ""), mangleShaderNames(progCtx.fragmentSource, "")));
1224                         log << TestLog::Section("ShaderProgram" + toString(progCtxNdx), "Shader program " + toString(progCtxNdx)) << prog << TestLog::EndSection;
1225                         if (!prog.isOk())
1226                                 anyProgramsFailed = true;
1227                 }
1228
1229                 if (anyProgramsFailed)
1230                         throw tcu::TestError("One or more shader programs failed to compile");
1231         }
1232
1233         DE_ASSERT(!m_debugInfoRenderer);
1234         if (m_showDebugInfo)
1235                 m_debugInfoRenderer = new DebugInfoRenderer(m_renderCtx);
1236 }
1237
1238 void LongStressCase::deinit (void)
1239 {
1240         m_programResources.clear();
1241
1242         delete m_programs;
1243         m_programs = DE_NULL;
1244
1245         delete m_buffers;
1246         m_buffers = DE_NULL;
1247
1248         delete m_textures;
1249         m_textures = DE_NULL;
1250
1251         delete m_debugInfoRenderer;
1252         m_debugInfoRenderer = DE_NULL;
1253 }
1254
1255 LongStressCase::IterateResult LongStressCase::iterate (void)
1256 {
1257         TestLog&                                        log                                                     = m_testCtx.getLog();
1258         const int                                       renderWidth                                     = m_renderCtx.getRenderTarget().getWidth();
1259         const int                                       renderHeight                            = m_renderCtx.getRenderTarget().getHeight();
1260         const bool                                      useClientMemoryIndexData        = m_rnd.getFloat() < m_probabilities.clientMemoryIndexData;
1261         const bool                                      useDrawArrays                           = m_rnd.getFloat() < m_probabilities.useDrawArrays;
1262         const bool                                      separateAttributeBuffers        = m_rnd.getFloat() < m_probabilities.separateAttributeBuffers;
1263         const int                                       progContextNdx                          = m_rnd.getInt(0, (int)m_programContexts.size()-1);
1264         const ProgramContext&           programContext                          = m_programContexts[progContextNdx];
1265         ProgramResources&                       programResources                        = m_programResources[progContextNdx];
1266         const string                            programName                                     = "prog" + toString(progContextNdx);
1267         const string                            textureNamePrefix                       = "tex" + toString(progContextNdx) + "_";
1268         const string                            unitedAttrBufferNamePrefix      = "attrBuf" + toString(progContextNdx) + "_";
1269         const string                            indexBufferName                         = "indexBuf" + toString(progContextNdx);
1270         const string                            separateAttrBufNamePrefix       = "attrBuf" + toString(progContextNdx) + "_";
1271
1272         if (m_currentIteration == 0)
1273                 m_lastLogTime = m_startTimeSeconds = deGetTime();
1274
1275         // Make or re-compile programs.
1276         {
1277                 const bool hadProgram = m_programs->has(programName);
1278
1279                 if (!hadProgram)
1280                         m_programs->make(programName);
1281
1282                 Program& prog = m_programs->get(programName);
1283
1284                 if (!hadProgram || m_rnd.getFloat() < m_probabilities.rebuildProgram)
1285                 {
1286                         programResources.shaderNameManglingSuffix = toString((deUint16)deUint64Hash((deUint64)m_currentIteration ^ deGetTime()));
1287
1288                         prog.setSources(mangleShaderNames(programContext.vertexSource, programResources.shaderNameManglingSuffix),
1289                                                         mangleShaderNames(programContext.fragmentSource, programResources.shaderNameManglingSuffix));
1290
1291                         prog.build(log);
1292                 }
1293
1294                 prog.use();
1295         }
1296
1297         Program& program = m_programs->get(programName);
1298
1299         // Make or re-upload textures.
1300
1301         for (int texNdx = 0; texNdx < (int)programContext.textureSpecs.size(); texNdx++)
1302         {
1303                 const string            texName         = textureNamePrefix + toString(texNdx);
1304                 const bool                      hadTexture      = m_textures->has(texName);
1305                 const TextureSpec&      spec            = programContext.textureSpecs[texNdx];
1306
1307                 if (!hadTexture)
1308                         m_textures->make(texName, spec.textureType);
1309
1310                 if (!hadTexture || m_rnd.getFloat() < m_probabilities.reuploadTexture)
1311                 {
1312                         Texture& texture = m_textures->get(texName);
1313
1314                         m_textures->removeGarbageUntilUnder(m_maxTexMemoryUsageBytes - texture.getApproxMemUsageDiff(spec.width, spec.height, spec.internalFormat, spec.useMipmap), m_rnd);
1315
1316                         if (!hadTexture || m_rnd.getFloat() < m_probabilities.reuploadWithTexImage)
1317                                 texture.setData(programResources.dummyTextures[texNdx]->getAccess(), spec.width, spec.height, spec.internalFormat, spec.useMipmap);
1318                         else
1319                                 texture.setSubData(programResources.dummyTextures[texNdx]->getAccess(), 0, 0, spec.width, spec.height);
1320
1321                         texture.toUnit(0);
1322                         texture.setWrap(spec.sWrap, spec.tWrap);
1323                         texture.setFilter(spec.minFilter, spec.magFilter);
1324                 }
1325         }
1326
1327         // Bind textures to units, in random order (because when multiple texture specs have same unit, we want to pick one randomly).
1328
1329         {
1330                 vector<int> texSpecIndices(programContext.textureSpecs.size());
1331                 for (int i = 0; i < (int)texSpecIndices.size(); i++)
1332                         texSpecIndices[i] = i;
1333                 m_rnd.shuffle(texSpecIndices.begin(), texSpecIndices.end());
1334                 for (int i = 0; i < (int)texSpecIndices.size(); i++)
1335                         m_textures->get(textureNamePrefix + toString(texSpecIndices[i])).toUnit(programContext.textureSpecs[i].textureUnit);
1336         }
1337
1338         // Make or re-upload index buffer.
1339
1340         if (!useDrawArrays)
1341         {
1342                 m_rnd.shuffle(m_vertexIndices.begin(), m_vertexIndices.end());
1343
1344                 if (!useClientMemoryIndexData)
1345                 {
1346                         const bool hadIndexBuffer = m_buffers->has(indexBufferName);
1347
1348                         if (!hadIndexBuffer)
1349                                 m_buffers->make(indexBufferName);
1350
1351                         Buffer& indexBuf = m_buffers->get(indexBufferName);
1352
1353                         if (!hadIndexBuffer || m_rnd.getFloat() < m_probabilities.reuploadBuffer)
1354                         {
1355                                 m_buffers->removeGarbageUntilUnder(m_maxBufMemoryUsageBytes - indexBuf.getApproxMemUsageDiff(m_vertexIndices), m_rnd);
1356                                 const deUint32 target = m_rnd.getFloat() < m_probabilities.randomBufferUploadTarget ? randomBufferTarget(m_rnd, m_isGLES3) : GL_ELEMENT_ARRAY_BUFFER;
1357
1358                                 if (!hadIndexBuffer || m_rnd.getFloat() < m_probabilities.reuploadWithBufferData)
1359                                         indexBuf.setData(m_vertexIndices, target, m_rnd.getFloat() < m_probabilities.randomBufferUsage ? randomBufferUsage(m_rnd, m_isGLES3) : m_indexBufferUsage);
1360                                 else
1361                                         indexBuf.setSubData(m_vertexIndices, 0, m_numVerticesPerDrawCall, target);
1362                         }
1363                 }
1364         }
1365
1366         // Set vertex attributes. If not using client-memory data, make or re-upload attribute buffers.
1367
1368         generateAttribs(programResources.attrDataBuf, programResources.attrDataOffsets, programResources.attrDataSizes,
1369                                         programContext.attributes, programContext.positionAttrName, m_numVerticesPerDrawCall, m_rnd);
1370
1371         if (!(m_rnd.getFloat() < m_probabilities.clientMemoryAttributeData))
1372         {
1373                 if (separateAttributeBuffers)
1374                 {
1375                         for (int attrNdx = 0; attrNdx < (int)programContext.attributes.size(); attrNdx++)
1376                         {
1377                                 const int usedRedundantBufferNdx = m_rnd.getInt(0, m_redundantBufferFactor-1);
1378
1379                                 for (int redundantBufferNdx = 0; redundantBufferNdx < m_redundantBufferFactor; redundantBufferNdx++)
1380                                 {
1381                                         const string    curAttrBufName          = separateAttrBufNamePrefix + toString(attrNdx) + "_" + toString(redundantBufferNdx);
1382                                         const bool              hadCurAttrBuffer        = m_buffers->has(curAttrBufName);
1383
1384                                         if (!hadCurAttrBuffer)
1385                                                 m_buffers->make(curAttrBufName);
1386
1387                                         Buffer& curAttrBuf = m_buffers->get(curAttrBufName);
1388
1389                                         if (!hadCurAttrBuffer || m_rnd.getFloat() < m_probabilities.reuploadBuffer)
1390                                         {
1391                                                 m_buffers->removeGarbageUntilUnder(m_maxBufMemoryUsageBytes - curAttrBuf.getApproxMemUsageDiff(programResources.attrDataSizes[attrNdx]), m_rnd);
1392                                                 const deUint32 target = m_rnd.getFloat() < m_probabilities.randomBufferUploadTarget ? randomBufferTarget(m_rnd, m_isGLES3) : GL_ARRAY_BUFFER;
1393
1394                                                 if (!hadCurAttrBuffer || m_rnd.getFloat() < m_probabilities.reuploadWithBufferData)
1395                                                         curAttrBuf.setData(&programResources.attrDataBuf[programResources.attrDataOffsets[attrNdx]], programResources.attrDataSizes[attrNdx], target,
1396                                                                                            m_rnd.getFloat() < m_probabilities.randomBufferUsage ? randomBufferUsage(m_rnd, m_isGLES3) : m_attrBufferUsage);
1397                                                 else
1398                                                         curAttrBuf.setSubData(&programResources.attrDataBuf[programResources.attrDataOffsets[attrNdx]], 0, programResources.attrDataSizes[attrNdx], target);
1399                                         }
1400
1401                                         if (redundantBufferNdx == usedRedundantBufferNdx)
1402                                                 program.setAttribute(curAttrBuf, 0, programContext.attributes[attrNdx], programResources.shaderNameManglingSuffix);
1403                                 }
1404                         }
1405                 }
1406                 else
1407                 {
1408                         const int usedRedundantBufferNdx = m_rnd.getInt(0, m_redundantBufferFactor-1);
1409
1410                         for (int redundantBufferNdx = 0; redundantBufferNdx < m_redundantBufferFactor; redundantBufferNdx++)
1411                         {
1412                                 const string    attrBufName             = unitedAttrBufferNamePrefix + toString(redundantBufferNdx);
1413                                 const bool              hadAttrBuffer   = m_buffers->has(attrBufName);
1414
1415                                 if (!hadAttrBuffer)
1416                                         m_buffers->make(attrBufName);
1417
1418                                 Buffer& attrBuf = m_buffers->get(attrBufName);
1419
1420                                 if (!hadAttrBuffer || m_rnd.getFloat() < m_probabilities.reuploadBuffer)
1421                                 {
1422                                         m_buffers->removeGarbageUntilUnder(m_maxBufMemoryUsageBytes - attrBuf.getApproxMemUsageDiff(programResources.attrDataBuf), m_rnd);
1423                                         const deUint32 target = m_rnd.getFloat() < m_probabilities.randomBufferUploadTarget ? randomBufferTarget(m_rnd, m_isGLES3) : GL_ARRAY_BUFFER;
1424
1425                                         if (!hadAttrBuffer || m_rnd.getFloat() < m_probabilities.reuploadWithBufferData)
1426                                                 attrBuf.setData(programResources.attrDataBuf, target, m_rnd.getFloat() < m_probabilities.randomBufferUsage ? randomBufferUsage(m_rnd, m_isGLES3) : m_attrBufferUsage);
1427                                         else
1428                                                 attrBuf.setSubData(programResources.attrDataBuf, 0, (int)programResources.attrDataBuf.size(), target);
1429                                 }
1430
1431                                 if (redundantBufferNdx == usedRedundantBufferNdx)
1432                                 {
1433                                         for (int i = 0; i < (int)programContext.attributes.size(); i++)
1434                                                 program.setAttribute(attrBuf, programResources.attrDataOffsets[i], programContext.attributes[i], programResources.shaderNameManglingSuffix);
1435                                 }
1436                         }
1437                 }
1438         }
1439         else
1440         {
1441                 for (int i = 0; i < (int)programContext.attributes.size(); i++)
1442                         program.setAttributeClientMem(&programResources.attrDataBuf[programResources.attrDataOffsets[i]], programContext.attributes[i], programResources.shaderNameManglingSuffix);
1443         }
1444
1445         // Draw.
1446
1447         glViewport(0, 0, renderWidth, renderHeight);
1448
1449         glClearDepthf(1.0f);
1450         glClear(GL_DEPTH_BUFFER_BIT);
1451         glEnable(GL_DEPTH_TEST);
1452
1453         for (int i = 0; i < m_numDrawCallsPerIteration; i++)
1454         {
1455                 program.use();
1456                 program.setRandomUniforms(programContext.uniforms, programResources.shaderNameManglingSuffix, m_rnd);
1457
1458                 if (useDrawArrays)
1459                         glDrawArrays(GL_TRIANGLE_STRIP, 0, m_numVerticesPerDrawCall);
1460                 else
1461                 {
1462                         if (useClientMemoryIndexData)
1463                         {
1464                                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1465                                 glDrawElements(GL_TRIANGLE_STRIP, m_numVerticesPerDrawCall, GL_UNSIGNED_SHORT, &m_vertexIndices[0]);
1466                         }
1467                         else
1468                         {
1469                                 m_buffers->get(indexBufferName).bind(GL_ELEMENT_ARRAY_BUFFER);
1470                                 glDrawElements(GL_TRIANGLE_STRIP, m_numVerticesPerDrawCall, GL_UNSIGNED_SHORT, DE_NULL);
1471                         }
1472                 }
1473         }
1474
1475         for(int i = 0; i < (int)programContext.attributes.size(); i++)
1476                 program.disableAttributeArray(programContext.attributes[i], programResources.shaderNameManglingSuffix);
1477
1478         if (m_showDebugInfo)
1479                 m_debugInfoRenderer->drawInfo(deGetTime()-m_startTimeSeconds, m_textures->computeApproxMemUsage(), m_maxTexMemoryUsageBytes, m_buffers->computeApproxMemUsage(), m_maxBufMemoryUsageBytes, m_currentIteration);
1480
1481         if (m_currentIteration > 0)
1482         {
1483                 // Log if a certain amount of time has passed since last log entry (or if this is the last iteration).
1484
1485                 const deUint64  loggingIntervalSeconds  = 10;
1486                 const deUint64  time                                    = deGetTime();
1487                 const deUint64  timeDiff                                = time - m_lastLogTime;
1488                 const int               iterDiff                                = m_currentIteration - m_lastLogIteration;
1489
1490                 if (timeDiff >= loggingIntervalSeconds || m_currentIteration == m_numIterations-1)
1491                 {
1492                         log << TestLog::Section("LogEntry" + toString(m_currentLogEntryNdx), "Log entry " + toString(m_currentLogEntryNdx))
1493                                 << TestLog::Message << "Time elapsed: " << getTimeStr(time - m_startTimeSeconds) << TestLog::EndMessage
1494                                 << TestLog::Message << "Frame number: " << m_currentIteration << TestLog::EndMessage
1495                                 << TestLog::Message << "Time since last log entry: " << timeDiff << "s" << TestLog::EndMessage
1496                                 << TestLog::Message << "Frames since last log entry: " << iterDiff << TestLog::EndMessage
1497                                 << TestLog::Message << "Average frame time since last log entry: " << de::floatToString((float)timeDiff / (float)iterDiff, 2) << "s" << TestLog::EndMessage
1498                                 << TestLog::Message << "Approximate texture memory usage: "
1499                                                                         << de::floatToString((float)m_textures->computeApproxMemUsage() / Mi, 2) << " MiB / "
1500                                                                         << de::floatToString((float)m_maxTexMemoryUsageBytes / Mi, 2) << " MiB"
1501                                                                         << TestLog::EndMessage
1502                                 << TestLog::Message << "Approximate buffer memory usage: "
1503                                                                                 << de::floatToString((float)m_buffers->computeApproxMemUsage() / Mi, 2) << " MiB / "
1504                                                                                 << de::floatToString((float)m_maxBufMemoryUsageBytes / Mi, 2) << " MiB"
1505                                                                                 << TestLog::EndMessage
1506                                 << TestLog::EndSection;
1507
1508                         m_lastLogTime           = time;
1509                         m_lastLogIteration      = m_currentIteration;
1510                         m_currentLogEntryNdx++;
1511                 }
1512         }
1513
1514         // Possibly remove or set-as-garbage some objects, depending on given probabilities.
1515
1516         for (int texNdx = 0; texNdx < (int)programContext.textureSpecs.size(); texNdx++)
1517         {
1518                 const string texName = textureNamePrefix + toString(texNdx);
1519                 if (m_rnd.getFloat() < m_probabilities.deleteTexture)
1520                         m_textures->remove(texName);
1521                 else if (m_rnd.getFloat() < m_probabilities.wastefulTextureMemoryUsage)
1522                         m_textures->markAsGarbage(texName);
1523
1524         }
1525
1526         if (m_buffers->has(indexBufferName))
1527         {
1528                 if (m_rnd.getFloat() < m_probabilities.deleteBuffer)
1529                         m_buffers->remove(indexBufferName);
1530                 else if (m_rnd.getFloat() < m_probabilities.wastefulBufferMemoryUsage)
1531                         m_buffers->markAsGarbage(indexBufferName);
1532
1533         }
1534
1535         if (separateAttributeBuffers)
1536         {
1537                 for (int attrNdx = 0; attrNdx < (int)programContext.attributes.size(); attrNdx++)
1538                 {
1539                         const string curAttrBufNamePrefix = separateAttrBufNamePrefix + toString(attrNdx) + "_";
1540
1541                         if (m_buffers->has(curAttrBufNamePrefix + "0"))
1542                         {
1543                                 if (m_rnd.getFloat() < m_probabilities.deleteBuffer)
1544                                 {
1545                                         for (int i = 0; i < m_redundantBufferFactor; i++)
1546                                                 m_buffers->remove(curAttrBufNamePrefix + toString(i));
1547                                 }
1548                                 else if (m_rnd.getFloat() < m_probabilities.wastefulBufferMemoryUsage)
1549                                 {
1550                                         for (int i = 0; i < m_redundantBufferFactor; i++)
1551                                                 m_buffers->markAsGarbage(curAttrBufNamePrefix + toString(i));
1552                                 }
1553                         }
1554                 }
1555         }
1556         else
1557         {
1558                 if (m_buffers->has(unitedAttrBufferNamePrefix + "0"))
1559                 {
1560                         if (m_rnd.getFloat() < m_probabilities.deleteBuffer)
1561                         {
1562                                 for (int i = 0; i < m_redundantBufferFactor; i++)
1563                                         m_buffers->remove(unitedAttrBufferNamePrefix + toString(i));
1564                         }
1565                         else if (m_rnd.getFloat() < m_probabilities.wastefulBufferMemoryUsage)
1566                         {
1567                                 for (int i = 0; i < m_redundantBufferFactor; i++)
1568                                         m_buffers->markAsGarbage(unitedAttrBufferNamePrefix + toString(i));
1569                         }
1570                 }
1571         }
1572
1573         GLU_CHECK_MSG("End of LongStressCase::iterate()");
1574
1575         m_currentIteration++;
1576         if (m_currentIteration == m_numIterations)
1577         {
1578                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Passed");
1579                 return STOP;
1580         }
1581         else
1582                 return CONTINUE;
1583 }
1584
1585 } // gls
1586 } // deqp