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