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