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