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