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