Home | History | Annotate | Download | only in performance
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 2.0 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 Texture upload performance tests.
     22  *
     23  * \todo [2012-10-01 pyry]
     24  *  - Test different pixel unpack alignments
     25  *  - Use multiple textures
     26  *  - Trash cache prior to uploading from data ptr
     27  *//*--------------------------------------------------------------------*/
     28 
     29 #include "es2pTextureUploadTests.hpp"
     30 #include "tcuTexture.hpp"
     31 #include "tcuTextureUtil.hpp"
     32 #include "tcuTestLog.hpp"
     33 #include "tcuSurface.hpp"
     34 #include "gluTextureUtil.hpp"
     35 #include "gluShaderProgram.hpp"
     36 #include "gluPixelTransfer.hpp"
     37 #include "deStringUtil.hpp"
     38 #include "deRandom.hpp"
     39 #include "deClock.h"
     40 #include "deString.h"
     41 
     42 #include "glsCalibration.hpp"
     43 
     44 #include "glwEnums.hpp"
     45 #include "glwFunctions.hpp"
     46 
     47 #include <algorithm>
     48 #include <vector>
     49 
     50 namespace deqp
     51 {
     52 namespace gles2
     53 {
     54 namespace Performance
     55 {
     56 
     57 using tcu::Vec2;
     58 using tcu::Vec3;
     59 using tcu::Vec4;
     60 using tcu::IVec4;
     61 using std::string;
     62 using std::vector;
     63 using tcu::TestLog;
     64 using tcu::TextureFormat;
     65 using namespace glw; // GL types
     66 
     67 static const int	VIEWPORT_SIZE	= 64;
     68 static const float	quadCoords[] =
     69 {
     70 	-1.0f, -1.0f,
     71 	 1.0f, -1.0f,
     72 	-1.0f,  1.0f,
     73 	 1.0f,  1.0f
     74 };
     75 
     76 class TextureUploadCase : public TestCase
     77 {
     78 public:
     79 								TextureUploadCase	(Context& context, const char* name, const char* description, UploadFunction uploadFunction, deUint32 format, deUint32 type, int texSize);
     80 								~TextureUploadCase	(void);
     81 
     82 	virtual void				init				(void);
     83 	void						deinit				(void);
     84 
     85 	virtual IterateResult		iterate				(void) = 0;
     86 	void						logResults			(void);
     87 
     88 protected:
     89 	UploadFunction				m_uploadFunction;
     90 	deUint32					m_format;
     91 	deUint32					m_type;
     92 	int							m_texSize;
     93 	int							m_alignment;
     94 
     95 	gls::TheilSenCalibrator		m_calibrator;
     96 	glu::ShaderProgram*			m_program;
     97 	deUint32					m_texture;
     98 	de::Random					m_rnd;
     99 	TestLog&					m_log;
    100 
    101 	vector<deUint8>				m_texData;
    102 };
    103 
    104 TextureUploadCase::TextureUploadCase (Context& context, const char* name, const char* description, UploadFunction uploadFunction, deUint32 format, deUint32 type, int texSize)
    105 	: TestCase			(context, tcu::NODETYPE_PERFORMANCE, name, description)
    106 	, m_uploadFunction	(uploadFunction)
    107 	, m_format			(format)
    108 	, m_type			(type)
    109 	, m_texSize			(texSize)
    110 	, m_alignment		(4)
    111 	, m_calibrator		()
    112 	, m_program			(DE_NULL)
    113 	, m_texture			(0)
    114 	, m_rnd				(deStringHash(name))
    115 	, m_log				(context.getTestContext().getLog())
    116 {
    117 }
    118 
    119 TextureUploadCase::~TextureUploadCase (void)
    120 {
    121 	TextureUploadCase::deinit();
    122 }
    123 
    124 void TextureUploadCase::deinit (void)
    125 {
    126 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    127 
    128 	if (m_program)
    129 	{
    130 		delete m_program;
    131 		m_program = DE_NULL;
    132 	}
    133 
    134 	gl.deleteTextures(1, &m_texture);
    135 	m_texture = 0;
    136 
    137 	m_texData.clear();
    138 }
    139 
    140 void TextureUploadCase::init (void)
    141 {
    142 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    143 	int maxTextureSize;
    144 	gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
    145 
    146 	if (m_texSize > maxTextureSize)
    147 	{
    148 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Unsupported texture size");
    149 		return;
    150 	}
    151 
    152 	// Create program
    153 
    154 	string vertexShaderSource = "";
    155 	string fragmentShaderSource = "";
    156 
    157 	vertexShaderSource.append(	"precision mediump	float;\n"
    158 								"attribute vec2		a_pos;\n"
    159 								"varying   vec2		v_texCoord;\n"
    160 								"\n"
    161 								"void main (void)\n"
    162 								"{\n"
    163 								"	v_texCoord	= a_pos;\n"
    164 								"	gl_Position = vec4(a_pos, 0.5, 1.0);\n"
    165 								"}\n");
    166 
    167 	fragmentShaderSource.append("precision	mediump	float;\n"
    168 								"uniform	lowp sampler2D	u_sampler;\n"
    169 								"varying	vec2			v_texCoord;\n"
    170 								"\n"
    171 								"void main (void)\n"
    172 								"{\n"
    173 								"	gl_FragColor = texture2D(u_sampler, v_texCoord.xy);\n"
    174 								"}\n");
    175 
    176 	DE_ASSERT(!m_program);
    177 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource));
    178 
    179 	if (!m_program->isOk())
    180 	{
    181 		m_log << *m_program;
    182 		TCU_FAIL("Failed to create shader program (m_programRender)");
    183 	}
    184 
    185 	gl.useProgram (m_program->getProgram());
    186 
    187 	// Init GL state
    188 
    189 	gl.viewport		(0, 0, VIEWPORT_SIZE, VIEWPORT_SIZE);
    190 	gl.disable		(GL_DEPTH_TEST);
    191 	gl.disable		(GL_CULL_FACE);
    192 	gl.enable		(GL_BLEND);
    193 	gl.blendFunc	(GL_ONE, GL_ONE);
    194 	gl.clearColor	(0.0f, 0.0f, 0.0f, 1.0f);
    195 	gl.clear		(GL_COLOR_BUFFER_BIT);
    196 
    197 	deUint32 uSampler	= gl.getUniformLocation(m_program->getProgram(), "u_sampler");
    198 	deUint32 aPos		= gl.getAttribLocation (m_program->getProgram(), "a_pos");
    199 	gl.enableVertexAttribArray	(aPos);
    200 	gl.vertexAttribPointer		(aPos,	2, GL_FLOAT, GL_FALSE, 0, &quadCoords[0]);
    201 	gl.uniform1i				(uSampler, 0);
    202 
    203 	// Create texture
    204 
    205 	gl.activeTexture	(GL_TEXTURE0);
    206 	gl.genTextures		(1, &m_texture);
    207 	gl.bindTexture		(GL_TEXTURE_2D, m_texture);
    208 	gl.pixelStorei		(GL_UNPACK_ALIGNMENT, m_alignment);
    209 	gl.texParameteri	(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    210 	gl.texParameteri	(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    211 	gl.texParameteri	(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    212 	gl.texParameteri	(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    213 
    214 	// Prepare texture data
    215 
    216 	{
    217 		const tcu::TextureFormat&	texFmt		= glu::mapGLTransferFormat(m_format, m_type);
    218 		int							pixelSize	= texFmt.getPixelSize();
    219 		int							stride		= deAlign32(pixelSize*m_texSize, m_alignment);
    220 
    221 		m_texData.resize(stride*m_texSize);
    222 
    223 		tcu::PixelBufferAccess		access		(texFmt, m_texSize, m_texSize, 1, stride, 0, &m_texData[0]);
    224 
    225 		tcu::fillWithComponentGradients(access, tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
    226 	}
    227 
    228 	// Do a dry-run to ensure the pipes are hot
    229 
    230 	gl.texImage2D	(GL_TEXTURE_2D, 0, m_format, m_texSize, m_texSize, 0, m_format, m_type, &m_texData[0]);
    231 	gl.drawArrays	(GL_TRIANGLE_STRIP, 0, 4);
    232 	gl.finish		();
    233 }
    234 
    235 void TextureUploadCase::logResults (void)
    236 {
    237 	const gls::MeasureState& measureState = m_calibrator.getMeasureState();
    238 
    239 	// Log measurement details
    240 
    241 	m_log << TestLog::Section("Measurement details", "Measurement details");
    242 	m_log << TestLog::Message << "Uploading texture with " << (m_uploadFunction == UPLOAD_TEXIMAGE2D ? "glTexImage2D" : "glTexSubImage2D") << "." << TestLog::EndMessage; // \todo [arttu] Change enum to struct with name included
    243 	m_log << TestLog::Message << "Texture size = "	<< m_texSize	 << "x" << m_texSize	 << "." << TestLog::EndMessage;
    244 	m_log << TestLog::Message << "Viewport size = " << VIEWPORT_SIZE << "x" << VIEWPORT_SIZE << "." << TestLog::EndMessage;
    245 	m_log << TestLog::Message << measureState.numDrawCalls << " upload calls / iteration" << TestLog::EndMessage;
    246 	m_log << TestLog::EndSection;
    247 
    248 	// Log results
    249 
    250 	TestLog& log = m_testCtx.getLog();
    251 	log << TestLog::Section("Results", "Results");
    252 
    253 	// Log individual frame durations
    254 	//for (int i = 0; i < m_calibrator.measureState.numFrames; i++)
    255 	//	m_log << TestLog::Message	<< "Frame "	<< i+1 << " duration: \t" << m_calibrator.measureState.frameTimes[i] << " us."<< TestLog::EndMessage;
    256 
    257 	std::vector<deUint64> sortedFrameTimes(measureState.frameTimes.begin(), measureState.frameTimes.end());
    258 	std::sort(sortedFrameTimes.begin(), sortedFrameTimes.end());
    259 	vector<deUint64>::const_iterator first	= sortedFrameTimes.begin();
    260 	vector<deUint64>::const_iterator last	= sortedFrameTimes.end();
    261 	vector<deUint64>::const_iterator middle	= first + (last - first) / 2;
    262 
    263 	deUint64 medianFrameTime			=  *middle;
    264 	double medianMTexelsPerSeconds		= (double)(m_texSize*m_texSize*measureState.numDrawCalls) / (double)medianFrameTime;
    265 	double medianTexelDrawDurationNs	= (double)medianFrameTime * 1000.0 / (double)(m_texSize*m_texSize*measureState.numDrawCalls);
    266 
    267 	deUint64	totalTime			= measureState.getTotalTime();
    268 	int			numFrames			= (int)measureState.frameTimes.size();
    269 	deInt64		numTexturesDrawn	= measureState.numDrawCalls * numFrames;
    270 	deInt64		numPixels			= (deInt64)m_texSize * (deInt64)m_texSize * numTexturesDrawn;
    271 
    272 	double		framesPerSecond			= (double)numFrames / ((double)totalTime / 1000000.0);
    273 	double		avgFrameTime			= (double)totalTime / (double)numFrames;
    274 	double		avgMTexelsPerSeconds	= (double)numPixels / (double)totalTime;
    275 	double		avgTexelDrawDurationNs	= (double)totalTime * 1000.0 / (double)numPixels;
    276 
    277 	log << TestLog::Float("FramesPerSecond",	"Frames per second in measurement\t\t",		"Frames/s",		QP_KEY_TAG_PERFORMANCE,	(float)framesPerSecond);
    278 	log << TestLog::Float("AverageFrameTime",	"Average frame duration in measurement\t",	"us",			QP_KEY_TAG_PERFORMANCE,	(float)avgFrameTime);
    279 	log << TestLog::Float("AverageTexelPerf",	"Average texel upload performance\t\t",		"MTex/s",		QP_KEY_TAG_PERFORMANCE,	(float)avgMTexelsPerSeconds);
    280 	log << TestLog::Float("AverageTexelTime",	"Average texel upload duration\t\t",		"ns",			QP_KEY_TAG_PERFORMANCE,	(float)avgTexelDrawDurationNs);
    281 	log << TestLog::Float("MedianTexelPerf",	"Median texel upload performance\t\t",		"MTex/s",		QP_KEY_TAG_PERFORMANCE,	(float)medianMTexelsPerSeconds);
    282 	log << TestLog::Float("MedianTexelTime",	"Median texel upload duration\t\t",			"ns",			QP_KEY_TAG_PERFORMANCE,	(float)medianTexelDrawDurationNs);
    283 
    284 	log << TestLog::EndSection;
    285 
    286 	gls::logCalibrationInfo(log, m_calibrator);	// Log calibration details
    287 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString((float)avgMTexelsPerSeconds, 2).c_str());
    288 }
    289 
    290 // Texture upload call case
    291 
    292 class TextureUploadCallCase : public TextureUploadCase
    293 {
    294 public:
    295 							TextureUploadCallCase	(Context& context, const char* name, const char* description, UploadFunction uploadFunction, deUint32 format, deUint32 type, int texSize);
    296 							~TextureUploadCallCase	(void);
    297 
    298 	IterateResult			iterate					(void);
    299 	void					render					(void);
    300 };
    301 
    302 TextureUploadCallCase::TextureUploadCallCase (Context& context, const char* name, const char* description, UploadFunction uploadFunction, deUint32 format, deUint32 type, int texSize)
    303 	: TextureUploadCase (context, name, description, uploadFunction, format, type, texSize)
    304 {
    305 }
    306 
    307 TextureUploadCallCase::~TextureUploadCallCase (void)
    308 {
    309 	TextureUploadCase::deinit();
    310 }
    311 
    312 void TextureUploadCallCase::render (void)
    313 {
    314 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    315 
    316 	// Draw multiple quads to ensure enough workload
    317 
    318 	switch (m_uploadFunction)
    319 	{
    320 		case UPLOAD_TEXIMAGE2D:
    321 			gl.texImage2D(GL_TEXTURE_2D, 0, m_format, m_texSize, m_texSize, 0, m_format, m_type, &m_texData[0]);
    322 			break;
    323 		case UPLOAD_TEXSUBIMAGE2D:
    324 			gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_texSize, m_texSize, m_format, m_type, &m_texData[0]);
    325 			break;
    326 		default:
    327 			DE_ASSERT(false);
    328 	}
    329 }
    330 
    331 tcu::TestNode::IterateResult TextureUploadCallCase::iterate (void)
    332 {
    333 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    334 
    335 	if (m_testCtx.getTestResult() == QP_TEST_RESULT_NOT_SUPPORTED)
    336 		return STOP;
    337 
    338 	for (;;)
    339 	{
    340 		gls::TheilSenCalibrator::State state = m_calibrator.getState();
    341 
    342 		if (state == gls::TheilSenCalibrator::STATE_MEASURE)
    343 		{
    344 			int			numCalls	= m_calibrator.getCallCount();
    345 			deUint64	startTime	= deGetMicroseconds();
    346 
    347 			for (int i = 0; i < numCalls; i++)
    348 				render();
    349 
    350 			gl.finish();
    351 
    352 			deUint64	endTime		= deGetMicroseconds();
    353 			deUint64	duration	= endTime-startTime;
    354 
    355 			m_calibrator.recordIteration(duration);
    356 		}
    357 		else if (state == gls::TheilSenCalibrator::STATE_RECOMPUTE_PARAMS)
    358 		{
    359 			m_calibrator.recomputeParameters();
    360 		}
    361 		else
    362 		{
    363 			DE_ASSERT(state == gls::TheilSenCalibrator::STATE_FINISHED);
    364 			break;
    365 		}
    366 
    367 		// Touch watchdog between iterations to avoid timeout.
    368 		{
    369 			qpWatchDog* dog = m_testCtx.getWatchDog();
    370 			if (dog)
    371 				qpWatchDog_touch(dog);
    372 		}
    373 	}
    374 
    375 	GLU_EXPECT_NO_ERROR(gl.getError(), "iterate");
    376 	logResults();
    377 	return STOP;
    378 }
    379 
    380 // Texture upload and draw case
    381 
    382 class TextureUploadAndDrawCase : public TextureUploadCase
    383 {
    384 public:
    385 								TextureUploadAndDrawCase	(Context& context, const char* name, const char* description, UploadFunction uploadFunction, deUint32 format, deUint32 type, int texSize);
    386 								~TextureUploadAndDrawCase	(void);
    387 
    388 	IterateResult				iterate						(void);
    389 	void						render						(void);
    390 
    391 private:
    392 	bool						m_lastIterationRender;
    393 	deUint64					m_renderStart;
    394 };
    395 
    396 TextureUploadAndDrawCase::TextureUploadAndDrawCase (Context& context, const char* name, const char* description, UploadFunction uploadFunction, deUint32 format, deUint32 type, int texSize)
    397 	: TextureUploadCase		(context, name, description, uploadFunction, format, type, texSize)
    398 	, m_lastIterationRender	(false)
    399 	, m_renderStart			(0)
    400 {
    401 }
    402 
    403 TextureUploadAndDrawCase::~TextureUploadAndDrawCase (void)
    404 {
    405 	TextureUploadCase::deinit();
    406 }
    407 
    408 void TextureUploadAndDrawCase::render (void)
    409 {
    410 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    411 
    412 	// Draw multiple quads to ensure enough workload
    413 
    414 	switch (m_uploadFunction)
    415 	{
    416 		case UPLOAD_TEXIMAGE2D:
    417 			gl.texImage2D(GL_TEXTURE_2D, 0, m_format, m_texSize, m_texSize, 0, m_format, m_type, &m_texData[0]);
    418 			break;
    419 		case UPLOAD_TEXSUBIMAGE2D:
    420 			gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_texSize, m_texSize, m_format, m_type, &m_texData[0]);
    421 			break;
    422 		default:
    423 			DE_ASSERT(false);
    424 	}
    425 
    426 	gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
    427 }
    428 
    429 tcu::TestNode::IterateResult TextureUploadAndDrawCase::iterate (void)
    430 {
    431 	if (m_testCtx.getTestResult() == QP_TEST_RESULT_NOT_SUPPORTED)
    432 		return STOP;
    433 
    434 	if (m_lastIterationRender && (m_calibrator.getState() == gls::TheilSenCalibrator::STATE_MEASURE))
    435 	{
    436 		deUint64 curTime = deGetMicroseconds();
    437 		m_calibrator.recordIteration(curTime - m_renderStart);
    438 	}
    439 
    440 	gls::TheilSenCalibrator::State state = m_calibrator.getState();
    441 
    442 	if (state == gls::TheilSenCalibrator::STATE_MEASURE)
    443 	{
    444 		// Render
    445 		int	numCalls = m_calibrator.getCallCount();
    446 
    447 		m_renderStart			= deGetMicroseconds();
    448 		m_lastIterationRender	= true;
    449 
    450 		for (int i = 0; i < numCalls; i++)
    451 			render();
    452 
    453 		return CONTINUE;
    454 	}
    455 	else if (state == gls::TheilSenCalibrator::STATE_RECOMPUTE_PARAMS)
    456 	{
    457 		m_calibrator.recomputeParameters();
    458 		m_lastIterationRender = false;
    459 		return CONTINUE;
    460 	}
    461 	else
    462 	{
    463 		DE_ASSERT(state == gls::TheilSenCalibrator::STATE_FINISHED);
    464 		GLU_EXPECT_NO_ERROR(m_context.getRenderContext().getFunctions().getError(), "finish");
    465 		logResults();
    466 		return STOP;
    467 	}
    468 }
    469 
    470 // Texture upload tests
    471 
    472 TextureUploadTests::TextureUploadTests (Context& context)
    473 	: TestCaseGroup(context, "upload", "Texture upload tests")
    474 {
    475 }
    476 
    477 TextureUploadTests::~TextureUploadTests (void)
    478 {
    479 	TextureUploadTests::deinit();
    480 }
    481 
    482 void TextureUploadTests::deinit (void)
    483 {
    484 }
    485 
    486 void TextureUploadTests::init (void)
    487 {
    488 	TestCaseGroup* uploadCall		= new TestCaseGroup(m_context, "upload",			"Texture upload");
    489 	TestCaseGroup* uploadAndDraw	= new TestCaseGroup(m_context, "upload_draw_swap",	"Texture upload, draw & buffer swap");
    490 
    491 	addChild(uploadCall);
    492 	addChild(uploadAndDraw);
    493 
    494 	static const struct
    495 	{
    496 		const char*		name;
    497 		const char*		nameLower;
    498 		UploadFunction	func;
    499 	} uploadFunctions[] =
    500 	{
    501 		{ "texImage2D",		"teximage2d",		UPLOAD_TEXIMAGE2D },
    502 		{ "texSubImage2D",	"texsubimage2d",	UPLOAD_TEXSUBIMAGE2D }
    503 	};
    504 
    505 	static const struct
    506 	{
    507 		const char*	name;
    508 		deUint32	format;
    509 		deUint32	type;
    510 	} textureCombinations[] =
    511 	{
    512 		{ "rgb_ubyte",				GL_RGB,				GL_UNSIGNED_BYTE },
    513 		{ "rgba_ubyte",				GL_RGBA,			GL_UNSIGNED_BYTE },
    514 		{ "alpha_ubyte",			GL_ALPHA,			GL_UNSIGNED_BYTE },
    515 		{ "luminance_ubyte",		GL_LUMINANCE,		GL_UNSIGNED_BYTE },
    516 		{ "luminance-alpha_ubyte",	GL_LUMINANCE_ALPHA,	GL_UNSIGNED_BYTE },
    517 		{ "rgb_ushort565",			GL_RGB,				GL_UNSIGNED_SHORT_5_6_5 },
    518 		{ "rgba_ushort4444",		GL_RGBA,			GL_UNSIGNED_SHORT_4_4_4_4 },
    519 		{ "rgba_ushort5551",		GL_RGBA,			GL_UNSIGNED_SHORT_5_5_5_1 },
    520 	};
    521 
    522 	static const struct
    523 	{
    524 		int				size;
    525 		TestCaseGroup*	uploadCallGroup;
    526 		TestCaseGroup*	uploadAndDrawGroup;
    527 	} textureSizes[] =
    528 	{
    529 		{ 16,	new TestCaseGroup(m_context, "16x16",		"Texture size 16x16"),		new TestCaseGroup(m_context, "16x16",		"Texture size 16x16") },
    530 		{ 256,	new TestCaseGroup(m_context, "256x256",		"Texture size 256x256"),	new TestCaseGroup(m_context, "256x256",		"Texture size 256x256") },
    531 		{ 257,	new TestCaseGroup(m_context, "257x257",		"Texture size 257x257"),	new TestCaseGroup(m_context, "257x257",		"Texture size 257x257") },
    532 		{ 1024,	new TestCaseGroup(m_context, "1024x1024",	"Texture size 1024x1024"),	new TestCaseGroup(m_context, "1024x1024",	"Texture size 1024x1024") },
    533 		{ 2048,	new TestCaseGroup(m_context, "2048x2048",	"Texture size 2048x2048"),	new TestCaseGroup(m_context, "2048x2048",	"Texture size 2048x2048") },
    534 	};
    535 
    536 #define FOR_EACH(ITERATOR, ARRAY, BODY)	\
    537 	for (int ITERATOR = 0; ITERATOR < DE_LENGTH_OF_ARRAY(ARRAY); ITERATOR++)	\
    538 		BODY
    539 
    540 	FOR_EACH(uploadFunc,	 uploadFunctions,
    541 	FOR_EACH(texSize,		 textureSizes,
    542 	FOR_EACH(texCombination, textureCombinations,
    543 	{
    544 		string			caseName	= string("") + uploadFunctions[uploadFunc].nameLower + "_" + textureCombinations[texCombination].name;
    545 		UploadFunction	function	= uploadFunctions[uploadFunc].func;
    546 		deUint32		format		= textureCombinations[texCombination].format;
    547 		deUint32		type		= textureCombinations[texCombination].type;
    548 		int				size		= textureSizes[texSize].size;
    549 
    550 		textureSizes[texSize].uploadCallGroup->addChild		(new TextureUploadCallCase		(m_context, caseName.c_str(), "", function, format, type, size));
    551 		textureSizes[texSize].uploadAndDrawGroup->addChild	(new TextureUploadAndDrawCase	(m_context, caseName.c_str(), "", function, format, type, size));
    552 	})));
    553 
    554 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(textureSizes); i++)
    555 	{
    556 		uploadCall->addChild	(textureSizes[i].uploadCallGroup);
    557 		uploadAndDraw->addChild	(textureSizes[i].uploadAndDrawGroup);
    558 	}
    559 }
    560 
    561 
    562 } // Performance
    563 } // gles2
    564 } // deqp
    565