Home | History | Annotate | Download | only in performance
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.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 Buffer data upload performance tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es3pBufferDataUploadTests.hpp"
     25 #include "glsCalibration.hpp"
     26 #include "tcuTestLog.hpp"
     27 #include "tcuVectorUtil.hpp"
     28 #include "tcuSurface.hpp"
     29 #include "tcuCPUWarmup.hpp"
     30 #include "tcuRenderTarget.hpp"
     31 #include "gluRenderContext.hpp"
     32 #include "gluShaderProgram.hpp"
     33 #include "gluStrUtil.hpp"
     34 #include "gluPixelTransfer.hpp"
     35 #include "gluObjectWrapper.hpp"
     36 #include "glwFunctions.hpp"
     37 #include "glwEnums.hpp"
     38 #include "deClock.h"
     39 #include "deMath.h"
     40 #include "deStringUtil.hpp"
     41 #include "deRandom.hpp"
     42 #include "deMemory.h"
     43 #include "deThread.h"
     44 #include "deMeta.hpp"
     45 
     46 #include <algorithm>
     47 #include <iomanip>
     48 #include <limits>
     49 
     50 namespace deqp
     51 {
     52 namespace gles3
     53 {
     54 namespace Performance
     55 {
     56 namespace
     57 {
     58 
     59 using gls::theilSenSiegelLinearRegression;
     60 using gls::LineParametersWithConfidence;
     61 using de::meta::EnableIf;
     62 using de::meta::Not;
     63 
     64 static const char* const s_dummyVertexShader =		"#version 300 es\n"
     65 													"in highp vec4 a_position;\n"
     66 													"void main (void)\n"
     67 													"{\n"
     68 													"	gl_Position = a_position;\n"
     69 													"}\n";
     70 
     71 static const char* const s_dummyFragnentShader =	"#version 300 es\n"
     72 													"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
     73 													"void main (void)\n"
     74 													"{\n"
     75 													"	dEQP_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
     76 													"}\n";
     77 
     78 static const char* const s_colorVertexShader =		"#version 300 es\n"
     79 													"in highp vec4 a_position;\n"
     80 													"in highp vec4 a_color;\n"
     81 													"out highp vec4 v_color;\n"
     82 													"void main (void)\n"
     83 													"{\n"
     84 													"	gl_Position = a_position;\n"
     85 													"	v_color = a_color;\n"
     86 													"}\n";
     87 
     88 static const char* const s_colorFragmentShader =	"#version 300 es\n"
     89 													"layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
     90 													"in mediump vec4 v_color;\n"
     91 													"void main (void)\n"
     92 													"{\n"
     93 													"	dEQP_FragColor = v_color;\n"
     94 													"}\n";
     95 
     96 struct SingleOperationDuration
     97 {
     98 	deUint64 totalDuration;
     99 	deUint64 fitResponseDuration; // used for fitting
    100 };
    101 
    102 struct MapBufferRangeDuration
    103 {
    104 	deUint64 mapDuration;
    105 	deUint64 unmapDuration;
    106 	deUint64 writeDuration;
    107 	deUint64 allocDuration;
    108 	deUint64 totalDuration;
    109 
    110 	deUint64 fitResponseDuration;
    111 };
    112 
    113 struct MapBufferRangeDurationNoAlloc
    114 {
    115 	deUint64 mapDuration;
    116 	deUint64 unmapDuration;
    117 	deUint64 writeDuration;
    118 	deUint64 totalDuration;
    119 
    120 	deUint64 fitResponseDuration;
    121 };
    122 
    123 struct MapBufferRangeFlushDuration
    124 {
    125 	deUint64 mapDuration;
    126 	deUint64 unmapDuration;
    127 	deUint64 writeDuration;
    128 	deUint64 flushDuration;
    129 	deUint64 allocDuration;
    130 	deUint64 totalDuration;
    131 
    132 	deUint64 fitResponseDuration;
    133 };
    134 
    135 struct MapBufferRangeFlushDurationNoAlloc
    136 {
    137 	deUint64 mapDuration;
    138 	deUint64 unmapDuration;
    139 	deUint64 writeDuration;
    140 	deUint64 flushDuration;
    141 	deUint64 totalDuration;
    142 
    143 	deUint64 fitResponseDuration;
    144 };
    145 
    146 struct RenderReadDuration
    147 {
    148 	deUint64 renderDuration;
    149 	deUint64 readDuration;
    150 	deUint64 renderReadDuration;
    151 	deUint64 totalDuration;
    152 
    153 	deUint64 fitResponseDuration;
    154 };
    155 
    156 struct UnrelatedUploadRenderReadDuration
    157 {
    158 	deUint64 renderDuration;
    159 	deUint64 readDuration;
    160 	deUint64 renderReadDuration;
    161 	deUint64 totalDuration;
    162 
    163 	deUint64 fitResponseDuration;
    164 };
    165 
    166 struct UploadRenderReadDuration
    167 {
    168 	deUint64 uploadDuration;
    169 	deUint64 renderDuration;
    170 	deUint64 readDuration;
    171 	deUint64 totalDuration;
    172 	deUint64 renderReadDuration;
    173 
    174 	deUint64 fitResponseDuration;
    175 };
    176 
    177 struct UploadRenderReadDurationWithUnrelatedUploadSize
    178 {
    179 	deUint64 uploadDuration;
    180 	deUint64 renderDuration;
    181 	deUint64 readDuration;
    182 	deUint64 totalDuration;
    183 	deUint64 renderReadDuration;
    184 
    185 	deUint64 fitResponseDuration;
    186 };
    187 
    188 struct RenderUploadRenderReadDuration
    189 {
    190 	deUint64 firstRenderDuration;
    191 	deUint64 uploadDuration;
    192 	deUint64 secondRenderDuration;
    193 	deUint64 readDuration;
    194 	deUint64 totalDuration;
    195 	deUint64 renderReadDuration;
    196 
    197 	deUint64 fitResponseDuration;
    198 };
    199 
    200 template <typename SampleT>
    201 struct UploadSampleResult
    202 {
    203 	typedef SampleT SampleType;
    204 
    205 	int			bufferSize;
    206 	int			allocatedSize;
    207 	int			writtenSize;
    208 	SampleType	duration;
    209 };
    210 
    211 template <typename SampleT>
    212 struct RenderSampleResult
    213 {
    214 	typedef SampleT SampleType;
    215 
    216 	int			uploadedDataSize;
    217 	int			renderDataSize;
    218 	int			unrelatedDataSize;
    219 	int			numVertices;
    220 	SampleT		duration;
    221 };
    222 
    223 struct SingleOperationStatistics
    224 {
    225 	float minTime;
    226 	float maxTime;
    227 	float medianTime;
    228 	float min2DecileTime;		// !< minimum value in the 2nd decile
    229 	float max9DecileTime;		// !< maximum value in the 9th decile
    230 };
    231 
    232 struct SingleCallStatistics
    233 {
    234 	SingleOperationStatistics	result;
    235 
    236 	float						medianRate;
    237 	float						maxDiffTime;
    238 	float						maxDiff9DecileTime;
    239 	float						medianDiffTime;
    240 
    241 	float						maxRelDiffTime;
    242 	float						max9DecileRelDiffTime;
    243 	float						medianRelDiffTime;
    244 };
    245 
    246 struct MapCallStatistics
    247 {
    248 	SingleOperationStatistics	map;
    249 	SingleOperationStatistics	unmap;
    250 	SingleOperationStatistics	write;
    251 	SingleOperationStatistics	alloc;
    252 	SingleOperationStatistics	result;
    253 
    254 	float						medianRate;
    255 	float						maxDiffTime;
    256 	float						maxDiff9DecileTime;
    257 	float						medianDiffTime;
    258 
    259 	float						maxRelDiffTime;
    260 	float						max9DecileRelDiffTime;
    261 	float						medianRelDiffTime;
    262 };
    263 
    264 struct MapFlushCallStatistics
    265 {
    266 	SingleOperationStatistics	map;
    267 	SingleOperationStatistics	unmap;
    268 	SingleOperationStatistics	write;
    269 	SingleOperationStatistics	flush;
    270 	SingleOperationStatistics	alloc;
    271 	SingleOperationStatistics	result;
    272 
    273 	float						medianRate;
    274 	float						maxDiffTime;
    275 	float						maxDiff9DecileTime;
    276 	float						medianDiffTime;
    277 
    278 	float						maxRelDiffTime;
    279 	float						max9DecileRelDiffTime;
    280 	float						medianRelDiffTime;
    281 };
    282 
    283 struct RenderReadStatistics
    284 {
    285 	SingleOperationStatistics	render;
    286 	SingleOperationStatistics	read;
    287 	SingleOperationStatistics	result;
    288 	SingleOperationStatistics	total;
    289 
    290 	float						medianRate;
    291 	float						maxDiffTime;
    292 	float						maxDiff9DecileTime;
    293 	float						medianDiffTime;
    294 
    295 	float						maxRelDiffTime;
    296 	float						max9DecileRelDiffTime;
    297 	float						medianRelDiffTime;
    298 };
    299 
    300 struct UploadRenderReadStatistics
    301 {
    302 	SingleOperationStatistics	upload;
    303 	SingleOperationStatistics	render;
    304 	SingleOperationStatistics	read;
    305 	SingleOperationStatistics	result;
    306 	SingleOperationStatistics	total;
    307 
    308 	float						medianRate;
    309 	float						maxDiffTime;
    310 	float						maxDiff9DecileTime;
    311 	float						medianDiffTime;
    312 
    313 	float						maxRelDiffTime;
    314 	float						max9DecileRelDiffTime;
    315 	float						medianRelDiffTime;
    316 };
    317 
    318 struct RenderUploadRenderReadStatistics
    319 {
    320 	SingleOperationStatistics	firstRender;
    321 	SingleOperationStatistics	upload;
    322 	SingleOperationStatistics	secondRender;
    323 	SingleOperationStatistics	read;
    324 	SingleOperationStatistics	result;
    325 	SingleOperationStatistics	total;
    326 
    327 	float						medianRate;
    328 	float						maxDiffTime;
    329 	float						maxDiff9DecileTime;
    330 	float						medianDiffTime;
    331 
    332 	float						maxRelDiffTime;
    333 	float						max9DecileRelDiffTime;
    334 	float						medianRelDiffTime;
    335 };
    336 
    337 template <typename T>
    338 struct SampleTypeTraits
    339 {
    340 };
    341 
    342 template <>
    343 struct SampleTypeTraits<SingleOperationDuration>
    344 {
    345 	typedef SingleCallStatistics StatsType;
    346 
    347 	enum { HAS_MAP_STATS		= 0	};
    348 	enum { HAS_UNMAP_STATS		= 0	};
    349 	enum { HAS_WRITE_STATS		= 0	};
    350 	enum { HAS_FLUSH_STATS		= 0	};
    351 	enum { HAS_ALLOC_STATS		= 0	};
    352 	enum { LOG_CONTRIBUTIONS	= 0	};
    353 };
    354 
    355 template <>
    356 struct SampleTypeTraits<MapBufferRangeDuration>
    357 {
    358 	typedef MapCallStatistics StatsType;
    359 
    360 	enum { HAS_MAP_STATS		= 1	};
    361 	enum { HAS_UNMAP_STATS		= 1	};
    362 	enum { HAS_WRITE_STATS		= 1	};
    363 	enum { HAS_FLUSH_STATS		= 0	};
    364 	enum { HAS_ALLOC_STATS		= 1	};
    365 	enum { LOG_CONTRIBUTIONS	= 1	};
    366 };
    367 
    368 template <>
    369 struct SampleTypeTraits<MapBufferRangeDurationNoAlloc>
    370 {
    371 	typedef MapCallStatistics StatsType;
    372 
    373 	enum { HAS_MAP_STATS		= 1	};
    374 	enum { HAS_UNMAP_STATS		= 1	};
    375 	enum { HAS_WRITE_STATS		= 1	};
    376 	enum { HAS_FLUSH_STATS		= 0	};
    377 	enum { HAS_ALLOC_STATS		= 0	};
    378 	enum { LOG_CONTRIBUTIONS	= 1	};
    379 };
    380 
    381 template <>
    382 struct SampleTypeTraits<MapBufferRangeFlushDuration>
    383 {
    384 	typedef MapFlushCallStatistics StatsType;
    385 
    386 	enum { HAS_MAP_STATS		= 1	};
    387 	enum { HAS_UNMAP_STATS		= 1	};
    388 	enum { HAS_WRITE_STATS		= 1	};
    389 	enum { HAS_FLUSH_STATS		= 1	};
    390 	enum { HAS_ALLOC_STATS		= 1	};
    391 	enum { LOG_CONTRIBUTIONS	= 1	};
    392 };
    393 
    394 template <>
    395 struct SampleTypeTraits<MapBufferRangeFlushDurationNoAlloc>
    396 {
    397 	typedef MapFlushCallStatistics StatsType;
    398 
    399 	enum { HAS_MAP_STATS		= 1	};
    400 	enum { HAS_UNMAP_STATS		= 1	};
    401 	enum { HAS_WRITE_STATS		= 1	};
    402 	enum { HAS_FLUSH_STATS		= 1	};
    403 	enum { HAS_ALLOC_STATS		= 0	};
    404 	enum { LOG_CONTRIBUTIONS	= 1	};
    405 };
    406 
    407 template <>
    408 struct SampleTypeTraits<RenderReadDuration>
    409 {
    410 	typedef RenderReadStatistics StatsType;
    411 
    412 	enum { HAS_RENDER_STATS			= 1	};
    413 	enum { HAS_READ_STATS			= 1	};
    414 	enum { HAS_UPLOAD_STATS			= 0	};
    415 	enum { HAS_TOTAL_STATS			= 1	};
    416 	enum { HAS_FIRST_RENDER_STATS	= 0	};
    417 	enum { HAS_SECOND_RENDER_STATS	= 0	};
    418 
    419 	enum { LOG_CONTRIBUTIONS	= 1	};
    420 };
    421 
    422 template <>
    423 struct SampleTypeTraits<UnrelatedUploadRenderReadDuration>
    424 {
    425 	typedef RenderReadStatistics StatsType;
    426 
    427 	enum { HAS_RENDER_STATS			= 1	};
    428 	enum { HAS_READ_STATS			= 1	};
    429 	enum { HAS_UPLOAD_STATS			= 0	};
    430 	enum { HAS_TOTAL_STATS			= 1	};
    431 	enum { HAS_FIRST_RENDER_STATS	= 0	};
    432 	enum { HAS_SECOND_RENDER_STATS	= 0	};
    433 
    434 	enum { LOG_CONTRIBUTIONS	= 1	};
    435 };
    436 
    437 template <>
    438 struct SampleTypeTraits<UploadRenderReadDuration>
    439 {
    440 	typedef UploadRenderReadStatistics StatsType;
    441 
    442 	enum { HAS_RENDER_STATS			= 1	};
    443 	enum { HAS_READ_STATS			= 1	};
    444 	enum { HAS_UPLOAD_STATS			= 1	};
    445 	enum { HAS_TOTAL_STATS			= 1	};
    446 	enum { HAS_FIRST_RENDER_STATS	= 0	};
    447 	enum { HAS_SECOND_RENDER_STATS	= 0	};
    448 
    449 	enum { LOG_CONTRIBUTIONS			= 1	};
    450 	enum { LOG_UNRELATED_UPLOAD_SIZE	= 0 };
    451 };
    452 
    453 template <>
    454 struct SampleTypeTraits<UploadRenderReadDurationWithUnrelatedUploadSize>
    455 {
    456 	typedef UploadRenderReadStatistics StatsType;
    457 
    458 	enum { HAS_RENDER_STATS			= 1	};
    459 	enum { HAS_READ_STATS			= 1	};
    460 	enum { HAS_UPLOAD_STATS			= 1	};
    461 	enum { HAS_TOTAL_STATS			= 1	};
    462 	enum { HAS_FIRST_RENDER_STATS	= 0	};
    463 	enum { HAS_SECOND_RENDER_STATS	= 0	};
    464 
    465 	enum { LOG_CONTRIBUTIONS			= 1	};
    466 	enum { LOG_UNRELATED_UPLOAD_SIZE	= 1 };
    467 };
    468 
    469 template <>
    470 struct SampleTypeTraits<RenderUploadRenderReadDuration>
    471 {
    472 	typedef RenderUploadRenderReadStatistics StatsType;
    473 
    474 	enum { HAS_RENDER_STATS			= 0	};
    475 	enum { HAS_READ_STATS			= 1	};
    476 	enum { HAS_UPLOAD_STATS			= 1	};
    477 	enum { HAS_TOTAL_STATS			= 1	};
    478 	enum { HAS_FIRST_RENDER_STATS	= 1	};
    479 	enum { HAS_SECOND_RENDER_STATS	= 1	};
    480 
    481 	enum { LOG_CONTRIBUTIONS			= 1	};
    482 	enum { LOG_UNRELATED_UPLOAD_SIZE	= 1 };
    483 };
    484 
    485 struct UploadSampleAnalyzeResult
    486 {
    487 	float transferRateMedian;
    488 	float transferRateAtRange;
    489 	float transferRateAtInfinity;
    490 };
    491 
    492 struct RenderSampleAnalyzeResult
    493 {
    494 	float renderRateMedian;
    495 	float renderRateAtRange;
    496 	float renderRateAtInfinity;
    497 };
    498 
    499 class UnmapFailureError : public std::exception
    500 {
    501 public:
    502 	UnmapFailureError (void) : std::exception() {}
    503 };
    504 
    505 static std::string getHumanReadableByteSize (int numBytes)
    506 {
    507 	std::ostringstream buf;
    508 
    509 	if (numBytes < 1024)
    510 		buf << numBytes << " byte(s)";
    511 	else if (numBytes < 1024 * 1024)
    512 		buf << de::floatToString((float)numBytes/1024.0f, 1) << " KiB";
    513 	else
    514 		buf << de::floatToString((float)numBytes/1024.0f/1024.0f, 1) << " MiB";
    515 
    516 	return buf.str();
    517 }
    518 
    519 static deUint64 medianTimeMemcpy (void* dst, const void* src, int numBytes)
    520 {
    521 	// Time used by memcpy is assumed to be asymptotically linear
    522 
    523 	// With large numBytes, the probability of context switch or other random
    524 	// event is high. Apply memcpy in parts and report how much time would
    525 	// memcpy have used with the median transfer rate.
    526 
    527 	// Less than 1MiB, no need to do anything special
    528 	if (numBytes < 1048576)
    529 	{
    530 		deUint64 startTime;
    531 		deUint64 endTime;
    532 
    533 		deYield();
    534 
    535 		startTime = deGetMicroseconds();
    536 		deMemcpy(dst, src, numBytes);
    537 		endTime = deGetMicroseconds();
    538 
    539 		return endTime - startTime;
    540 	}
    541 	else
    542 	{
    543 		// Do memcpy in multiple parts
    544 
    545 		const int	numSections		= 5;
    546 		const int	sectionAlign	= 16;
    547 
    548 		int			sectionStarts[numSections+1];
    549 		int			sectionLens[numSections];
    550 		deUint64	sectionTimes[numSections];
    551 		deUint64	medianTime;
    552 		deUint64	bestTime		= 0;
    553 
    554 		for (int sectionNdx = 0; sectionNdx < numSections; ++sectionNdx)
    555 			sectionStarts[sectionNdx] = deAlign32((numBytes * sectionNdx / numSections), sectionAlign);
    556 		sectionStarts[numSections] = numBytes;
    557 
    558 		for (int sectionNdx = 0; sectionNdx < numSections; ++sectionNdx)
    559 			sectionLens[sectionNdx] = sectionStarts[sectionNdx+1] - sectionStarts[sectionNdx];
    560 
    561 		// Memcpy is usually called after mapbuffer range which may take
    562 		// a lot of time. To prevent power management from kicking in during
    563 		// copy, warm up more.
    564 		{
    565 			deYield();
    566 			tcu::warmupCPU();
    567 			deYield();
    568 		}
    569 
    570 		for (int sectionNdx = 0; sectionNdx < numSections; ++sectionNdx)
    571 		{
    572 			deUint64 startTime;
    573 			deUint64 endTime;
    574 
    575 			startTime = deGetMicroseconds();
    576 			deMemcpy((deUint8*)dst + sectionStarts[sectionNdx], (const deUint8*)src + sectionStarts[sectionNdx], sectionLens[sectionNdx]);
    577 			endTime = deGetMicroseconds();
    578 
    579 			sectionTimes[sectionNdx] = endTime - startTime;
    580 
    581 			if (!bestTime || sectionTimes[sectionNdx] < bestTime)
    582 				bestTime = sectionTimes[sectionNdx];
    583 
    584 			// Detect if write takes 50% longer than it should, and warm up if that happened
    585 			if (sectionNdx != numSections-1 && (float)sectionTimes[sectionNdx] > 1.5f * (float)bestTime)
    586 			{
    587 				deYield();
    588 				tcu::warmupCPU();
    589 				deYield();
    590 			}
    591 		}
    592 
    593 		std::sort(sectionTimes, sectionTimes + numSections);
    594 
    595 		if ((numSections % 2) == 0)
    596 			medianTime = (sectionTimes[numSections / 2 - 1] + sectionTimes[numSections / 2]) / 2;
    597 		else
    598 			medianTime = sectionTimes[numSections / 2];
    599 
    600 		return medianTime*numSections;
    601 	}
    602 }
    603 
    604 static float dummyCalculation (float initial, int workSize)
    605 {
    606 	float	a = initial;
    607 	int		b = 123;
    608 
    609 	for (int ndx = 0; ndx < workSize; ++ndx)
    610 	{
    611 		a = deFloatCos(a + (float)b);
    612 		b = (b + 63) % 107 + de::abs((int)(a*10.0f));
    613 	}
    614 
    615 	return a + (float)b;
    616 }
    617 
    618 static void busyWait (int microseconds)
    619 {
    620 	const deUint64	maxSingleWaitTime	= 1000; // 1ms
    621 	const deUint64	endTime				= deGetMicroseconds() + microseconds;
    622 	float			dummy				= *tcu::warmupCPUInternal::g_dummy.m_v;
    623 	int				workSize			= 500;
    624 
    625 	// exponentially increase work, cap to 1ms
    626 	while (deGetMicroseconds() < endTime)
    627 	{
    628 		const deUint64	startTime		= deGetMicroseconds();
    629 		deUint64		totalTime;
    630 
    631 		dummy = dummyCalculation(dummy, workSize);
    632 
    633 		totalTime = deGetMicroseconds() - startTime;
    634 
    635 		if (totalTime >= maxSingleWaitTime)
    636 			break;
    637 		else
    638 			workSize *= 2;
    639 	}
    640 
    641 	// "wait"
    642 	while (deGetMicroseconds() < endTime)
    643 		dummy = dummyCalculation(dummy, workSize);
    644 
    645 	*tcu::warmupCPUInternal::g_dummy.m_v = dummy;
    646 }
    647 
    648 // Sample from given values using linear interpolation at a given position as if values were laid to range [0, 1]
    649 template <typename T>
    650 static float linearSample (const std::vector<T>& values, float position)
    651 {
    652 	DE_ASSERT(position >= 0.0f);
    653 	DE_ASSERT(position <= 1.0f);
    654 
    655 	const float	floatNdx			= (float)(values.size() - 1) * position;
    656 	const int	lowerNdx			= (int)deFloatFloor(floatNdx);
    657 	const int	higherNdx			= lowerNdx + 1;
    658 	const float	interpolationFactor = floatNdx - (float)lowerNdx;
    659 
    660 	DE_ASSERT(lowerNdx >= 0 && lowerNdx < (int)values.size());
    661 	DE_ASSERT(higherNdx >= 0 && higherNdx < (int)values.size());
    662 	DE_ASSERT(interpolationFactor >= 0 && interpolationFactor < 1.0f);
    663 
    664 	return tcu::mix((float)values[lowerNdx], (float)values[higherNdx], interpolationFactor);
    665 }
    666 
    667 template <typename T>
    668 SingleOperationStatistics calculateSingleOperationStatistics (const std::vector<T>& samples, deUint64 T::SampleType::*target)
    669 {
    670 	SingleOperationStatistics	stats;
    671 	std::vector<deUint64>		values(samples.size());
    672 
    673 	for (int ndx = 0; ndx < (int)samples.size(); ++ndx)
    674 		values[ndx] = samples[ndx].duration.*target;
    675 
    676 	std::sort(values.begin(), values.end());
    677 
    678 	stats.minTime			= (float)values.front();
    679 	stats.maxTime			= (float)values.back();
    680 	stats.medianTime		= linearSample(values, 0.5f);
    681 	stats.min2DecileTime	= linearSample(values, 0.1f);
    682 	stats.max9DecileTime	= linearSample(values, 0.9f);
    683 
    684 	return stats;
    685 }
    686 
    687 template <typename StatisticsType, typename SampleType>
    688 void calculateBasicStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples, int SampleType::*predictor)
    689 {
    690 	std::vector<deUint64> values(samples.size());
    691 
    692 	for (int ndx = 0; ndx < (int)samples.size(); ++ndx)
    693 		values[ndx] = samples[ndx].duration.fitResponseDuration;
    694 
    695 	// median rate
    696 	{
    697 		std::vector<float> processingRates(samples.size());
    698 
    699 		for (int ndx = 0; ndx < (int)samples.size(); ++ndx)
    700 		{
    701 			const float timeInSeconds = (float)values[ndx] / 1000.0f / 1000.0f;
    702 			processingRates[ndx] = (float)(samples[ndx].*predictor) / timeInSeconds;
    703 		}
    704 
    705 		std::sort(processingRates.begin(), processingRates.end());
    706 
    707 		stats.medianRate = linearSample(processingRates, 0.5f);
    708 	}
    709 
    710 	// results compared to the approximation
    711 	{
    712 		std::vector<float> timeDiffs(samples.size());
    713 
    714 		for (int ndx = 0; ndx < (int)samples.size(); ++ndx)
    715 		{
    716 			const float prediction	= (float)(samples[ndx].*predictor) * fit.coefficient + fit.offset;
    717 			const float actual		= (float)values[ndx];
    718 			timeDiffs[ndx] = actual - prediction;
    719 		}
    720 		std::sort(timeDiffs.begin(), timeDiffs.end());
    721 
    722 		stats.maxDiffTime			= timeDiffs.back();
    723 		stats.maxDiff9DecileTime	= linearSample(timeDiffs, 0.9f);
    724 		stats.medianDiffTime		= linearSample(timeDiffs, 0.5f);
    725 	}
    726 
    727 	// relative comparison to the approximation
    728 	{
    729 		std::vector<float> relativeDiffs(samples.size());
    730 
    731 		for (int ndx = 0; ndx < (int)samples.size(); ++ndx)
    732 		{
    733 			const float prediction	= (float)(samples[ndx].*predictor) * fit.coefficient + fit.offset;
    734 			const float actual		= (float)values[ndx];
    735 
    736 			// Ignore cases where we predict negative times, or if
    737 			// ratio would be (nearly) infinite: ignore if predicted
    738 			// time is less than 1 microsecond
    739 			if (prediction < 1.0f)
    740 				relativeDiffs[ndx] = 0.0f;
    741 			else
    742 				relativeDiffs[ndx] = (actual - prediction) / prediction;
    743 		}
    744 		std::sort(relativeDiffs.begin(), relativeDiffs.end());
    745 
    746 		stats.maxRelDiffTime		= relativeDiffs.back();
    747 		stats.max9DecileRelDiffTime	= linearSample(relativeDiffs, 0.9f);
    748 		stats.medianRelDiffTime		= linearSample(relativeDiffs, 0.5f);
    749 	}
    750 
    751 	// values calculated using sorted timings
    752 
    753 	std::sort(values.begin(), values.end());
    754 
    755 	stats.result.minTime = (float)values.front();
    756 	stats.result.maxTime = (float)values.back();
    757 	stats.result.medianTime = linearSample(values, 0.5f);
    758 	stats.result.min2DecileTime = linearSample(values, 0.1f);
    759 	stats.result.max9DecileTime = linearSample(values, 0.9f);
    760 }
    761 
    762 template <typename StatisticsType, typename SampleType>
    763 void calculateBasicTransferStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples)
    764 {
    765 	calculateBasicStatistics(stats, fit, samples, &SampleType::writtenSize);
    766 }
    767 
    768 template <typename StatisticsType, typename SampleType>
    769 void calculateBasicRenderStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples)
    770 {
    771 	calculateBasicStatistics(stats, fit, samples, &SampleType::renderDataSize);
    772 }
    773 
    774 static SingleCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples)
    775 {
    776 	SingleCallStatistics stats;
    777 
    778 	calculateBasicTransferStatistics(stats, fit, samples);
    779 
    780 	return stats;
    781 }
    782 
    783 static MapCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples)
    784 {
    785 	MapCallStatistics stats;
    786 
    787 	calculateBasicTransferStatistics(stats, fit, samples);
    788 
    789 	stats.map	= calculateSingleOperationStatistics(samples, &MapBufferRangeDuration::mapDuration);
    790 	stats.unmap	= calculateSingleOperationStatistics(samples, &MapBufferRangeDuration::unmapDuration);
    791 	stats.write	= calculateSingleOperationStatistics(samples, &MapBufferRangeDuration::writeDuration);
    792 	stats.alloc	= calculateSingleOperationStatistics(samples, &MapBufferRangeDuration::allocDuration);
    793 
    794 	return stats;
    795 }
    796 
    797 static MapFlushCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples)
    798 {
    799 	MapFlushCallStatistics stats;
    800 
    801 	calculateBasicTransferStatistics(stats, fit, samples);
    802 
    803 	stats.map	= calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDuration::mapDuration);
    804 	stats.unmap	= calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDuration::unmapDuration);
    805 	stats.write	= calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDuration::writeDuration);
    806 	stats.flush	= calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDuration::flushDuration);
    807 	stats.alloc	= calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDuration::allocDuration);
    808 
    809 	return stats;
    810 }
    811 
    812 static MapCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples)
    813 {
    814 	MapCallStatistics stats;
    815 
    816 	calculateBasicTransferStatistics(stats, fit, samples);
    817 
    818 	stats.map	= calculateSingleOperationStatistics(samples, &MapBufferRangeDurationNoAlloc::mapDuration);
    819 	stats.unmap	= calculateSingleOperationStatistics(samples, &MapBufferRangeDurationNoAlloc::unmapDuration);
    820 	stats.write	= calculateSingleOperationStatistics(samples, &MapBufferRangeDurationNoAlloc::writeDuration);
    821 
    822 	return stats;
    823 }
    824 
    825 static MapFlushCallStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples)
    826 {
    827 	MapFlushCallStatistics stats;
    828 
    829 	calculateBasicTransferStatistics(stats, fit, samples);
    830 
    831 	stats.map	= calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDurationNoAlloc::mapDuration);
    832 	stats.unmap	= calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDurationNoAlloc::unmapDuration);
    833 	stats.write	= calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDurationNoAlloc::writeDuration);
    834 	stats.flush	= calculateSingleOperationStatistics(samples, &MapBufferRangeFlushDurationNoAlloc::flushDuration);
    835 
    836 	return stats;
    837 }
    838 
    839 static RenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<RenderReadDuration> >& samples)
    840 {
    841 	RenderReadStatistics stats;
    842 
    843 	calculateBasicRenderStatistics(stats, fit, samples);
    844 
    845 	stats.render	= calculateSingleOperationStatistics(samples, &RenderReadDuration::renderDuration);
    846 	stats.read		= calculateSingleOperationStatistics(samples, &RenderReadDuration::readDuration);
    847 	stats.total		= calculateSingleOperationStatistics(samples, &RenderReadDuration::totalDuration);
    848 
    849 	return stats;
    850 }
    851 
    852 static RenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples)
    853 {
    854 	RenderReadStatistics stats;
    855 
    856 	calculateBasicRenderStatistics(stats, fit, samples);
    857 
    858 	stats.render	= calculateSingleOperationStatistics(samples, &UnrelatedUploadRenderReadDuration::renderDuration);
    859 	stats.read		= calculateSingleOperationStatistics(samples, &UnrelatedUploadRenderReadDuration::readDuration);
    860 	stats.total		= calculateSingleOperationStatistics(samples, &UnrelatedUploadRenderReadDuration::totalDuration);
    861 
    862 	return stats;
    863 }
    864 
    865 static UploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples)
    866 {
    867 	UploadRenderReadStatistics stats;
    868 
    869 	calculateBasicRenderStatistics(stats, fit, samples);
    870 
    871 	stats.upload	= calculateSingleOperationStatistics(samples, &UploadRenderReadDuration::uploadDuration);
    872 	stats.render	= calculateSingleOperationStatistics(samples, &UploadRenderReadDuration::renderDuration);
    873 	stats.read		= calculateSingleOperationStatistics(samples, &UploadRenderReadDuration::readDuration);
    874 	stats.total		= calculateSingleOperationStatistics(samples, &UploadRenderReadDuration::totalDuration);
    875 
    876 	return stats;
    877 }
    878 
    879 static UploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples)
    880 {
    881 	UploadRenderReadStatistics stats;
    882 
    883 	calculateBasicRenderStatistics(stats, fit, samples);
    884 
    885 	stats.upload	= calculateSingleOperationStatistics(samples, &UploadRenderReadDurationWithUnrelatedUploadSize::uploadDuration);
    886 	stats.render	= calculateSingleOperationStatistics(samples, &UploadRenderReadDurationWithUnrelatedUploadSize::renderDuration);
    887 	stats.read		= calculateSingleOperationStatistics(samples, &UploadRenderReadDurationWithUnrelatedUploadSize::readDuration);
    888 	stats.total		= calculateSingleOperationStatistics(samples, &UploadRenderReadDurationWithUnrelatedUploadSize::totalDuration);
    889 
    890 	return stats;
    891 }
    892 
    893 static RenderUploadRenderReadStatistics calculateSampleStatistics (const LineParametersWithConfidence& fit, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples)
    894 {
    895 	RenderUploadRenderReadStatistics stats;
    896 
    897 	calculateBasicRenderStatistics(stats, fit, samples);
    898 
    899 	stats.firstRender	= calculateSingleOperationStatistics(samples, &RenderUploadRenderReadDuration::firstRenderDuration);
    900 	stats.upload		= calculateSingleOperationStatistics(samples, &RenderUploadRenderReadDuration::uploadDuration);
    901 	stats.secondRender	= calculateSingleOperationStatistics(samples, &RenderUploadRenderReadDuration::secondRenderDuration);
    902 	stats.read			= calculateSingleOperationStatistics(samples, &RenderUploadRenderReadDuration::readDuration);
    903 	stats.total			= calculateSingleOperationStatistics(samples, &RenderUploadRenderReadDuration::totalDuration);
    904 
    905 	return stats;
    906 }
    907 
    908 template <typename DurationType>
    909 static LineParametersWithConfidence fitLineToSamples (const std::vector<UploadSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration)
    910 {
    911 	std::vector<tcu::Vec2> samplePoints;
    912 
    913 	for (int sampleNdx = beginNdx; sampleNdx < endNdx; sampleNdx += step)
    914 	{
    915 		tcu::Vec2 point;
    916 
    917 		point.x() = (float)(samples[sampleNdx].writtenSize);
    918 		point.y() = (float)(samples[sampleNdx].duration.*target);
    919 
    920 		samplePoints.push_back(point);
    921 	}
    922 
    923 	return theilSenSiegelLinearRegression(samplePoints, 0.6f);
    924 }
    925 
    926 template <typename DurationType>
    927 static LineParametersWithConfidence fitLineToSamples (const std::vector<RenderSampleResult<DurationType> >& samples, int beginNdx, int endNdx, int step, deUint64 DurationType::*target = &DurationType::fitResponseDuration)
    928 {
    929 	std::vector<tcu::Vec2> samplePoints;
    930 
    931 	for (int sampleNdx = beginNdx; sampleNdx < endNdx; sampleNdx += step)
    932 	{
    933 		tcu::Vec2 point;
    934 
    935 		point.x() = (float)(samples[sampleNdx].renderDataSize);
    936 		point.y() = (float)(samples[sampleNdx].duration.*target);
    937 
    938 		samplePoints.push_back(point);
    939 	}
    940 
    941 	return theilSenSiegelLinearRegression(samplePoints, 0.6f);
    942 }
    943 
    944 template <typename T>
    945 static LineParametersWithConfidence fitLineToSamples (const std::vector<T>& samples, int beginNdx, int endNdx, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration)
    946 {
    947 	return fitLineToSamples(samples, beginNdx, endNdx, 1, target);
    948 }
    949 
    950 template <typename T>
    951 static LineParametersWithConfidence fitLineToSamples (const std::vector<T>& samples, deUint64 T::SampleType::*target = &T::SampleType::fitResponseDuration)
    952 {
    953 	return fitLineToSamples(samples, 0, (int)samples.size(), target);
    954 }
    955 
    956 static float getAreaBetweenLines (float xmin, float xmax, float lineAOffset, float lineACoefficient, float lineBOffset, float lineBCoefficient)
    957 {
    958 	const float lineAMin		= lineAOffset + lineACoefficient * xmin;
    959 	const float lineAMax		= lineAOffset + lineACoefficient * xmax;
    960 	const float lineBMin		= lineBOffset + lineBCoefficient * xmin;
    961 	const float lineBMax		= lineBOffset + lineBCoefficient * xmax;
    962 	const bool	aOverBAtBegin	= (lineAMin > lineBMin);
    963 	const bool	aOverBAtEnd		= (lineAMax > lineBMax);
    964 
    965 	if (aOverBAtBegin == aOverBAtEnd)
    966 	{
    967 		// lines do not intersect
    968 
    969 		const float midpoint	= (xmin + xmax) / 2.0f;
    970 		const float width		= (xmax - xmin);
    971 
    972 		const float lineAHeight	= lineAOffset + lineACoefficient * midpoint;
    973 		const float lineBHeight	= lineBOffset + lineBCoefficient * midpoint;
    974 
    975 		return width * de::abs(lineAHeight - lineBHeight);
    976 	}
    977 	else
    978 	{
    979 
    980 		// lines intersect
    981 
    982 		const float approachCoeffient	= de::abs(lineACoefficient - lineBCoefficient);
    983 		const float epsilon				= 0.0001f;
    984 		const float leftHeight			= de::abs(lineAMin - lineBMin);
    985 		const float rightHeight			= de::abs(lineAMax - lineBMax);
    986 
    987 		if (approachCoeffient < epsilon)
    988 			return 0.0f;
    989 
    990 		return (0.5f * leftHeight * (leftHeight / approachCoeffient)) + (0.5f * rightHeight * (rightHeight / approachCoeffient));
    991 	}
    992 }
    993 
    994 template <typename T>
    995 static float calculateSampleFitLinearity (const std::vector<T>& samples, int T::*predictor)
    996 {
    997 	// Compare the fitted line of first half of the samples to the fitted line of
    998 	// the second half of the samples. Calculate a AABB that fully contains every
    999 	// sample's x component and both fit lines in this range. Calculate the ratio
   1000 	// of the area between the lines and the AABB.
   1001 
   1002 	const float				epsilon				= 1.e-6f;
   1003 	const int				midPoint			= (int)samples.size() / 2;
   1004 	const LineParametersWithConfidence	startApproximation	= fitLineToSamples(samples, 0, midPoint, &T::SampleType::fitResponseDuration);
   1005 	const LineParametersWithConfidence	endApproximation	= fitLineToSamples(samples, midPoint, (int)samples.size(), &T::SampleType::fitResponseDuration);
   1006 
   1007 	const float				aabbMinX			= (float)(samples.front().*predictor);
   1008 	const float				aabbMinY			= de::min(startApproximation.offset + startApproximation.coefficient*aabbMinX, endApproximation.offset + endApproximation.coefficient*aabbMinX);
   1009 	const float				aabbMaxX			= (float)(samples.back().*predictor);
   1010 	const float				aabbMaxY			= de::max(startApproximation.offset + startApproximation.coefficient*aabbMaxX, endApproximation.offset + endApproximation.coefficient*aabbMaxX);
   1011 
   1012 	const float				aabbArea			= (aabbMaxX - aabbMinX) * (aabbMaxY - aabbMinY);
   1013 	const float				areaBetweenLines	= getAreaBetweenLines(aabbMinX, aabbMaxX, startApproximation.offset, startApproximation.coefficient, endApproximation.offset, endApproximation.coefficient);
   1014 	const float				errorAreaRatio		= (aabbArea < epsilon) ? (1.0f) : (areaBetweenLines / aabbArea);
   1015 
   1016 	return de::clamp(1.0f - errorAreaRatio, 0.0f, 1.0f);
   1017 }
   1018 
   1019 template <typename DurationType>
   1020 static float calculateSampleFitLinearity (const std::vector<UploadSampleResult<DurationType> >& samples)
   1021 {
   1022 	return calculateSampleFitLinearity(samples, &UploadSampleResult<DurationType>::writtenSize);
   1023 }
   1024 
   1025 template <typename DurationType>
   1026 static float calculateSampleFitLinearity (const std::vector<RenderSampleResult<DurationType> >& samples)
   1027 {
   1028 	return calculateSampleFitLinearity(samples, &RenderSampleResult<DurationType>::renderDataSize);
   1029 }
   1030 
   1031 template <typename T>
   1032 static float calculateSampleTemporalStability (const std::vector<T>& samples, int T::*predictor)
   1033 {
   1034 	// Samples are sampled in the following order: 1) even samples (in random order) 2) odd samples (in random order)
   1035 	// Compare the fitted line of even samples to the fitted line of the odd samples. Calculate a AABB that fully
   1036 	// contains every sample's x component and both fit lines in this range. Calculate the ratio of the area between
   1037 	// the lines and the AABB.
   1038 
   1039 	const float				epsilon				= 1.e-6f;
   1040 	const LineParametersWithConfidence	evenApproximation	= fitLineToSamples(samples, 0, (int)samples.size(), 2, &T::SampleType::fitResponseDuration);
   1041 	const LineParametersWithConfidence	oddApproximation	= fitLineToSamples(samples, 1, (int)samples.size(), 2, &T::SampleType::fitResponseDuration);
   1042 
   1043 	const float				aabbMinX			= (float)(samples.front().*predictor);
   1044 	const float				aabbMinY			= de::min(evenApproximation.offset + evenApproximation.coefficient*aabbMinX, oddApproximation.offset + oddApproximation.coefficient*aabbMinX);
   1045 	const float				aabbMaxX			= (float)(samples.back().*predictor);
   1046 	const float				aabbMaxY			= de::max(evenApproximation.offset + evenApproximation.coefficient*aabbMaxX, oddApproximation.offset + oddApproximation.coefficient*aabbMaxX);
   1047 
   1048 	const float				aabbArea			= (aabbMaxX - aabbMinX) * (aabbMaxY - aabbMinY);
   1049 	const float				areaBetweenLines	= getAreaBetweenLines(aabbMinX, aabbMaxX, evenApproximation.offset, evenApproximation.coefficient, oddApproximation.offset, oddApproximation.coefficient);
   1050 	const float				errorAreaRatio		= (aabbArea < epsilon) ? (1.0f) : (areaBetweenLines / aabbArea);
   1051 
   1052 	return de::clamp(1.0f - errorAreaRatio, 0.0f, 1.0f);
   1053 }
   1054 
   1055 template <typename DurationType>
   1056 static float calculateSampleTemporalStability (const std::vector<UploadSampleResult<DurationType> >& samples)
   1057 {
   1058 	return calculateSampleTemporalStability(samples, &UploadSampleResult<DurationType>::writtenSize);
   1059 }
   1060 
   1061 template <typename DurationType>
   1062 static float calculateSampleTemporalStability (const std::vector<RenderSampleResult<DurationType> >& samples)
   1063 {
   1064 	return calculateSampleTemporalStability(samples, &RenderSampleResult<DurationType>::renderDataSize);
   1065 }
   1066 
   1067 template <typename DurationType>
   1068 static void bucketizeSamplesUniformly (const std::vector<UploadSampleResult<DurationType> >& samples, std::vector<UploadSampleResult<DurationType> >* buckets, int numBuckets, int& minBufferSize, int& maxBufferSize)
   1069 {
   1070 	minBufferSize = 0;
   1071 	maxBufferSize = 0;
   1072 
   1073 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1074 	{
   1075 		DE_ASSERT(samples[sampleNdx].allocatedSize != 0);
   1076 
   1077 		if (!minBufferSize || samples[sampleNdx].allocatedSize < minBufferSize)
   1078 			minBufferSize = samples[sampleNdx].allocatedSize;
   1079 		if (!maxBufferSize || samples[sampleNdx].allocatedSize > maxBufferSize)
   1080 			maxBufferSize = samples[sampleNdx].allocatedSize;
   1081 	}
   1082 
   1083 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1084 	{
   1085 		const float bucketNdxFloat	= (float)(samples[sampleNdx].allocatedSize - minBufferSize) / (float)(maxBufferSize - minBufferSize) * (float)numBuckets;
   1086 		const int bucketNdx			= de::clamp((int)deFloatFloor(bucketNdxFloat), 0, numBuckets-1);
   1087 
   1088 		buckets[bucketNdx].push_back(samples[sampleNdx]);
   1089 	}
   1090 }
   1091 
   1092 template <typename SampleType>
   1093 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Type logMapRangeStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1094 {
   1095 	log	<< tcu::TestLog::Float("MapRangeMin", "MapRange: Min time", "us", QP_KEY_TAG_TIME, stats.map.minTime)
   1096 		<< tcu::TestLog::Float("MapRangeMax", "MapRange: Max time", "us", QP_KEY_TAG_TIME, stats.map.maxTime)
   1097 		<< tcu::TestLog::Float("MapRangeMin90", "MapRange: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.map.min2DecileTime)
   1098 		<< tcu::TestLog::Float("MapRangeMax90", "MapRange: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.map.max9DecileTime)
   1099 		<< tcu::TestLog::Float("MapRangeMedian", "MapRange: Median time", "us", QP_KEY_TAG_TIME, stats.map.medianTime);
   1100 }
   1101 
   1102 template <typename SampleType>
   1103 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::Type logUnmapStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1104 {
   1105 	log	<< tcu::TestLog::Float("UnmapMin", "Unmap: Min time", "us", QP_KEY_TAG_TIME, stats.unmap.minTime)
   1106 		<< tcu::TestLog::Float("UnmapMax", "Unmap: Max time", "us", QP_KEY_TAG_TIME, stats.unmap.maxTime)
   1107 		<< tcu::TestLog::Float("UnmapMin90", "Unmap: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.unmap.min2DecileTime)
   1108 		<< tcu::TestLog::Float("UnmapMax90", "Unmap: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.unmap.max9DecileTime)
   1109 		<< tcu::TestLog::Float("UnmapMedian", "Unmap: Median time", "us", QP_KEY_TAG_TIME, stats.unmap.medianTime);
   1110 }
   1111 
   1112 template <typename SampleType>
   1113 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::Type logWriteStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1114 {
   1115 	log	<< tcu::TestLog::Float("WriteMin", "Write: Min time", "us", QP_KEY_TAG_TIME, stats.write.minTime)
   1116 		<< tcu::TestLog::Float("WriteMax", "Write: Max time", "us", QP_KEY_TAG_TIME, stats.write.maxTime)
   1117 		<< tcu::TestLog::Float("WriteMin90", "Write: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.write.min2DecileTime)
   1118 		<< tcu::TestLog::Float("WriteMax90", "Write: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.write.max9DecileTime)
   1119 		<< tcu::TestLog::Float("WriteMedian", "Write: Median time", "us", QP_KEY_TAG_TIME, stats.write.medianTime);
   1120 }
   1121 
   1122 template <typename SampleType>
   1123 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::Type logFlushStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1124 {
   1125 	log	<< tcu::TestLog::Float("FlushMin", "Flush: Min time", "us", QP_KEY_TAG_TIME, stats.flush.minTime)
   1126 		<< tcu::TestLog::Float("FlushMax", "Flush: Max time", "us", QP_KEY_TAG_TIME, stats.flush.maxTime)
   1127 		<< tcu::TestLog::Float("FlushMin90", "Flush: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.flush.min2DecileTime)
   1128 		<< tcu::TestLog::Float("FlushMax90", "Flush: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.flush.max9DecileTime)
   1129 		<< tcu::TestLog::Float("FlushMedian", "Flush: Median time", "us", QP_KEY_TAG_TIME, stats.flush.medianTime);
   1130 }
   1131 
   1132 template <typename SampleType>
   1133 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::Type logAllocStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1134 {
   1135 	log	<< tcu::TestLog::Float("AllocMin", "Alloc: Min time", "us", QP_KEY_TAG_TIME, stats.alloc.minTime)
   1136 		<< tcu::TestLog::Float("AllocMax", "Alloc: Max time", "us", QP_KEY_TAG_TIME, stats.alloc.maxTime)
   1137 		<< tcu::TestLog::Float("AllocMin90", "Alloc: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.alloc.min2DecileTime)
   1138 		<< tcu::TestLog::Float("AllocMax90", "Alloc: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.alloc.max9DecileTime)
   1139 		<< tcu::TestLog::Float("AllocMedian", "Alloc: Median time", "us", QP_KEY_TAG_TIME, stats.alloc.medianTime);
   1140 }
   1141 
   1142 template <typename SampleType>
   1143 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Value>::Type logMapRangeStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1144 {
   1145 	DE_UNREF(log);
   1146 	DE_UNREF(stats);
   1147 }
   1148 
   1149 template <typename SampleType>
   1150 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::Value>::Type logUnmapStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1151 {
   1152 	DE_UNREF(log);
   1153 	DE_UNREF(stats);
   1154 }
   1155 
   1156 template <typename SampleType>
   1157 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::Value>::Type logWriteStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1158 {
   1159 	DE_UNREF(log);
   1160 	DE_UNREF(stats);
   1161 }
   1162 
   1163 template <typename SampleType>
   1164 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::Value>::Type logFlushStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1165 {
   1166 	DE_UNREF(log);
   1167 	DE_UNREF(stats);
   1168 }
   1169 
   1170 template <typename SampleType>
   1171 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::Value>::Type logAllocStats (tcu::TestLog& log, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1172 {
   1173 	DE_UNREF(log);
   1174 	DE_UNREF(stats);
   1175 }
   1176 
   1177 template <typename SampleType>
   1178 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Type logMapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1179 {
   1180 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::mapDuration);
   1181 	log	<< tcu::TestLog::Float("MapConstantCost", "Map: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1182 		<< tcu::TestLog::Float("MapLinearCost", "Map: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1183 		<< tcu::TestLog::Float("MapMedianCost", "Map: Median cost", "us", QP_KEY_TAG_TIME, stats.map.medianTime);
   1184 }
   1185 
   1186 template <typename SampleType>
   1187 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::Type logUnmapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1188 {
   1189 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::unmapDuration);
   1190 	log	<< tcu::TestLog::Float("UnmapConstantCost", "Unmap: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1191 		<< tcu::TestLog::Float("UnmapLinearCost", "Unmap: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1192 		<< tcu::TestLog::Float("UnmapMedianCost", "Unmap: Median cost", "us", QP_KEY_TAG_TIME, stats.unmap.medianTime);
   1193 }
   1194 
   1195 template <typename SampleType>
   1196 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::Type logWriteContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1197 {
   1198 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::writeDuration);
   1199 	log	<< tcu::TestLog::Float("WriteConstantCost", "Write: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1200 		<< tcu::TestLog::Float("WriteLinearCost", "Write: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1201 		<< tcu::TestLog::Float("WriteMedianCost", "Write: Median cost", "us", QP_KEY_TAG_TIME, stats.write.medianTime);
   1202 }
   1203 
   1204 template <typename SampleType>
   1205 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::Type logFlushContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1206 {
   1207 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::flushDuration);
   1208 	log	<< tcu::TestLog::Float("FlushConstantCost", "Flush: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1209 		<< tcu::TestLog::Float("FlushLinearCost", "Flush: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1210 		<< tcu::TestLog::Float("FlushMedianCost", "Flush: Median cost", "us", QP_KEY_TAG_TIME, stats.flush.medianTime);
   1211 }
   1212 
   1213 template <typename SampleType>
   1214 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::Type logAllocContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1215 {
   1216 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::allocDuration);
   1217 	log	<< tcu::TestLog::Float("AllocConstantCost", "Alloc: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1218 		<< tcu::TestLog::Float("AllocLinearCost", "Alloc: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1219 		<< tcu::TestLog::Float("AllocMedianCost", "Alloc: Median cost", "us", QP_KEY_TAG_TIME, stats.alloc.medianTime);
   1220 }
   1221 
   1222 template <typename SampleType>
   1223 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_RENDER_STATS>::Type logRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1224 {
   1225 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::renderDuration);
   1226 	log	<< tcu::TestLog::Float("DrawCallConstantCost", "DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1227 		<< tcu::TestLog::Float("DrawCallLinearCost", "DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1228 		<< tcu::TestLog::Float("DrawCallMedianCost", "DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.render.medianTime);
   1229 }
   1230 
   1231 template <typename SampleType>
   1232 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_READ_STATS>::Type logReadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1233 {
   1234 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::readDuration);
   1235 	log	<< tcu::TestLog::Float("ReadConstantCost", "Read: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1236 		<< tcu::TestLog::Float("ReadLinearCost", "Read: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1237 		<< tcu::TestLog::Float("ReadMedianCost", "Read: Median cost", "us", QP_KEY_TAG_TIME, stats.read.medianTime);
   1238 }
   1239 
   1240 template <typename SampleType>
   1241 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_UPLOAD_STATS>::Type logUploadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1242 {
   1243 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::uploadDuration);
   1244 	log	<< tcu::TestLog::Float("UploadConstantCost", "Upload: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1245 		<< tcu::TestLog::Float("UploadLinearCost", "Upload: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1246 		<< tcu::TestLog::Float("UploadMedianCost", "Upload: Median cost", "us", QP_KEY_TAG_TIME, stats.upload.medianTime);
   1247 }
   1248 
   1249 template <typename SampleType>
   1250 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_TOTAL_STATS>::Type logTotalContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1251 {
   1252 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::totalDuration);
   1253 	log	<< tcu::TestLog::Float("TotalConstantCost", "Total: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1254 		<< tcu::TestLog::Float("TotalLinearCost", "Total: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1255 		<< tcu::TestLog::Float("TotalMedianCost", "Total: Median cost", "us", QP_KEY_TAG_TIME, stats.total.medianTime);
   1256 }
   1257 
   1258 template <typename SampleType>
   1259 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_FIRST_RENDER_STATS>::Type logFirstRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1260 {
   1261 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::firstRenderDuration);
   1262 	log	<< tcu::TestLog::Float("FirstDrawCallConstantCost", "First DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1263 		<< tcu::TestLog::Float("FirstDrawCallLinearCost", "First DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1264 		<< tcu::TestLog::Float("FirstDrawCallMedianCost", "First DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.firstRender.medianTime);
   1265 }
   1266 
   1267 template <typename SampleType>
   1268 static typename EnableIf<void, SampleTypeTraits<SampleType>::HAS_SECOND_RENDER_STATS>::Type logSecondRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1269 {
   1270 	const LineParametersWithConfidence contributionFitting = fitLineToSamples(samples, &SampleType::secondRenderDuration);
   1271 	log	<< tcu::TestLog::Float("SecondDrawCallConstantCost", "Second DrawCall: Approximated contant cost", "us", QP_KEY_TAG_TIME, contributionFitting.offset)
   1272 		<< tcu::TestLog::Float("SecondDrawCallLinearCost", "Second DrawCall: Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, contributionFitting.coefficient * 1024.0f * 1024.0f)
   1273 		<< tcu::TestLog::Float("SecondDrawCallMedianCost", "Second DrawCall: Median cost", "us", QP_KEY_TAG_TIME, stats.secondRender.medianTime);
   1274 }
   1275 
   1276 template <typename SampleType>
   1277 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_MAP_STATS>::Value>::Type logMapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1278 {
   1279 	DE_UNREF(log);
   1280 	DE_UNREF(samples);
   1281 	DE_UNREF(stats);
   1282 }
   1283 
   1284 template <typename SampleType>
   1285 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_UNMAP_STATS>::Value>::Type logUnmapContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1286 {
   1287 	DE_UNREF(log);
   1288 	DE_UNREF(samples);
   1289 	DE_UNREF(stats);
   1290 }
   1291 
   1292 template <typename SampleType>
   1293 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_WRITE_STATS>::Value>::Type logWriteContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1294 {
   1295 	DE_UNREF(log);
   1296 	DE_UNREF(samples);
   1297 	DE_UNREF(stats);
   1298 }
   1299 
   1300 template <typename SampleType>
   1301 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_FLUSH_STATS>::Value>::Type logFlushContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1302 {
   1303 	DE_UNREF(log);
   1304 	DE_UNREF(samples);
   1305 	DE_UNREF(stats);
   1306 }
   1307 
   1308 template <typename SampleType>
   1309 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_ALLOC_STATS>::Value>::Type logAllocContribution (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1310 {
   1311 	DE_UNREF(log);
   1312 	DE_UNREF(samples);
   1313 	DE_UNREF(stats);
   1314 }
   1315 
   1316 template <typename SampleType>
   1317 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_RENDER_STATS>::Value>::Type logRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1318 {
   1319 	DE_UNREF(log);
   1320 	DE_UNREF(samples);
   1321 	DE_UNREF(stats);
   1322 }
   1323 
   1324 template <typename SampleType>
   1325 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_READ_STATS>::Value>::Type logReadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1326 {
   1327 	DE_UNREF(log);
   1328 	DE_UNREF(samples);
   1329 	DE_UNREF(stats);
   1330 }
   1331 
   1332 template <typename SampleType>
   1333 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_UPLOAD_STATS>::Value>::Type logUploadContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1334 {
   1335 	DE_UNREF(log);
   1336 	DE_UNREF(samples);
   1337 	DE_UNREF(stats);
   1338 }
   1339 
   1340 template <typename SampleType>
   1341 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_TOTAL_STATS>::Value>::Type logTotalContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1342 {
   1343 	DE_UNREF(log);
   1344 	DE_UNREF(samples);
   1345 	DE_UNREF(stats);
   1346 }
   1347 
   1348 template <typename SampleType>
   1349 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_FIRST_RENDER_STATS>::Value>::Type logFirstRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1350 {
   1351 	DE_UNREF(log);
   1352 	DE_UNREF(samples);
   1353 	DE_UNREF(stats);
   1354 }
   1355 
   1356 template <typename SampleType>
   1357 static typename EnableIf<void, Not<SampleTypeTraits<SampleType>::HAS_SECOND_RENDER_STATS>::Value>::Type logSecondRenderContribution (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples, const typename SampleTypeTraits<SampleType>::StatsType& stats)
   1358 {
   1359 	DE_UNREF(log);
   1360 	DE_UNREF(samples);
   1361 	DE_UNREF(stats);
   1362 }
   1363 
   1364 void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<SingleOperationDuration> >& samples)
   1365 {
   1366 	log << tcu::TestLog::SampleList("Samples", "Samples")
   1367 		<< tcu::TestLog::SampleInfo
   1368 		<< tcu::TestLog::ValueInfo("WrittenSize",		"Written size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1369 		<< tcu::TestLog::ValueInfo("BufferSize",		"Buffer size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1370 		<< tcu::TestLog::ValueInfo("UploadTime",		"Upload time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1371 		<< tcu::TestLog::ValueInfo("FitResidual",		"Fit residual",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1372 		<< tcu::TestLog::EndSampleInfo;
   1373 
   1374 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1375 	{
   1376 		const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].writtenSize);
   1377 		log	<< tcu::TestLog::Sample
   1378 			<< samples[sampleNdx].writtenSize
   1379 			<< samples[sampleNdx].bufferSize
   1380 			<< (int)samples[sampleNdx].duration.totalDuration
   1381 			<< fitResidual
   1382 			<< tcu::TestLog::EndSample;
   1383 	}
   1384 
   1385 	log << tcu::TestLog::EndSampleList;
   1386 }
   1387 
   1388 void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDuration> >& samples)
   1389 {
   1390 	log << tcu::TestLog::SampleList("Samples", "Samples")
   1391 		<< tcu::TestLog::SampleInfo
   1392 		<< tcu::TestLog::ValueInfo("WrittenSize",		"Written size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1393 		<< tcu::TestLog::ValueInfo("BufferSize",		"Buffer size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1394 		<< tcu::TestLog::ValueInfo("TotalTime",			"Total time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1395 		<< tcu::TestLog::ValueInfo("AllocTime",			"Alloc time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1396 		<< tcu::TestLog::ValueInfo("MapTime",			"Map time",				"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1397 		<< tcu::TestLog::ValueInfo("UnmapTime",			"Unmap time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1398 		<< tcu::TestLog::ValueInfo("WriteTime",			"Write time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1399 		<< tcu::TestLog::ValueInfo("FitResidual",		"Fit residual",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1400 		<< tcu::TestLog::EndSampleInfo;
   1401 
   1402 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1403 	{
   1404 		const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].writtenSize);
   1405 		log	<< tcu::TestLog::Sample
   1406 			<< samples[sampleNdx].writtenSize
   1407 			<< samples[sampleNdx].bufferSize
   1408 			<< (int)samples[sampleNdx].duration.totalDuration
   1409 			<< (int)samples[sampleNdx].duration.allocDuration
   1410 			<< (int)samples[sampleNdx].duration.mapDuration
   1411 			<< (int)samples[sampleNdx].duration.unmapDuration
   1412 			<< (int)samples[sampleNdx].duration.writeDuration
   1413 			<< fitResidual
   1414 			<< tcu::TestLog::EndSample;
   1415 	}
   1416 
   1417 	log << tcu::TestLog::EndSampleList;
   1418 }
   1419 
   1420 void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc> >& samples)
   1421 {
   1422 	log << tcu::TestLog::SampleList("Samples", "Samples")
   1423 		<< tcu::TestLog::SampleInfo
   1424 		<< tcu::TestLog::ValueInfo("WrittenSize",		"Written size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1425 		<< tcu::TestLog::ValueInfo("BufferSize",		"Buffer size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1426 		<< tcu::TestLog::ValueInfo("TotalTime",			"Total time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1427 		<< tcu::TestLog::ValueInfo("MapTime",			"Map time",				"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1428 		<< tcu::TestLog::ValueInfo("UnmapTime",			"Unmap time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1429 		<< tcu::TestLog::ValueInfo("WriteTime",			"Write time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1430 		<< tcu::TestLog::ValueInfo("FitResidual",		"Fit residual",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1431 		<< tcu::TestLog::EndSampleInfo;
   1432 
   1433 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1434 	{
   1435 		const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].writtenSize);
   1436 		log	<< tcu::TestLog::Sample
   1437 			<< samples[sampleNdx].writtenSize
   1438 			<< samples[sampleNdx].bufferSize
   1439 			<< (int)samples[sampleNdx].duration.totalDuration
   1440 			<< (int)samples[sampleNdx].duration.mapDuration
   1441 			<< (int)samples[sampleNdx].duration.unmapDuration
   1442 			<< (int)samples[sampleNdx].duration.writeDuration
   1443 			<< fitResidual
   1444 			<< tcu::TestLog::EndSample;
   1445 	}
   1446 
   1447 	log << tcu::TestLog::EndSampleList;
   1448 }
   1449 
   1450 void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDuration> >& samples)
   1451 {
   1452 	log << tcu::TestLog::SampleList("Samples", "Samples")
   1453 		<< tcu::TestLog::SampleInfo
   1454 		<< tcu::TestLog::ValueInfo("WrittenSize",		"Written size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1455 		<< tcu::TestLog::ValueInfo("BufferSize",		"Buffer size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1456 		<< tcu::TestLog::ValueInfo("TotalTime",			"Total time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1457 		<< tcu::TestLog::ValueInfo("AllocTime",			"Alloc time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1458 		<< tcu::TestLog::ValueInfo("MapTime",			"Map time",				"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1459 		<< tcu::TestLog::ValueInfo("UnmapTime",			"Unmap time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1460 		<< tcu::TestLog::ValueInfo("WriteTime",			"Write time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1461 		<< tcu::TestLog::ValueInfo("FlushTime",			"Flush time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1462 		<< tcu::TestLog::ValueInfo("FitResidual",		"Fit residual",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1463 		<< tcu::TestLog::EndSampleInfo;
   1464 
   1465 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1466 	{
   1467 		const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].writtenSize);
   1468 		log	<< tcu::TestLog::Sample
   1469 			<< samples[sampleNdx].writtenSize
   1470 			<< samples[sampleNdx].bufferSize
   1471 			<< (int)samples[sampleNdx].duration.totalDuration
   1472 			<< (int)samples[sampleNdx].duration.allocDuration
   1473 			<< (int)samples[sampleNdx].duration.mapDuration
   1474 			<< (int)samples[sampleNdx].duration.unmapDuration
   1475 			<< (int)samples[sampleNdx].duration.writeDuration
   1476 			<< (int)samples[sampleNdx].duration.flushDuration
   1477 			<< fitResidual
   1478 			<< tcu::TestLog::EndSample;
   1479 	}
   1480 
   1481 	log << tcu::TestLog::EndSampleList;
   1482 }
   1483 
   1484 void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> >& samples)
   1485 {
   1486 	log << tcu::TestLog::SampleList("Samples", "Samples")
   1487 		<< tcu::TestLog::SampleInfo
   1488 		<< tcu::TestLog::ValueInfo("WrittenSize",		"Written size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1489 		<< tcu::TestLog::ValueInfo("BufferSize",		"Buffer size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1490 		<< tcu::TestLog::ValueInfo("TotalTime",			"Total time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1491 		<< tcu::TestLog::ValueInfo("MapTime",			"Map time",				"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1492 		<< tcu::TestLog::ValueInfo("UnmapTime",			"Unmap time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1493 		<< tcu::TestLog::ValueInfo("WriteTime",			"Write time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1494 		<< tcu::TestLog::ValueInfo("FlushTime",			"Flush time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1495 		<< tcu::TestLog::ValueInfo("FitResidual",		"Fit residual",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1496 		<< tcu::TestLog::EndSampleInfo;
   1497 
   1498 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1499 	{
   1500 		const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].writtenSize);
   1501 		log	<< tcu::TestLog::Sample
   1502 			<< samples[sampleNdx].writtenSize
   1503 			<< samples[sampleNdx].bufferSize
   1504 			<< (int)samples[sampleNdx].duration.totalDuration
   1505 			<< (int)samples[sampleNdx].duration.mapDuration
   1506 			<< (int)samples[sampleNdx].duration.unmapDuration
   1507 			<< (int)samples[sampleNdx].duration.writeDuration
   1508 			<< (int)samples[sampleNdx].duration.flushDuration
   1509 			<< fitResidual
   1510 			<< tcu::TestLog::EndSample;
   1511 	}
   1512 
   1513 	log << tcu::TestLog::EndSampleList;
   1514 }
   1515 
   1516 void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<RenderReadDuration> >& samples)
   1517 {
   1518 	log << tcu::TestLog::SampleList("Samples", "Samples")
   1519 		<< tcu::TestLog::SampleInfo
   1520 		<< tcu::TestLog::ValueInfo("DataSize",			"Data processed",		"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1521 		<< tcu::TestLog::ValueInfo("VertexCount",		"Number of vertices",	"vertices",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1522 		<< tcu::TestLog::ValueInfo("TotalTime",			"Total time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1523 		<< tcu::TestLog::ValueInfo("DrawCallTime",		"Draw call time",		"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1524 		<< tcu::TestLog::ValueInfo("ReadTime",			"ReadPixels time",		"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1525 		<< tcu::TestLog::ValueInfo("FitResidual",		"Fit residual",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1526 		<< tcu::TestLog::EndSampleInfo;
   1527 
   1528 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1529 	{
   1530 		const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].renderDataSize);
   1531 		log	<< tcu::TestLog::Sample
   1532 			<< samples[sampleNdx].renderDataSize
   1533 			<< samples[sampleNdx].numVertices
   1534 			<< (int)samples[sampleNdx].duration.renderReadDuration
   1535 			<< (int)samples[sampleNdx].duration.renderDuration
   1536 			<< (int)samples[sampleNdx].duration.readDuration
   1537 			<< fitResidual
   1538 			<< tcu::TestLog::EndSample;
   1539 	}
   1540 
   1541 	log << tcu::TestLog::EndSampleList;
   1542 }
   1543 
   1544 void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration> >& samples)
   1545 {
   1546 	log << tcu::TestLog::SampleList("Samples", "Samples")
   1547 		<< tcu::TestLog::SampleInfo
   1548 		<< tcu::TestLog::ValueInfo("DataSize",				"Data processed",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1549 		<< tcu::TestLog::ValueInfo("VertexCount",			"Number of vertices",		"vertices",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1550 		<< tcu::TestLog::ValueInfo("UnrelatedUploadSize",	"Unrelated upload size",	"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1551 		<< tcu::TestLog::ValueInfo("TotalTime",				"Total time",				"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1552 		<< tcu::TestLog::ValueInfo("DrawCallTime",			"Draw call time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1553 		<< tcu::TestLog::ValueInfo("ReadTime",				"ReadPixels time",			"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1554 		<< tcu::TestLog::ValueInfo("FitResidual",			"Fit residual",				"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1555 		<< tcu::TestLog::EndSampleInfo;
   1556 
   1557 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1558 	{
   1559 		const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].renderDataSize);
   1560 		log	<< tcu::TestLog::Sample
   1561 			<< samples[sampleNdx].renderDataSize
   1562 			<< samples[sampleNdx].numVertices
   1563 			<< samples[sampleNdx].unrelatedDataSize
   1564 			<< (int)samples[sampleNdx].duration.renderReadDuration
   1565 			<< (int)samples[sampleNdx].duration.renderDuration
   1566 			<< (int)samples[sampleNdx].duration.readDuration
   1567 			<< fitResidual
   1568 			<< tcu::TestLog::EndSample;
   1569 	}
   1570 
   1571 	log << tcu::TestLog::EndSampleList;
   1572 }
   1573 
   1574 void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDuration> >& samples)
   1575 {
   1576 	log << tcu::TestLog::SampleList("Samples", "Samples")
   1577 		<< tcu::TestLog::SampleInfo
   1578 		<< tcu::TestLog::ValueInfo("DataSize",			"Data processed",					"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1579 		<< tcu::TestLog::ValueInfo("UploadSize",		"Data uploaded",					"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1580 		<< tcu::TestLog::ValueInfo("VertexCount",		"Number of vertices",				"vertices",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1581 		<< tcu::TestLog::ValueInfo("DrawReadTime",		"Draw call and ReadPixels time",	"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1582 		<< tcu::TestLog::ValueInfo("TotalTime",			"Total time",						"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1583 		<< tcu::TestLog::ValueInfo("Upload time",		"Upload time",						"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1584 		<< tcu::TestLog::ValueInfo("DrawCallTime",		"Draw call time",					"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1585 		<< tcu::TestLog::ValueInfo("ReadTime",			"ReadPixels time",					"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1586 		<< tcu::TestLog::ValueInfo("FitResidual",		"Fit residual",						"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1587 		<< tcu::TestLog::EndSampleInfo;
   1588 
   1589 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1590 	{
   1591 		const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].renderDataSize);
   1592 		log	<< tcu::TestLog::Sample
   1593 			<< samples[sampleNdx].renderDataSize
   1594 			<< samples[sampleNdx].uploadedDataSize
   1595 			<< samples[sampleNdx].numVertices
   1596 			<< (int)samples[sampleNdx].duration.renderReadDuration
   1597 			<< (int)samples[sampleNdx].duration.totalDuration
   1598 			<< (int)samples[sampleNdx].duration.uploadDuration
   1599 			<< (int)samples[sampleNdx].duration.renderDuration
   1600 			<< (int)samples[sampleNdx].duration.readDuration
   1601 			<< fitResidual
   1602 			<< tcu::TestLog::EndSample;
   1603 	}
   1604 
   1605 	log << tcu::TestLog::EndSampleList;
   1606 }
   1607 
   1608 void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize> >& samples)
   1609 {
   1610 	log << tcu::TestLog::SampleList("Samples", "Samples")
   1611 		<< tcu::TestLog::SampleInfo
   1612 		<< tcu::TestLog::ValueInfo("DataSize",				"Data processed",					"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1613 		<< tcu::TestLog::ValueInfo("UploadSize",			"Data uploaded",					"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1614 		<< tcu::TestLog::ValueInfo("VertexCount",			"Number of vertices",				"vertices",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1615 		<< tcu::TestLog::ValueInfo("UnrelatedUploadSize",	"Unrelated upload size",			"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1616 		<< tcu::TestLog::ValueInfo("DrawReadTime",			"Draw call and ReadPixels time",	"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1617 		<< tcu::TestLog::ValueInfo("TotalTime",				"Total time",						"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1618 		<< tcu::TestLog::ValueInfo("Upload time",			"Upload time",						"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1619 		<< tcu::TestLog::ValueInfo("DrawCallTime",			"Draw call time",					"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1620 		<< tcu::TestLog::ValueInfo("ReadTime",				"ReadPixels time",					"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1621 		<< tcu::TestLog::ValueInfo("FitResidual",			"Fit residual",						"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1622 		<< tcu::TestLog::EndSampleInfo;
   1623 
   1624 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1625 	{
   1626 		const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].renderDataSize);
   1627 		log	<< tcu::TestLog::Sample
   1628 			<< samples[sampleNdx].renderDataSize
   1629 			<< samples[sampleNdx].uploadedDataSize
   1630 			<< samples[sampleNdx].numVertices
   1631 			<< samples[sampleNdx].unrelatedDataSize
   1632 			<< (int)samples[sampleNdx].duration.renderReadDuration
   1633 			<< (int)samples[sampleNdx].duration.totalDuration
   1634 			<< (int)samples[sampleNdx].duration.uploadDuration
   1635 			<< (int)samples[sampleNdx].duration.renderDuration
   1636 			<< (int)samples[sampleNdx].duration.readDuration
   1637 			<< fitResidual
   1638 			<< tcu::TestLog::EndSample;
   1639 	}
   1640 
   1641 	log << tcu::TestLog::EndSampleList;
   1642 }
   1643 
   1644 void logSampleList (tcu::TestLog& log, const LineParametersWithConfidence& theilSenFitting, const std::vector<RenderSampleResult<RenderUploadRenderReadDuration> >& samples)
   1645 {
   1646 	log << tcu::TestLog::SampleList("Samples", "Samples")
   1647 		<< tcu::TestLog::SampleInfo
   1648 		<< tcu::TestLog::ValueInfo("DataSize",				"Data processed",						"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1649 		<< tcu::TestLog::ValueInfo("UploadSize",			"Data uploaded",						"bytes",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1650 		<< tcu::TestLog::ValueInfo("VertexCount",			"Number of vertices",					"vertices",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   1651 		<< tcu::TestLog::ValueInfo("DrawReadTime",			"Second draw call and ReadPixels time",	"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1652 		<< tcu::TestLog::ValueInfo("TotalTime",				"Total time",							"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1653 		<< tcu::TestLog::ValueInfo("FirstDrawCallTime",		"First draw call time",					"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1654 		<< tcu::TestLog::ValueInfo("Upload time",			"Upload time",							"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1655 		<< tcu::TestLog::ValueInfo("SecondDrawCallTime",	"Second draw call time",				"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1656 		<< tcu::TestLog::ValueInfo("ReadTime",				"ReadPixels time",						"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1657 		<< tcu::TestLog::ValueInfo("FitResidual",			"Fit residual",							"us",		QP_SAMPLE_VALUE_TAG_RESPONSE)
   1658 		<< tcu::TestLog::EndSampleInfo;
   1659 
   1660 	for (int sampleNdx = 0; sampleNdx < (int)samples.size(); ++sampleNdx)
   1661 	{
   1662 		const float fitResidual = (float)samples[sampleNdx].duration.fitResponseDuration - (theilSenFitting.offset + theilSenFitting.coefficient * (float)samples[sampleNdx].renderDataSize);
   1663 		log	<< tcu::TestLog::Sample
   1664 			<< samples[sampleNdx].renderDataSize
   1665 			<< samples[sampleNdx].uploadedDataSize
   1666 			<< samples[sampleNdx].numVertices
   1667 			<< (int)samples[sampleNdx].duration.renderReadDuration
   1668 			<< (int)samples[sampleNdx].duration.totalDuration
   1669 			<< (int)samples[sampleNdx].duration.firstRenderDuration
   1670 			<< (int)samples[sampleNdx].duration.uploadDuration
   1671 			<< (int)samples[sampleNdx].duration.secondRenderDuration
   1672 			<< (int)samples[sampleNdx].duration.readDuration
   1673 			<< fitResidual
   1674 			<< tcu::TestLog::EndSample;
   1675 	}
   1676 
   1677 	log << tcu::TestLog::EndSampleList;
   1678 }
   1679 
   1680 template <typename SampleType>
   1681 static UploadSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const std::vector<UploadSampleResult<SampleType> >& samples, bool logBucketPerformance)
   1682 {
   1683 	// Assume data is linear with some outliers, fit a line
   1684 	const LineParametersWithConfidence						theilSenFitting						= fitLineToSamples(samples);
   1685 	const typename SampleTypeTraits<SampleType>::StatsType	resultStats							= calculateSampleStatistics(theilSenFitting, samples);
   1686 	float													approximatedTransferRate;
   1687 	float													approximatedTransferRateNoConstant;
   1688 
   1689 	// Output raw samples
   1690 	{
   1691 		const tcu::ScopedLogSection	section(log, "Samples", "Samples");
   1692 		logSampleList(log, theilSenFitting, samples);
   1693 	}
   1694 
   1695 	// Calculate results for different ranges
   1696 	if (logBucketPerformance)
   1697 	{
   1698 		const int										numBuckets				= 4;
   1699 		int												minBufferSize			= 0;
   1700 		int												maxBufferSize			= 0;
   1701 		std::vector<UploadSampleResult<SampleType> >	buckets[numBuckets];
   1702 
   1703 		bucketizeSamplesUniformly(samples, &buckets[0], numBuckets, minBufferSize, maxBufferSize);
   1704 
   1705 		for (int bucketNdx = 0; bucketNdx < numBuckets; ++bucketNdx)
   1706 		{
   1707 			if (buckets[bucketNdx].empty())
   1708 				continue;
   1709 
   1710 			// Print a nice result summary
   1711 
   1712 			const int												bucketRangeMin	= minBufferSize + (int)(((float) bucketNdx    / (float)numBuckets) * (float)(maxBufferSize - minBufferSize));
   1713 			const int												bucketRangeMax	= minBufferSize + (int)(((float)(bucketNdx+1) / (float)numBuckets) * (float)(maxBufferSize - minBufferSize));
   1714 			const typename SampleTypeTraits<SampleType>::StatsType	stats			= calculateSampleStatistics(theilSenFitting, buckets[bucketNdx]);
   1715 			const tcu::ScopedLogSection								section			(log, "BufferSizeRange", std::string("Transfer performance with buffer size in range [").append(getHumanReadableByteSize(bucketRangeMin).append(", ").append(getHumanReadableByteSize(bucketRangeMax).append("]"))));
   1716 
   1717 			logMapRangeStats<SampleType>(log, stats);
   1718 			logUnmapStats<SampleType>(log, stats);
   1719 			logWriteStats<SampleType>(log, stats);
   1720 			logFlushStats<SampleType>(log, stats);
   1721 			logAllocStats<SampleType>(log, stats);
   1722 
   1723 			log	<< tcu::TestLog::Float("Min", "Total: Min time", "us", QP_KEY_TAG_TIME, stats.result.minTime)
   1724 				<< tcu::TestLog::Float("Max", "Total: Max time", "us", QP_KEY_TAG_TIME, stats.result.maxTime)
   1725 				<< tcu::TestLog::Float("Min90", "Total: 90%-Min time", "us", QP_KEY_TAG_TIME, stats.result.min2DecileTime)
   1726 				<< tcu::TestLog::Float("Max90", "Total: 90%-Max time", "us", QP_KEY_TAG_TIME, stats.result.max9DecileTime)
   1727 				<< tcu::TestLog::Float("Median", "Total: Median time", "us", QP_KEY_TAG_TIME, stats.result.medianTime)
   1728 				<< tcu::TestLog::Float("MedianTransfer", "Median transfer rate", "MB / s", QP_KEY_TAG_PERFORMANCE, stats.medianRate / 1024.0f / 1024.0f)
   1729 				<< tcu::TestLog::Float("MaxDiff", "Max difference to approximated", "us", QP_KEY_TAG_TIME, stats.maxDiffTime)
   1730 				<< tcu::TestLog::Float("Max90Diff", "90%-Max difference to approximated", "us", QP_KEY_TAG_TIME, stats.maxDiff9DecileTime)
   1731 				<< tcu::TestLog::Float("MedianDiff", "Median difference to approximated", "us", QP_KEY_TAG_TIME, stats.medianDiffTime)
   1732 				<< tcu::TestLog::Float("MaxRelDiff", "Max relative difference to approximated", "%", QP_KEY_TAG_NONE, stats.maxRelDiffTime * 100.0f)
   1733 				<< tcu::TestLog::Float("Max90RelDiff", "90%-Max relative difference to approximated", "%", QP_KEY_TAG_NONE, stats.max9DecileRelDiffTime * 100.0f)
   1734 				<< tcu::TestLog::Float("MedianRelDiff", "Median relative difference to approximated", "%", QP_KEY_TAG_NONE, stats.medianRelDiffTime * 100.0f);
   1735 		}
   1736 	}
   1737 
   1738 	// Contributions
   1739 	if (SampleTypeTraits<SampleType>::LOG_CONTRIBUTIONS)
   1740 	{
   1741 		const tcu::ScopedLogSection	section(log, "Contribution", "Contributions");
   1742 
   1743 		logMapContribution(log, samples, resultStats);
   1744 		logUnmapContribution(log, samples, resultStats);
   1745 		logWriteContribution(log, samples, resultStats);
   1746 		logFlushContribution(log, samples, resultStats);
   1747 		logAllocContribution(log, samples, resultStats);
   1748 	}
   1749 
   1750 	// Print results
   1751 	{
   1752 		const tcu::ScopedLogSection	section(log, "Results", "Results");
   1753 
   1754 		const int	medianBufferSize					= (samples.front().bufferSize + samples.back().bufferSize) / 2;
   1755 		const float	approximatedTransferTime			= (theilSenFitting.offset + theilSenFitting.coefficient * (float)medianBufferSize) / 1000.0f / 1000.0f;
   1756 		const float	approximatedTransferTimeNoConstant	= (theilSenFitting.coefficient * (float)medianBufferSize) / 1000.0f / 1000.0f;
   1757 		const float	sampleLinearity						= calculateSampleFitLinearity(samples);
   1758 		const float	sampleTemporalStability				= calculateSampleTemporalStability(samples);
   1759 
   1760 		approximatedTransferRateNoConstant				= (float)medianBufferSize / approximatedTransferTimeNoConstant;
   1761 		approximatedTransferRate						= (float)medianBufferSize / approximatedTransferTime;
   1762 
   1763 		log	<< tcu::TestLog::Float("ResultLinearity", "Sample linearity", "%", QP_KEY_TAG_QUALITY, sampleLinearity * 100.0f)
   1764 			<< tcu::TestLog::Float("SampleTemporalStability", "Sample temporal stability", "%", QP_KEY_TAG_QUALITY, sampleTemporalStability * 100.0f)
   1765 			<< tcu::TestLog::Float("ApproximatedConstantCost", "Approximated contant cost", "us", QP_KEY_TAG_TIME, theilSenFitting.offset)
   1766 			<< tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceLower)
   1767 			<< tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceUpper)
   1768 			<< tcu::TestLog::Float("ApproximatedLinearCost", "Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient * 1024.0f * 1024.0f)
   1769 			<< tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceLower * 1024.0f * 1024.0f)
   1770 			<< tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceUpper * 1024.0f * 1024.0f)
   1771 			<< tcu::TestLog::Float("ApproximatedTransferRate", "Approximated transfer rate", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedTransferRate / 1024.0f / 1024.0f)
   1772 			<< tcu::TestLog::Float("ApproximatedTransferRateNoConstant", "Approximated transfer rate without constant cost", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedTransferRateNoConstant / 1024.0f / 1024.0f)
   1773 			<< tcu::TestLog::Float("SampleMedianTime", "Median sample time", "us", QP_KEY_TAG_TIME, resultStats.result.medianTime)
   1774 			<< tcu::TestLog::Float("SampleMedianTransfer", "Median transfer rate", "MB / s", QP_KEY_TAG_PERFORMANCE, resultStats.medianRate / 1024.0f / 1024.0f);
   1775 	}
   1776 
   1777 	// return approximated transfer rate
   1778 	{
   1779 		UploadSampleAnalyzeResult result;
   1780 
   1781 		result.transferRateMedian = resultStats.medianRate;
   1782 		result.transferRateAtRange = approximatedTransferRate;
   1783 		result.transferRateAtInfinity = approximatedTransferRateNoConstant;
   1784 
   1785 		return result;
   1786 	}
   1787 }
   1788 
   1789 template <typename SampleType>
   1790 static RenderSampleAnalyzeResult analyzeSampleResults (tcu::TestLog& log, const std::vector<RenderSampleResult<SampleType> >& samples)
   1791 {
   1792 	// Assume data is linear with some outliers, fit a line
   1793 	const LineParametersWithConfidence						theilSenFitting						= fitLineToSamples(samples);
   1794 	const typename SampleTypeTraits<SampleType>::StatsType	resultStats							= calculateSampleStatistics(theilSenFitting, samples);
   1795 	float													approximatedProcessingRate;
   1796 	float													approximatedProcessingRateNoConstant;
   1797 
   1798 	// output raw samples
   1799 	{
   1800 		const tcu::ScopedLogSection	section(log, "Samples", "Samples");
   1801 		logSampleList(log, theilSenFitting, samples);
   1802 	}
   1803 
   1804 	// Contributions
   1805 	if (SampleTypeTraits<SampleType>::LOG_CONTRIBUTIONS)
   1806 	{
   1807 		const tcu::ScopedLogSection	section(log, "Contribution", "Contributions");
   1808 
   1809 		logFirstRenderContribution(log, samples, resultStats);
   1810 		logUploadContribution(log, samples, resultStats);
   1811 		logRenderContribution(log, samples, resultStats);
   1812 		logSecondRenderContribution(log, samples, resultStats);
   1813 		logReadContribution(log, samples, resultStats);
   1814 		logTotalContribution(log, samples, resultStats);
   1815 	}
   1816 
   1817 	// print results
   1818 	{
   1819 		const tcu::ScopedLogSection	section(log, "Results", "Results");
   1820 
   1821 		const int	medianDataSize						= (samples.front().renderDataSize + samples.back().renderDataSize) / 2;
   1822 		const float	approximatedRenderTime				= (theilSenFitting.offset + theilSenFitting.coefficient * (float)medianDataSize) / 1000.0f / 1000.0f;
   1823 		const float	approximatedRenderTimeNoConstant	= (theilSenFitting.coefficient * (float)medianDataSize) / 1000.0f / 1000.0f;
   1824 		const float	sampleLinearity						= calculateSampleFitLinearity(samples);
   1825 		const float	sampleTemporalStability				= calculateSampleTemporalStability(samples);
   1826 
   1827 		approximatedProcessingRateNoConstant			= (float)medianDataSize / approximatedRenderTimeNoConstant;
   1828 		approximatedProcessingRate						= (float)medianDataSize / approximatedRenderTime;
   1829 
   1830 		log	<< tcu::TestLog::Float("ResultLinearity", "Sample linearity", "%", QP_KEY_TAG_QUALITY, sampleLinearity * 100.0f)
   1831 			<< tcu::TestLog::Float("SampleTemporalStability", "Sample temporal stability", "%", QP_KEY_TAG_QUALITY, sampleTemporalStability * 100.0f)
   1832 			<< tcu::TestLog::Float("ApproximatedConstantCost", "Approximated contant cost", "us", QP_KEY_TAG_TIME, theilSenFitting.offset)
   1833 			<< tcu::TestLog::Float("ApproximatedConstantCostConfidence60Lower", "Approximated contant cost 60% confidence lower limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceLower)
   1834 			<< tcu::TestLog::Float("ApproximatedConstantCostConfidence60Upper", "Approximated contant cost 60% confidence upper limit", "us", QP_KEY_TAG_TIME, theilSenFitting.offsetConfidenceUpper)
   1835 			<< tcu::TestLog::Float("ApproximatedLinearCost", "Approximated linear cost", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficient * 1024.0f * 1024.0f)
   1836 			<< tcu::TestLog::Float("ApproximatedLinearCostConfidence60Lower", "Approximated linear cost 60% confidence lower limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceLower * 1024.0f * 1024.0f)
   1837 			<< tcu::TestLog::Float("ApproximatedLinearCostConfidence60Upper", "Approximated linear cost 60% confidence upper limit", "us / MB", QP_KEY_TAG_TIME, theilSenFitting.coefficientConfidenceUpper * 1024.0f * 1024.0f)
   1838 			<< tcu::TestLog::Float("ApproximatedProcessRate", "Approximated processing rate", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedProcessingRate / 1024.0f / 1024.0f)
   1839 			<< tcu::TestLog::Float("ApproximatedProcessRateNoConstant", "Approximated processing rate without constant cost", "MB / s", QP_KEY_TAG_PERFORMANCE, approximatedProcessingRateNoConstant / 1024.0f / 1024.0f)
   1840 			<< tcu::TestLog::Float("SampleMedianTime", "Median sample time", "us", QP_KEY_TAG_TIME, resultStats.result.medianTime)
   1841 			<< tcu::TestLog::Float("SampleMedianProcess", "Median processing rate", "MB / s", QP_KEY_TAG_PERFORMANCE, resultStats.medianRate / 1024.0f / 1024.0f);
   1842 	}
   1843 
   1844 	// return approximated render rate
   1845 	{
   1846 		RenderSampleAnalyzeResult result;
   1847 
   1848 		result.renderRateMedian		= resultStats.medianRate;
   1849 		result.renderRateAtRange	= approximatedProcessingRate;
   1850 		result.renderRateAtInfinity = approximatedProcessingRateNoConstant;
   1851 
   1852 		return result;
   1853 	}
   1854 	return RenderSampleAnalyzeResult();
   1855 }
   1856 
   1857 static void generateTwoPassRandomIterationOrder (std::vector<int>& iterationOrder, int numSamples)
   1858 {
   1859 	de::Random	rnd			(0xabc);
   1860 	const int	midPoint	= (numSamples+1) / 2;		// !< ceil(m_numSamples / 2)
   1861 
   1862 	DE_ASSERT((int)iterationOrder.size() == numSamples);
   1863 
   1864 	// Two "passes" over range, randomize order in both passes
   1865 	// This allows to us detect if iterations are not independent
   1866 	// (first run and later run samples differ significantly?)
   1867 
   1868 	for (int sampleNdx = 0; sampleNdx < midPoint; ++sampleNdx)
   1869 		iterationOrder[sampleNdx] = sampleNdx * 2;
   1870 	for (int sampleNdx = midPoint; sampleNdx < numSamples; ++sampleNdx)
   1871 		iterationOrder[sampleNdx] = (sampleNdx - midPoint) * 2 + 1;
   1872 
   1873 	for (int ndx = 0; ndx < midPoint; ++ndx)
   1874 		std::swap(iterationOrder[ndx], iterationOrder[rnd.getInt(0, midPoint - 1)]);
   1875 	for (int ndx = midPoint; ndx < (int)iterationOrder.size(); ++ndx)
   1876 		std::swap(iterationOrder[ndx], iterationOrder[rnd.getInt(midPoint, (int)iterationOrder.size()-1)]);
   1877 }
   1878 
   1879 template <typename SampleType>
   1880 class BasicBufferCase : public TestCase
   1881 {
   1882 public:
   1883 
   1884 	enum Flags
   1885 	{
   1886 		FLAG_ALLOCATE_LARGER_BUFFER = 0x01,
   1887 	};
   1888 							BasicBufferCase		(Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, int numSamples, int flags);
   1889 							~BasicBufferCase	(void);
   1890 
   1891 	virtual void			init				(void);
   1892 	virtual void			deinit				(void);
   1893 
   1894 protected:
   1895 	IterateResult			iterate				(void);
   1896 
   1897 	virtual bool			runSample			(int iteration, UploadSampleResult<SampleType>& sample) = 0;
   1898 	virtual void			logAndSetTestResult	(const std::vector<UploadSampleResult<SampleType> >& results) = 0;
   1899 
   1900 	void					disableGLWarmup		(void);
   1901 	void					waitGLResults		(void);
   1902 
   1903 	enum
   1904 	{
   1905 		DUMMY_RENDER_AREA_SIZE = 32
   1906 	};
   1907 
   1908 	glu::ShaderProgram*		m_dummyProgram;
   1909 	deInt32					m_dummyProgramPosLoc;
   1910 	deUint32				m_bufferID;
   1911 
   1912 	const int				m_numSamples;
   1913 	const int				m_bufferSizeMin;
   1914 	const int				m_bufferSizeMax;
   1915 	const bool				m_allocateLargerBuffer;
   1916 
   1917 private:
   1918 	int						m_iteration;
   1919 	std::vector<int>		m_iterationOrder;
   1920 	std::vector<UploadSampleResult<SampleType> > m_results;
   1921 
   1922 	bool					m_useGL;
   1923 	int						m_bufferRandomizerTimer;
   1924 };
   1925 
   1926 template <typename SampleType>
   1927 BasicBufferCase<SampleType>::BasicBufferCase (Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, int numSamples, int flags)
   1928 	: TestCase					(context, tcu::NODETYPE_PERFORMANCE, name, desc)
   1929 	, m_dummyProgram			(DE_NULL)
   1930 	, m_dummyProgramPosLoc		(-1)
   1931 	, m_bufferID				(0)
   1932 	, m_numSamples				(numSamples)
   1933 	, m_bufferSizeMin			(bufferSizeMin)
   1934 	, m_bufferSizeMax			(bufferSizeMax)
   1935 	, m_allocateLargerBuffer	((flags & FLAG_ALLOCATE_LARGER_BUFFER) != 0)
   1936 	, m_iteration				(0)
   1937 	, m_iterationOrder			(numSamples)
   1938 	, m_results					(numSamples)
   1939 	, m_useGL					(true)
   1940 	, m_bufferRandomizerTimer	(0)
   1941 {
   1942 	// "randomize" iteration order. Deterministic, patternless
   1943 	generateTwoPassRandomIterationOrder(m_iterationOrder, m_numSamples);
   1944 
   1945 	// choose buffer sizes
   1946 	for (int sampleNdx = 0; sampleNdx < m_numSamples; ++sampleNdx)
   1947 	{
   1948 		const int rawBufferSize			= (int)deFloatFloor((float)bufferSizeMin + (float)(bufferSizeMax - bufferSizeMin) * ((float)(sampleNdx + 1) / (float)m_numSamples));
   1949 		const int bufferSize			= deAlign32(rawBufferSize, 16);
   1950 		const int allocatedBufferSize	= deAlign32((m_allocateLargerBuffer) ? ((int)((float)bufferSize * 1.5f)) : (bufferSize), 16);
   1951 
   1952 		m_results[sampleNdx].bufferSize		= bufferSize;
   1953 		m_results[sampleNdx].allocatedSize	= allocatedBufferSize;
   1954 		m_results[sampleNdx].writtenSize	= -1;
   1955 	}
   1956 }
   1957 
   1958 template <typename SampleType>
   1959 BasicBufferCase<SampleType>::~BasicBufferCase (void)
   1960 {
   1961 	deinit();
   1962 }
   1963 
   1964 template <typename SampleType>
   1965 void BasicBufferCase<SampleType>::init (void)
   1966 {
   1967 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   1968 
   1969 	if (!m_useGL)
   1970 		return;
   1971 
   1972 	// \note Viewport size is not checked, it won't matter if the render target actually is smaller hhan DUMMY_RENDER_AREA_SIZE
   1973 
   1974 	// dummy shader
   1975 
   1976 	m_dummyProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_dummyVertexShader) << glu::FragmentSource(s_dummyFragnentShader));
   1977 	if (!m_dummyProgram->isOk())
   1978 	{
   1979 		m_testCtx.getLog() << *m_dummyProgram;
   1980 		throw tcu::TestError("failed to build shader program");
   1981 	}
   1982 
   1983 	m_dummyProgramPosLoc = gl.getAttribLocation(m_dummyProgram->getProgram(), "a_position");
   1984 	if (m_dummyProgramPosLoc == -1)
   1985 		throw tcu::TestError("a_position location was -1");
   1986 }
   1987 
   1988 template <typename SampleType>
   1989 void BasicBufferCase<SampleType>::deinit (void)
   1990 {
   1991 	if (m_bufferID)
   1992 	{
   1993 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_bufferID);
   1994 		m_bufferID = 0;
   1995 	}
   1996 
   1997 	delete m_dummyProgram;
   1998 	m_dummyProgram = DE_NULL;
   1999 }
   2000 
   2001 template <typename SampleType>
   2002 TestCase::IterateResult BasicBufferCase<SampleType>::iterate (void)
   2003 {
   2004 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
   2005 	static bool				buffersWarmedUp	= false;
   2006 
   2007 	static const deUint32	usages[] =
   2008 	{
   2009 		GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY,
   2010 		GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY,
   2011 		GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, GL_DYNAMIC_COPY,
   2012 	};
   2013 
   2014 	// Allocate some random sized buffers and remove them to
   2015 	// make sure the first samples too have some buffers removed
   2016 	// just before their allocation. This is only needed by the
   2017 	// the first test.
   2018 
   2019 	if (m_useGL && !buffersWarmedUp)
   2020 	{
   2021 		const int					numRandomBuffers				= 6;
   2022 		const int					numRepeats						= 10;
   2023 		const int					maxBufferSize					= 16777216;
   2024 		const std::vector<deUint8>	zeroData						(maxBufferSize, 0x00);
   2025 		de::Random					rnd								(0x1234);
   2026 		deUint32					bufferIDs[numRandomBuffers]		= {0};
   2027 
   2028 		gl.useProgram(m_dummyProgram->getProgram());
   2029 		gl.viewport(0, 0, DUMMY_RENDER_AREA_SIZE, DUMMY_RENDER_AREA_SIZE);
   2030 		gl.enableVertexAttribArray(m_dummyProgramPosLoc);
   2031 
   2032 		for (int ndx = 0; ndx < numRepeats; ++ndx)
   2033 		{
   2034 			// Create buffer and maybe draw from it
   2035 			for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx)
   2036 			{
   2037 				const int		randomSize	= deAlign32(rnd.getInt(1, maxBufferSize), 4*4);
   2038 				const deUint32	usage		= usages[rnd.getUint32() % (deUint32)DE_LENGTH_OF_ARRAY(usages)];
   2039 
   2040 				gl.genBuffers(1, &bufferIDs[randomBufferNdx]);
   2041 				gl.bindBuffer(GL_ARRAY_BUFFER, bufferIDs[randomBufferNdx]);
   2042 				gl.bufferData(GL_ARRAY_BUFFER, randomSize, &zeroData[0], usage);
   2043 
   2044 				if (rnd.getBool())
   2045 				{
   2046 					gl.vertexAttribPointer(m_dummyProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
   2047 					gl.drawArrays(GL_POINTS, 0, 1);
   2048 					gl.drawArrays(GL_POINTS, randomSize / (int)sizeof(float[4]) - 1, 1);
   2049 				}
   2050 			}
   2051 
   2052 			for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx)
   2053 				gl.deleteBuffers(1, &bufferIDs[randomBufferNdx]);
   2054 
   2055 			waitGLResults();
   2056 			GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer gen");
   2057 
   2058 			m_testCtx.touchWatchdog();
   2059 		}
   2060 
   2061 		buffersWarmedUp = true;
   2062 		return CONTINUE;
   2063 	}
   2064 	else if (m_useGL && m_bufferRandomizerTimer++ % 8 == 0)
   2065 	{
   2066 		// Do some random buffer operations to every now and then
   2067 		// to make sure the previous test iterations won't affect
   2068 		// following test runs.
   2069 
   2070 		const int					numRandomBuffers				= 3;
   2071 		const int					maxBufferSize					= 16777216;
   2072 		const std::vector<deUint8>	zeroData						(maxBufferSize, 0x00);
   2073 		de::Random					rnd								(0x1234 + 0xabc * m_bufferRandomizerTimer);
   2074 
   2075 		// BufferData
   2076 		{
   2077 			deUint32 bufferIDs[numRandomBuffers] = {0};
   2078 
   2079 			for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx)
   2080 			{
   2081 				const int		randomSize	= deAlign32(rnd.getInt(1, maxBufferSize), 4*4);
   2082 				const deUint32	usage		= usages[rnd.getUint32() % (deUint32)DE_LENGTH_OF_ARRAY(usages)];
   2083 
   2084 				gl.genBuffers(1, &bufferIDs[randomBufferNdx]);
   2085 				gl.bindBuffer(GL_ARRAY_BUFFER, bufferIDs[randomBufferNdx]);
   2086 				gl.bufferData(GL_ARRAY_BUFFER, randomSize, &zeroData[0], usage);
   2087 			}
   2088 
   2089 			for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx)
   2090 				gl.deleteBuffers(1, &bufferIDs[randomBufferNdx]);
   2091 		}
   2092 
   2093 		GLU_EXPECT_NO_ERROR(gl.getError(), "buffer ops");
   2094 
   2095 		// Do some memory mappings
   2096 		{
   2097 			deUint32 bufferIDs[numRandomBuffers] = {0};
   2098 
   2099 			for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx)
   2100 			{
   2101 				const int		randomSize	= deAlign32(rnd.getInt(1, maxBufferSize), 4*4);
   2102 				const deUint32	usage		= usages[rnd.getUint32() % (deUint32)DE_LENGTH_OF_ARRAY(usages)];
   2103 				void*			ptr;
   2104 
   2105 				gl.genBuffers(1, &bufferIDs[randomBufferNdx]);
   2106 				gl.bindBuffer(GL_ARRAY_BUFFER, bufferIDs[randomBufferNdx]);
   2107 				gl.bufferData(GL_ARRAY_BUFFER, randomSize, &zeroData[0], usage);
   2108 
   2109 				gl.vertexAttribPointer(m_dummyProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
   2110 				gl.drawArrays(GL_POINTS, 0, 1);
   2111 				gl.drawArrays(GL_POINTS, randomSize / (int)sizeof(float[4]) - 1, 1);
   2112 
   2113 				if (rnd.getBool())
   2114 					waitGLResults();
   2115 
   2116 				ptr = gl.mapBufferRange(GL_ARRAY_BUFFER, 0, randomSize, GL_MAP_WRITE_BIT);
   2117 				if (ptr)
   2118 				{
   2119 					medianTimeMemcpy(ptr, &zeroData[0], randomSize);
   2120 					gl.unmapBuffer(GL_ARRAY_BUFFER);
   2121 				}
   2122 			}
   2123 
   2124 			for (int randomBufferNdx = 0; randomBufferNdx < numRandomBuffers; ++randomBufferNdx)
   2125 				gl.deleteBuffers(1, &bufferIDs[randomBufferNdx]);
   2126 
   2127 			waitGLResults();
   2128 		}
   2129 
   2130 		GLU_EXPECT_NO_ERROR(gl.getError(), "buffer maps");
   2131 		return CONTINUE;
   2132 	}
   2133 	else
   2134 	{
   2135 		const int	currentIteration	= m_iteration;
   2136 		const int	sampleNdx			= m_iterationOrder[currentIteration];
   2137 		const bool	sampleRunSuccessful	= runSample(currentIteration, m_results[sampleNdx]);
   2138 
   2139 		GLU_EXPECT_NO_ERROR(gl.getError(), "post runSample()");
   2140 
   2141 		// Retry failed samples
   2142 		if (!sampleRunSuccessful)
   2143 			return CONTINUE;
   2144 
   2145 		if (++m_iteration >= m_numSamples)
   2146 		{
   2147 			logAndSetTestResult(m_results);
   2148 			return STOP;
   2149 		}
   2150 		else
   2151 			return CONTINUE;
   2152 	}
   2153 }
   2154 
   2155 template <typename SampleType>
   2156 void BasicBufferCase<SampleType>::disableGLWarmup (void)
   2157 {
   2158 	m_useGL = false;
   2159 }
   2160 
   2161 template <typename SampleType>
   2162 void BasicBufferCase<SampleType>::waitGLResults (void)
   2163 {
   2164 	tcu::Surface dummySurface(DUMMY_RENDER_AREA_SIZE, DUMMY_RENDER_AREA_SIZE);
   2165 	glu::readPixels(m_context.getRenderContext(), 0, 0, dummySurface.getAccess());
   2166 }
   2167 
   2168 template <typename SampleType>
   2169 class BasicUploadCase : public BasicBufferCase<SampleType>
   2170 {
   2171 public:
   2172 	enum CaseType
   2173 	{
   2174 		CASE_NO_BUFFERS = 0,
   2175 		CASE_NEW_BUFFER,
   2176 		CASE_UNSPECIFIED_BUFFER,
   2177 		CASE_SPECIFIED_BUFFER,
   2178 		CASE_USED_BUFFER,
   2179 		CASE_USED_LARGER_BUFFER,
   2180 
   2181 		CASE_LAST
   2182 	};
   2183 
   2184 	enum CaseFlags
   2185 	{
   2186 		FLAG_DONT_LOG_BUFFER_INFO				= 0x01,
   2187 		FLAG_RESULT_BUFFER_UNSPECIFIED_CONTENT	= 0x02,
   2188 	};
   2189 
   2190 	enum ResultType
   2191 	{
   2192 		RESULT_MEDIAN_TRANSFER_RATE = 0,
   2193 		RESULT_ASYMPTOTIC_TRANSFER_RATE,
   2194 	};
   2195 
   2196 						BasicUploadCase		(Context& context,
   2197 											 const char* name,
   2198 											 const char* desc,
   2199 											 int bufferSizeMin,
   2200 											 int bufferSizeMax,
   2201 											 int numSamples,
   2202 											 deUint32 bufferUsage,
   2203 											 CaseType caseType,
   2204 											 ResultType resultType,
   2205 											 int flags = 0);
   2206 
   2207 						~BasicUploadCase	(void);
   2208 
   2209 	virtual void		init				(void);
   2210 	virtual void		deinit				(void);
   2211 
   2212 private:
   2213 	bool				runSample			(int iteration, UploadSampleResult<SampleType>& sample);
   2214 	void				createBuffer		(int bufferSize, int iteration);
   2215 	void				deleteBuffer		(int bufferSize);
   2216 	void				useBuffer			(int bufferSize);
   2217 
   2218 	virtual void		testBufferUpload	(UploadSampleResult<SampleType>& result, int writeSize) = 0;
   2219 	void				logAndSetTestResult	(const std::vector<UploadSampleResult<SampleType> >& results);
   2220 
   2221 	deUint32			m_dummyBufferID;
   2222 
   2223 protected:
   2224 	const CaseType		m_caseType;
   2225 	const ResultType	m_resultType;
   2226 	const deUint32		m_bufferUsage;
   2227 	const bool			m_logBufferInfo;
   2228 	const bool			m_bufferUnspecifiedContent;
   2229 	std::vector<deUint8> m_zeroData;
   2230 
   2231 	using BasicBufferCase<SampleType>::m_testCtx;
   2232 	using BasicBufferCase<SampleType>::m_context;
   2233 
   2234 	using BasicBufferCase<SampleType>::DUMMY_RENDER_AREA_SIZE;
   2235 	using BasicBufferCase<SampleType>::m_dummyProgram;
   2236 	using BasicBufferCase<SampleType>::m_dummyProgramPosLoc;
   2237 	using BasicBufferCase<SampleType>::m_bufferID;
   2238 	using BasicBufferCase<SampleType>::m_numSamples;
   2239 	using BasicBufferCase<SampleType>::m_bufferSizeMin;
   2240 	using BasicBufferCase<SampleType>::m_bufferSizeMax;
   2241 	using BasicBufferCase<SampleType>::m_allocateLargerBuffer;
   2242 };
   2243 
   2244 template <typename SampleType>
   2245 BasicUploadCase<SampleType>::BasicUploadCase (Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, int numSamples, deUint32 bufferUsage, CaseType caseType, ResultType resultType, int flags)
   2246 	: BasicBufferCase<SampleType>	(context, name, desc, bufferSizeMin, bufferSizeMax, numSamples, (caseType == CASE_USED_LARGER_BUFFER) ? (BasicBufferCase<SampleType>::FLAG_ALLOCATE_LARGER_BUFFER) : (0))
   2247 	, m_dummyBufferID				(0)
   2248 	, m_caseType					(caseType)
   2249 	, m_resultType					(resultType)
   2250 	, m_bufferUsage					(bufferUsage)
   2251 	, m_logBufferInfo				((flags & FLAG_DONT_LOG_BUFFER_INFO) == 0)
   2252 	, m_bufferUnspecifiedContent	((flags & FLAG_RESULT_BUFFER_UNSPECIFIED_CONTENT) != 0)
   2253 	, m_zeroData					()
   2254 {
   2255 	DE_ASSERT(m_caseType < CASE_LAST);
   2256 }
   2257 
   2258 template <typename SampleType>
   2259 BasicUploadCase<SampleType>::~BasicUploadCase (void)
   2260 {
   2261 	deinit();
   2262 }
   2263 
   2264 template <typename SampleType>
   2265 void BasicUploadCase<SampleType>::init (void)
   2266 {
   2267 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2268 
   2269 	BasicBufferCase<SampleType>::init();
   2270 
   2271 	// zero buffer as upload source
   2272 	m_zeroData.resize(m_bufferSizeMax, 0x00);
   2273 
   2274 	// dummy buffer
   2275 
   2276 	gl.genBuffers(1, &m_dummyBufferID);
   2277 	GLU_EXPECT_NO_ERROR(gl.getError(), "Gen buf");
   2278 
   2279 	// log basic info
   2280 
   2281 	m_testCtx.getLog()
   2282 		<< tcu::TestLog::Message
   2283 		<< "Testing performance with " << m_numSamples << " test samples. Sample order is randomized. All samples at even positions (first = 0) are tested before samples at odd positions.\n"
   2284 		<< "Buffer sizes are in range [" << getHumanReadableByteSize(m_bufferSizeMin) << ", " << getHumanReadableByteSize(m_bufferSizeMax) << "]."
   2285 		<< tcu::TestLog::EndMessage;
   2286 
   2287 	if (m_logBufferInfo)
   2288 	{
   2289 		switch (m_caseType)
   2290 		{
   2291 			case CASE_NO_BUFFERS:
   2292 				break;
   2293 
   2294 			case CASE_NEW_BUFFER:
   2295 				m_testCtx.getLog() << tcu::TestLog::Message << "Target buffer is generated but not specified (i.e glBufferData() not called)." << tcu::TestLog::EndMessage;
   2296 				break;
   2297 
   2298 			case CASE_UNSPECIFIED_BUFFER:
   2299 				m_testCtx.getLog() << tcu::TestLog::Message << "Target buffer is allocated with glBufferData(NULL)." << tcu::TestLog::EndMessage;
   2300 				break;
   2301 
   2302 			case CASE_SPECIFIED_BUFFER:
   2303 				m_testCtx.getLog() << tcu::TestLog::Message << "Target buffer contents are specified prior testing with glBufferData(data)." << tcu::TestLog::EndMessage;
   2304 				break;
   2305 
   2306 			case CASE_USED_BUFFER:
   2307 				m_testCtx.getLog() << tcu::TestLog::Message << "Target buffer has been used in drawing before testing." << tcu::TestLog::EndMessage;
   2308 				break;
   2309 
   2310 			case CASE_USED_LARGER_BUFFER:
   2311 				m_testCtx.getLog() << tcu::TestLog::Message << "Target buffer is larger and has been used in drawing before testing." << tcu::TestLog::EndMessage;
   2312 				break;
   2313 
   2314 			default:
   2315 				DE_ASSERT(false);
   2316 				break;
   2317 		}
   2318 	}
   2319 
   2320 	if (m_resultType == RESULT_MEDIAN_TRANSFER_RATE)
   2321 		m_testCtx.getLog() << tcu::TestLog::Message << "Test result is the median transfer rate of the test samples." << tcu::TestLog::EndMessage;
   2322 	else if (m_resultType == RESULT_ASYMPTOTIC_TRANSFER_RATE)
   2323 		m_testCtx.getLog() << tcu::TestLog::Message << "Test result is the asymptotic transfer rate as the buffer size approaches infinity." << tcu::TestLog::EndMessage;
   2324 	else
   2325 		DE_ASSERT(false);
   2326 }
   2327 
   2328 template <typename SampleType>
   2329 void BasicUploadCase<SampleType>::deinit (void)
   2330 {
   2331 	if (m_dummyBufferID)
   2332 	{
   2333 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_dummyBufferID);
   2334 		m_dummyBufferID = 0;
   2335 	}
   2336 
   2337 	m_zeroData = std::vector<deUint8>();
   2338 
   2339 	BasicBufferCase<SampleType>::deinit();
   2340 }
   2341 
   2342 template <typename SampleType>
   2343 bool BasicUploadCase<SampleType>::runSample (int iteration, UploadSampleResult<SampleType>& sample)
   2344 {
   2345 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
   2346 	const int				allocatedBufferSize	= sample.allocatedSize;
   2347 	const int				bufferSize			= sample.bufferSize;
   2348 
   2349 	if (m_caseType != CASE_NO_BUFFERS)
   2350 		createBuffer(iteration, allocatedBufferSize);
   2351 
   2352 	// warmup CPU before the test to make sure the power management governor
   2353 	// keeps us in the "high performance" mode
   2354 	{
   2355 		deYield();
   2356 		tcu::warmupCPU();
   2357 		deYield();
   2358 	}
   2359 
   2360 	testBufferUpload(sample, bufferSize);
   2361 	GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer upload sample");
   2362 
   2363 	if (m_caseType != CASE_NO_BUFFERS)
   2364 		deleteBuffer(bufferSize);
   2365 
   2366 	return true;
   2367 }
   2368 
   2369 template <typename SampleType>
   2370 void BasicUploadCase<SampleType>::createBuffer (int iteration, int bufferSize)
   2371 {
   2372 	DE_ASSERT(!m_bufferID);
   2373 	DE_ASSERT(m_caseType != CASE_NO_BUFFERS);
   2374 
   2375 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2376 
   2377 	// create buffer
   2378 
   2379 	if (m_caseType == CASE_NO_BUFFERS)
   2380 		return;
   2381 
   2382 	// create empty buffer
   2383 
   2384 	gl.genBuffers(1, &m_bufferID);
   2385 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bufferID);
   2386 	GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer gen");
   2387 
   2388 	if (m_caseType == CASE_NEW_BUFFER)
   2389 	{
   2390 		// upload something else first, this should reduce noise in samples
   2391 
   2392 		de::Random					rng				(0xbadc * iteration);
   2393 		const int					sizeDelta		= rng.getInt(0, 2097140);
   2394 		const int					dummyUploadSize = deAlign32(1048576 + sizeDelta, 4*4); // Vary buffer size to make sure it is always reallocated
   2395 		const std::vector<deUint8>	dummyData		(dummyUploadSize, 0x20);
   2396 
   2397 		gl.bindBuffer(GL_ARRAY_BUFFER, m_dummyBufferID);
   2398 		gl.bufferData(GL_ARRAY_BUFFER, dummyUploadSize, &dummyData[0], m_bufferUsage);
   2399 
   2400 		// make sure upload won't interfere with the test
   2401 		useBuffer(dummyUploadSize);
   2402 
   2403 		// don't kill the buffer so that the following upload cannot potentially reuse the buffer
   2404 
   2405 		return;
   2406 	}
   2407 
   2408 	// specify it
   2409 
   2410 	if (m_caseType == CASE_UNSPECIFIED_BUFFER)
   2411 		gl.bufferData(GL_ARRAY_BUFFER, bufferSize, DE_NULL, m_bufferUsage);
   2412 	else
   2413 	{
   2414 		const std::vector<deUint8> dummyData(bufferSize, 0x20);
   2415 		gl.bufferData(GL_ARRAY_BUFFER, bufferSize, &dummyData[0], m_bufferUsage);
   2416 	}
   2417 
   2418 	if (m_caseType == CASE_UNSPECIFIED_BUFFER || m_caseType == CASE_SPECIFIED_BUFFER)
   2419 		return;
   2420 
   2421 	// use it and make sure it is uploaded
   2422 
   2423 	useBuffer(bufferSize);
   2424 	DE_ASSERT(m_caseType == CASE_USED_BUFFER || m_caseType == CASE_USED_LARGER_BUFFER);
   2425 }
   2426 
   2427 template <typename SampleType>
   2428 void BasicUploadCase<SampleType>::deleteBuffer (int bufferSize)
   2429 {
   2430 	DE_ASSERT(m_bufferID);
   2431 	DE_ASSERT(m_caseType != CASE_NO_BUFFERS);
   2432 
   2433 	// render from the buffer to make sure it actually made it to the gpu. This is to
   2434 	// make sure that if the upload actually happens later or is happening right now in
   2435 	// the background, it will not interfere with further test runs
   2436 
   2437 	// if buffer contains unspecified content, sourcing data from it results in undefined
   2438 	// results, possibly including program termination. Specify all data to prevent such
   2439 	// case from happening
   2440 
   2441 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2442 
   2443 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bufferID);
   2444 
   2445 	if (m_bufferUnspecifiedContent)
   2446 	{
   2447 		const std::vector<deUint8> dummyData(bufferSize, 0x20);
   2448 		gl.bufferData(GL_ARRAY_BUFFER, bufferSize, &dummyData[0], m_bufferUsage);
   2449 
   2450 		GLU_EXPECT_NO_ERROR(gl.getError(), "re-specify buffer");
   2451 	}
   2452 
   2453 	useBuffer(bufferSize);
   2454 
   2455 	gl.deleteBuffers(1, &m_bufferID);
   2456 	m_bufferID = 0;
   2457 }
   2458 
   2459 template <typename SampleType>
   2460 void BasicUploadCase<SampleType>::useBuffer (int bufferSize)
   2461 {
   2462 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2463 
   2464 	gl.useProgram(m_dummyProgram->getProgram());
   2465 
   2466 	gl.viewport(0, 0, DUMMY_RENDER_AREA_SIZE, DUMMY_RENDER_AREA_SIZE);
   2467 	gl.vertexAttribPointer(m_dummyProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
   2468 	gl.enableVertexAttribArray(m_dummyProgramPosLoc);
   2469 
   2470 	// use whole buffer to make sure buffer is uploaded by drawing first and last
   2471 	DE_ASSERT(bufferSize % (int)sizeof(float[4]) == 0);
   2472 	gl.drawArrays(GL_POINTS, 0, 1);
   2473 	gl.drawArrays(GL_POINTS, bufferSize / (int)sizeof(float[4]) - 1, 1);
   2474 
   2475 	BasicBufferCase<SampleType>::waitGLResults();
   2476 }
   2477 
   2478 template <typename SampleType>
   2479 void BasicUploadCase<SampleType>::logAndSetTestResult (const std::vector<UploadSampleResult<SampleType> >& results)
   2480 {
   2481 	const UploadSampleAnalyzeResult	analysis	= analyzeSampleResults(m_testCtx.getLog(), results, true);
   2482 
   2483 	// with small buffers, report the median transfer rate of the samples
   2484 	// with large buffers, report the expected preformance of infinitely large buffers
   2485 	const float						rate		= (m_resultType == RESULT_ASYMPTOTIC_TRANSFER_RATE) ? (analysis.transferRateAtInfinity) : (analysis.transferRateMedian);
   2486 
   2487 	if (rate == std::numeric_limits<float>::infinity())
   2488 	{
   2489 		// sample times are 1) invalid or 2) timer resolution too low
   2490 		// report speed 0 bytes / s since real value cannot be determined
   2491 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(0.0f, 2).c_str());
   2492 	}
   2493 	else
   2494 	{
   2495 		// report transfer rate in MB / s
   2496 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(rate / 1024.0f / 1024.0f, 2).c_str());
   2497 	}
   2498 }
   2499 
   2500 class ReferenceMemcpyCase : public BasicUploadCase<SingleOperationDuration>
   2501 {
   2502 public:
   2503 				ReferenceMemcpyCase		(Context& ctx, const char* name, const char* desc, int minBufferSize, int maxBufferSize, int numSamples, bool largeBuffersCase);
   2504 				~ReferenceMemcpyCase	(void);
   2505 
   2506 	void		init					(void);
   2507 	void		deinit					(void);
   2508 private:
   2509 	void		testBufferUpload		(UploadSampleResult<SingleOperationDuration>& result, int bufferSize);
   2510 
   2511 	std::vector<deUint8> m_dstBuf;
   2512 };
   2513 
   2514 ReferenceMemcpyCase::ReferenceMemcpyCase (Context& ctx, const char* name, const char* desc, int minBufferSize, int maxBufferSize, int numSamples, bool largeBuffersCase)
   2515 	: BasicUploadCase<SingleOperationDuration>	(ctx, name, desc, minBufferSize, maxBufferSize, numSamples, 0, CASE_NO_BUFFERS, (largeBuffersCase) ? (RESULT_ASYMPTOTIC_TRANSFER_RATE) : (RESULT_MEDIAN_TRANSFER_RATE))
   2516 	, m_dstBuf									()
   2517 {
   2518 	disableGLWarmup();
   2519 }
   2520 
   2521 ReferenceMemcpyCase::~ReferenceMemcpyCase (void)
   2522 {
   2523 }
   2524 
   2525 void ReferenceMemcpyCase::init (void)
   2526 {
   2527 	// Describe what the test tries to do
   2528 	m_testCtx.getLog() << tcu::TestLog::Message << "Testing performance of memcpy()." << tcu::TestLog::EndMessage;
   2529 
   2530 	m_dstBuf.resize(m_bufferSizeMax, 0x00);
   2531 
   2532 	BasicUploadCase<SingleOperationDuration>::init();
   2533 }
   2534 
   2535 void ReferenceMemcpyCase::deinit (void)
   2536 {
   2537 	m_dstBuf = std::vector<deUint8>();
   2538 	BasicUploadCase<SingleOperationDuration>::deinit();
   2539 }
   2540 
   2541 void ReferenceMemcpyCase::testBufferUpload (UploadSampleResult<SingleOperationDuration>& result, int bufferSize)
   2542 {
   2543 	// write
   2544 	result.duration.totalDuration = medianTimeMemcpy(&m_dstBuf[0], &m_zeroData[0], bufferSize);
   2545 	result.duration.fitResponseDuration = result.duration.totalDuration;
   2546 
   2547 	result.writtenSize = bufferSize;
   2548 }
   2549 
   2550 class BufferDataUploadCase : public BasicUploadCase<SingleOperationDuration>
   2551 {
   2552 public:
   2553 				BufferDataUploadCase	(Context& ctx, const char* name, const char* desc, int minBufferSize, int maxBufferSize, int numSamples, deUint32 bufferUsage, CaseType caseType);
   2554 				~BufferDataUploadCase	(void);
   2555 
   2556 	void		init					(void);
   2557 private:
   2558 	void		testBufferUpload		(UploadSampleResult<SingleOperationDuration>& result, int bufferSize);
   2559 };
   2560 
   2561 BufferDataUploadCase::BufferDataUploadCase (Context& ctx, const char* name, const char* desc, int minBufferSize, int maxBufferSize, int numSamples, deUint32 bufferUsage, CaseType caseType)
   2562 	: BasicUploadCase<SingleOperationDuration>(ctx, name, desc, minBufferSize, maxBufferSize, numSamples, bufferUsage, caseType, RESULT_MEDIAN_TRANSFER_RATE)
   2563 {
   2564 }
   2565 
   2566 BufferDataUploadCase::~BufferDataUploadCase (void)
   2567 {
   2568 }
   2569 
   2570 void BufferDataUploadCase::init (void)
   2571 {
   2572 	// Describe what the test tries to do
   2573 	m_testCtx.getLog() << tcu::TestLog::Message << "Testing glBufferData() function." << tcu::TestLog::EndMessage;
   2574 
   2575 	BasicUploadCase<SingleOperationDuration>::init();
   2576 }
   2577 
   2578 void BufferDataUploadCase::testBufferUpload (UploadSampleResult<SingleOperationDuration>& result, int bufferSize)
   2579 {
   2580 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2581 
   2582 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bufferID);
   2583 
   2584 	// upload
   2585 	{
   2586 		deUint64 startTime;
   2587 		deUint64 endTime;
   2588 
   2589 		startTime = deGetMicroseconds();
   2590 		gl.bufferData(GL_ARRAY_BUFFER, bufferSize, &m_zeroData[0], m_bufferUsage);
   2591 		endTime = deGetMicroseconds();
   2592 
   2593 		result.duration.totalDuration = endTime - startTime;
   2594 		result.duration.fitResponseDuration = result.duration.totalDuration;
   2595 		result.writtenSize = bufferSize;
   2596 	}
   2597 }
   2598 
   2599 class BufferSubDataUploadCase : public BasicUploadCase<SingleOperationDuration>
   2600 {
   2601 public:
   2602 	enum Flags
   2603 	{
   2604 		FLAG_FULL_UPLOAD			= 0x01,
   2605 		FLAG_PARTIAL_UPLOAD			= 0x02,
   2606 		FLAG_INVALIDATE_BEFORE_USE	= 0x04,
   2607 	};
   2608 
   2609 				BufferSubDataUploadCase		(Context& ctx, const char* name, const char* desc, int minBufferSize, int maxBufferSize, int numSamples, deUint32 bufferUsage, CaseType parentCase, int flags);
   2610 				~BufferSubDataUploadCase	(void);
   2611 
   2612 	void		init						(void);
   2613 private:
   2614 	void		testBufferUpload			(UploadSampleResult<SingleOperationDuration>& result, int bufferSize);
   2615 
   2616 	const bool	m_fullUpload;
   2617 	const bool	m_invalidateBeforeUse;
   2618 };
   2619 
   2620 BufferSubDataUploadCase::BufferSubDataUploadCase (Context& ctx, const char* name, const char* desc, int minBufferSize, int maxBufferSize, int numSamples, deUint32 bufferUsage, CaseType parentCase, int flags)
   2621 	: BasicUploadCase<SingleOperationDuration>	(ctx, name, desc, minBufferSize, maxBufferSize, numSamples, bufferUsage, parentCase, RESULT_MEDIAN_TRANSFER_RATE)
   2622 	, m_fullUpload								((flags & FLAG_FULL_UPLOAD) != 0)
   2623 	, m_invalidateBeforeUse						((flags & FLAG_INVALIDATE_BEFORE_USE) != 0)
   2624 {
   2625 	DE_ASSERT((flags & (FLAG_FULL_UPLOAD | FLAG_PARTIAL_UPLOAD)) != 0);
   2626 	DE_ASSERT((flags & (FLAG_FULL_UPLOAD | FLAG_PARTIAL_UPLOAD)) != (FLAG_FULL_UPLOAD | FLAG_PARTIAL_UPLOAD));
   2627 }
   2628 
   2629 BufferSubDataUploadCase::~BufferSubDataUploadCase (void)
   2630 {
   2631 }
   2632 
   2633 void BufferSubDataUploadCase::init (void)
   2634 {
   2635 	// Describe what the test tries to do
   2636 	m_testCtx.getLog()
   2637 		<< tcu::TestLog::Message
   2638 		<< "Testing glBufferSubData() function call performance. "
   2639 		<< ((m_fullUpload) ? ("The whole buffer is updated with glBufferSubData. ") : ("Half of the buffer data is updated with glBufferSubData. "))
   2640 		<< ((m_invalidateBeforeUse) ? ("The buffer is cleared with glBufferData(..., NULL) before glBufferSubData upload.") : ("")) << "\n"
   2641 		<< tcu::TestLog::EndMessage;
   2642 
   2643 	BasicUploadCase<SingleOperationDuration>::init();
   2644 }
   2645 
   2646 void BufferSubDataUploadCase::testBufferUpload (UploadSampleResult<SingleOperationDuration>& result, int bufferSize)
   2647 {
   2648 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2649 
   2650 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bufferID);
   2651 
   2652 	// "invalidate", upload null
   2653 	if (m_invalidateBeforeUse)
   2654 		gl.bufferData(GL_ARRAY_BUFFER, bufferSize, DE_NULL, m_bufferUsage);
   2655 
   2656 	// upload
   2657 	{
   2658 		deUint64 startTime;
   2659 		deUint64 endTime;
   2660 
   2661 		startTime = deGetMicroseconds();
   2662 
   2663 		if (m_fullUpload)
   2664 			gl.bufferSubData(GL_ARRAY_BUFFER, 0, bufferSize, &m_zeroData[0]);
   2665 		else
   2666 		{
   2667 			// upload to buffer center
   2668 			gl.bufferSubData(GL_ARRAY_BUFFER, bufferSize / 4, bufferSize / 2, &m_zeroData[0]);
   2669 		}
   2670 
   2671 		endTime = deGetMicroseconds();
   2672 
   2673 		result.duration.totalDuration = endTime - startTime;
   2674 		result.duration.fitResponseDuration = result.duration.totalDuration;
   2675 
   2676 		if (m_fullUpload)
   2677 			result.writtenSize = bufferSize;
   2678 		else
   2679 			result.writtenSize = bufferSize / 2;
   2680 	}
   2681 }
   2682 
   2683 class MapBufferRangeCase : public BasicUploadCase<MapBufferRangeDuration>
   2684 {
   2685 public:
   2686 	enum Flags
   2687 	{
   2688 		FLAG_PARTIAL						= 0x01,
   2689 		FLAG_MANUAL_INVALIDATION			= 0x02,
   2690 		FLAG_USE_UNUSED_UNSPECIFIED_BUFFER	= 0x04,
   2691 		FLAG_USE_UNUSED_SPECIFIED_BUFFER	= 0x08,
   2692 	};
   2693 
   2694 					MapBufferRangeCase			(Context& ctx, const char* name, const char* desc, int minBufferSize, int maxBufferSize, int numSamples, deUint32 bufferUsage, deUint32 mapFlags, int caseFlags);
   2695 					~MapBufferRangeCase			(void);
   2696 
   2697 	void			init						(void);
   2698 private:
   2699 	static CaseType getBaseCaseType				(int caseFlags);
   2700 	static int		getBaseFlags				(deUint32 mapFlags, int caseFlags);
   2701 
   2702 	void			testBufferUpload			(UploadSampleResult<MapBufferRangeDuration>& result, int bufferSize);
   2703 	void			attemptBufferMap			(UploadSampleResult<MapBufferRangeDuration>& result, int bufferSize);
   2704 
   2705 	const bool		m_manualInvalidation;
   2706 	const bool		m_fullUpload;
   2707 	const bool		m_useUnusedUnspecifiedBuffer;
   2708 	const bool		m_useUnusedSpecifiedBuffer;
   2709 	const deUint32	m_mapFlags;
   2710 	int				m_unmapFailures;
   2711 };
   2712 
   2713 MapBufferRangeCase::MapBufferRangeCase (Context& ctx, const char* name, const char* desc, int minBufferSize, int maxBufferSize, int numSamples, deUint32 bufferUsage, deUint32 mapFlags, int caseFlags)
   2714 	: BasicUploadCase<MapBufferRangeDuration>	(ctx, name, desc, minBufferSize, maxBufferSize, numSamples, bufferUsage, getBaseCaseType(caseFlags), RESULT_MEDIAN_TRANSFER_RATE, getBaseFlags(mapFlags, caseFlags))
   2715 	, m_manualInvalidation						((caseFlags&FLAG_MANUAL_INVALIDATION) != 0)
   2716 	, m_fullUpload								((caseFlags&FLAG_PARTIAL) == 0)
   2717 	, m_useUnusedUnspecifiedBuffer				((caseFlags&FLAG_USE_UNUSED_UNSPECIFIED_BUFFER) != 0)
   2718 	, m_useUnusedSpecifiedBuffer				((caseFlags&FLAG_USE_UNUSED_SPECIFIED_BUFFER) != 0)
   2719 	, m_mapFlags								(mapFlags)
   2720 	, m_unmapFailures							(0)
   2721 {
   2722 	DE_ASSERT(!(m_useUnusedUnspecifiedBuffer && m_useUnusedSpecifiedBuffer));
   2723 	DE_ASSERT(!((m_useUnusedUnspecifiedBuffer || m_useUnusedSpecifiedBuffer) && m_manualInvalidation));
   2724 }
   2725 
   2726 MapBufferRangeCase::~MapBufferRangeCase (void)
   2727 {
   2728 }
   2729 
   2730 void MapBufferRangeCase::init (void)
   2731 {
   2732 	// Describe what the test tries to do
   2733 	m_testCtx.getLog()
   2734 		<< tcu::TestLog::Message
   2735 		<< "Testing glMapBufferRange() and glUnmapBuffer() function call performance.\n"
   2736 		<< ((m_fullUpload) ? ("The whole buffer is mapped.") : ("Half of the buffer is mapped.")) << "\n"
   2737 		<< ((m_useUnusedUnspecifiedBuffer) ? ("The buffer has not been used before mapping and is allocated with unspecified contents.\n") : (""))
   2738 		<< ((m_useUnusedSpecifiedBuffer) ? ("The buffer has not been used before mapping and is allocated with specified contents.\n") : (""))
   2739 		<< ((!m_useUnusedSpecifiedBuffer && !m_useUnusedUnspecifiedBuffer) ? ("The buffer has previously been used in a drawing operation.\n") : (""))
   2740 		<< ((m_manualInvalidation) ? ("The buffer is cleared with glBufferData(..., NULL) before mapping.\n") : (""))
   2741 		<< "Map bits:\n"
   2742 		<< ((m_mapFlags & GL_MAP_WRITE_BIT) ? ("\tGL_MAP_WRITE_BIT\n") : (""))
   2743 		<< ((m_mapFlags & GL_MAP_READ_BIT) ? ("\tGL_MAP_READ_BIT\n") : (""))
   2744 		<< ((m_mapFlags & GL_MAP_INVALIDATE_RANGE_BIT) ? ("\tGL_MAP_INVALIDATE_RANGE_BIT\n") : (""))
   2745 		<< ((m_mapFlags & GL_MAP_INVALIDATE_BUFFER_BIT) ? ("\tGL_MAP_INVALIDATE_BUFFER_BIT\n") : (""))
   2746 		<< ((m_mapFlags & GL_MAP_UNSYNCHRONIZED_BIT) ? ("\tGL_MAP_UNSYNCHRONIZED_BIT\n") : (""))
   2747 		<< tcu::TestLog::EndMessage;
   2748 
   2749 	BasicUploadCase<MapBufferRangeDuration>::init();
   2750 }
   2751 
   2752 MapBufferRangeCase::CaseType MapBufferRangeCase::getBaseCaseType (int caseFlags)
   2753 {
   2754 	if ((caseFlags & FLAG_USE_UNUSED_UNSPECIFIED_BUFFER) == 0 && (caseFlags & FLAG_USE_UNUSED_SPECIFIED_BUFFER) == 0)
   2755 		return CASE_USED_BUFFER;
   2756 	else
   2757 		return CASE_NEW_BUFFER;
   2758 }
   2759 
   2760 int MapBufferRangeCase::getBaseFlags (deUint32 mapFlags, int caseFlags)
   2761 {
   2762 	int flags = FLAG_DONT_LOG_BUFFER_INFO;
   2763 
   2764 	// If buffer contains unspecified data when it is sourced (i.e drawn)
   2765 	// results are undefined, and system errors may occur. Signal parent
   2766 	// class to take this into account
   2767 	if (caseFlags & FLAG_PARTIAL)
   2768 	{
   2769 		if ((mapFlags & GL_MAP_INVALIDATE_BUFFER_BIT) != 0			||
   2770 			(caseFlags & FLAG_MANUAL_INVALIDATION) != 0				||
   2771 			(caseFlags & FLAG_USE_UNUSED_UNSPECIFIED_BUFFER) != 0)
   2772 		{
   2773 			flags |= FLAG_RESULT_BUFFER_UNSPECIFIED_CONTENT;
   2774 		}
   2775 	}
   2776 
   2777 	return flags;
   2778 }
   2779 
   2780 void MapBufferRangeCase::testBufferUpload (UploadSampleResult<MapBufferRangeDuration>& result, int bufferSize)
   2781 {
   2782 	const int unmapFailureThreshold = 4;
   2783 
   2784 	for (; m_unmapFailures < unmapFailureThreshold; ++m_unmapFailures)
   2785 	{
   2786 		try
   2787 		{
   2788 			attemptBufferMap(result, bufferSize);
   2789 			return;
   2790 		}
   2791 		catch (UnmapFailureError&)
   2792 		{
   2793 		}
   2794 	}
   2795 
   2796 	throw tcu::TestError("Unmapping failures exceeded limit");
   2797 }
   2798 
   2799 void MapBufferRangeCase::attemptBufferMap (UploadSampleResult<MapBufferRangeDuration>& result, int bufferSize)
   2800 {
   2801 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2802 
   2803 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bufferID);
   2804 
   2805 	if (m_fullUpload)
   2806 		result.writtenSize = bufferSize;
   2807 	else
   2808 		result.writtenSize = bufferSize / 2;
   2809 
   2810 	// Create unused buffer
   2811 
   2812 	if (m_manualInvalidation || m_useUnusedUnspecifiedBuffer)
   2813 	{
   2814 		deUint64 startTime;
   2815 		deUint64 endTime;
   2816 
   2817 		// "invalidate" or allocate, upload null
   2818 		startTime = deGetMicroseconds();
   2819 		gl.bufferData(GL_ARRAY_BUFFER, bufferSize, DE_NULL, m_bufferUsage);
   2820 		endTime = deGetMicroseconds();
   2821 
   2822 		result.duration.allocDuration = endTime - startTime;
   2823 	}
   2824 	else if (m_useUnusedSpecifiedBuffer)
   2825 	{
   2826 		deUint64 startTime;
   2827 		deUint64 endTime;
   2828 
   2829 		// Specify buffer contents
   2830 		startTime = deGetMicroseconds();
   2831 		gl.bufferData(GL_ARRAY_BUFFER, bufferSize, &m_zeroData[0], m_bufferUsage);
   2832 		endTime = deGetMicroseconds();
   2833 
   2834 		result.duration.allocDuration = endTime - startTime;
   2835 	}
   2836 	else
   2837 	{
   2838 		// No alloc, no time
   2839 		result.duration.allocDuration = 0;
   2840 	}
   2841 
   2842 	// upload
   2843 	{
   2844 		void* mapPtr;
   2845 
   2846 		// Map
   2847 		{
   2848 			deUint64 startTime;
   2849 			deUint64 endTime;
   2850 
   2851 			startTime = deGetMicroseconds();
   2852 			if (m_fullUpload)
   2853 				mapPtr = gl.mapBufferRange(GL_ARRAY_BUFFER, 0, result.writtenSize, m_mapFlags);
   2854 			else
   2855 			{
   2856 				// upload to buffer center
   2857 				mapPtr = gl.mapBufferRange(GL_ARRAY_BUFFER, bufferSize / 4, result.writtenSize, m_mapFlags);
   2858 			}
   2859 			endTime = deGetMicroseconds();
   2860 
   2861 			if (!mapPtr)
   2862 				throw tcu::Exception("MapBufferRange returned NULL");
   2863 
   2864 			result.duration.mapDuration = endTime - startTime;
   2865 		}
   2866 
   2867 		// Write
   2868 		{
   2869 			result.duration.writeDuration = medianTimeMemcpy(mapPtr, &m_zeroData[0], result.writtenSize);
   2870 		}
   2871 
   2872 		// Unmap
   2873 		{
   2874 			deUint64		startTime;
   2875 			deUint64		endTime;
   2876 			glw::GLboolean	unmapSuccessful;
   2877 
   2878 			startTime = deGetMicroseconds();
   2879 			unmapSuccessful = gl.unmapBuffer(GL_ARRAY_BUFFER);
   2880 			endTime = deGetMicroseconds();
   2881 
   2882 			// if unmapping fails, just try again later
   2883 			if (!unmapSuccessful)
   2884 				throw UnmapFailureError();
   2885 
   2886 			result.duration.unmapDuration = endTime - startTime;
   2887 		}
   2888 
   2889 		result.duration.totalDuration = result.duration.mapDuration + result.duration.writeDuration + result.duration.unmapDuration + result.duration.allocDuration;
   2890 		result.duration.fitResponseDuration = result.duration.totalDuration;
   2891 	}
   2892 }
   2893 
   2894 class MapBufferRangeFlushCase : public BasicUploadCase<MapBufferRangeFlushDuration>
   2895 {
   2896 public:
   2897 	enum Flags
   2898 	{
   2899 		FLAG_PARTIAL						= 0x01,
   2900 		FLAG_FLUSH_IN_PARTS					= 0x02,
   2901 		FLAG_USE_UNUSED_UNSPECIFIED_BUFFER	= 0x04,
   2902 		FLAG_USE_UNUSED_SPECIFIED_BUFFER	= 0x08,
   2903 		FLAG_FLUSH_PARTIAL					= 0x10,
   2904 	};
   2905 
   2906 					MapBufferRangeFlushCase		(Context& ctx, const char* name, const char* desc, int minBufferSize, int maxBufferSize, int numSamples, deUint32 bufferUsage, deUint32 mapFlags, int caseFlags);
   2907 					~MapBufferRangeFlushCase	(void);
   2908 
   2909 	void			init						(void);
   2910 private:
   2911 	static CaseType getBaseCaseType				(int caseFlags);
   2912 	static int		getBaseFlags				(deUint32 mapFlags, int caseFlags);
   2913 
   2914 	void			testBufferUpload			(UploadSampleResult<MapBufferRangeFlushDuration>& result, int bufferSize);
   2915 	void			attemptBufferMap			(UploadSampleResult<MapBufferRangeFlushDuration>& result, int bufferSize);
   2916 
   2917 	const bool		m_fullUpload;
   2918 	const bool		m_flushInParts;
   2919 	const bool		m_flushPartial;
   2920 	const bool		m_useUnusedUnspecifiedBuffer;
   2921 	const bool		m_useUnusedSpecifiedBuffer;
   2922 	const deUint32	m_mapFlags;
   2923 	int				m_unmapFailures;
   2924 };
   2925 
   2926 MapBufferRangeFlushCase::MapBufferRangeFlushCase (Context& ctx, const char* name, const char* desc, int minBufferSize, int maxBufferSize, int numSamples, deUint32 bufferUsage, deUint32 mapFlags, int caseFlags)
   2927 	: BasicUploadCase<MapBufferRangeFlushDuration>	(ctx, name, desc, minBufferSize, maxBufferSize, numSamples, bufferUsage, getBaseCaseType(caseFlags), RESULT_MEDIAN_TRANSFER_RATE, getBaseFlags(mapFlags, caseFlags))
   2928 	, m_fullUpload									((caseFlags&FLAG_PARTIAL) == 0)
   2929 	, m_flushInParts								((caseFlags&FLAG_FLUSH_IN_PARTS) != 0)
   2930 	, m_flushPartial								((caseFlags&FLAG_FLUSH_PARTIAL) != 0)
   2931 	, m_useUnusedUnspecifiedBuffer					((caseFlags&FLAG_USE_UNUSED_UNSPECIFIED_BUFFER) != 0)
   2932 	, m_useUnusedSpecifiedBuffer					((caseFlags&FLAG_USE_UNUSED_SPECIFIED_BUFFER) != 0)
   2933 	, m_mapFlags									(mapFlags)
   2934 	, m_unmapFailures								(0)
   2935 {
   2936 	DE_ASSERT(!(m_flushPartial && m_flushInParts));
   2937 	DE_ASSERT(!(m_flushPartial && !m_fullUpload));
   2938 }
   2939 
   2940 MapBufferRangeFlushCase::~MapBufferRangeFlushCase (void)
   2941 {
   2942 }
   2943 
   2944 void MapBufferRangeFlushCase::init (void)
   2945 {
   2946 	// Describe what the test tries to do
   2947 	m_testCtx.getLog()
   2948 		<< tcu::TestLog::Message
   2949 		<< "Testing glMapBufferRange(), glFlushMappedBufferRange() and glUnmapBuffer() function call performance.\n"
   2950 		<< ((m_fullUpload) ? ("The whole buffer is mapped.") : ("Half of the buffer is mapped.")) << "\n"
   2951 		<< ((m_flushInParts) ?
   2952 			("The mapped range is partitioned to 4 subranges and each partition is flushed separately.") :
   2953 			(m_flushPartial) ?
   2954 				("Half of the buffer range is flushed.") :
   2955 				("The whole mapped range is flushed in one flush call.")) << "\n"
   2956 		<< ((m_useUnusedUnspecifiedBuffer) ? ("The buffer has not been used before mapping and is allocated with unspecified contents.\n") : (""))
   2957 		<< ((m_useUnusedSpecifiedBuffer) ? ("The buffer has not been used before mapping and is allocated with specified contents.\n") : (""))
   2958 		<< ((!m_useUnusedSpecifiedBuffer && !m_useUnusedUnspecifiedBuffer) ? ("The buffer has previously been used in a drawing operation.\n") : (""))
   2959 		<< "Map bits:\n"
   2960 		<< ((m_mapFlags & GL_MAP_WRITE_BIT) ? ("\tGL_MAP_WRITE_BIT\n") : (""))
   2961 		<< ((m_mapFlags & GL_MAP_READ_BIT) ? ("\tGL_MAP_READ_BIT\n") : (""))
   2962 		<< ((m_mapFlags & GL_MAP_INVALIDATE_RANGE_BIT) ? ("\tGL_MAP_INVALIDATE_RANGE_BIT\n") : (""))
   2963 		<< ((m_mapFlags & GL_MAP_INVALIDATE_BUFFER_BIT) ? ("\tGL_MAP_INVALIDATE_BUFFER_BIT\n") : (""))
   2964 		<< ((m_mapFlags & GL_MAP_UNSYNCHRONIZED_BIT) ? ("\tGL_MAP_UNSYNCHRONIZED_BIT\n") : (""))
   2965 		<< ((m_mapFlags & GL_MAP_FLUSH_EXPLICIT_BIT) ? ("\tGL_MAP_FLUSH_EXPLICIT_BIT\n") : (""))
   2966 		<< tcu::TestLog::EndMessage;
   2967 
   2968 	BasicUploadCase<MapBufferRangeFlushDuration>::init();
   2969 }
   2970 
   2971 MapBufferRangeFlushCase::CaseType MapBufferRangeFlushCase::getBaseCaseType (int caseFlags)
   2972 {
   2973 	if ((caseFlags & FLAG_USE_UNUSED_UNSPECIFIED_BUFFER) == 0 && (caseFlags & FLAG_USE_UNUSED_SPECIFIED_BUFFER) == 0)
   2974 		return CASE_USED_BUFFER;
   2975 	else
   2976 		return CASE_NEW_BUFFER;
   2977 }
   2978 
   2979 int MapBufferRangeFlushCase::getBaseFlags (deUint32 mapFlags, int caseFlags)
   2980 {
   2981 	int flags = FLAG_DONT_LOG_BUFFER_INFO;
   2982 
   2983 	// If buffer contains unspecified data when it is sourced (i.e drawn)
   2984 	// results are undefined, and system errors may occur. Signal parent
   2985 	// class to take this into account
   2986 	if (caseFlags & FLAG_PARTIAL)
   2987 	{
   2988 		if ((mapFlags & GL_MAP_INVALIDATE_BUFFER_BIT) != 0			||
   2989 			(caseFlags & FLAG_USE_UNUSED_UNSPECIFIED_BUFFER) != 0	||
   2990 			(caseFlags & FLAG_FLUSH_PARTIAL) != 0)
   2991 		{
   2992 			flags |= FLAG_RESULT_BUFFER_UNSPECIFIED_CONTENT;
   2993 		}
   2994 	}
   2995 
   2996 	return flags;
   2997 }
   2998 
   2999 void MapBufferRangeFlushCase::testBufferUpload (UploadSampleResult<MapBufferRangeFlushDuration>& result, int bufferSize)
   3000 {
   3001 	const int unmapFailureThreshold = 4;
   3002 
   3003 	for (; m_unmapFailures < unmapFailureThreshold; ++m_unmapFailures)
   3004 	{
   3005 		try
   3006 		{
   3007 			attemptBufferMap(result, bufferSize);
   3008 			return;
   3009 		}
   3010 		catch (UnmapFailureError&)
   3011 		{
   3012 		}
   3013 	}
   3014 
   3015 	throw tcu::TestError("Unmapping failures exceeded limit");
   3016 }
   3017 
   3018 void MapBufferRangeFlushCase::attemptBufferMap (UploadSampleResult<MapBufferRangeFlushDuration>& result, int bufferSize)
   3019 {
   3020 	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
   3021 	const int				mappedSize	= (m_fullUpload) ? (bufferSize) : (bufferSize / 2);
   3022 
   3023 	if (m_fullUpload && !m_flushPartial)
   3024 		result.writtenSize = bufferSize;
   3025 	else
   3026 		result.writtenSize = bufferSize / 2;
   3027 
   3028 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bufferID);
   3029 
   3030 	// Create unused buffer
   3031 
   3032 	if (m_useUnusedUnspecifiedBuffer)
   3033 	{
   3034 		deUint64 startTime;
   3035 		deUint64 endTime;
   3036 
   3037 		// Don't specify contents
   3038 		startTime = deGetMicroseconds();
   3039 		gl.bufferData(GL_ARRAY_BUFFER, bufferSize, DE_NULL, m_bufferUsage);
   3040 		endTime = deGetMicroseconds();
   3041 
   3042 		result.duration.allocDuration = endTime - startTime;
   3043 	}
   3044 	else if (m_useUnusedSpecifiedBuffer)
   3045 	{
   3046 		deUint64 startTime;
   3047 		deUint64 endTime;
   3048 
   3049 		// Specify buffer contents
   3050 		startTime = deGetMicroseconds();
   3051 		gl.bufferData(GL_ARRAY_BUFFER, bufferSize, &m_zeroData[0], m_bufferUsage);
   3052 		endTime = deGetMicroseconds();
   3053 
   3054 		result.duration.allocDuration = endTime - startTime;
   3055 	}
   3056 	else
   3057 	{
   3058 		// No alloc, no time
   3059 		result.duration.allocDuration = 0;
   3060 	}
   3061 
   3062 	// upload
   3063 	{
   3064 		void* mapPtr;
   3065 
   3066 		// Map
   3067 		{
   3068 			deUint64 startTime;
   3069 			deUint64 endTime;
   3070 
   3071 			startTime = deGetMicroseconds();
   3072 			if (m_fullUpload)
   3073 				mapPtr = gl.mapBufferRange(GL_ARRAY_BUFFER, 0, mappedSize, m_mapFlags);
   3074 			else
   3075 			{
   3076 				// upload to buffer center
   3077 				mapPtr = gl.mapBufferRange(GL_ARRAY_BUFFER, bufferSize / 4, mappedSize, m_mapFlags);
   3078 			}
   3079 			endTime = deGetMicroseconds();
   3080 
   3081 			if (!mapPtr)
   3082 				throw tcu::Exception("MapBufferRange returned NULL");
   3083 
   3084 			result.duration.mapDuration = endTime - startTime;
   3085 		}
   3086 
   3087 		// Write
   3088 		{
   3089 			if (!m_flushPartial)
   3090 				result.duration.writeDuration = medianTimeMemcpy(mapPtr, &m_zeroData[0], result.writtenSize);
   3091 			else
   3092 				result.duration.writeDuration = medianTimeMemcpy((deUint8*)mapPtr + bufferSize / 4, &m_zeroData[0], result.writtenSize);
   3093 		}
   3094 
   3095 		// Flush
   3096 		{
   3097 			deUint64	startTime;
   3098 			deUint64	endTime;
   3099 
   3100 			startTime = deGetMicroseconds();
   3101 
   3102 			if (m_flushPartial)
   3103 				gl.flushMappedBufferRange(GL_ARRAY_BUFFER, mappedSize/4, mappedSize/2);
   3104 			else if (!m_flushInParts)
   3105 				gl.flushMappedBufferRange(GL_ARRAY_BUFFER, 0, mappedSize);
   3106 			else
   3107 			{
   3108 				const int p1 = 0;
   3109 				const int p2 = mappedSize / 3;
   3110 				const int p3 = mappedSize / 2;
   3111 				const int p4 = mappedSize * 2 / 4;
   3112 				const int p5 = mappedSize;
   3113 
   3114 				// flush in mixed order
   3115 				gl.flushMappedBufferRange(GL_ARRAY_BUFFER, p2,	p3-p2);
   3116 				gl.flushMappedBufferRange(GL_ARRAY_BUFFER, p1,	p2-p1);
   3117 				gl.flushMappedBufferRange(GL_ARRAY_BUFFER, p4,	p5-p4);
   3118 				gl.flushMappedBufferRange(GL_ARRAY_BUFFER, p3,	p4-p3);
   3119 			}
   3120 
   3121 			endTime = deGetMicroseconds();
   3122 
   3123 			result.duration.flushDuration = endTime - startTime;
   3124 		}
   3125 
   3126 		// Unmap
   3127 		{
   3128 			deUint64		startTime;
   3129 			deUint64		endTime;
   3130 			glw::GLboolean	unmapSuccessful;
   3131 
   3132 			startTime = deGetMicroseconds();
   3133 			unmapSuccessful = gl.unmapBuffer(GL_ARRAY_BUFFER);
   3134 			endTime = deGetMicroseconds();
   3135 
   3136 			// if unmapping fails, just try again later
   3137 			if (!unmapSuccessful)
   3138 				throw UnmapFailureError();
   3139 
   3140 			result.duration.unmapDuration = endTime - startTime;
   3141 		}
   3142 
   3143 		result.duration.totalDuration = result.duration.mapDuration + result.duration.writeDuration + result.duration.flushDuration + result.duration.unmapDuration + result.duration.allocDuration;
   3144 		result.duration.fitResponseDuration = result.duration.totalDuration;
   3145 	}
   3146 }
   3147 
   3148 template <typename SampleType>
   3149 class ModifyAfterBasicCase : public BasicBufferCase<SampleType>
   3150 {
   3151 public:
   3152 						ModifyAfterBasicCase	(Context& context, const char* name, const char* description, int bufferSizeMin, int bufferSizeMax, deUint32 usage, bool bufferUnspecifiedAfterTest);
   3153 						~ModifyAfterBasicCase	(void);
   3154 
   3155 	void				init					(void);
   3156 	void				deinit					(void);
   3157 
   3158 protected:
   3159 	void				drawBufferRange			(int begin, int end);
   3160 
   3161 private:
   3162 	enum
   3163 	{
   3164 		NUM_SAMPLES = 20,
   3165 	};
   3166 
   3167 
   3168 	bool				runSample				(int iteration, UploadSampleResult<SampleType>& sample);
   3169 	bool				prepareAndRunTest		(int iteration, UploadSampleResult<SampleType>& result, int bufferSize);
   3170 	void				logAndSetTestResult		(const std::vector<UploadSampleResult<SampleType> >& results);
   3171 
   3172 	virtual void		testWithBufferSize		(UploadSampleResult<SampleType>& result, int bufferSize) = 0;
   3173 
   3174 	int					m_unmappingErrors;
   3175 
   3176 protected:
   3177 	const bool			m_bufferUnspecifiedAfterTest;
   3178 	const deUint32		m_bufferUsage;
   3179 	std::vector<deUint8> m_zeroData;
   3180 
   3181 	using BasicBufferCase<SampleType>::m_testCtx;
   3182 	using BasicBufferCase<SampleType>::m_context;
   3183 
   3184 	using BasicBufferCase<SampleType>::DUMMY_RENDER_AREA_SIZE;
   3185 	using BasicBufferCase<SampleType>::m_dummyProgram;
   3186 	using BasicBufferCase<SampleType>::m_dummyProgramPosLoc;
   3187 	using BasicBufferCase<SampleType>::m_bufferID;
   3188 	using BasicBufferCase<SampleType>::m_numSamples;
   3189 	using BasicBufferCase<SampleType>::m_bufferSizeMin;
   3190 	using BasicBufferCase<SampleType>::m_bufferSizeMax;
   3191 	using BasicBufferCase<SampleType>::m_allocateLargerBuffer;
   3192 };
   3193 
   3194 template <typename SampleType>
   3195 ModifyAfterBasicCase<SampleType>::ModifyAfterBasicCase (Context& context, const char* name, const char* description, int bufferSizeMin, int bufferSizeMax, deUint32 usage, bool bufferUnspecifiedAfterTest)
   3196 	: BasicBufferCase<SampleType>	(context, name, description, bufferSizeMin, bufferSizeMax, NUM_SAMPLES, 0)
   3197 	, m_unmappingErrors				(0)
   3198 	, m_bufferUnspecifiedAfterTest	(bufferUnspecifiedAfterTest)
   3199 	, m_bufferUsage					(usage)
   3200 	, m_zeroData					()
   3201 {
   3202 }
   3203 
   3204 template <typename SampleType>
   3205 ModifyAfterBasicCase<SampleType>::~ModifyAfterBasicCase (void)
   3206 {
   3207 	BasicBufferCase<SampleType>::deinit();
   3208 }
   3209 
   3210 template <typename SampleType>
   3211 void ModifyAfterBasicCase<SampleType>::init (void)
   3212 {
   3213 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   3214 
   3215 	// init parent
   3216 
   3217 	BasicBufferCase<SampleType>::init();
   3218 
   3219 	// upload source
   3220 	m_zeroData.resize(m_bufferSizeMax, 0x00);
   3221 
   3222 	// log basic info
   3223 
   3224 	m_testCtx.getLog()
   3225 		<< tcu::TestLog::Message
   3226 		<< "Testing performance with " << (int)NUM_SAMPLES << " test samples. Sample order is randomized. All samples at even positions (first = 0) are tested before samples at odd positions.\n"
   3227 		<< "Buffer sizes are in range [" << getHumanReadableByteSize(m_bufferSizeMin) << ", " << getHumanReadableByteSize(m_bufferSizeMax) << "]."
   3228 		<< tcu::TestLog::EndMessage;
   3229 
   3230 	// log which transfer rate is the test result and buffer info
   3231 
   3232 	m_testCtx.getLog()
   3233 		<< tcu::TestLog::Message
   3234 		<< "Test result is the median transfer rate of the test samples.\n"
   3235 		<< "Buffer usage = " << glu::getUsageName(m_bufferUsage)
   3236 		<< tcu::TestLog::EndMessage;
   3237 
   3238 	// Set state for drawing so that we don't have to change these during the iteration
   3239 	{
   3240 		gl.useProgram(m_dummyProgram->getProgram());
   3241 		gl.viewport(0, 0, DUMMY_RENDER_AREA_SIZE, DUMMY_RENDER_AREA_SIZE);
   3242 		gl.enableVertexAttribArray(m_dummyProgramPosLoc);
   3243 	}
   3244 }
   3245 
   3246 template <typename SampleType>
   3247 void ModifyAfterBasicCase<SampleType>::deinit (void)
   3248 {
   3249 	m_zeroData = std::vector<deUint8>();
   3250 
   3251 	BasicBufferCase<SampleType>::deinit();
   3252 }
   3253 
   3254 template <typename SampleType>
   3255 void ModifyAfterBasicCase<SampleType>::drawBufferRange (int begin, int end)
   3256 {
   3257 	DE_ASSERT(begin % (int)sizeof(float[4]) == 0);
   3258 	DE_ASSERT(end % (int)sizeof(float[4]) == 0);
   3259 
   3260 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   3261 
   3262 	// use given range
   3263 	gl.drawArrays(GL_POINTS, begin / (int)sizeof(float[4]), 1);
   3264 	gl.drawArrays(GL_POINTS, end / (int)sizeof(float[4]) - 1, 1);
   3265 }
   3266 
   3267 template <typename SampleType>
   3268 bool ModifyAfterBasicCase<SampleType>::runSample (int iteration, UploadSampleResult<SampleType>& sample)
   3269 {
   3270 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
   3271 	const int				bufferSize			= sample.bufferSize;
   3272 	bool					testOk;
   3273 
   3274 	testOk = prepareAndRunTest(iteration, sample, bufferSize);
   3275 	GLU_EXPECT_NO_ERROR(gl.getError(), "Buffer upload sample");
   3276 
   3277 	if (!testOk)
   3278 	{
   3279 		const int unmapFailureThreshold = 4;
   3280 
   3281 		// only unmapping error can cause iteration failure
   3282 		if (++m_unmappingErrors >= unmapFailureThreshold)
   3283 			throw tcu::TestError("Too many unmapping errors, cannot continue.");
   3284 
   3285 		// just try again
   3286 		return false;
   3287 	}
   3288 
   3289 	return true;
   3290 }
   3291 
   3292 template <typename SampleType>
   3293 bool ModifyAfterBasicCase<SampleType>::prepareAndRunTest (int iteration, UploadSampleResult<SampleType>& result, int bufferSize)
   3294 {
   3295 	DE_UNREF(iteration);
   3296 
   3297 	DE_ASSERT(!m_bufferID);
   3298 	DE_ASSERT(deIsAligned32(bufferSize, 4*4)); // aligned to vec4
   3299 
   3300 	const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
   3301 	bool						testRunOk		= true;
   3302 	bool						unmappingFailed	= false;
   3303 
   3304 	// Upload initial buffer to the GPU...
   3305 	gl.genBuffers(1, &m_bufferID);
   3306 	gl.bindBuffer(GL_ARRAY_BUFFER, m_bufferID);
   3307 	gl.bufferData(GL_ARRAY_BUFFER, bufferSize, &m_zeroData[0], m_bufferUsage);
   3308 
   3309 	// ...use it...
   3310 	gl.vertexAttribPointer(m_dummyProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
   3311 	drawBufferRange(0, bufferSize);
   3312 
   3313 	// ..and make sure it is uploaded
   3314 	BasicBufferCase<SampleType>::waitGLResults();
   3315 
   3316 	// warmup CPU before the test to make sure the power management governor
   3317 	// keeps us in the "high performance" mode
   3318 	{
   3319 		deYield();
   3320 		tcu::warmupCPU();
   3321 		deYield();
   3322 	}
   3323 
   3324 	// test
   3325 	try
   3326 	{
   3327 		// buffer is uploaded to the GPU. Draw from it.
   3328 		drawBufferRange(0, bufferSize);
   3329 
   3330 		// and test upload
   3331 		testWithBufferSize(result, bufferSize);
   3332 	}
   3333 	catch (UnmapFailureError&)
   3334 	{
   3335 		testRunOk = false;
   3336 		unmappingFailed = true;
   3337 	}
   3338 
   3339 	// clean up: make sure buffer is not in upload queue and delete it
   3340 
   3341 	// sourcing unspecified data causes undefined results, possibly program termination
   3342 	if (m_bufferUnspecifiedAfterTest || unmappingFailed)
   3343 		gl.bufferData(GL_ARRAY_BUFFER, bufferSize, &m_zeroData[0], m_bufferUsage);
   3344 
   3345 	drawBufferRange(0, bufferSize);
   3346 	BasicBufferCase<SampleType>::waitGLResults();
   3347 
   3348 	gl.deleteBuffers(1, &m_bufferID);
   3349 	m_bufferID = 0;
   3350 
   3351 	return testRunOk;
   3352 }
   3353 
   3354 template <typename SampleType>
   3355 void ModifyAfterBasicCase<SampleType>::logAndSetTestResult (const std::vector<UploadSampleResult<SampleType> >& results)
   3356 {
   3357 	const UploadSampleAnalyzeResult analysis = analyzeSampleResults(m_testCtx.getLog(), results, false);
   3358 
   3359 	// Return median transfer rate of the samples
   3360 
   3361 	if (analysis.transferRateMedian == std::numeric_limits<float>::infinity())
   3362 	{
   3363 		// sample times are 1) invalid or 2) timer resolution too low
   3364 		// report speed 0 bytes / s since real value cannot be determined
   3365 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(0.0f, 2).c_str());
   3366 	}
   3367 	else
   3368 	{
   3369 		// report transfer rate in MB / s
   3370 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(analysis.transferRateMedian / 1024.0f / 1024.0f, 2).c_str());
   3371 	}
   3372 }
   3373 
   3374 class ModifyAfterWithBufferDataCase : public ModifyAfterBasicCase<SingleOperationDuration>
   3375 {
   3376 public:
   3377 
   3378 	enum CaseFlags
   3379 	{
   3380 		FLAG_RESPECIFY_SIZE		= 0x1,
   3381 		FLAG_UPLOAD_REPEATED	= 0x2,
   3382 	};
   3383 
   3384 					ModifyAfterWithBufferDataCase	(Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, deUint32 usage, int flags);
   3385 					~ModifyAfterWithBufferDataCase	(void);
   3386 
   3387 	void			init							(void);
   3388 	void			deinit							(void);
   3389 private:
   3390 	void			testWithBufferSize				(UploadSampleResult<SingleOperationDuration>& result, int bufferSize);
   3391 
   3392 	enum
   3393 	{
   3394 		NUM_REPEATS = 2
   3395 	};
   3396 
   3397 	const bool		m_respecifySize;
   3398 	const bool		m_repeatedUpload;
   3399 	const float		m_sizeDifferenceFactor;
   3400 };
   3401 
   3402 ModifyAfterWithBufferDataCase::ModifyAfterWithBufferDataCase (Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, deUint32 usage, int flags)
   3403 	: ModifyAfterBasicCase<SingleOperationDuration> (context, name, desc, bufferSizeMin, bufferSizeMax, usage, false)
   3404 	, m_respecifySize								((flags & FLAG_RESPECIFY_SIZE) != 0)
   3405 	, m_repeatedUpload								((flags & FLAG_UPLOAD_REPEATED) != 0)
   3406 	, m_sizeDifferenceFactor						(1.3f)
   3407 {
   3408 	DE_ASSERT(!(m_repeatedUpload && m_respecifySize));
   3409 }
   3410 
   3411 ModifyAfterWithBufferDataCase::~ModifyAfterWithBufferDataCase (void)
   3412 {
   3413 	deinit();
   3414 }
   3415 
   3416 void ModifyAfterWithBufferDataCase::init (void)
   3417 {
   3418 	// Log the purpose of the test
   3419 
   3420 	if (m_repeatedUpload)
   3421 		m_testCtx.getLog() << tcu::TestLog::Message << "Testing performance of BufferData() command after \"specify buffer contents - draw buffer\" command pair is repeated " << (int)NUM_REPEATS << " times." << tcu::TestLog::EndMessage;
   3422 	else
   3423 		m_testCtx.getLog() << tcu::TestLog::Message << "Testing performance of BufferData() command after a draw command that sources data from the target buffer." << tcu::TestLog::EndMessage;
   3424 
   3425 	m_testCtx.getLog()
   3426 		<< tcu::TestLog::Message
   3427 		<< ((m_respecifySize) ?
   3428 			("Buffer size is increased and contents are modified with BufferData().\n") :
   3429 			("Buffer contents are modified with BufferData().\n"))
   3430 		<< tcu::TestLog::EndMessage;
   3431 
   3432 	// init parent
   3433 	ModifyAfterBasicCase<SingleOperationDuration>::init();
   3434 
   3435 	// make sure our zeroBuffer is large enough
   3436 	if (m_respecifySize)
   3437 	{
   3438 		const int largerBufferSize = deAlign32((int)((float)m_bufferSizeMax * m_sizeDifferenceFactor), 4*4);
   3439 		m_zeroData.resize(largerBufferSize, 0x00);
   3440 	}
   3441 }
   3442 
   3443 void ModifyAfterWithBufferDataCase::deinit (void)
   3444 {
   3445 	ModifyAfterBasicCase<SingleOperationDuration>::deinit();
   3446 }
   3447 
   3448 void ModifyAfterWithBufferDataCase::testWithBufferSize (UploadSampleResult<SingleOperationDuration>& result, int bufferSize)
   3449 {
   3450 	// always draw the same amount to make compares between cases sensible
   3451 	const int					drawStart			= deAlign32(bufferSize / 4, 4*4);
   3452 	const int					drawEnd				= deAlign32(bufferSize * 3 / 4, 4*4);
   3453 
   3454 	const glw::Functions&		gl					= m_context.getRenderContext().getFunctions();
   3455 	const int					largerBufferSize	= deAlign32((int)((float)bufferSize * m_sizeDifferenceFactor), 4*4);
   3456 	const int					newBufferSize		= (m_respecifySize) ? (largerBufferSize) : (bufferSize);
   3457 	deUint64					startTime;
   3458 	deUint64					endTime;
   3459 
   3460 	// repeat upload-draw
   3461 	if (m_repeatedUpload)
   3462 	{
   3463 		for (int repeatNdx = 0; repeatNdx < NUM_REPEATS; ++repeatNdx)
   3464 		{
   3465 			gl.bufferData(GL_ARRAY_BUFFER, newBufferSize, &m_zeroData[0], m_bufferUsage);
   3466 			drawBufferRange(drawStart, drawEnd);
   3467 		}
   3468 	}
   3469 
   3470 	// test upload
   3471 	startTime = deGetMicroseconds();
   3472 	gl.bufferData(GL_ARRAY_BUFFER, newBufferSize, &m_zeroData[0], m_bufferUsage);
   3473 	endTime = deGetMicroseconds();
   3474 
   3475 	result.duration.totalDuration = endTime - startTime;
   3476 	result.duration.fitResponseDuration = result.duration.totalDuration;
   3477 	result.writtenSize = newBufferSize;
   3478 }
   3479 
   3480 class ModifyAfterWithBufferSubDataCase : public ModifyAfterBasicCase<SingleOperationDuration>
   3481 {
   3482 public:
   3483 
   3484 	enum CaseFlags
   3485 	{
   3486 		FLAG_PARTIAL			= 0x1,
   3487 		FLAG_UPLOAD_REPEATED	= 0x2,
   3488 	};
   3489 
   3490 					ModifyAfterWithBufferSubDataCase	(Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, deUint32 usage, int flags);
   3491 					~ModifyAfterWithBufferSubDataCase	(void);
   3492 
   3493 	void			init								(void);
   3494 	void			deinit								(void);
   3495 private:
   3496 	void			testWithBufferSize					(UploadSampleResult<SingleOperationDuration>& result, int bufferSize);
   3497 
   3498 	enum
   3499 	{
   3500 		NUM_REPEATS = 2
   3501 	};
   3502 
   3503 	const bool		m_partialUpload;
   3504 	const bool		m_repeatedUpload;
   3505 };
   3506 
   3507 ModifyAfterWithBufferSubDataCase::ModifyAfterWithBufferSubDataCase (Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, deUint32 usage, int flags)
   3508 	: ModifyAfterBasicCase<SingleOperationDuration>	(context, name, desc, bufferSizeMin, bufferSizeMax, usage, false)
   3509 	, m_partialUpload								((flags & FLAG_PARTIAL) != 0)
   3510 	, m_repeatedUpload								((flags & FLAG_UPLOAD_REPEATED) != 0)
   3511 {
   3512 }
   3513 
   3514 ModifyAfterWithBufferSubDataCase::~ModifyAfterWithBufferSubDataCase (void)
   3515 {
   3516 	deinit();
   3517 }
   3518 
   3519 void ModifyAfterWithBufferSubDataCase::init (void)
   3520 {
   3521 	// Log the purpose of the test
   3522 
   3523 	if (m_repeatedUpload)
   3524 		m_testCtx.getLog() << tcu::TestLog::Message << "Testing performance of BufferSubData() command after \"specify buffer contents - draw buffer\" command pair is repeated " << (int)NUM_REPEATS << " times." << tcu::TestLog::EndMessage;
   3525 	else
   3526 		m_testCtx.getLog() << tcu::TestLog::Message << "Testing performance of BufferSubData() command after a draw command that sources data from the target buffer." << tcu::TestLog::EndMessage;
   3527 
   3528 	m_testCtx.getLog()
   3529 		<< tcu::TestLog::Message
   3530 		<< ((m_partialUpload) ?
   3531 			("Half of the buffer contents are modified.\n") :
   3532 			("Buffer contents are fully respecified.\n"))
   3533 		<< tcu::TestLog::EndMessage;
   3534 
   3535 	ModifyAfterBasicCase<SingleOperationDuration>::init();
   3536 }
   3537 
   3538 void ModifyAfterWithBufferSubDataCase::deinit (void)
   3539 {
   3540 	ModifyAfterBasicCase<SingleOperationDuration>::deinit();
   3541 }
   3542 
   3543 void ModifyAfterWithBufferSubDataCase::testWithBufferSize (UploadSampleResult<SingleOperationDuration>& result, int bufferSize)
   3544 {
   3545 	// always draw the same amount to make compares between cases sensible
   3546 	const int					drawStart			= deAlign32(bufferSize / 4, 4*4);
   3547 	const int					drawEnd				= deAlign32(bufferSize * 3 / 4, 4*4);
   3548 
   3549 	const glw::Functions&		gl					= m_context.getRenderContext().getFunctions();
   3550 	const int					subdataOffset		= deAlign32((m_partialUpload) ? (bufferSize / 4) : (0), 4*4);
   3551 	const int					subdataSize			= deAlign32((m_partialUpload) ? (bufferSize / 2) : (bufferSize), 4*4);
   3552 	deUint64					startTime;
   3553 	deUint64					endTime;
   3554 
   3555 	// make upload-draw stream
   3556 	if (m_repeatedUpload)
   3557 	{
   3558 		for (int repeatNdx = 0; repeatNdx < NUM_REPEATS; ++repeatNdx)
   3559 		{
   3560 			gl.bufferSubData(GL_ARRAY_BUFFER, subdataOffset, subdataSize, &m_zeroData[0]);
   3561 			drawBufferRange(drawStart, drawEnd);
   3562 		}
   3563 	}
   3564 
   3565 	// test upload
   3566 	startTime = deGetMicroseconds();
   3567 	gl.bufferSubData(GL_ARRAY_BUFFER, subdataOffset, subdataSize, &m_zeroData[0]);
   3568 	endTime = deGetMicroseconds();
   3569 
   3570 	result.duration.totalDuration = endTime - startTime;
   3571 	result.duration.fitResponseDuration = result.duration.totalDuration;
   3572 	result.writtenSize = subdataSize;
   3573 }
   3574 
   3575 class ModifyAfterWithMapBufferRangeCase : public ModifyAfterBasicCase<MapBufferRangeDurationNoAlloc>
   3576 {
   3577 public:
   3578 
   3579 	enum CaseFlags
   3580 	{
   3581 		FLAG_PARTIAL = 0x1,
   3582 	};
   3583 
   3584 					ModifyAfterWithMapBufferRangeCase	(Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, deUint32 usage, int flags, deUint32 glMapFlags);
   3585 					~ModifyAfterWithMapBufferRangeCase	(void);
   3586 
   3587 	void			init								(void);
   3588 	void			deinit								(void);
   3589 private:
   3590 	static bool		isBufferUnspecifiedAfterUpload		(int flags, deUint32 mapFlags);
   3591 	void			testWithBufferSize					(UploadSampleResult<MapBufferRangeDurationNoAlloc>& result, int bufferSize);
   3592 
   3593 	const bool		m_partialUpload;
   3594 	const deUint32	m_mapFlags;
   3595 };
   3596 
   3597 ModifyAfterWithMapBufferRangeCase::ModifyAfterWithMapBufferRangeCase (Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, deUint32 usage, int flags, deUint32 glMapFlags)
   3598 	: ModifyAfterBasicCase<MapBufferRangeDurationNoAlloc>	(context, name, desc, bufferSizeMin, bufferSizeMax, usage, isBufferUnspecifiedAfterUpload(flags, glMapFlags))
   3599 	, m_partialUpload										((flags & FLAG_PARTIAL) != 0)
   3600 	, m_mapFlags											(glMapFlags)
   3601 {
   3602 }
   3603 
   3604 ModifyAfterWithMapBufferRangeCase::~ModifyAfterWithMapBufferRangeCase (void)
   3605 {
   3606 	deinit();
   3607 }
   3608 
   3609 void ModifyAfterWithMapBufferRangeCase::init (void)
   3610 {
   3611 	// Log the purpose of the test
   3612 
   3613 	m_testCtx.getLog()
   3614 		<< tcu::TestLog::Message
   3615 		<< "Testing performance of MapBufferRange() command after a draw command that sources data from the target buffer.\n"
   3616 		<< ((m_partialUpload) ?
   3617 			("Half of the buffer is mapped.\n") :
   3618 			("Whole buffer is mapped.\n"))
   3619 		<< "Map bits:\n"
   3620 		<< ((m_mapFlags & GL_MAP_WRITE_BIT) ? ("\tGL_MAP_WRITE_BIT\n") : (""))
   3621 		<< ((m_mapFlags & GL_MAP_READ_BIT) ? ("\tGL_MAP_READ_BIT\n") : (""))
   3622 		<< ((m_mapFlags & GL_MAP_INVALIDATE_RANGE_BIT) ? ("\tGL_MAP_INVALIDATE_RANGE_BIT\n") : (""))
   3623 		<< ((m_mapFlags & GL_MAP_INVALIDATE_BUFFER_BIT) ? ("\tGL_MAP_INVALIDATE_BUFFER_BIT\n") : (""))
   3624 		<< ((m_mapFlags & GL_MAP_UNSYNCHRONIZED_BIT) ? ("\tGL_MAP_UNSYNCHRONIZED_BIT\n") : (""))
   3625 		<< ((m_mapFlags & GL_MAP_FLUSH_EXPLICIT_BIT) ? ("\tGL_MAP_FLUSH_EXPLICIT_BIT\n") : (""))
   3626 		<< tcu::TestLog::EndMessage;
   3627 
   3628 	ModifyAfterBasicCase<MapBufferRangeDurationNoAlloc>::init();
   3629 }
   3630 
   3631 void ModifyAfterWithMapBufferRangeCase::deinit (void)
   3632 {
   3633 	ModifyAfterBasicCase<MapBufferRangeDurationNoAlloc>::deinit();
   3634 }
   3635 
   3636 bool ModifyAfterWithMapBufferRangeCase::isBufferUnspecifiedAfterUpload (int flags, deUint32 mapFlags)
   3637 {
   3638 	if ((flags & FLAG_PARTIAL) != 0 && ((mapFlags & GL_MAP_INVALIDATE_BUFFER_BIT) != 0))
   3639 		return true;
   3640 
   3641 	return false;
   3642 }
   3643 
   3644 void ModifyAfterWithMapBufferRangeCase::testWithBufferSize (UploadSampleResult<MapBufferRangeDurationNoAlloc>& result, int bufferSize)
   3645 {
   3646 	const glw::Functions&		gl					= m_context.getRenderContext().getFunctions();
   3647 	const int					subdataOffset		= deAlign32((m_partialUpload) ? (bufferSize / 4) : (0), 4*4);
   3648 	const int					subdataSize			= deAlign32((m_partialUpload) ? (bufferSize / 2) : (bufferSize), 4*4);
   3649 	void*						mapPtr;
   3650 
   3651 	// map
   3652 	{
   3653 		deUint64 startTime;
   3654 		deUint64 endTime;
   3655 
   3656 		startTime = deGetMicroseconds();
   3657 		mapPtr = gl.mapBufferRange(GL_ARRAY_BUFFER, subdataOffset, subdataSize, m_mapFlags);
   3658 		endTime = deGetMicroseconds();
   3659 
   3660 		if (!mapPtr)
   3661 			throw tcu::TestError("mapBufferRange returned null");
   3662 
   3663 		result.duration.mapDuration = endTime - startTime;
   3664 	}
   3665 
   3666 	// write
   3667 	{
   3668 		result.duration.writeDuration = medianTimeMemcpy(mapPtr, &m_zeroData[0], subdataSize);
   3669 	}
   3670 
   3671 	// unmap
   3672 	{
   3673 		deUint64		startTime;
   3674 		deUint64		endTime;
   3675 		glw::GLboolean	unmapSucceeded;
   3676 
   3677 		startTime = deGetMicroseconds();
   3678 		unmapSucceeded = gl.unmapBuffer(GL_ARRAY_BUFFER);
   3679 		endTime = deGetMicroseconds();
   3680 
   3681 		if (unmapSucceeded != GL_TRUE)
   3682 			throw UnmapFailureError();
   3683 
   3684 		result.duration.unmapDuration = endTime - startTime;
   3685 	}
   3686 
   3687 	result.duration.totalDuration = result.duration.mapDuration + result.duration.writeDuration + result.duration.unmapDuration;
   3688 	result.duration.fitResponseDuration = result.duration.totalDuration;
   3689 	result.writtenSize = subdataSize;
   3690 }
   3691 
   3692 class ModifyAfterWithMapBufferFlushCase : public ModifyAfterBasicCase<MapBufferRangeFlushDurationNoAlloc>
   3693 {
   3694 public:
   3695 
   3696 	enum CaseFlags
   3697 	{
   3698 		FLAG_PARTIAL = 0x1,
   3699 	};
   3700 
   3701 					ModifyAfterWithMapBufferFlushCase	(Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, deUint32 usage, int flags, deUint32 glMapFlags);
   3702 					~ModifyAfterWithMapBufferFlushCase	(void);
   3703 
   3704 	void			init								(void);
   3705 	void			deinit								(void);
   3706 private:
   3707 	static bool		isBufferUnspecifiedAfterUpload		(int flags, deUint32 mapFlags);
   3708 	void			testWithBufferSize					(UploadSampleResult<MapBufferRangeFlushDurationNoAlloc>& result, int bufferSize);
   3709 
   3710 	const bool		m_partialUpload;
   3711 	const deUint32	m_mapFlags;
   3712 };
   3713 
   3714 ModifyAfterWithMapBufferFlushCase::ModifyAfterWithMapBufferFlushCase (Context& context, const char* name, const char* desc, int bufferSizeMin, int bufferSizeMax, deUint32 usage, int flags, deUint32 glMapFlags)
   3715 	: ModifyAfterBasicCase<MapBufferRangeFlushDurationNoAlloc>	(context, name, desc, bufferSizeMin, bufferSizeMax, usage, isBufferUnspecifiedAfterUpload(flags, glMapFlags))
   3716 	, m_partialUpload											((flags & FLAG_PARTIAL) != 0)
   3717 	, m_mapFlags												(glMapFlags)
   3718 {
   3719 }
   3720 
   3721 ModifyAfterWithMapBufferFlushCase::~ModifyAfterWithMapBufferFlushCase (void)
   3722 {
   3723 	deinit();
   3724 }
   3725 
   3726 void ModifyAfterWithMapBufferFlushCase::init (void)
   3727 {
   3728 	// Log the purpose of the test
   3729 
   3730 	m_testCtx.getLog()
   3731 		<< tcu::TestLog::Message
   3732 		<< "Testing performance of MapBufferRange() command after a draw command that sources data from the target buffer.\n"
   3733 		<< ((m_partialUpload) ?
   3734 			("Half of the buffer is mapped.\n") :
   3735 			("Whole buffer is mapped.\n"))
   3736 		<< "Map bits:\n"
   3737 		<< ((m_mapFlags & GL_MAP_WRITE_BIT) ? ("\tGL_MAP_WRITE_BIT\n") : (""))
   3738 		<< ((m_mapFlags & GL_MAP_READ_BIT) ? ("\tGL_MAP_READ_BIT\n") : (""))
   3739 		<< ((m_mapFlags & GL_MAP_INVALIDATE_RANGE_BIT) ? ("\tGL_MAP_INVALIDATE_RANGE_BIT\n") : (""))
   3740 		<< ((m_mapFlags & GL_MAP_INVALIDATE_BUFFER_BIT) ? ("\tGL_MAP_INVALIDATE_BUFFER_BIT\n") : (""))
   3741 		<< ((m_mapFlags & GL_MAP_UNSYNCHRONIZED_BIT) ? ("\tGL_MAP_UNSYNCHRONIZED_BIT\n") : (""))
   3742 		<< ((m_mapFlags & GL_MAP_FLUSH_EXPLICIT_BIT) ? ("\tGL_MAP_FLUSH_EXPLICIT_BIT\n") : (""))
   3743 		<< tcu::TestLog::EndMessage;
   3744 
   3745 	ModifyAfterBasicCase<MapBufferRangeFlushDurationNoAlloc>::init();
   3746 }
   3747 
   3748 void ModifyAfterWithMapBufferFlushCase::deinit (void)
   3749 {
   3750 	ModifyAfterBasicCase<MapBufferRangeFlushDurationNoAlloc>::deinit();
   3751 }
   3752 
   3753 bool ModifyAfterWithMapBufferFlushCase::isBufferUnspecifiedAfterUpload (int flags, deUint32 mapFlags)
   3754 {
   3755 	if ((flags & FLAG_PARTIAL) != 0 && ((mapFlags & GL_MAP_INVALIDATE_BUFFER_BIT) != 0))
   3756 		return true;
   3757 
   3758 	return false;
   3759 }
   3760 
   3761 void ModifyAfterWithMapBufferFlushCase::testWithBufferSize (UploadSampleResult<MapBufferRangeFlushDurationNoAlloc>& result, int bufferSize)
   3762 {
   3763 	const glw::Functions&		gl					= m_context.getRenderContext().getFunctions();
   3764 	const int					subdataOffset		= deAlign32((m_partialUpload) ? (bufferSize / 4) : (0), 4*4);
   3765 	const int					subdataSize			= deAlign32((m_partialUpload) ? (bufferSize / 2) : (bufferSize), 4*4);
   3766 	void*						mapPtr;
   3767 
   3768 	// map
   3769 	{
   3770 		deUint64 startTime;
   3771 		deUint64 endTime;
   3772 
   3773 		startTime = deGetMicroseconds();
   3774 		mapPtr = gl.mapBufferRange(GL_ARRAY_BUFFER, subdataOffset, subdataSize, m_mapFlags);
   3775 		endTime = deGetMicroseconds();
   3776 
   3777 		if (!mapPtr)
   3778 			throw tcu::TestError("mapBufferRange returned null");
   3779 
   3780 		result.duration.mapDuration = endTime - startTime;
   3781 	}
   3782 
   3783 	// write
   3784 	{
   3785 		result.duration.writeDuration = medianTimeMemcpy(mapPtr, &m_zeroData[0], subdataSize);
   3786 	}
   3787 
   3788 	// flush
   3789 	{
   3790 		deUint64 startTime;
   3791 		deUint64 endTime;
   3792 
   3793 		startTime = deGetMicroseconds();
   3794 		gl.flushMappedBufferRange(GL_ARRAY_BUFFER, 0, subdataSize);
   3795 		endTime = deGetMicroseconds();
   3796 
   3797 		result.duration.flushDuration = endTime - startTime;
   3798 	}
   3799 
   3800 	// unmap
   3801 	{
   3802 		deUint64		startTime;
   3803 		deUint64		endTime;
   3804 		glw::GLboolean	unmapSucceeded;
   3805 
   3806 		startTime = deGetMicroseconds();
   3807 		unmapSucceeded = gl.unmapBuffer(GL_ARRAY_BUFFER);
   3808 		endTime = deGetMicroseconds();
   3809 
   3810 		if (unmapSucceeded != GL_TRUE)
   3811 			throw UnmapFailureError();
   3812 
   3813 		result.duration.unmapDuration = endTime - startTime;
   3814 	}
   3815 
   3816 	result.duration.totalDuration = result.duration.mapDuration + result.duration.writeDuration + result.duration.unmapDuration + result.duration.flushDuration;
   3817 	result.duration.fitResponseDuration = result.duration.totalDuration;
   3818 	result.writtenSize = subdataSize;
   3819 }
   3820 
   3821 enum DrawMethod
   3822 {
   3823 	DRAWMETHOD_DRAW_ARRAYS = 0,
   3824 	DRAWMETHOD_DRAW_ELEMENTS,
   3825 
   3826 	DRAWMETHOD_LAST
   3827 };
   3828 
   3829 enum TargetBuffer
   3830 {
   3831 	TARGETBUFFER_VERTEX = 0,
   3832 	TARGETBUFFER_INDEX,
   3833 
   3834 	TARGETBUFFER_LAST
   3835 };
   3836 
   3837 enum BufferState
   3838 {
   3839 	BUFFERSTATE_NEW = 0,
   3840 	BUFFERSTATE_EXISTING,
   3841 
   3842 	BUFFERSTATE_LAST
   3843 };
   3844 
   3845 enum UploadMethod
   3846 {
   3847 	UPLOADMETHOD_BUFFER_DATA = 0,
   3848 	UPLOADMETHOD_BUFFER_SUB_DATA,
   3849 	UPLOADMETHOD_MAP_BUFFER_RANGE,
   3850 
   3851 	UPLOADMETHOD_LAST
   3852 };
   3853 
   3854 enum UnrelatedBufferType
   3855 {
   3856 	UNRELATEDBUFFERTYPE_NONE = 0,
   3857 	UNRELATEDBUFFERTYPE_VERTEX,
   3858 
   3859 	UNRELATEDBUFFERTYPE_LAST
   3860 };
   3861 
   3862 enum UploadRange
   3863 {
   3864 	UPLOADRANGE_FULL = 0,
   3865 	UPLOADRANGE_PARTIAL,
   3866 
   3867 	UPLOADRANGE_LAST
   3868 };
   3869 
   3870 struct LayeredGridSpec
   3871 {
   3872 	int gridWidth;
   3873 	int gridHeight;
   3874 	int gridLayers;
   3875 };
   3876 
   3877 static int getLayeredGridNumVertices (const LayeredGridSpec& scene)
   3878 {
   3879 	return scene.gridWidth * scene.gridHeight * scene.gridLayers * 6;
   3880 }
   3881 
   3882 static void generateLayeredGridVertexAttribData4C4V (std::vector<tcu::Vec4>& vertexData, const LayeredGridSpec& scene)
   3883 {
   3884 	// interleave color & vertex data
   3885 	const tcu::Vec4 green	(0.0f, 1.0f, 0.0f, 0.7f);
   3886 	const tcu::Vec4 yellow	(1.0f, 1.0f, 0.0f, 0.8f);
   3887 
   3888 	vertexData.resize(getLayeredGridNumVertices(scene) * 2);
   3889 
   3890 	for (int cellY = 0; cellY < scene.gridHeight; ++cellY)
   3891 	for (int cellX = 0; cellX < scene.gridWidth; ++cellX)
   3892 	for (int cellZ = 0; cellZ < scene.gridLayers; ++cellZ)
   3893 	{
   3894 		const tcu::Vec4	color		= (((cellX + cellY + cellZ) % 2) == 0) ? (green) : (yellow);
   3895 		const float		cellLeft	= (float(cellX  ) / (float)scene.gridWidth  - 0.5f) * 2.0f;
   3896 		const float		cellRight	= (float(cellX+1) / (float)scene.gridWidth  - 0.5f) * 2.0f;
   3897 		const float		cellTop		= (float(cellY+1) / (float)scene.gridHeight - 0.5f) * 2.0f;
   3898 		const float		cellBottom	= (float(cellY  ) / (float)scene.gridHeight - 0.5f) * 2.0f;
   3899 
   3900 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 +  0] = color;
   3901 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 +  1] = tcu::Vec4(cellLeft, cellTop, 0.0f, 1.0f);
   3902 
   3903 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 +  2] = color;
   3904 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 +  3] = tcu::Vec4(cellLeft, cellBottom, 0.0f, 1.0f);
   3905 
   3906 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 +  4] = color;
   3907 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 +  5] = tcu::Vec4(cellRight, cellBottom, 0.0f, 1.0f);
   3908 
   3909 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 +  6] = color;
   3910 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 +  7] = tcu::Vec4(cellLeft, cellTop, 0.0f, 1.0f);
   3911 
   3912 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 +  8] = color;
   3913 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 +  9] = tcu::Vec4(cellRight, cellBottom, 0.0f, 1.0f);
   3914 
   3915 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 + 10] = color;
   3916 		vertexData[(cellY * scene.gridWidth * scene.gridLayers + cellX * scene.gridLayers + cellZ) * 12 + 11] = tcu::Vec4(cellRight, cellTop, 0.0f, 1.0f);
   3917 	}
   3918 }
   3919 
   3920 static void generateLayeredGridIndexData (std::vector<deUint32>& indexData, const LayeredGridSpec& scene)
   3921 {
   3922 	indexData.resize(getLayeredGridNumVertices(scene) * 2);
   3923 
   3924 	for (int ndx = 0; ndx < scene.gridLayers * scene.gridHeight * scene.gridWidth * 6; ++ndx)
   3925 		indexData[ndx] = ndx;
   3926 }
   3927 
   3928 class RenderPerformanceTestBase : public TestCase
   3929 {
   3930 public:
   3931 							RenderPerformanceTestBase	(Context& context, const char* name, const char* description);
   3932 							~RenderPerformanceTestBase	(void);
   3933 
   3934 protected:
   3935 	void					init						(void);
   3936 	void					deinit						(void);
   3937 
   3938 	void					waitGLResults				(void) const;
   3939 	void					setupVertexAttribs			(void) const;
   3940 
   3941 	enum
   3942 	{
   3943 		RENDER_AREA_SIZE = 128
   3944 	};
   3945 
   3946 private:
   3947 	glu::ShaderProgram*		m_renderProgram;
   3948 	int						m_colorLoc;
   3949 	int						m_positionLoc;
   3950 };
   3951 
   3952 RenderPerformanceTestBase::RenderPerformanceTestBase (Context& context, const char* name, const char* description)
   3953 	: TestCase			(context, tcu::NODETYPE_PERFORMANCE, name, description)
   3954 	, m_renderProgram	(DE_NULL)
   3955 	, m_colorLoc		(0)
   3956 	, m_positionLoc		(0)
   3957 {
   3958 }
   3959 
   3960 RenderPerformanceTestBase::~RenderPerformanceTestBase (void)
   3961 {
   3962 	deinit();
   3963 }
   3964 
   3965 void RenderPerformanceTestBase::init (void)
   3966 {
   3967 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   3968 
   3969 	m_renderProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(s_colorVertexShader) << glu::FragmentSource(s_colorFragmentShader));
   3970 	if (!m_renderProgram->isOk())
   3971 	{
   3972 		m_testCtx.getLog() << *m_renderProgram;
   3973 		throw tcu::TestError("could not build program");
   3974 	}
   3975 
   3976 	m_colorLoc = gl.getAttribLocation(m_renderProgram->getProgram(), "a_color");
   3977 	m_positionLoc = gl.getAttribLocation(m_renderProgram->getProgram(), "a_position");
   3978 
   3979 	if (m_colorLoc == -1)
   3980 		throw tcu::TestError("Location of attribute a_color was -1");
   3981 	if (m_positionLoc == -1)
   3982 		throw tcu::TestError("Location of attribute a_position was -1");
   3983 }
   3984 
   3985 void RenderPerformanceTestBase::deinit (void)
   3986 {
   3987 	delete m_renderProgram;
   3988 	m_renderProgram = DE_NULL;
   3989 }
   3990 
   3991 void RenderPerformanceTestBase::setupVertexAttribs (void) const
   3992 {
   3993 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   3994 
   3995 	// buffers are bound
   3996 
   3997 	gl.enableVertexAttribArray(m_colorLoc);
   3998 	gl.enableVertexAttribArray(m_positionLoc);
   3999 
   4000 	gl.vertexAttribPointer(m_colorLoc,    4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(8 * sizeof(float)), (const tcu::Vec4*)DE_NULL + 0);
   4001 	gl.vertexAttribPointer(m_positionLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(8 * sizeof(float)), (const tcu::Vec4*)DE_NULL + 1);
   4002 
   4003 	gl.useProgram(m_renderProgram->getProgram());
   4004 
   4005 	GLU_EXPECT_NO_ERROR(gl.getError(), "set up rendering");
   4006 }
   4007 
   4008 void RenderPerformanceTestBase::waitGLResults (void) const
   4009 {
   4010 	tcu::Surface dummySurface(RENDER_AREA_SIZE, RENDER_AREA_SIZE);
   4011 	glu::readPixels(m_context.getRenderContext(), 0, 0, dummySurface.getAccess());
   4012 }
   4013 
   4014 template <typename SampleType>
   4015 class RenderCase : public RenderPerformanceTestBase
   4016 {
   4017 public:
   4018 									RenderCase						(Context& context, const char* name, const char* description, DrawMethod drawMethod);
   4019 									~RenderCase						(void);
   4020 
   4021 protected:
   4022 	void							init							(void);
   4023 	void							deinit							(void);
   4024 
   4025 private:
   4026 	IterateResult					iterate							(void);
   4027 
   4028 protected:
   4029 	struct SampleResult
   4030 	{
   4031 		LayeredGridSpec					scene;
   4032 		RenderSampleResult<SampleType>	result;
   4033 	};
   4034 
   4035 	int								getMinWorkloadSize				(void) const;
   4036 	int								getMaxWorkloadSize				(void) const;
   4037 	int								getMinWorkloadDataSize			(void) const;
   4038 	int								getMaxWorkloadDataSize			(void) const;
   4039 	int								getVertexDataSize				(void) const;
   4040 	int								getNumSamples					(void) const;
   4041 	void							uploadScene						(const LayeredGridSpec& scene);
   4042 
   4043 	virtual void					runSample						(SampleResult& sample) = 0;
   4044 	virtual void					logAndSetTestResult				(const std::vector<SampleResult>& results);
   4045 
   4046 	void							mapResultsToRenderRateFormat	(std::vector<RenderSampleResult<SampleType> >& dst, const std::vector<SampleResult>& src) const;
   4047 
   4048 	const DrawMethod				m_drawMethod;
   4049 
   4050 private:
   4051 	glw::GLuint						m_attributeBufferID;
   4052 	glw::GLuint						m_indexBufferID;
   4053 	int								m_iterationNdx;
   4054 	std::vector<int>				m_iterationOrder;
   4055 	std::vector<SampleResult>		m_results;
   4056 	int								m_numUnmapFailures;
   4057 };
   4058 
   4059 template <typename SampleType>
   4060 RenderCase<SampleType>::RenderCase (Context& context, const char* name, const char* description, DrawMethod drawMethod)
   4061 	: RenderPerformanceTestBase	(context, name, description)
   4062 	, m_drawMethod				(drawMethod)
   4063 	, m_attributeBufferID		(0)
   4064 	, m_indexBufferID			(0)
   4065 	, m_iterationNdx			(0)
   4066 	, m_numUnmapFailures		(0)
   4067 {
   4068 	DE_ASSERT(drawMethod < DRAWMETHOD_LAST);
   4069 }
   4070 
   4071 template <typename SampleType>
   4072 RenderCase<SampleType>::~RenderCase (void)
   4073 {
   4074 	deinit();
   4075 }
   4076 
   4077 template <typename SampleType>
   4078 void RenderCase<SampleType>::init (void)
   4079 {
   4080 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   4081 
   4082 	RenderPerformanceTestBase::init();
   4083 
   4084 	// requirements
   4085 
   4086 	if (m_context.getRenderTarget().getWidth() < RENDER_AREA_SIZE ||
   4087 		m_context.getRenderTarget().getHeight() < RENDER_AREA_SIZE)
   4088 		throw tcu::NotSupportedError("Test case requires " + de::toString<int>(RENDER_AREA_SIZE) + "x" + de::toString<int>(RENDER_AREA_SIZE) + " render target");
   4089 
   4090 	// gl state
   4091 
   4092 	gl.viewport(0, 0, RENDER_AREA_SIZE, RENDER_AREA_SIZE);
   4093 
   4094 	// enable bleding to prevent grid layers from being discarded
   4095 	gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   4096 	gl.blendEquation(GL_FUNC_ADD);
   4097 	gl.enable(GL_BLEND);
   4098 
   4099 	// generate iterations
   4100 
   4101 	{
   4102 		const int gridSizes[] = { 20, 26, 32, 38, 44, 50, 56, 62, 68, 74, 80,  86,  92,  98,  104, 110, 116, 122, 128 };
   4103 
   4104 		for (int gridNdx = 0; gridNdx < DE_LENGTH_OF_ARRAY(gridSizes); ++gridNdx)
   4105 		{
   4106 			m_results.push_back(SampleResult());
   4107 
   4108 			m_results.back().scene.gridHeight = gridSizes[gridNdx];
   4109 			m_results.back().scene.gridWidth = gridSizes[gridNdx];
   4110 			m_results.back().scene.gridLayers = 5;
   4111 
   4112 			m_results.back().result.numVertices = getLayeredGridNumVertices(m_results.back().scene);
   4113 
   4114 			// test cases set these, initialize to dummy values
   4115 			m_results.back().result.renderDataSize = -1;
   4116 			m_results.back().result.uploadedDataSize = -1;
   4117 			m_results.back().result.unrelatedDataSize = -1;
   4118 		}
   4119 	}
   4120 
   4121 	// randomize iteration order
   4122 	{
   4123 		m_iterationOrder.resize(m_results.size());
   4124 		generateTwoPassRandomIterationOrder(m_iterationOrder, (int)m_iterationOrder.size());
   4125 	}
   4126 }
   4127 
   4128 template <typename SampleType>
   4129 void RenderCase<SampleType>::deinit (void)
   4130 {
   4131 	RenderPerformanceTestBase::deinit();
   4132 
   4133 	if (m_attributeBufferID)
   4134 	{
   4135 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_attributeBufferID);
   4136 		m_attributeBufferID = 0;
   4137 	}
   4138 
   4139 	if (m_indexBufferID)
   4140 	{
   4141 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indexBufferID);
   4142 		m_indexBufferID = 0;
   4143 	}
   4144 }
   4145 
   4146 template <typename SampleType>
   4147 typename RenderCase<SampleType>::IterateResult RenderCase<SampleType>::iterate (void)
   4148 {
   4149 	const int		unmapFailureThreshold	= 3;
   4150 	const int		currentIteration		= m_iterationNdx;
   4151 	const int		currentConfigNdx		= m_iterationOrder[currentIteration];
   4152 	SampleResult&	currentSample			= m_results[currentConfigNdx];
   4153 
   4154 	try
   4155 	{
   4156 		runSample(currentSample);
   4157 		++m_iterationNdx;
   4158 	}
   4159 	catch (const UnmapFailureError& ex)
   4160 	{
   4161 		DE_UNREF(ex);
   4162 		++m_numUnmapFailures;
   4163 	}
   4164 
   4165 	if (m_numUnmapFailures > unmapFailureThreshold)
   4166 		throw tcu::TestError("Got too many unmap errors");
   4167 
   4168 	if (m_iterationNdx < (int)m_iterationOrder.size())
   4169 		return CONTINUE;
   4170 
   4171 	logAndSetTestResult(m_results);
   4172 	return STOP;
   4173 }
   4174 
   4175 template <typename SampleType>
   4176 int RenderCase<SampleType>::getMinWorkloadSize (void) const
   4177 {
   4178 	int result = getLayeredGridNumVertices(m_results[0].scene);
   4179 
   4180 	for (int ndx = 1; ndx < (int)m_results.size(); ++ndx)
   4181 	{
   4182 		const int workloadSize = getLayeredGridNumVertices(m_results[ndx].scene);
   4183 		result = de::min(result, workloadSize);
   4184 	}
   4185 
   4186 	return result;
   4187 }
   4188 
   4189 template <typename SampleType>
   4190 int RenderCase<SampleType>::getMaxWorkloadSize (void) const
   4191 {
   4192 	int result = getLayeredGridNumVertices(m_results[0].scene);
   4193 
   4194 	for (int ndx = 1; ndx < (int)m_results.size(); ++ndx)
   4195 	{
   4196 		const int workloadSize = getLayeredGridNumVertices(m_results[ndx].scene);
   4197 		result = de::max(result, workloadSize);
   4198 	}
   4199 
   4200 	return result;
   4201 }
   4202 
   4203 template <typename SampleType>
   4204 int RenderCase<SampleType>::getMinWorkloadDataSize (void) const
   4205 {
   4206 	return getMinWorkloadSize() * getVertexDataSize();
   4207 }
   4208 
   4209 template <typename SampleType>
   4210 int RenderCase<SampleType>::getMaxWorkloadDataSize (void) const
   4211 {
   4212 	return getMaxWorkloadSize() * getVertexDataSize();
   4213 }
   4214 
   4215 template <typename SampleType>
   4216 int RenderCase<SampleType>::getVertexDataSize (void) const
   4217 {
   4218 	const int numVectors	= 2;
   4219 	const int vec4Size		= 4 * sizeof(float);
   4220 
   4221 	return numVectors * vec4Size;
   4222 }
   4223 
   4224 template <typename SampleType>
   4225 int RenderCase<SampleType>::getNumSamples (void) const
   4226 {
   4227 	return (int)m_results.size();
   4228 }
   4229 
   4230 template <typename SampleType>
   4231 void RenderCase<SampleType>::uploadScene (const LayeredGridSpec& scene)
   4232 {
   4233 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   4234 
   4235 	// vertex buffer
   4236 	{
   4237 		std::vector<tcu::Vec4> vertexData;
   4238 
   4239 		generateLayeredGridVertexAttribData4C4V(vertexData, scene);
   4240 
   4241 		if (m_attributeBufferID == 0)
   4242 			gl.genBuffers(1, &m_attributeBufferID);
   4243 		gl.bindBuffer(GL_ARRAY_BUFFER, m_attributeBufferID);
   4244 		gl.bufferData(GL_ARRAY_BUFFER, (int)(vertexData.size() * sizeof(tcu::Vec4)), &vertexData[0], GL_STATIC_DRAW);
   4245 	}
   4246 
   4247 	// index buffer
   4248 	if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   4249 	{
   4250 		std::vector<deUint32> indexData;
   4251 
   4252 		generateLayeredGridIndexData(indexData, scene);
   4253 
   4254 		if (m_indexBufferID == 0)
   4255 			gl.genBuffers(1, &m_indexBufferID);
   4256 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBufferID);
   4257 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(indexData.size() * sizeof(deUint32)), &indexData[0], GL_STATIC_DRAW);
   4258 	}
   4259 
   4260 	GLU_EXPECT_NO_ERROR(gl.getError(), "create buffers");
   4261 }
   4262 
   4263 template <typename SampleType>
   4264 void RenderCase<SampleType>::logAndSetTestResult (const std::vector<SampleResult>& results)
   4265 {
   4266 	std::vector<RenderSampleResult<SampleType> > mappedResults;
   4267 
   4268 	mapResultsToRenderRateFormat(mappedResults, results);
   4269 
   4270 	{
   4271 		const RenderSampleAnalyzeResult	analysis	= analyzeSampleResults(m_testCtx.getLog(), mappedResults);
   4272 		const float						rate		= analysis.renderRateAtRange;
   4273 
   4274 		if (rate == std::numeric_limits<float>::infinity())
   4275 		{
   4276 			// sample times are 1) invalid or 2) timer resolution too low
   4277 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(0.0f, 2).c_str());
   4278 		}
   4279 		else
   4280 		{
   4281 			// report transfer rate in millions of MiB/s
   4282 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(rate / 1024.0f / 1024.0f, 2).c_str());
   4283 		}
   4284 	}
   4285 }
   4286 
   4287 template <typename SampleType>
   4288 void RenderCase<SampleType>::mapResultsToRenderRateFormat (std::vector<RenderSampleResult<SampleType> >& dst, const std::vector<SampleResult>& src) const
   4289 {
   4290 	dst.resize(src.size());
   4291 
   4292 	for (int ndx = 0; ndx < (int)src.size(); ++ndx)
   4293 		dst[ndx] = src[ndx].result;
   4294 }
   4295 
   4296 class ReferenceRenderTimeCase : public RenderCase<RenderReadDuration>
   4297 {
   4298 public:
   4299 			ReferenceRenderTimeCase		(Context& context, const char* name, const char* description, DrawMethod drawMethod);
   4300 
   4301 private:
   4302 	void	init						(void);
   4303 	void	runSample					(SampleResult& sample);
   4304 };
   4305 
   4306 ReferenceRenderTimeCase::ReferenceRenderTimeCase (Context& context, const char* name, const char* description, DrawMethod drawMethod)
   4307 	: RenderCase<RenderReadDuration>	(context, name, description, drawMethod)
   4308 {
   4309 }
   4310 
   4311 void ReferenceRenderTimeCase::init (void)
   4312 {
   4313 	const char* const targetFunctionName = (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS) ? ("drawArrays") : ("drawElements");
   4314 
   4315 	// init parent
   4316 	RenderCase<RenderReadDuration>::init();
   4317 
   4318 	// log
   4319 	m_testCtx.getLog()
   4320 		<< tcu::TestLog::Message
   4321 		<< "Measuring the time used in " << targetFunctionName << " and readPixels call with different rendering workloads.\n"
   4322 		<< getNumSamples() << " test samples. Sample order is randomized.\n"
   4323 		<< "All samples at even positions (first = 0) are tested before samples at odd positions.\n"
   4324 		<< "Generated workload is multiple viewport-covering grids with varying number of cells, each cell is two separate triangles.\n"
   4325 		<< "Workload sizes are in the range ["
   4326 			<< getMinWorkloadSize() << ",  "
   4327 			<< getMaxWorkloadSize() << "] vertices (["
   4328 			<< getHumanReadableByteSize(getMinWorkloadDataSize()) << ","
   4329 			<< getHumanReadableByteSize(getMaxWorkloadDataSize()) << "] to be processed).\n"
   4330 		<< "Test result is the approximated total processing rate in MiB / s.\n"
   4331 		<< ((m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS) ? ("Note that index array size is not included in the processed size.\n") : (""))
   4332 		<< "Note! Test result should only be used as a baseline reference result for buffer.data_upload.* test group results."
   4333 		<< tcu::TestLog::EndMessage;
   4334 }
   4335 
   4336 void ReferenceRenderTimeCase::runSample (SampleResult& sample)
   4337 {
   4338 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
   4339 	tcu::Surface			resultSurface	(RENDER_AREA_SIZE, RENDER_AREA_SIZE);
   4340 	const int				numVertices		= getLayeredGridNumVertices(sample.scene);
   4341 	const glu::Buffer		arrayBuffer		(m_context.getRenderContext());
   4342 	const glu::Buffer		indexBuffer		(m_context.getRenderContext());
   4343 	std::vector<tcu::Vec4>	vertexData;
   4344 	std::vector<deUint32>	indexData;
   4345 	deUint64				startTime;
   4346 	deUint64				endTime;
   4347 
   4348 	// generate and upload buffers
   4349 
   4350 	generateLayeredGridVertexAttribData4C4V(vertexData, sample.scene);
   4351 	gl.bindBuffer(GL_ARRAY_BUFFER, *arrayBuffer);
   4352 	gl.bufferData(GL_ARRAY_BUFFER, (int)(vertexData.size() * sizeof(tcu::Vec4)), &vertexData[0], GL_STATIC_DRAW);
   4353 
   4354 	if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   4355 	{
   4356 		generateLayeredGridIndexData(indexData, sample.scene);
   4357 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
   4358 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(indexData.size() * sizeof(deUint32)), &indexData[0], GL_STATIC_DRAW);
   4359 	}
   4360 
   4361 	setupVertexAttribs();
   4362 
   4363 	// make sure data is uploaded
   4364 
   4365 	if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   4366 		gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   4367 	else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   4368 		gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   4369 	else
   4370 		DE_ASSERT(false);
   4371 	waitGLResults();
   4372 
   4373 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   4374 	gl.clear(GL_COLOR_BUFFER_BIT);
   4375 	waitGLResults();
   4376 
   4377 	tcu::warmupCPU();
   4378 
   4379 	// Measure both draw and associated readpixels
   4380 	{
   4381 		startTime = deGetMicroseconds();
   4382 
   4383 		if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   4384 			gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   4385 		else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   4386 			gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   4387 		else
   4388 			DE_ASSERT(false);
   4389 
   4390 		endTime = deGetMicroseconds();
   4391 
   4392 		sample.result.duration.renderDuration = endTime - startTime;
   4393 	}
   4394 
   4395 	{
   4396 		startTime = deGetMicroseconds();
   4397 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
   4398 		endTime = deGetMicroseconds();
   4399 
   4400 		sample.result.duration.readDuration = endTime - startTime;
   4401 	}
   4402 
   4403 	sample.result.renderDataSize = getVertexDataSize() * sample.result.numVertices;
   4404 	sample.result.uploadedDataSize = 0;
   4405 	sample.result.unrelatedDataSize = 0;
   4406 	sample.result.duration.renderReadDuration = sample.result.duration.renderDuration + sample.result.duration.readDuration;
   4407 	sample.result.duration.totalDuration = sample.result.duration.renderDuration + sample.result.duration.readDuration;
   4408 	sample.result.duration.fitResponseDuration = sample.result.duration.renderReadDuration;
   4409 }
   4410 
   4411 class UnrelatedUploadRenderTimeCase : public RenderCase<UnrelatedUploadRenderReadDuration>
   4412 {
   4413 public:
   4414 									UnrelatedUploadRenderTimeCase	(Context& context, const char* name, const char* description, DrawMethod drawMethod, UploadMethod unrelatedUploadMethod);
   4415 
   4416 private:
   4417 	void							init							(void);
   4418 	void							runSample						(SampleResult& sample);
   4419 
   4420 	const UploadMethod				m_unrelatedUploadMethod;
   4421 };
   4422 
   4423 UnrelatedUploadRenderTimeCase::UnrelatedUploadRenderTimeCase (Context& context, const char* name, const char* description, DrawMethod drawMethod, UploadMethod unrelatedUploadMethod)
   4424 	: RenderCase<UnrelatedUploadRenderReadDuration>	(context, name, description, drawMethod)
   4425 	, m_unrelatedUploadMethod						(unrelatedUploadMethod)
   4426 {
   4427 	DE_ASSERT(m_unrelatedUploadMethod < UPLOADMETHOD_LAST);
   4428 }
   4429 
   4430 void UnrelatedUploadRenderTimeCase::init (void)
   4431 {
   4432 	const char* const	targetFunctionName	= (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS) ? ("drawArrays") : ("drawElements");
   4433 	tcu::MessageBuilder	message				(&m_testCtx.getLog());
   4434 
   4435 	// init parent
   4436 	RenderCase<UnrelatedUploadRenderReadDuration>::init();
   4437 
   4438 	// log
   4439 
   4440 	message
   4441 		<< "Measuring the time used in " << targetFunctionName << " and readPixels call with different rendering workloads.\n"
   4442 		<< "Uploading an unrelated buffer just before issuing the rendering command with "
   4443 			<< ((m_unrelatedUploadMethod != UPLOADMETHOD_BUFFER_DATA)		? ("bufferData")		:
   4444 				(m_unrelatedUploadMethod != UPLOADMETHOD_BUFFER_SUB_DATA)	? ("bufferSubData")		:
   4445 				(m_unrelatedUploadMethod != UPLOADMETHOD_MAP_BUFFER_RANGE)	? ("mapBufferRange")	:
   4446 				((const char*)DE_NULL))
   4447 			<< ".\n"
   4448 		<< getNumSamples() << " test samples. Sample order is randomized.\n"
   4449 		<< "All samples at even positions (first = 0) are tested before samples at odd positions.\n"
   4450 		<< "Generated workload is multiple viewport-covering grids with varying number of cells, each cell is two separate triangles.\n"
   4451 		<< "Workload sizes are in the range ["
   4452 			<< getMinWorkloadSize() << ",  "
   4453 			<< getMaxWorkloadSize() << "] vertices (["
   4454 			<< getHumanReadableByteSize(getMinWorkloadDataSize()) << ","
   4455 			<< getHumanReadableByteSize(getMaxWorkloadDataSize()) << "] to be processed).\n"
   4456 		<< "Unrelated upload sizes are in the range ["
   4457 			<< getHumanReadableByteSize(getMinWorkloadDataSize()) << ", "
   4458 			<< getHumanReadableByteSize(getMaxWorkloadDataSize()) << "]\n"
   4459 		<< "Test result is the approximated total processing rate in MiB / s.\n"
   4460 		<< ((m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS) ? ("Note that index array size is not included in the processed size.\n") : (""))
   4461 		<< "Note that the data size and the time used in the unrelated upload is not included in the results.\n"
   4462 		<< "Note! Test result may not be useful as is but instead should be compared against the reference.* group and upload_and_draw.*_and_unrelated_upload group results.\n"
   4463 		<< tcu::TestLog::EndMessage;
   4464 }
   4465 
   4466 void UnrelatedUploadRenderTimeCase::runSample (SampleResult& sample)
   4467 {
   4468 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
   4469 	tcu::Surface			resultSurface		(RENDER_AREA_SIZE, RENDER_AREA_SIZE);
   4470 	const int				numVertices			= getLayeredGridNumVertices(sample.scene);
   4471 	const glu::Buffer		arrayBuffer			(m_context.getRenderContext());
   4472 	const glu::Buffer		indexBuffer			(m_context.getRenderContext());
   4473 	const glu::Buffer		unrelatedBuffer		(m_context.getRenderContext());
   4474 	int						unrelatedUploadSize	= -1;
   4475 	int						renderUploadSize;
   4476 	std::vector<tcu::Vec4>	vertexData;
   4477 	std::vector<deUint32>	indexData;
   4478 	deUint64				startTime;
   4479 	deUint64				endTime;
   4480 
   4481 	// generate and upload buffers
   4482 
   4483 	generateLayeredGridVertexAttribData4C4V(vertexData, sample.scene);
   4484 	renderUploadSize = (int)(vertexData.size() * sizeof(tcu::Vec4));
   4485 
   4486 	gl.bindBuffer(GL_ARRAY_BUFFER, *arrayBuffer);
   4487 	gl.bufferData(GL_ARRAY_BUFFER, renderUploadSize, &vertexData[0], GL_STATIC_DRAW);
   4488 
   4489 	if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   4490 	{
   4491 		generateLayeredGridIndexData(indexData, sample.scene);
   4492 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
   4493 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(indexData.size() * sizeof(deUint32)), &indexData[0], GL_STATIC_DRAW);
   4494 	}
   4495 
   4496 	setupVertexAttribs();
   4497 
   4498 	// make sure data is uploaded
   4499 
   4500 	if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   4501 		gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   4502 	else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   4503 		gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   4504 	else
   4505 		DE_ASSERT(false);
   4506 	waitGLResults();
   4507 
   4508 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   4509 	gl.clear(GL_COLOR_BUFFER_BIT);
   4510 	waitGLResults();
   4511 
   4512 	tcu::warmupCPU();
   4513 
   4514 	// Unrelated upload
   4515 	if (m_unrelatedUploadMethod == UPLOADMETHOD_BUFFER_DATA)
   4516 	{
   4517 		unrelatedUploadSize = (int)(vertexData.size() * sizeof(tcu::Vec4));
   4518 
   4519 		gl.bindBuffer(GL_ARRAY_BUFFER, *unrelatedBuffer);
   4520 		gl.bufferData(GL_ARRAY_BUFFER, unrelatedUploadSize, &vertexData[0], GL_STATIC_DRAW);
   4521 	}
   4522 	else if (m_unrelatedUploadMethod == UPLOADMETHOD_BUFFER_SUB_DATA)
   4523 	{
   4524 		unrelatedUploadSize = (int)(vertexData.size() * sizeof(tcu::Vec4));
   4525 
   4526 		gl.bindBuffer(GL_ARRAY_BUFFER, *unrelatedBuffer);
   4527 		gl.bufferData(GL_ARRAY_BUFFER, unrelatedUploadSize, DE_NULL, GL_STATIC_DRAW);
   4528 		gl.bufferSubData(GL_ARRAY_BUFFER, 0, unrelatedUploadSize, &vertexData[0]);
   4529 	}
   4530 	else if (m_unrelatedUploadMethod == UPLOADMETHOD_MAP_BUFFER_RANGE)
   4531 	{
   4532 		void*			mapPtr;
   4533 		glw::GLboolean	unmapSuccessful;
   4534 
   4535 		unrelatedUploadSize = (int)(vertexData.size() * sizeof(tcu::Vec4));
   4536 
   4537 		gl.bindBuffer(GL_ARRAY_BUFFER, *unrelatedBuffer);
   4538 		gl.bufferData(GL_ARRAY_BUFFER, unrelatedUploadSize, DE_NULL, GL_STATIC_DRAW);
   4539 
   4540 		mapPtr = gl.mapBufferRange(GL_ARRAY_BUFFER, 0, unrelatedUploadSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
   4541 		if (!mapPtr)
   4542 			throw tcu::Exception("MapBufferRange returned NULL");
   4543 
   4544 		deMemcpy(mapPtr, &vertexData[0], unrelatedUploadSize);
   4545 
   4546 		// if unmapping fails, just try again later
   4547 		unmapSuccessful = gl.unmapBuffer(GL_ARRAY_BUFFER);
   4548 		if (!unmapSuccessful)
   4549 			throw UnmapFailureError();
   4550 	}
   4551 	else
   4552 		DE_ASSERT(false);
   4553 
   4554 	DE_ASSERT(unrelatedUploadSize != -1);
   4555 
   4556 	// Measure both draw and associated readpixels
   4557 	{
   4558 		startTime = deGetMicroseconds();
   4559 
   4560 		if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   4561 			gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   4562 		else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   4563 			gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   4564 		else
   4565 			DE_ASSERT(false);
   4566 
   4567 		endTime = deGetMicroseconds();
   4568 
   4569 		sample.result.duration.renderDuration = endTime - startTime;
   4570 	}
   4571 
   4572 	{
   4573 		startTime = deGetMicroseconds();
   4574 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
   4575 		endTime = deGetMicroseconds();
   4576 
   4577 		sample.result.duration.readDuration = endTime - startTime;
   4578 	}
   4579 
   4580 	sample.result.renderDataSize = getVertexDataSize() * sample.result.numVertices;
   4581 	sample.result.uploadedDataSize = renderUploadSize;
   4582 	sample.result.unrelatedDataSize = unrelatedUploadSize;
   4583 	sample.result.duration.renderReadDuration = sample.result.duration.renderDuration + sample.result.duration.readDuration;
   4584 	sample.result.duration.totalDuration = sample.result.duration.renderDuration + sample.result.duration.readDuration;
   4585 	sample.result.duration.fitResponseDuration = sample.result.duration.renderReadDuration;
   4586 }
   4587 
   4588 class ReferenceReadPixelsTimeCase : public TestCase
   4589 {
   4590 public:
   4591 					ReferenceReadPixelsTimeCase		(Context& context, const char* name, const char* description);
   4592 
   4593 private:
   4594 	void			init							(void);
   4595 	IterateResult	iterate							(void);
   4596 	void			logAndSetTestResult				(void);
   4597 
   4598 	enum
   4599 	{
   4600 		RENDER_AREA_SIZE = 128
   4601 	};
   4602 
   4603 	const int			m_numSamples;
   4604 	int					m_sampleNdx;
   4605 	std::vector<int>	m_samples;
   4606 };
   4607 
   4608 ReferenceReadPixelsTimeCase::ReferenceReadPixelsTimeCase (Context& context, const char* name, const char* description)
   4609 	: TestCase		(context, tcu::NODETYPE_PERFORMANCE, name, description)
   4610 	, m_numSamples	(20)
   4611 	, m_sampleNdx	(0)
   4612 	, m_samples		(m_numSamples)
   4613 {
   4614 }
   4615 
   4616 void ReferenceReadPixelsTimeCase::init (void)
   4617 {
   4618 	m_testCtx.getLog()
   4619 		<< tcu::TestLog::Message
   4620 		<< "Measuring the time used in a single readPixels call with " << m_numSamples << " test samples.\n"
   4621 		<< "Test result is the median of the samples in microseconds.\n"
   4622 		<< "Note! Test result should only be used as a baseline reference result for buffer.data_upload.* test group results."
   4623 		<< tcu::TestLog::EndMessage;
   4624 }
   4625 
   4626 ReferenceReadPixelsTimeCase::IterateResult ReferenceReadPixelsTimeCase::iterate (void)
   4627 {
   4628 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
   4629 	tcu::Surface			resultSurface	(RENDER_AREA_SIZE, RENDER_AREA_SIZE);
   4630 	deUint64				startTime;
   4631 	deUint64				endTime;
   4632 
   4633 	deYield();
   4634 	tcu::warmupCPU();
   4635 	deYield();
   4636 
   4637 	// "Render" something and wait for it
   4638 	gl.clearColor(0.0f, 1.0f, float(m_sampleNdx) / float(m_numSamples), 1.0f);
   4639 	gl.clear(GL_COLOR_BUFFER_BIT);
   4640 
   4641 	// wait for results
   4642 	glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
   4643 
   4644 	// measure time used in readPixels
   4645 	startTime = deGetMicroseconds();
   4646 	glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
   4647 	endTime = deGetMicroseconds();
   4648 
   4649 	m_samples[m_sampleNdx] = (int)(endTime - startTime);
   4650 
   4651 	if (++m_sampleNdx < m_numSamples)
   4652 		return CONTINUE;
   4653 
   4654 	logAndSetTestResult();
   4655 	return STOP;
   4656 }
   4657 
   4658 void ReferenceReadPixelsTimeCase::logAndSetTestResult (void)
   4659 {
   4660 	// Log sample list
   4661 	{
   4662 		m_testCtx.getLog()
   4663 			<< tcu::TestLog::SampleList("Samples", "Samples")
   4664 			<< tcu::TestLog::SampleInfo
   4665 			<< tcu::TestLog::ValueInfo("ReadTime", "ReadPixels time", "us", QP_SAMPLE_VALUE_TAG_RESPONSE)
   4666 			<< tcu::TestLog::EndSampleInfo;
   4667 
   4668 		for (int sampleNdx = 0; sampleNdx < (int)m_samples.size(); ++sampleNdx)
   4669 			m_testCtx.getLog()
   4670 				<< tcu::TestLog::Sample
   4671 				<< m_samples[sampleNdx]
   4672 				<< tcu::TestLog::EndSample;
   4673 
   4674 		m_testCtx.getLog() << tcu::TestLog::EndSampleList;
   4675 	}
   4676 
   4677 	// Log median
   4678 	{
   4679 		float median;
   4680 		float limit60Low;
   4681 		float limit60Up;
   4682 
   4683 		std::sort(m_samples.begin(), m_samples.end());
   4684 		median		= linearSample(m_samples, 0.5f);
   4685 		limit60Low	= linearSample(m_samples, 0.2f);
   4686 		limit60Up	= linearSample(m_samples, 0.8f);
   4687 
   4688 		m_testCtx.getLog()
   4689 			<< tcu::TestLog::Float("Median", "Median", "us", QP_KEY_TAG_TIME, median)
   4690 			<< tcu::TestLog::Message
   4691 			<< "60 % of samples within range:\n"
   4692 			<< tcu::TestLog::EndMessage
   4693 			<< tcu::TestLog::Float("Low60Range", "Lower", "us", QP_KEY_TAG_TIME, limit60Low)
   4694 			<< tcu::TestLog::Float("High60Range", "Upper", "us", QP_KEY_TAG_TIME, limit60Up);
   4695 
   4696 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString(median, 2).c_str());
   4697 	}
   4698 }
   4699 
   4700 template <typename SampleType>
   4701 class GenericUploadRenderTimeCase : public RenderCase<SampleType>
   4702 {
   4703 public:
   4704 	typedef typename RenderCase<SampleType>::SampleResult SampleResult;
   4705 
   4706 							GenericUploadRenderTimeCase	(Context&				context,
   4707 														 const char*			name,
   4708 														 const char*			description,
   4709 														 DrawMethod				method,
   4710 														 TargetBuffer			targetBuffer,
   4711 														 UploadMethod			uploadMethod,
   4712 														 BufferState			bufferState,
   4713 														 UploadRange			uploadRange,
   4714 														 UnrelatedBufferType	unrelatedBufferType);
   4715 
   4716 private:
   4717 	void						init					(void);
   4718 	void						runSample				(SampleResult& sample);
   4719 
   4720 	using RenderCase<SampleType>::RENDER_AREA_SIZE;
   4721 
   4722 	const TargetBuffer			m_targetBuffer;
   4723 	const BufferState			m_bufferState;
   4724 	const UploadMethod			m_uploadMethod;
   4725 	const UnrelatedBufferType	m_unrelatedBufferType;
   4726 	const UploadRange			m_uploadRange;
   4727 
   4728 	using RenderCase<SampleType>::m_context;
   4729 	using RenderCase<SampleType>::m_testCtx;
   4730 	using RenderCase<SampleType>::m_drawMethod;
   4731 };
   4732 
   4733 template <typename SampleType>
   4734 GenericUploadRenderTimeCase<SampleType>::GenericUploadRenderTimeCase (Context&				context,
   4735 																	  const char*			name,
   4736 																	  const char*			description,
   4737 																	  DrawMethod			method,
   4738 																	  TargetBuffer			targetBuffer,
   4739 																	  UploadMethod			uploadMethod,
   4740 																	  BufferState			bufferState,
   4741 																	  UploadRange			uploadRange,
   4742 																	  UnrelatedBufferType	unrelatedBufferType)
   4743 	: RenderCase<SampleType>	(context, name, description, method)
   4744 	, m_targetBuffer			(targetBuffer)
   4745 	, m_bufferState				(bufferState)
   4746 	, m_uploadMethod			(uploadMethod)
   4747 	, m_unrelatedBufferType		(unrelatedBufferType)
   4748 	, m_uploadRange				(uploadRange)
   4749 {
   4750 	DE_ASSERT(m_targetBuffer < TARGETBUFFER_LAST);
   4751 	DE_ASSERT(m_bufferState < BUFFERSTATE_LAST);
   4752 	DE_ASSERT(m_uploadMethod < UPLOADMETHOD_LAST);
   4753 	DE_ASSERT(m_unrelatedBufferType < UNRELATEDBUFFERTYPE_LAST);
   4754 	DE_ASSERT(m_uploadRange < UPLOADRANGE_LAST);
   4755 }
   4756 
   4757 template <typename SampleType>
   4758 void GenericUploadRenderTimeCase<SampleType>::init (void)
   4759 {
   4760 	// init parent
   4761 	RenderCase<SampleType>::init();
   4762 
   4763 	// log
   4764 	{
   4765 		const char* const	targetFunctionName		= (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS) ? ("drawArrays") : ("drawElements");
   4766 		const int			perVertexSize			= (m_targetBuffer == TARGETBUFFER_INDEX) ? ((int)sizeof(deUint32)) : ((int)sizeof(tcu::Vec4[2]));
   4767 		const int			fullMinUploadSize		= RenderCase<SampleType>::getMinWorkloadSize() * perVertexSize;
   4768 		const int			fullMaxUploadSize		= RenderCase<SampleType>::getMaxWorkloadSize() * perVertexSize;
   4769 		const int			minUploadSize			= (m_uploadRange == UPLOADRANGE_FULL) ? (fullMinUploadSize) : (deAlign32(fullMinUploadSize/2, 4));
   4770 		const int			maxUploadSize			= (m_uploadRange == UPLOADRANGE_FULL) ? (fullMaxUploadSize) : (deAlign32(fullMaxUploadSize/2, 4));
   4771 		const int			minUnrelatedUploadSize	= RenderCase<SampleType>::getMinWorkloadSize() * (int)sizeof(tcu::Vec4[2]);
   4772 		const int			maxUnrelatedUploadSize	= RenderCase<SampleType>::getMaxWorkloadSize() * (int)sizeof(tcu::Vec4[2]);
   4773 
   4774 		m_testCtx.getLog()
   4775 			<< tcu::TestLog::Message
   4776 			<< "Measuring the time used in " << targetFunctionName << " and readPixels call with different rendering workloads.\n"
   4777 			<< "The "
   4778 				<< ((m_targetBuffer == TARGETBUFFER_INDEX) ? ("index") : ("vertex attrib"))
   4779 				<< " buffer "
   4780 				<< ((m_bufferState == BUFFERSTATE_NEW) ? ("") : ("contents "))
   4781 				<< "sourced by the rendering command "
   4782 				<< ((m_bufferState == BUFFERSTATE_NEW)		? ("is uploaded ") :
   4783 					(m_uploadRange == UPLOADRANGE_FULL)		? ("are specified ") :
   4784 					(m_uploadRange == UPLOADRANGE_PARTIAL)	? ("are updated (partial upload) ") :
   4785 					((const char*)DE_NULL))
   4786 				<< "just before issuing the rendering command.\n"
   4787 			<< ((m_bufferState == BUFFERSTATE_EXISTING) ? ("The buffer has been used in rendering.\n") : ("The buffer is generated just before uploading.\n"))
   4788 			<< "Buffer "
   4789 				<< ((m_bufferState == BUFFERSTATE_NEW)		? ("is uploaded") :
   4790 					(m_uploadRange == UPLOADRANGE_FULL)		? ("contents are specified") :
   4791 					(m_uploadRange == UPLOADRANGE_PARTIAL)	? ("contents are partially updated") :
   4792 					((const char*)DE_NULL))
   4793 				<< " with "
   4794 				<< ((m_uploadMethod == UPLOADMETHOD_BUFFER_DATA) ? ("bufferData") : (m_uploadMethod == UPLOADMETHOD_BUFFER_SUB_DATA) ? ("bufferSubData") : ("mapBufferRange"))
   4795 				<< " command. Usage of the target buffer is DYNAMIC_DRAW.\n"
   4796 			<< ((m_uploadMethod == UPLOADMETHOD_MAP_BUFFER_RANGE) ? ("Mapping buffer with bits MAP_WRITE_BIT | MAP_INVALIDATE_RANGE_BIT | MAP_INVALIDATE_BUFFER_BIT | MAP_UNSYNCHRONIZED_BIT\n") : (""))
   4797 			<< ((m_unrelatedBufferType == UNRELATEDBUFFERTYPE_VERTEX) ? ("Uploading an unrelated buffer just before issuing the rendering command with bufferData.\n") : (""))
   4798 			<< RenderCase<SampleType>::getNumSamples() << " test samples. Sample order is randomized.\n"
   4799 			<< "All samples at even positions (first = 0) are tested before samples at odd positions.\n"
   4800 			<< "Generated workload is multiple viewport-covering grids with varying number of cells, each cell is two separate triangles.\n"
   4801 			<< "Workload sizes are in the range ["
   4802 				<< RenderCase<SampleType>::getMinWorkloadSize() << ",  "
   4803 				<< RenderCase<SampleType>::getMaxWorkloadSize() << "] vertices "
   4804 				<< "(["
   4805 				<< getHumanReadableByteSize(RenderCase<SampleType>::getMinWorkloadDataSize()) << ","
   4806 				<< getHumanReadableByteSize(RenderCase<SampleType>::getMaxWorkloadDataSize()) << "] to be processed).\n"
   4807 			<< "Upload sizes are in the range ["
   4808 				<< getHumanReadableByteSize(minUploadSize) << ","
   4809 				<< getHumanReadableByteSize(maxUploadSize) << "].\n"
   4810 			<< ((m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS) ?
   4811 				("Unrelated upload sizes are in the range [" + getHumanReadableByteSize(minUnrelatedUploadSize) + ", " + getHumanReadableByteSize(maxUnrelatedUploadSize) + "]\n") :
   4812 				(""))
   4813 			<< "Test result is the approximated processing rate in MiB / s.\n"
   4814 			<< "Note that while upload time is measured, the time used is not included in the results.\n"
   4815 			<< ((m_unrelatedBufferType == UNRELATEDBUFFERTYPE_VERTEX) ? ("Note that the data size and the time used in the unrelated upload is not included in the results.\n") : (""))
   4816 			<< ((m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS) ? ("Note that index array size is not included in the processed size.\n") : (""))
   4817 			<< "Note! Test result may not be useful as is but instead should be compared against the reference.* group and other upload_and_draw.* group results.\n"
   4818 			<< tcu::TestLog::EndMessage;
   4819 	}
   4820 }
   4821 
   4822 template <typename SampleType>
   4823 void GenericUploadRenderTimeCase<SampleType>::runSample (SampleResult& sample)
   4824 {
   4825 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
   4826 	const glu::Buffer		arrayBuffer			(m_context.getRenderContext());
   4827 	const glu::Buffer		indexBuffer			(m_context.getRenderContext());
   4828 	const glu::Buffer		unrelatedBuffer		(m_context.getRenderContext());
   4829 	const int				numVertices			= getLayeredGridNumVertices(sample.scene);
   4830 	tcu::Surface			resultSurface		(RENDER_AREA_SIZE, RENDER_AREA_SIZE);
   4831 	deUint64				startTime;
   4832 	deUint64				endTime;
   4833 	std::vector<tcu::Vec4>	vertexData;
   4834 	std::vector<deUint32>	indexData;
   4835 
   4836 	// create data
   4837 
   4838 	generateLayeredGridVertexAttribData4C4V(vertexData, sample.scene);
   4839 	if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   4840 		generateLayeredGridIndexData(indexData, sample.scene);
   4841 
   4842 	gl.bindBuffer(GL_ARRAY_BUFFER, *arrayBuffer);
   4843 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
   4844 	RenderCase<SampleType>::setupVertexAttribs();
   4845 
   4846 	// target should be an exisiting buffer? Draw from it once to make sure it exists on the gpu
   4847 
   4848 	if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS && m_bufferState == BUFFERSTATE_EXISTING)
   4849 	{
   4850 		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(vertexData.size() * sizeof(tcu::Vec4)), &vertexData[0], GL_DYNAMIC_DRAW);
   4851 		gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   4852 	}
   4853 	else if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS && m_bufferState == BUFFERSTATE_NEW)
   4854 	{
   4855 		// do not touch the vertex buffer
   4856 	}
   4857 	else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS && m_bufferState == BUFFERSTATE_EXISTING)
   4858 	{
   4859 		// hint that the target buffer will be modified soon
   4860 		const glw::GLenum vertexDataUsage	= (m_targetBuffer == TARGETBUFFER_VERTEX) ? (GL_DYNAMIC_DRAW) : (GL_STATIC_DRAW);
   4861 		const glw::GLenum indexDataUsage	= (m_targetBuffer == TARGETBUFFER_INDEX) ? (GL_DYNAMIC_DRAW) : (GL_STATIC_DRAW);
   4862 
   4863 		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(vertexData.size() * sizeof(tcu::Vec4)), &vertexData[0], vertexDataUsage);
   4864 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indexData.size() * sizeof(deUint32)), &indexData[0], indexDataUsage);
   4865 		gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   4866 	}
   4867 	else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS && m_bufferState == BUFFERSTATE_NEW)
   4868 	{
   4869 		if (m_targetBuffer == TARGETBUFFER_VERTEX)
   4870 		{
   4871 			// make the index buffer present on the gpu
   4872 			// use another vertex buffer to keep original buffer in unused state
   4873 			const glu::Buffer vertexCopyBuffer(m_context.getRenderContext());
   4874 
   4875 			gl.bindBuffer(GL_ARRAY_BUFFER, *vertexCopyBuffer);
   4876 			RenderCase<SampleType>::setupVertexAttribs();
   4877 
   4878 			gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(vertexData.size() * sizeof(tcu::Vec4)), &vertexData[0], GL_STATIC_DRAW);
   4879 			gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indexData.size() * sizeof(deUint32)), &indexData[0], GL_STATIC_DRAW);
   4880 			gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   4881 
   4882 			// restore original state
   4883 			gl.bindBuffer(GL_ARRAY_BUFFER, *arrayBuffer);
   4884 			RenderCase<SampleType>::setupVertexAttribs();
   4885 		}
   4886 		else if (m_targetBuffer == TARGETBUFFER_INDEX)
   4887 		{
   4888 			// make the vertex buffer present on the gpu
   4889 			gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(vertexData.size() * sizeof(tcu::Vec4)), &vertexData[0], GL_STATIC_DRAW);
   4890 			gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   4891 		}
   4892 		else
   4893 			DE_ASSERT(false);
   4894 	}
   4895 	else
   4896 		DE_ASSERT(false);
   4897 
   4898 	RenderCase<SampleType>::waitGLResults();
   4899 	GLU_EXPECT_NO_ERROR(gl.getError(), "post buffer prepare");
   4900 
   4901 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   4902 	gl.clear(GL_COLOR_BUFFER_BIT);
   4903 	RenderCase<SampleType>::waitGLResults();
   4904 
   4905 	tcu::warmupCPU();
   4906 
   4907 	// upload
   4908 
   4909 	{
   4910 		glw::GLenum		target;
   4911 		glw::GLsizeiptr	size;
   4912 		glw::GLintptr	offset = 0;
   4913 		const void*		source;
   4914 
   4915 		if (m_targetBuffer == TARGETBUFFER_VERTEX && m_uploadRange == UPLOADRANGE_FULL)
   4916 		{
   4917 			target	= GL_ARRAY_BUFFER;
   4918 			size	= (glw::GLsizeiptr)(vertexData.size() * sizeof(tcu::Vec4));
   4919 			source	= &vertexData[0];
   4920 		}
   4921 		else if (m_targetBuffer == TARGETBUFFER_INDEX && m_uploadRange == UPLOADRANGE_FULL)
   4922 		{
   4923 			target	= GL_ELEMENT_ARRAY_BUFFER;
   4924 			size	= (glw::GLsizeiptr)(indexData.size() * sizeof(deUint32));
   4925 			source	= &indexData[0];
   4926 		}
   4927 		else if (m_targetBuffer == TARGETBUFFER_VERTEX && m_uploadRange == UPLOADRANGE_PARTIAL)
   4928 		{
   4929 			DE_ASSERT(m_bufferState == BUFFERSTATE_EXISTING);
   4930 
   4931 			target	= GL_ARRAY_BUFFER;
   4932 			size	= (glw::GLsizeiptr)deAlign32((int)(vertexData.size() * sizeof(tcu::Vec4)) / 2, 4);
   4933 			offset	= (glw::GLintptr)deAlign32((int)size / 2, 4);
   4934 			source	= (const deUint8*)&vertexData[0] + offset;
   4935 		}
   4936 		else if (m_targetBuffer == TARGETBUFFER_INDEX && m_uploadRange == UPLOADRANGE_PARTIAL)
   4937 		{
   4938 			DE_ASSERT(m_bufferState == BUFFERSTATE_EXISTING);
   4939 
   4940 			// upload to 25% - 75% range
   4941 			target	= GL_ELEMENT_ARRAY_BUFFER;
   4942 			size	= (glw::GLsizeiptr)deAlign32((deInt32)(indexData.size() * sizeof(deUint32)) / 2, 4);
   4943 			offset	= (glw::GLintptr)deAlign32((int)size / 2, 4);
   4944 			source	= (const deUint8*)&indexData[0] + offset;
   4945 		}
   4946 		else
   4947 		{
   4948 			DE_ASSERT(false);
   4949 			return;
   4950 		}
   4951 
   4952 		startTime = deGetMicroseconds();
   4953 
   4954 		if (m_uploadMethod == UPLOADMETHOD_BUFFER_DATA)
   4955 			gl.bufferData(target, size, source, GL_DYNAMIC_DRAW);
   4956 		else if (m_uploadMethod == UPLOADMETHOD_BUFFER_SUB_DATA)
   4957 		{
   4958 			// create buffer storage
   4959 			if (m_bufferState == BUFFERSTATE_NEW)
   4960 				gl.bufferData(target, size, DE_NULL, GL_DYNAMIC_DRAW);
   4961 			gl.bufferSubData(target, offset, size, source);
   4962 		}
   4963 		else if (m_uploadMethod == UPLOADMETHOD_MAP_BUFFER_RANGE)
   4964 		{
   4965 			void*			mapPtr;
   4966 			glw::GLboolean	unmapSuccessful;
   4967 
   4968 			// create buffer storage
   4969 			if (m_bufferState == BUFFERSTATE_NEW)
   4970 				gl.bufferData(target, size, DE_NULL, GL_DYNAMIC_DRAW);
   4971 
   4972 			mapPtr = gl.mapBufferRange(target, offset, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
   4973 			if (!mapPtr)
   4974 				throw tcu::Exception("MapBufferRange returned NULL");
   4975 
   4976 			deMemcpy(mapPtr, source, (int)size);
   4977 
   4978 			// if unmapping fails, just try again later
   4979 			unmapSuccessful = gl.unmapBuffer(target);
   4980 			if (!unmapSuccessful)
   4981 				throw UnmapFailureError();
   4982 		}
   4983 		else
   4984 			DE_ASSERT(false);
   4985 
   4986 		endTime = deGetMicroseconds();
   4987 
   4988 		sample.result.uploadedDataSize = (int)size;
   4989 		sample.result.duration.uploadDuration = endTime - startTime;
   4990 	}
   4991 
   4992 	// unrelated
   4993 	if (m_unrelatedBufferType == UNRELATEDBUFFERTYPE_VERTEX)
   4994 	{
   4995 		const int unrelatedUploadSize = (int)(vertexData.size() * sizeof(tcu::Vec4));
   4996 
   4997 		gl.bindBuffer(GL_ARRAY_BUFFER, *unrelatedBuffer);
   4998 		gl.bufferData(GL_ARRAY_BUFFER, unrelatedUploadSize, &vertexData[0], GL_STATIC_DRAW);
   4999 		// Attibute pointers are not modified, no need restore state
   5000 
   5001 		sample.result.unrelatedDataSize = unrelatedUploadSize;
   5002 	}
   5003 
   5004 	// draw
   5005 	{
   5006 		startTime = deGetMicroseconds();
   5007 
   5008 		if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   5009 			gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   5010 		else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5011 			gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   5012 		else
   5013 			DE_ASSERT(false);
   5014 
   5015 		endTime = deGetMicroseconds();
   5016 
   5017 		sample.result.duration.renderDuration = endTime - startTime;
   5018 	}
   5019 
   5020 	// read
   5021 	{
   5022 		startTime = deGetMicroseconds();
   5023 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
   5024 		endTime = deGetMicroseconds();
   5025 
   5026 		sample.result.duration.readDuration = endTime - startTime;
   5027 	}
   5028 
   5029 	// set results
   5030 
   5031 	sample.result.renderDataSize = RenderCase<SampleType>::getVertexDataSize() * sample.result.numVertices;
   5032 
   5033 	sample.result.duration.renderReadDuration = sample.result.duration.renderDuration + sample.result.duration.readDuration;
   5034 	sample.result.duration.totalDuration = sample.result.duration.uploadDuration + sample.result.duration.renderDuration + sample.result.duration.readDuration;
   5035 	sample.result.duration.fitResponseDuration = sample.result.duration.renderReadDuration;
   5036 }
   5037 
   5038 class BufferInUseRenderTimeCase : public RenderCase<RenderUploadRenderReadDuration>
   5039 {
   5040 public:
   5041 	enum MapFlags
   5042 	{
   5043 		MAPFLAG_NONE = 0,
   5044 		MAPFLAG_INVALIDATE_BUFFER,
   5045 		MAPFLAG_INVALIDATE_RANGE,
   5046 
   5047 		MAPFLAG_LAST
   5048 	};
   5049 	enum UploadBufferTarget
   5050 	{
   5051 		UPLOADBUFFERTARGET_DIFFERENT_BUFFER = 0,
   5052 		UPLOADBUFFERTARGET_SAME_BUFFER,
   5053 
   5054 		UPLOADBUFFERTARGET_LAST
   5055 	};
   5056 								BufferInUseRenderTimeCase	(Context&			context,
   5057 															 const char*		name,
   5058 															 const char*		description,
   5059 															 DrawMethod			method,
   5060 															 MapFlags			mapFlags,
   5061 															 TargetBuffer		targetBuffer,
   5062 															 UploadMethod		uploadMethod,
   5063 															 UploadRange		uploadRange,
   5064 															 UploadBufferTarget	uploadTarget);
   5065 
   5066 private:
   5067 	void						init						(void);
   5068 	void						runSample					(SampleResult& sample);
   5069 
   5070 	const TargetBuffer			m_targetBuffer;
   5071 	const UploadMethod			m_uploadMethod;
   5072 	const UploadRange			m_uploadRange;
   5073 	const MapFlags				m_mapFlags;
   5074 	const UploadBufferTarget	m_uploadBufferTarget;
   5075 };
   5076 
   5077 BufferInUseRenderTimeCase::BufferInUseRenderTimeCase (Context&				context,
   5078 													  const char*			name,
   5079 													  const char*			description,
   5080 													  DrawMethod			method,
   5081 													  MapFlags				mapFlags,
   5082 													  TargetBuffer			targetBuffer,
   5083 													  UploadMethod			uploadMethod,
   5084 													  UploadRange			uploadRange,
   5085 													  UploadBufferTarget	uploadTarget)
   5086 	: RenderCase<RenderUploadRenderReadDuration>	(context, name, description, method)
   5087 	, m_targetBuffer								(targetBuffer)
   5088 	, m_uploadMethod								(uploadMethod)
   5089 	, m_uploadRange									(uploadRange)
   5090 	, m_mapFlags									(mapFlags)
   5091 	, m_uploadBufferTarget							(uploadTarget)
   5092 {
   5093 	DE_ASSERT(m_targetBuffer < TARGETBUFFER_LAST);
   5094 	DE_ASSERT(m_uploadMethod < UPLOADMETHOD_LAST);
   5095 	DE_ASSERT(m_uploadRange < UPLOADRANGE_LAST);
   5096 	DE_ASSERT(m_mapFlags < MAPFLAG_LAST);
   5097 	DE_ASSERT(m_uploadBufferTarget < UPLOADBUFFERTARGET_LAST);
   5098 }
   5099 
   5100 void BufferInUseRenderTimeCase::init (void)
   5101 {
   5102 	RenderCase<RenderUploadRenderReadDuration>::init();
   5103 
   5104 	// log
   5105 	{
   5106 		const char* const	targetFunctionName		= (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS) ? ("drawArrays") : ("drawElements");
   5107 		const char* const	uploadFunctionName		= (m_uploadMethod == UPLOADMETHOD_BUFFER_DATA) ? ("bufferData") : (m_uploadMethod == UPLOADMETHOD_BUFFER_SUB_DATA) ? ("bufferSubData") : ("mapBufferRange");
   5108 		const bool			isReferenceCase			= (m_uploadBufferTarget == UPLOADBUFFERTARGET_DIFFERENT_BUFFER);
   5109 		tcu::MessageBuilder	message					(&m_testCtx.getLog());
   5110 
   5111 		message	<< "Measuring the time used in " << targetFunctionName << " call, a buffer upload, "
   5112 				<< targetFunctionName << " call using the uploaded buffer and readPixels call with different upload sizes.\n";
   5113 
   5114 		if (isReferenceCase)
   5115 			message << "Rendering:\n"
   5116 					<< "    before test: create and use buffers B and C\n"
   5117 					<< "    first draw: render using buffer B\n"
   5118 					<< ((m_uploadRange == UPLOADRANGE_FULL)		? ("    upload: respecify buffer C contents\n")	:
   5119 						(m_uploadRange == UPLOADRANGE_PARTIAL)	? ("    upload: modify buffer C contents\n")	:
   5120 						((const char*)DE_NULL))
   5121 					<< "    second draw: render using buffer C\n"
   5122 					<< "    read: readPixels\n";
   5123 		else
   5124 			message << "Rendering:\n"
   5125 					<< "    before test: create and use buffer B\n"
   5126 					<< "    first draw: render using buffer B\n"
   5127 					<< ((m_uploadRange == UPLOADRANGE_FULL)		? ("    upload: respecify buffer B contents\n")	:
   5128 						(m_uploadRange == UPLOADRANGE_PARTIAL)	? ("    upload: modify buffer B contents\n")	:
   5129 						((const char*)DE_NULL))
   5130 					<< "    second draw: render using buffer B\n"
   5131 					<< "    read: readPixels\n";
   5132 
   5133 		message	<< "Uploading using " << uploadFunctionName
   5134 					<< ((m_mapFlags == MAPFLAG_INVALIDATE_RANGE)	? (", flags = MAP_WRITE_BIT | MAP_INVALIDATE_RANGE_BIT")	:
   5135 						(m_mapFlags == MAPFLAG_INVALIDATE_BUFFER)	? (", flags = MAP_WRITE_BIT | MAP_INVALIDATE_BUFFER_BIT")	:
   5136 						(m_mapFlags == MAPFLAG_NONE)				? ("")														:
   5137 						((const char*)DE_NULL))
   5138 					<< "\n"
   5139 				<< getNumSamples() << " test samples. Sample order is randomized.\n"
   5140 				<< "All samples at even positions (first = 0) are tested before samples at odd positions.\n"
   5141 				<< "Workload sizes are in the range ["
   5142 					<< getMinWorkloadSize() << ",  "
   5143 					<< getMaxWorkloadSize() << "] vertices "
   5144 					<< "(["
   5145 					<< getHumanReadableByteSize(getMinWorkloadDataSize()) << ","
   5146 					<< getHumanReadableByteSize(getMaxWorkloadDataSize()) << "] to be processed).\n"
   5147 				<< "Test result is the approximated processing rate in MiB / s of the second draw call and the readPixels call.\n";
   5148 
   5149 		if (isReferenceCase)
   5150 			message	<< "Note! Test result should only be used as a baseline reference result for buffer.render_after_upload.draw_modify_draw test group results.";
   5151 		else
   5152 			message	<< "Note! Test result may not be useful as is but instead should be compared against the buffer.render_after_upload.reference.draw_upload_draw group results.\n";
   5153 
   5154 		message << tcu::TestLog::EndMessage;
   5155 	}
   5156 }
   5157 
   5158 void BufferInUseRenderTimeCase::runSample (SampleResult& sample)
   5159 {
   5160 	const glw::Functions&	gl						= m_context.getRenderContext().getFunctions();
   5161 	const glu::Buffer		arrayBuffer				(m_context.getRenderContext());
   5162 	const glu::Buffer		indexBuffer				(m_context.getRenderContext());
   5163 	const glu::Buffer		alternativeUploadBuffer	(m_context.getRenderContext());
   5164 	const int				numVertices				= getLayeredGridNumVertices(sample.scene);
   5165 	tcu::Surface			resultSurface			(RENDER_AREA_SIZE, RENDER_AREA_SIZE);
   5166 	deUint64				startTime;
   5167 	deUint64				endTime;
   5168 	std::vector<tcu::Vec4>	vertexData;
   5169 	std::vector<deUint32>	indexData;
   5170 
   5171 	// create data
   5172 
   5173 	generateLayeredGridVertexAttribData4C4V(vertexData, sample.scene);
   5174 	if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5175 		generateLayeredGridIndexData(indexData, sample.scene);
   5176 
   5177 	// make buffers used
   5178 
   5179 	gl.bindBuffer(GL_ARRAY_BUFFER, *arrayBuffer);
   5180 	gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
   5181 	setupVertexAttribs();
   5182 
   5183 	if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   5184 	{
   5185 		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(vertexData.size() * sizeof(tcu::Vec4)), &vertexData[0], GL_STREAM_DRAW);
   5186 		gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   5187 	}
   5188 	else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5189 	{
   5190 		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(vertexData.size() * sizeof(tcu::Vec4)), &vertexData[0], GL_STREAM_DRAW);
   5191 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indexData.size() * sizeof(deUint32)), &indexData[0], GL_STREAM_DRAW);
   5192 		gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   5193 	}
   5194 	else
   5195 		DE_ASSERT(false);
   5196 
   5197 	// another pair of buffers for reference case
   5198 	if (m_uploadBufferTarget == UPLOADBUFFERTARGET_DIFFERENT_BUFFER)
   5199 	{
   5200 		if (m_targetBuffer == TARGETBUFFER_VERTEX)
   5201 		{
   5202 			gl.bindBuffer(GL_ARRAY_BUFFER, *alternativeUploadBuffer);
   5203 			gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(vertexData.size() * sizeof(tcu::Vec4)), &vertexData[0], GL_STREAM_DRAW);
   5204 
   5205 			setupVertexAttribs();
   5206 			gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   5207 		}
   5208 		else if (m_targetBuffer == TARGETBUFFER_INDEX)
   5209 		{
   5210 			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *alternativeUploadBuffer);
   5211 			gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indexData.size() * sizeof(deUint32)), &indexData[0], GL_STREAM_DRAW);
   5212 			gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   5213 		}
   5214 		else
   5215 			DE_ASSERT(false);
   5216 
   5217 		// restore state
   5218 		gl.bindBuffer(GL_ARRAY_BUFFER, *arrayBuffer);
   5219 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
   5220 		setupVertexAttribs();
   5221 	}
   5222 
   5223 	waitGLResults();
   5224 	GLU_EXPECT_NO_ERROR(gl.getError(), "post buffer prepare");
   5225 
   5226 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   5227 	gl.clear(GL_COLOR_BUFFER_BIT);
   5228 	waitGLResults();
   5229 
   5230 	tcu::warmupCPU();
   5231 
   5232 	// first draw
   5233 	{
   5234 		startTime = deGetMicroseconds();
   5235 
   5236 		if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   5237 			gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   5238 		else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5239 			gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   5240 		else
   5241 			DE_ASSERT(false);
   5242 
   5243 		endTime = deGetMicroseconds();
   5244 
   5245 		sample.result.duration.firstRenderDuration = endTime - startTime;
   5246 	}
   5247 
   5248 	// upload
   5249 	{
   5250 		glw::GLenum		target;
   5251 		glw::GLsizeiptr	size;
   5252 		glw::GLintptr	offset = 0;
   5253 		const void*		source;
   5254 
   5255 		if (m_targetBuffer == TARGETBUFFER_VERTEX && m_uploadRange == UPLOADRANGE_FULL)
   5256 		{
   5257 			target	= GL_ARRAY_BUFFER;
   5258 			size	= (glw::GLsizeiptr)(vertexData.size() * sizeof(tcu::Vec4));
   5259 			source	= &vertexData[0];
   5260 		}
   5261 		else if (m_targetBuffer == TARGETBUFFER_INDEX && m_uploadRange == UPLOADRANGE_FULL)
   5262 		{
   5263 			target	= GL_ELEMENT_ARRAY_BUFFER;
   5264 			size	= (glw::GLsizeiptr)(indexData.size() * sizeof(deUint32));
   5265 			source	= &indexData[0];
   5266 		}
   5267 		else if (m_targetBuffer == TARGETBUFFER_VERTEX && m_uploadRange == UPLOADRANGE_PARTIAL)
   5268 		{
   5269 			target	= GL_ARRAY_BUFFER;
   5270 			size	= (glw::GLsizeiptr)deAlign32((int)(vertexData.size() * sizeof(tcu::Vec4)) / 2, 4);
   5271 			offset	= (glw::GLintptr)deAlign32((int)size / 2, 4);
   5272 			source	= (const deUint8*)&vertexData[0] + offset;
   5273 		}
   5274 		else if (m_targetBuffer == TARGETBUFFER_INDEX && m_uploadRange == UPLOADRANGE_PARTIAL)
   5275 		{
   5276 			// upload to 25% - 75% range
   5277 			target	= GL_ELEMENT_ARRAY_BUFFER;
   5278 			size	= (glw::GLsizeiptr)deAlign32((deInt32)(indexData.size() * sizeof(deUint32)) / 2, 4);
   5279 			offset	= (glw::GLintptr)deAlign32((int)size / 2, 4);
   5280 			source	= (const deUint8*)&indexData[0] + offset;
   5281 		}
   5282 		else
   5283 		{
   5284 			DE_ASSERT(false);
   5285 			return;
   5286 		}
   5287 
   5288 		// reference case? don't modify the buffer in use
   5289 		if (m_uploadBufferTarget == UPLOADBUFFERTARGET_DIFFERENT_BUFFER)
   5290 			gl.bindBuffer(target, *alternativeUploadBuffer);
   5291 
   5292 		startTime = deGetMicroseconds();
   5293 
   5294 		if (m_uploadMethod == UPLOADMETHOD_BUFFER_DATA)
   5295 			gl.bufferData(target, size, source, GL_STREAM_DRAW);
   5296 		else if (m_uploadMethod == UPLOADMETHOD_BUFFER_SUB_DATA)
   5297 			gl.bufferSubData(target, offset, size, source);
   5298 		else if (m_uploadMethod == UPLOADMETHOD_MAP_BUFFER_RANGE)
   5299 		{
   5300 			const int		mapFlags	= (m_mapFlags == MAPFLAG_INVALIDATE_BUFFER)	? (GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)	:
   5301 										  (m_mapFlags == MAPFLAG_INVALIDATE_RANGE)	? (GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT)	:
   5302 										  (-1);
   5303 			void*			mapPtr;
   5304 			glw::GLboolean	unmapSuccessful;
   5305 
   5306 			mapPtr = gl.mapBufferRange(target, offset, size, mapFlags);
   5307 			if (!mapPtr)
   5308 				throw tcu::Exception("MapBufferRange returned NULL");
   5309 
   5310 			deMemcpy(mapPtr, source, (int)size);
   5311 
   5312 			// if unmapping fails, just try again later
   5313 			unmapSuccessful = gl.unmapBuffer(target);
   5314 			if (!unmapSuccessful)
   5315 				throw UnmapFailureError();
   5316 		}
   5317 		else
   5318 			DE_ASSERT(false);
   5319 
   5320 		endTime = deGetMicroseconds();
   5321 
   5322 		sample.result.uploadedDataSize = (int)size;
   5323 		sample.result.duration.uploadDuration = endTime - startTime;
   5324 	}
   5325 
   5326 	// second draw
   5327 	{
   5328 		// Source vertex data from alternative buffer in refernce case
   5329 		if (m_uploadBufferTarget == UPLOADBUFFERTARGET_DIFFERENT_BUFFER && m_targetBuffer == TARGETBUFFER_VERTEX)
   5330 			setupVertexAttribs();
   5331 
   5332 		startTime = deGetMicroseconds();
   5333 
   5334 		if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   5335 			gl.drawArrays(GL_TRIANGLES, 0, numVertices);
   5336 		else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5337 			gl.drawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_INT, DE_NULL);
   5338 		else
   5339 			DE_ASSERT(false);
   5340 
   5341 		endTime = deGetMicroseconds();
   5342 
   5343 		sample.result.duration.secondRenderDuration = endTime - startTime;
   5344 	}
   5345 
   5346 	// read
   5347 	{
   5348 		startTime = deGetMicroseconds();
   5349 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
   5350 		endTime = deGetMicroseconds();
   5351 
   5352 		sample.result.duration.readDuration = endTime - startTime;
   5353 	}
   5354 
   5355 	// set results
   5356 
   5357 	sample.result.renderDataSize = getVertexDataSize() * sample.result.numVertices;
   5358 
   5359 	sample.result.duration.renderReadDuration	= sample.result.duration.secondRenderDuration + sample.result.duration.readDuration;
   5360 	sample.result.duration.totalDuration		= sample.result.duration.firstRenderDuration +
   5361 												  sample.result.duration.uploadDuration +
   5362 												  sample.result.duration.secondRenderDuration +
   5363 												  sample.result.duration.readDuration;
   5364 	sample.result.duration.fitResponseDuration	= sample.result.duration.renderReadDuration;
   5365 }
   5366 
   5367 class UploadWaitDrawCase : public RenderPerformanceTestBase
   5368 {
   5369 public:
   5370 	struct Sample
   5371 	{
   5372 		int			numFrames;
   5373 		deUint64	uploadCallEndTime;
   5374 	};
   5375 	struct Result
   5376 	{
   5377 		deUint64	uploadDuration;
   5378 		deUint64	renderDuration;
   5379 		deUint64	readDuration;
   5380 		deUint64	renderReadDuration;
   5381 
   5382 		deUint64	timeBeforeUse;
   5383 	};
   5384 
   5385 							UploadWaitDrawCase				(Context&		context,
   5386 															 const char*	name,
   5387 															 const char*	description,
   5388 															 DrawMethod		drawMethod,
   5389 															 TargetBuffer	targetBuffer,
   5390 															 UploadMethod	uploadMethod,
   5391 															 BufferState	bufferState);
   5392 							~UploadWaitDrawCase				(void);
   5393 
   5394 private:
   5395 	void					init							(void);
   5396 	void					deinit							(void);
   5397 	IterateResult			iterate							(void);
   5398 
   5399 	void					uploadBuffer					(Sample& sample, Result& result);
   5400 	void					drawFromBuffer					(Sample& sample, Result& result);
   5401 	void					reuseAndDeleteBuffer			(void);
   5402 	void					logAndSetTestResult				(void);
   5403 	void					logSamples						(void);
   5404 	void					drawMisc						(void);
   5405 	int						findStabilizationSample			(deUint64 (Result::*target), const char* description);
   5406 	bool					checkSampleTemporalStability	(deUint64 (Result::*target), const char* description);
   5407 
   5408 	const DrawMethod		m_drawMethod;
   5409 	const TargetBuffer		m_targetBuffer;
   5410 	const UploadMethod		m_uploadMethod;
   5411 	const BufferState		m_bufferState;
   5412 
   5413 	const int				m_numSamplesPerSwap;
   5414 	const int				m_numMaxSwaps;
   5415 
   5416 	int						m_frameNdx;
   5417 	int						m_sampleNdx;
   5418 	int						m_numVertices;
   5419 
   5420 	std::vector<tcu::Vec4>	m_vertexData;
   5421 	std::vector<deUint32>	m_indexData;
   5422 	std::vector<Sample>		m_samples;
   5423 	std::vector<Result>		m_results;
   5424 	std::vector<int>		m_iterationOrder;
   5425 
   5426 	deUint32				m_vertexBuffer;
   5427 	deUint32				m_indexBuffer;
   5428 	deUint32				m_miscBuffer;
   5429 	int						m_numMiscVertices;
   5430 };
   5431 
   5432 UploadWaitDrawCase::UploadWaitDrawCase (Context&		context,
   5433 										const char*		name,
   5434 										const char*		description,
   5435 										DrawMethod		drawMethod,
   5436 										TargetBuffer	targetBuffer,
   5437 										UploadMethod	uploadMethod,
   5438 										BufferState		bufferState)
   5439 	: RenderPerformanceTestBase	(context, name, description)
   5440 	, m_drawMethod				(drawMethod)
   5441 	, m_targetBuffer			(targetBuffer)
   5442 	, m_uploadMethod			(uploadMethod)
   5443 	, m_bufferState				(bufferState)
   5444 	, m_numSamplesPerSwap		(10)
   5445 	, m_numMaxSwaps				(4)
   5446 	, m_frameNdx				(0)
   5447 	, m_sampleNdx				(0)
   5448 	, m_numVertices				(-1)
   5449 	, m_vertexBuffer			(0)
   5450 	, m_indexBuffer				(0)
   5451 	, m_miscBuffer				(0)
   5452 	, m_numMiscVertices			(-1)
   5453 {
   5454 }
   5455 
   5456 UploadWaitDrawCase::~UploadWaitDrawCase (void)
   5457 {
   5458 	deinit();
   5459 }
   5460 
   5461 void UploadWaitDrawCase::init (void)
   5462 {
   5463 	const glw::Functions&	gl						= m_context.getRenderContext().getFunctions();
   5464 	const int				vertexAttribSize		= (int)sizeof(tcu::Vec4) * 2; // color4, position4
   5465 	const int				vertexIndexSize			= (int)sizeof(deUint32);
   5466 	const int				vertexUploadDataSize	= (m_targetBuffer == TARGETBUFFER_VERTEX) ? (vertexAttribSize) : (vertexIndexSize);
   5467 
   5468 	RenderPerformanceTestBase::init();
   5469 
   5470 	// requirements
   5471 
   5472 	if (m_context.getRenderTarget().getWidth() < RENDER_AREA_SIZE ||
   5473 		m_context.getRenderTarget().getHeight() < RENDER_AREA_SIZE)
   5474 		throw tcu::NotSupportedError("Test case requires " + de::toString<int>(RENDER_AREA_SIZE) + "x" + de::toString<int>(RENDER_AREA_SIZE) + " render target");
   5475 
   5476 	// gl state
   5477 
   5478 	gl.viewport(0, 0, RENDER_AREA_SIZE, RENDER_AREA_SIZE);
   5479 
   5480 	// enable bleding to prevent grid layers from being discarded
   5481 
   5482 	gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   5483 	gl.blendEquation(GL_FUNC_ADD);
   5484 	gl.enable(GL_BLEND);
   5485 
   5486 	// scene
   5487 
   5488 	{
   5489 		LayeredGridSpec scene;
   5490 
   5491 		// create ~8MB workload with similar characteristics as in the other test
   5492 		// => makes comparison to other results more straightforward
   5493 		scene.gridWidth = 93;
   5494 		scene.gridHeight = 93;
   5495 		scene.gridLayers = 5;
   5496 
   5497 		generateLayeredGridVertexAttribData4C4V(m_vertexData, scene);
   5498 		generateLayeredGridIndexData(m_indexData, scene);
   5499 		m_numVertices = getLayeredGridNumVertices(scene);
   5500 	}
   5501 
   5502 	// buffers
   5503 
   5504 	if (m_bufferState == BUFFERSTATE_NEW)
   5505 	{
   5506 		if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5507 		{
   5508 			// reads from two buffers, prepare the static buffer
   5509 
   5510 			if (m_targetBuffer == TARGETBUFFER_VERTEX)
   5511 			{
   5512 				// index buffer is static, use another vertex buffer to keep original buffer in unused state
   5513 				const glu::Buffer vertexCopyBuffer(m_context.getRenderContext());
   5514 
   5515 				gl.genBuffers(1, &m_indexBuffer);
   5516 				gl.bindBuffer(GL_ARRAY_BUFFER, *vertexCopyBuffer);
   5517 				gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
   5518 				gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(m_vertexData.size() * sizeof(tcu::Vec4)), &m_vertexData[0], GL_STATIC_DRAW);
   5519 				gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(m_indexData.size() * sizeof(deUint32)), &m_indexData[0], GL_STATIC_DRAW);
   5520 
   5521 				setupVertexAttribs();
   5522 				gl.drawElements(GL_TRIANGLES, m_numVertices, GL_UNSIGNED_INT, DE_NULL);
   5523 			}
   5524 			else if (m_targetBuffer == TARGETBUFFER_INDEX)
   5525 			{
   5526 				// vertex buffer is static
   5527 				gl.genBuffers(1, &m_vertexBuffer);
   5528 				gl.bindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
   5529 				gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(m_vertexData.size() * sizeof(tcu::Vec4)), &m_vertexData[0], GL_STATIC_DRAW);
   5530 
   5531 				setupVertexAttribs();
   5532 				gl.drawArrays(GL_TRIANGLES, 0, m_numVertices);
   5533 			}
   5534 			else
   5535 				DE_ASSERT(false);
   5536 		}
   5537 	}
   5538 	else if (m_bufferState == BUFFERSTATE_EXISTING)
   5539 	{
   5540 		const glw::GLenum vertexUsage	= (m_targetBuffer == TARGETBUFFER_VERTEX) ? (GL_STATIC_DRAW) : (GL_STATIC_DRAW);
   5541 		const glw::GLenum indexUsage	= (m_targetBuffer == TARGETBUFFER_INDEX) ? (GL_STATIC_DRAW) : (GL_STATIC_DRAW);
   5542 
   5543 		gl.genBuffers(1, &m_vertexBuffer);
   5544 		gl.bindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
   5545 		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(m_vertexData.size() * sizeof(tcu::Vec4)), &m_vertexData[0], vertexUsage);
   5546 
   5547 		if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5548 		{
   5549 			gl.genBuffers(1, &m_indexBuffer);
   5550 			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
   5551 			gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(m_indexData.size() * sizeof(deUint32)), &m_indexData[0], indexUsage);
   5552 		}
   5553 
   5554 		setupVertexAttribs();
   5555 
   5556 		if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   5557 			gl.drawArrays(GL_TRIANGLES, 0, m_numVertices);
   5558 		else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5559 			gl.drawElements(GL_TRIANGLES, m_numVertices, GL_UNSIGNED_INT, DE_NULL);
   5560 		else
   5561 			DE_ASSERT(false);
   5562 	}
   5563 	else
   5564 		DE_ASSERT(false);
   5565 
   5566 	// misc draw buffer
   5567 	{
   5568 		std::vector<tcu::Vec4>	vertexData;
   5569 		LayeredGridSpec			scene;
   5570 
   5571 		// create ~1.5MB workload with similar characteristics
   5572 		scene.gridWidth = 40;
   5573 		scene.gridHeight = 40;
   5574 		scene.gridLayers = 5;
   5575 
   5576 		generateLayeredGridVertexAttribData4C4V(vertexData, scene);
   5577 
   5578 		gl.genBuffers(1, &m_miscBuffer);
   5579 		gl.bindBuffer(GL_ARRAY_BUFFER, m_miscBuffer);
   5580 		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(sizeof(tcu::Vec4) * vertexData.size()), &vertexData[0], GL_STATIC_DRAW);
   5581 
   5582 		m_numMiscVertices = getLayeredGridNumVertices(scene);
   5583 	}
   5584 
   5585 	// iterations
   5586 	{
   5587 		m_samples.resize((m_numMaxSwaps+1) * m_numSamplesPerSwap);
   5588 		m_results.resize((m_numMaxSwaps+1) * m_numSamplesPerSwap);
   5589 
   5590 		for (int numSwaps = 0; numSwaps <= m_numMaxSwaps; ++numSwaps)
   5591 		for (int sampleNdx = 0; sampleNdx < m_numSamplesPerSwap; ++sampleNdx)
   5592 		{
   5593 			const int index = numSwaps*m_numSamplesPerSwap + sampleNdx;
   5594 
   5595 			m_samples[index].numFrames = numSwaps;
   5596 		}
   5597 
   5598 		m_iterationOrder.resize(m_samples.size());
   5599 		generateTwoPassRandomIterationOrder(m_iterationOrder, (int)m_samples.size());
   5600 	}
   5601 
   5602 	// log
   5603 	m_testCtx.getLog()
   5604 		<< tcu::TestLog::Message
   5605 		<< "Measuring time used in " << ((m_drawMethod == DRAWMETHOD_DRAW_ARRAYS) ? ("drawArrays") : ("drawElements")) << " and readPixels call.\n"
   5606 		<< "Drawing using a buffer that has been uploaded N frames ago. Testing with N within range [0, " << m_numMaxSwaps << "].\n"
   5607 		<< "Uploaded buffer is a " << ((m_targetBuffer == TARGETBUFFER_VERTEX) ? ("vertex attribute") : ("index")) << " buffer.\n"
   5608 		<< "Uploading using "
   5609 			<< ((m_uploadMethod == UPLOADMETHOD_BUFFER_DATA)		? ("bufferData")																							:
   5610 				(m_uploadMethod == UPLOADMETHOD_BUFFER_SUB_DATA)	? ("bufferSubData")																							:
   5611 				(m_uploadMethod == UPLOADMETHOD_MAP_BUFFER_RANGE)	? ("mapBufferRange, flags = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT")	:
   5612 				((const char*)DE_NULL))
   5613 			<< "\n"
   5614 		<< "Upload size is " << getHumanReadableByteSize(m_numVertices * vertexUploadDataSize) << ".\n"
   5615 		<< ((m_bufferState == BUFFERSTATE_EXISTING) ? ("All test samples use the same buffer object.\n") : (""))
   5616 		<< "Test result is the number of frames (swaps) required for the render time to stabilize.\n"
   5617 		<< "Assuming combined time used in the draw call and readPixels call is stabilizes to a constant value.\n"
   5618 		<< tcu::TestLog::EndMessage;
   5619 }
   5620 
   5621 void UploadWaitDrawCase::deinit (void)
   5622 {
   5623 	RenderPerformanceTestBase::deinit();
   5624 
   5625 	if (m_vertexBuffer)
   5626 	{
   5627 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vertexBuffer);
   5628 		m_vertexBuffer = 0;
   5629 	}
   5630 	if (m_indexBuffer)
   5631 	{
   5632 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indexBuffer);
   5633 		m_indexBuffer = 0;
   5634 	}
   5635 	if (m_miscBuffer)
   5636 	{
   5637 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_miscBuffer);
   5638 		m_miscBuffer = 0;
   5639 	}
   5640 }
   5641 
   5642 UploadWaitDrawCase::IterateResult UploadWaitDrawCase::iterate (void)
   5643 {
   5644 	const glw::Functions&	gl								= m_context.getRenderContext().getFunctions();
   5645 	const int				betweenIterationDummyFrameCount = 5; // draw misc between test samples
   5646 	const int				frameNdx						= m_frameNdx++;
   5647 	const int				currentSampleNdx				= m_iterationOrder[m_sampleNdx];
   5648 
   5649 	// Simulate work for about 8ms
   5650 	busyWait(8000);
   5651 
   5652 	// Dummy rendering during dummy frames
   5653 	if (frameNdx != m_samples[currentSampleNdx].numFrames)
   5654 	{
   5655 		// draw similar from another buffer
   5656 		drawMisc();
   5657 	}
   5658 
   5659 	if (frameNdx == 0)
   5660 	{
   5661 		// upload and start the clock
   5662 		uploadBuffer(m_samples[currentSampleNdx], m_results[currentSampleNdx]);
   5663 	}
   5664 
   5665 	if (frameNdx == m_samples[currentSampleNdx].numFrames) // \note: not else if, m_samples[currentSampleNdx].numFrames can be 0
   5666 	{
   5667 		// draw using the uploaded buffer
   5668 		drawFromBuffer(m_samples[currentSampleNdx], m_results[currentSampleNdx]);
   5669 
   5670 		// re-use buffer for something else to make sure test iteration do not affect each other
   5671 		if (m_bufferState == BUFFERSTATE_NEW)
   5672 			reuseAndDeleteBuffer();
   5673 	}
   5674 	else if (frameNdx == m_samples[currentSampleNdx].numFrames + betweenIterationDummyFrameCount)
   5675 	{
   5676 		// next sample
   5677 		++m_sampleNdx;
   5678 		m_frameNdx = 0;
   5679 	}
   5680 
   5681 	GLU_EXPECT_NO_ERROR(gl.getError(), "post-iterate");
   5682 
   5683 	if (m_sampleNdx < (int)m_samples.size())
   5684 		return CONTINUE;
   5685 
   5686 	logAndSetTestResult();
   5687 	return STOP;
   5688 }
   5689 
   5690 void UploadWaitDrawCase::uploadBuffer (Sample& sample, Result& result)
   5691 {
   5692 	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
   5693 	deUint64				startTime;
   5694 	deUint64				endTime;
   5695 	glw::GLenum				target;
   5696 	glw::GLsizeiptr			size;
   5697 	const void*				source;
   5698 
   5699 	// data source
   5700 
   5701 	if (m_targetBuffer == TARGETBUFFER_VERTEX)
   5702 	{
   5703 		DE_ASSERT((m_vertexBuffer == 0) == (m_bufferState == BUFFERSTATE_NEW));
   5704 
   5705 		target	= GL_ARRAY_BUFFER;
   5706 		size	= (glw::GLsizeiptr)(m_vertexData.size() * sizeof(tcu::Vec4));
   5707 		source	= &m_vertexData[0];
   5708 	}
   5709 	else if (m_targetBuffer == TARGETBUFFER_INDEX)
   5710 	{
   5711 		DE_ASSERT((m_indexBuffer == 0) == (m_bufferState == BUFFERSTATE_NEW));
   5712 
   5713 		target	= GL_ELEMENT_ARRAY_BUFFER;
   5714 		size	= (glw::GLsizeiptr)(m_indexData.size() * sizeof(deUint32));
   5715 		source	= &m_indexData[0];
   5716 	}
   5717 	else
   5718 	{
   5719 		DE_ASSERT(false);
   5720 		return;
   5721 	}
   5722 
   5723 	// gen buffer
   5724 
   5725 	if (m_bufferState == BUFFERSTATE_NEW)
   5726 	{
   5727 		if (m_targetBuffer == TARGETBUFFER_VERTEX)
   5728 		{
   5729 			gl.genBuffers(1, &m_vertexBuffer);
   5730 			gl.bindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
   5731 		}
   5732 		else if (m_targetBuffer == TARGETBUFFER_INDEX)
   5733 		{
   5734 			gl.genBuffers(1, &m_indexBuffer);
   5735 			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
   5736 		}
   5737 		else
   5738 			DE_ASSERT(false);
   5739 
   5740 		if (m_uploadMethod == UPLOADMETHOD_BUFFER_SUB_DATA ||
   5741 			m_uploadMethod == UPLOADMETHOD_MAP_BUFFER_RANGE)
   5742 		{
   5743 			gl.bufferData(target, size, DE_NULL, GL_STATIC_DRAW);
   5744 		}
   5745 	}
   5746 	else if (m_bufferState == BUFFERSTATE_EXISTING)
   5747 	{
   5748 		if (m_targetBuffer == TARGETBUFFER_VERTEX)
   5749 			gl.bindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
   5750 		else if (m_targetBuffer == TARGETBUFFER_INDEX)
   5751 			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
   5752 		else
   5753 			DE_ASSERT(false);
   5754 	}
   5755 	else
   5756 		DE_ASSERT(false);
   5757 
   5758 	// upload
   5759 
   5760 	startTime = deGetMicroseconds();
   5761 
   5762 	if (m_uploadMethod == UPLOADMETHOD_BUFFER_DATA)
   5763 		gl.bufferData(target, size, source, GL_STATIC_DRAW);
   5764 	else if (m_uploadMethod == UPLOADMETHOD_BUFFER_SUB_DATA)
   5765 		gl.bufferSubData(target, 0, size, source);
   5766 	else if (m_uploadMethod == UPLOADMETHOD_MAP_BUFFER_RANGE)
   5767 	{
   5768 		void*			mapPtr;
   5769 		glw::GLboolean	unmapSuccessful;
   5770 
   5771 		mapPtr = gl.mapBufferRange(target, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
   5772 		if (!mapPtr)
   5773 			throw tcu::Exception("MapBufferRange returned NULL");
   5774 
   5775 		deMemcpy(mapPtr, source, (int)size);
   5776 
   5777 		// if unmapping fails, just try again later
   5778 		unmapSuccessful = gl.unmapBuffer(target);
   5779 		if (!unmapSuccessful)
   5780 			throw UnmapFailureError();
   5781 	}
   5782 	else
   5783 		DE_ASSERT(false);
   5784 
   5785 	endTime = deGetMicroseconds();
   5786 
   5787 	sample.uploadCallEndTime = endTime;
   5788 	result.uploadDuration = endTime - startTime;
   5789 }
   5790 
   5791 void UploadWaitDrawCase::drawFromBuffer (Sample& sample, Result& result)
   5792 {
   5793 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
   5794 	tcu::Surface			resultSurface	(RENDER_AREA_SIZE, RENDER_AREA_SIZE);
   5795 	deUint64				startTime;
   5796 	deUint64				endTime;
   5797 
   5798 	DE_ASSERT(m_vertexBuffer != 0);
   5799 	if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   5800 		DE_ASSERT(m_indexBuffer == 0);
   5801 	else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5802 		DE_ASSERT(m_indexBuffer != 0);
   5803 	else
   5804 		DE_ASSERT(false);
   5805 
   5806 	// draw
   5807 	{
   5808 		gl.bindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
   5809 		if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5810 			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);
   5811 
   5812 		setupVertexAttribs();
   5813 
   5814 		// microseconds passed since return from upload call
   5815 		result.timeBeforeUse = deGetMicroseconds() - sample.uploadCallEndTime;
   5816 
   5817 		startTime = deGetMicroseconds();
   5818 
   5819 		if (m_drawMethod == DRAWMETHOD_DRAW_ARRAYS)
   5820 			gl.drawArrays(GL_TRIANGLES, 0, m_numVertices);
   5821 		else if (m_drawMethod == DRAWMETHOD_DRAW_ELEMENTS)
   5822 			gl.drawElements(GL_TRIANGLES, m_numVertices, GL_UNSIGNED_INT, DE_NULL);
   5823 		else
   5824 			DE_ASSERT(false);
   5825 
   5826 		endTime = deGetMicroseconds();
   5827 
   5828 		result.renderDuration = endTime - startTime;
   5829 	}
   5830 
   5831 	// read
   5832 	{
   5833 		startTime = deGetMicroseconds();
   5834 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
   5835 		endTime = deGetMicroseconds();
   5836 
   5837 		result.readDuration = endTime - startTime;
   5838 	}
   5839 
   5840 	result.renderReadDuration = result.renderDuration + result.readDuration;
   5841 }
   5842 
   5843 void UploadWaitDrawCase::reuseAndDeleteBuffer (void)
   5844 {
   5845 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   5846 
   5847 	if (m_targetBuffer == TARGETBUFFER_INDEX)
   5848 	{
   5849 		// respecify and delete index buffer
   5850 		static const deUint32 indices[3] = {1, 3, 8};
   5851 
   5852 		DE_ASSERT(m_indexBuffer != 0);
   5853 
   5854 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
   5855 		gl.drawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, DE_NULL);
   5856 		gl.deleteBuffers(1, &m_indexBuffer);
   5857 		m_indexBuffer = 0;
   5858 	}
   5859 	else if (m_targetBuffer == TARGETBUFFER_VERTEX)
   5860 	{
   5861 		// respecify and delete vertex buffer
   5862 		static const tcu::Vec4 coloredTriangle[6] =
   5863 		{
   5864 			tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(-0.4f, -0.4f, 0.0f, 1.0f),
   5865 			tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(-0.2f,  0.4f, 0.0f, 1.0f),
   5866 			tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4( 0.8f, -0.1f, 0.0f, 1.0f),
   5867 		};
   5868 
   5869 		DE_ASSERT(m_vertexBuffer != 0);
   5870 
   5871 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(coloredTriangle), coloredTriangle, GL_STATIC_DRAW);
   5872 		gl.drawArrays(GL_TRIANGLES, 0, 3);
   5873 		gl.deleteBuffers(1, &m_vertexBuffer);
   5874 		m_vertexBuffer = 0;
   5875 	}
   5876 
   5877 	waitGLResults();
   5878 }
   5879 
   5880 void UploadWaitDrawCase::logAndSetTestResult (void)
   5881 {
   5882 	int		uploadStabilization;
   5883 	int		renderReadStabilization;
   5884 	int		renderStabilization;
   5885 	int		readStabilization;
   5886 	bool	temporallyStable;
   5887 
   5888 	{
   5889 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "Samples", "Result samples");
   5890 		logSamples();
   5891 	}
   5892 
   5893 	{
   5894 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "Stabilization", "Sample stability");
   5895 
   5896 		// log stabilization points
   5897 		renderReadStabilization	= findStabilizationSample(&Result::renderReadDuration, "Combined draw and read");
   5898 		uploadStabilization		= findStabilizationSample(&Result::uploadDuration, "Upload time");
   5899 		renderStabilization		= findStabilizationSample(&Result::renderDuration, "Draw call time");
   5900 		readStabilization		= findStabilizationSample(&Result::readDuration, "ReadPixels time");
   5901 
   5902 		temporallyStable		= true;
   5903 		temporallyStable		&= checkSampleTemporalStability(&Result::renderReadDuration, "Combined draw and read");
   5904 		temporallyStable		&= checkSampleTemporalStability(&Result::uploadDuration, "Upload time");
   5905 		temporallyStable		&= checkSampleTemporalStability(&Result::renderDuration, "Draw call time");
   5906 		temporallyStable		&= checkSampleTemporalStability(&Result::readDuration, "ReadPixels time");
   5907 	}
   5908 
   5909 	{
   5910 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "Results", "Results");
   5911 
   5912 		// Check result sanily
   5913 		if (uploadStabilization != 0)
   5914 			m_testCtx.getLog() << tcu::TestLog::Message << "Warning! Upload times are not stable, test result may not be accurate." << tcu::TestLog::EndMessage;
   5915 		if (!temporallyStable)
   5916 			m_testCtx.getLog() << tcu::TestLog::Message << "Warning! Time samples do not seem to be temporally stable, sample times seem to drift to one direction during test execution." << tcu::TestLog::EndMessage;
   5917 
   5918 		// render & read
   5919 		if (renderReadStabilization == -1)
   5920 			m_testCtx.getLog() << tcu::TestLog::Message << "Combined time used in draw call and ReadPixels did not stabilize." << tcu::TestLog::EndMessage;
   5921 		else
   5922 			m_testCtx.getLog() << tcu::TestLog::Integer("RenderReadStabilizationPoint", "Combined draw call and ReadPixels call time stabilization time", "frames", QP_KEY_TAG_TIME, renderReadStabilization);
   5923 
   5924 		// draw call
   5925 		if (renderStabilization == -1)
   5926 			m_testCtx.getLog() << tcu::TestLog::Message << "Time used in draw call did not stabilize." << tcu::TestLog::EndMessage;
   5927 		else
   5928 			m_testCtx.getLog() << tcu::TestLog::Integer("DrawCallStabilizationPoint", "Draw call time stabilization time", "frames", QP_KEY_TAG_TIME, renderStabilization);
   5929 
   5930 		// readpixels
   5931 		if (readStabilization == -1)
   5932 			m_testCtx.getLog() << tcu::TestLog::Message << "Time used in ReadPixels did not stabilize." << tcu::TestLog::EndMessage;
   5933 		else
   5934 			m_testCtx.getLog() << tcu::TestLog::Integer("ReadPixelsStabilizationPoint", "ReadPixels call time stabilization time", "frames", QP_KEY_TAG_TIME, readStabilization);
   5935 
   5936 		// Report renderReadStabilization
   5937 		if (renderReadStabilization != -1)
   5938 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(renderReadStabilization).c_str());
   5939 		else
   5940 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::toString(m_numMaxSwaps).c_str()); // don't report -1
   5941 	}
   5942 }
   5943 
   5944 void UploadWaitDrawCase::logSamples (void)
   5945 {
   5946 	// Inverse m_iterationOrder
   5947 
   5948 	std::vector<int> runOrder(m_iterationOrder.size());
   5949 	for (int ndx = 0; ndx < (int)m_iterationOrder.size(); ++ndx)
   5950 		runOrder[m_iterationOrder[ndx]] = ndx;
   5951 
   5952 	// Log samples
   5953 
   5954 	m_testCtx.getLog()
   5955 		<< tcu::TestLog::SampleList("Samples", "Samples")
   5956 		<< tcu::TestLog::SampleInfo
   5957 		<< tcu::TestLog::ValueInfo("NumSwaps",		"SwapBuffers before use",			"",		QP_SAMPLE_VALUE_TAG_PREDICTOR)
   5958 		<< tcu::TestLog::ValueInfo("Delay",			"Time before use",					"us",	QP_SAMPLE_VALUE_TAG_PREDICTOR)
   5959 		<< tcu::TestLog::ValueInfo("RunOrder",		"Sample run order",					"",		QP_SAMPLE_VALUE_TAG_PREDICTOR)
   5960 		<< tcu::TestLog::ValueInfo("DrawReadTime",	"Draw call and ReadPixels time",	"us",	QP_SAMPLE_VALUE_TAG_RESPONSE)
   5961 		<< tcu::TestLog::ValueInfo("TotalTime",		"Total time",						"us",	QP_SAMPLE_VALUE_TAG_RESPONSE)
   5962 		<< tcu::TestLog::ValueInfo("Upload time",	"Upload time",						"us",	QP_SAMPLE_VALUE_TAG_RESPONSE)
   5963 		<< tcu::TestLog::ValueInfo("DrawCallTime",	"Draw call time",					"us",	QP_SAMPLE_VALUE_TAG_RESPONSE)
   5964 		<< tcu::TestLog::ValueInfo("ReadTime",		"ReadPixels time",					"us",	QP_SAMPLE_VALUE_TAG_RESPONSE)
   5965 		<< tcu::TestLog::EndSampleInfo;
   5966 
   5967 	for (int sampleNdx = 0; sampleNdx < (int)m_samples.size(); ++sampleNdx)
   5968 		m_testCtx.getLog()
   5969 			<< tcu::TestLog::Sample
   5970 			<< m_samples[sampleNdx].numFrames
   5971 			<< (int)m_results[sampleNdx].timeBeforeUse
   5972 			<< runOrder[sampleNdx]
   5973 			<< (int)m_results[sampleNdx].renderReadDuration
   5974 			<< (int)(m_results[sampleNdx].renderReadDuration + m_results[sampleNdx].uploadDuration)
   5975 			<< (int)m_results[sampleNdx].uploadDuration
   5976 			<< (int)m_results[sampleNdx].renderDuration
   5977 			<< (int)m_results[sampleNdx].readDuration
   5978 			<< tcu::TestLog::EndSample;
   5979 
   5980 	m_testCtx.getLog() << tcu::TestLog::EndSampleList;
   5981 }
   5982 
   5983 void UploadWaitDrawCase::drawMisc (void)
   5984 {
   5985 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   5986 
   5987 	gl.bindBuffer(GL_ARRAY_BUFFER, m_miscBuffer);
   5988 	setupVertexAttribs();
   5989 	gl.drawArrays(GL_TRIANGLES, 0, m_numMiscVertices);
   5990 }
   5991 
   5992 struct DistributionCompareResult
   5993 {
   5994 	bool	equal;
   5995 	float	standardDeviations;
   5996 };
   5997 
   5998 template <typename Comparer>
   5999 static float sumOfRanks (const std::vector<deUint64>& testSamples, const std::vector<deUint64>& allSamples, const Comparer& comparer)
   6000 {
   6001 	float sum = 0;
   6002 
   6003 	for (int sampleNdx = 0; sampleNdx < (int)testSamples.size(); ++sampleNdx)
   6004 	{
   6005 		const deUint64	testSample		= testSamples[sampleNdx];
   6006 		const int		lowerIndex		= (int)(std::lower_bound(allSamples.begin(), allSamples.end(), testSample, comparer) - allSamples.begin());
   6007 		const int		upperIndex		= (int)(std::upper_bound(allSamples.begin(), allSamples.end(), testSample, comparer) - allSamples.begin());
   6008 		const int		lowerRank		= lowerIndex + 1;	// convert zero-indexed to rank
   6009 		const int		upperRank		= upperIndex;		// convert zero-indexed to rank, upperIndex is last equal + 1
   6010 		const float		rankMidpoint	= (float)(lowerRank + upperRank) / 2.0f;
   6011 
   6012 		sum += rankMidpoint;
   6013 	}
   6014 
   6015 	return sum;
   6016 }
   6017 
   6018 template <typename Comparer>
   6019 static DistributionCompareResult distributionCompare (const std::vector<deUint64>& orderedObservationsA, const std::vector<deUint64>& orderedObservationsB, const Comparer& comparer)
   6020 {
   6021 	// Mann-Whitney U test
   6022 
   6023 	const int				n1			= (int)orderedObservationsA.size();
   6024 	const int				n2			= (int)orderedObservationsB.size();
   6025 	std::vector<deUint64>	allSamples	(n1 + n2);
   6026 
   6027 	std::copy(orderedObservationsA.begin(), orderedObservationsA.end(), allSamples.begin());
   6028 	std::copy(orderedObservationsB.begin(), orderedObservationsB.end(), allSamples.begin() + n1);
   6029 	std::sort(allSamples.begin(), allSamples.end());
   6030 
   6031 	{
   6032 		const float					R1		= sumOfRanks(orderedObservationsA, allSamples, comparer);
   6033 
   6034 		const float					U1		= (float)(n1*n2 + n1*(n1 + 1)/2) - R1;
   6035 		const float					U2		= (float)(n1 * n2) - U1;
   6036 		const float					U		= de::min(U1, U2);
   6037 
   6038 		// \note: sample sizes might not be large enough to expect normal distribution but we do it anyway
   6039 
   6040 		const float					mU		= (float)(n1 * n2) / 2.0f;
   6041 		const float					sigmaU	= deFloatSqrt((float)(n1*n2*(n1+n2+1)) / 12.0f);
   6042 		const float					z		= (U - mU) / sigmaU;
   6043 
   6044 		DistributionCompareResult	result;
   6045 
   6046 		result.equal				= (de::abs(z) <= 1.96f); // accept within 95% confidence interval
   6047 		result.standardDeviations	= z;
   6048 
   6049 		return result;
   6050 	}
   6051 }
   6052 
   6053 template <typename T>
   6054 struct ThresholdComparer
   6055 {
   6056 	float	relativeThreshold;
   6057 	T		absoluteThreshold;
   6058 
   6059 	bool operator() (const T& a, const T& b) const
   6060 	{
   6061 		const float diff = de::abs((float)a - (float)b);
   6062 
   6063 		// thresholds
   6064 		if (diff <= (float)absoluteThreshold)
   6065 			return false;
   6066 		if (diff <= float(a)*relativeThreshold ||
   6067 			diff <= float(b)*relativeThreshold)
   6068 			return false;
   6069 
   6070 		// cmp
   6071 		return a < b;
   6072 	}
   6073 };
   6074 
   6075 int UploadWaitDrawCase::findStabilizationSample (deUint64 (UploadWaitDrawCase::Result::*target), const char* description)
   6076 {
   6077 	std::vector<std::vector<deUint64> >	sampleObservations(m_numMaxSwaps+1);
   6078 	ThresholdComparer<deUint64>			comparer;
   6079 
   6080 	comparer.relativeThreshold = 0.15f;	// 15%
   6081 	comparer.absoluteThreshold = 100;	// (us), assumed sampling precision
   6082 
   6083 	// get observations and order them
   6084 
   6085 	for (int swapNdx = 0; swapNdx <= m_numMaxSwaps; ++swapNdx)
   6086 	{
   6087 		int insertNdx = 0;
   6088 
   6089 		sampleObservations[swapNdx].resize(m_numSamplesPerSwap);
   6090 
   6091 		for (int ndx = 0; ndx < (int)m_samples.size(); ++ndx)
   6092 			if (m_samples[ndx].numFrames == swapNdx)
   6093 				sampleObservations[swapNdx][insertNdx++] = m_results[ndx].*target;
   6094 
   6095 		DE_ASSERT(insertNdx == m_numSamplesPerSwap);
   6096 
   6097 		std::sort(sampleObservations[swapNdx].begin(), sampleObservations[swapNdx].end());
   6098 	}
   6099 
   6100 	// find stabilization point
   6101 
   6102 	for (int sampleNdx = m_numMaxSwaps-1; sampleNdx != -1; --sampleNdx )
   6103 	{
   6104 		// Distribution is equal to all following distributions
   6105 		for (int cmpTargetDistribution = sampleNdx+1; cmpTargetDistribution <= m_numMaxSwaps; ++cmpTargetDistribution)
   6106 		{
   6107 			// Stable section ends here?
   6108 			const DistributionCompareResult result = distributionCompare(sampleObservations[sampleNdx], sampleObservations[cmpTargetDistribution], comparer);
   6109 			if (!result.equal)
   6110 			{
   6111 				// Last two samples are not equal? Samples never stabilized
   6112 				if (sampleNdx == m_numMaxSwaps-1)
   6113 				{
   6114 					m_testCtx.getLog()
   6115 						<< tcu::TestLog::Message
   6116 						<< description << ": Samples with swap count " << sampleNdx << " and " << cmpTargetDistribution << " do not seem to have the same distribution:\n"
   6117 						<< "\tDifference in standard deviations: " << result.standardDeviations << "\n"
   6118 						<< "\tSwap count " << sampleNdx << " median: " << linearSample(sampleObservations[sampleNdx], 0.5f) << "\n"
   6119 						<< "\tSwap count " << cmpTargetDistribution << " median: " << linearSample(sampleObservations[cmpTargetDistribution], 0.5f) << "\n"
   6120 						<< tcu::TestLog::EndMessage;
   6121 					return -1;
   6122 				}
   6123 				else
   6124 				{
   6125 					m_testCtx.getLog()
   6126 						<< tcu::TestLog::Message
   6127 						<< description << ": Samples with swap count " << sampleNdx << " and " << cmpTargetDistribution << " do not seem to have the same distribution:\n"
   6128 						<< "\tSamples with swap count " << sampleNdx << " are not part of the tail of stable results.\n"
   6129 						<< "\tDifference in standard deviations: " << result.standardDeviations << "\n"
   6130 						<< "\tSwap count " << sampleNdx << " median: " << linearSample(sampleObservations[sampleNdx], 0.5f) << "\n"
   6131 						<< "\tSwap count " << cmpTargetDistribution << " median: " << linearSample(sampleObservations[cmpTargetDistribution], 0.5f) << "\n"
   6132 						<< tcu::TestLog::EndMessage;
   6133 
   6134 					return sampleNdx+1;
   6135 				}
   6136 			}
   6137 		}
   6138 	}
   6139 
   6140 	m_testCtx.getLog()
   6141 		<< tcu::TestLog::Message
   6142 		<< description << ": All samples seem to have the same distribution"
   6143 		<< tcu::TestLog::EndMessage;
   6144 
   6145 	// all distributions equal
   6146 	return 0;
   6147 }
   6148 
   6149 bool UploadWaitDrawCase::checkSampleTemporalStability (deUint64 (UploadWaitDrawCase::Result::*target), const char* description)
   6150 {
   6151 	// Try to find correlation with sample order and sample times
   6152 
   6153 	const int						numDataPoints	= (int)m_iterationOrder.size();
   6154 	std::vector<tcu::Vec2>			dataPoints		(m_iterationOrder.size());
   6155 	LineParametersWithConfidence	lineFit;
   6156 
   6157 	for (int ndx = 0; ndx < (int)m_iterationOrder.size(); ++ndx)
   6158 	{
   6159 		dataPoints[m_iterationOrder[ndx]].x() = (float)ndx;
   6160 		dataPoints[m_iterationOrder[ndx]].y() = (float)(m_results[m_iterationOrder[ndx]].*target);
   6161 	}
   6162 
   6163 	lineFit = theilSenSiegelLinearRegression(dataPoints, 0.6f);
   6164 
   6165 	// Difference of more than 25% of the offset along the whole sample range
   6166 	if (de::abs(lineFit.coefficient) * (float)numDataPoints > de::abs(lineFit.offset) * 0.25f)
   6167 	{
   6168 		m_testCtx.getLog()
   6169 			<< tcu::TestLog::Message
   6170 			<< description << ": Correlation with data point observation order and result time. Results are not temporally stable, observations are not independent.\n"
   6171 			<< "\tCoefficient: " << lineFit.coefficient << " (us / observation)\n"
   6172 			<< tcu::TestLog::EndMessage;
   6173 
   6174 		return false;
   6175 	}
   6176 	else
   6177 		return true;
   6178 }
   6179 
   6180 } // anonymous
   6181 
   6182 BufferDataUploadTests::BufferDataUploadTests (Context& context)
   6183 	: TestCaseGroup(context, "data_upload", "Buffer data upload performance tests")
   6184 {
   6185 }
   6186 
   6187 BufferDataUploadTests::~BufferDataUploadTests (void)
   6188 {
   6189 }
   6190 
   6191 void BufferDataUploadTests::init (void)
   6192 {
   6193 	static const struct BufferUsage
   6194 	{
   6195 		const char* name;
   6196 		deUint32	usage;
   6197 		bool		primaryUsage;
   6198 	} bufferUsages[] =
   6199 	{
   6200 		{ "stream_draw",	GL_STREAM_DRAW,		true	},
   6201 		{ "stream_read",	GL_STREAM_READ,		false	},
   6202 		{ "stream_copy",	GL_STREAM_COPY,		false	},
   6203 		{ "static_draw",	GL_STATIC_DRAW,		true	},
   6204 		{ "static_read",	GL_STATIC_READ,		false	},
   6205 		{ "static_copy",	GL_STATIC_COPY,		false	},
   6206 		{ "dynamic_draw",	GL_DYNAMIC_DRAW,	true	},
   6207 		{ "dynamic_read",	GL_DYNAMIC_READ,	false	},
   6208 		{ "dynamic_copy",	GL_DYNAMIC_COPY,	false	},
   6209 	};
   6210 
   6211 	tcu::TestCaseGroup* const referenceGroup			= new tcu::TestCaseGroup(m_testCtx, "reference",			"Reference functions");
   6212 	tcu::TestCaseGroup* const functionCallGroup			= new tcu::TestCaseGroup(m_testCtx, "function_call",		"Function call timing");
   6213 	tcu::TestCaseGroup* const modifyAfterUseGroup		= new tcu::TestCaseGroup(m_testCtx, "modify_after_use",		"Function call time after buffer has been used");
   6214 	tcu::TestCaseGroup* const renderAfterUploadGroup	= new tcu::TestCaseGroup(m_testCtx, "render_after_upload",	"Function call time of draw commands after buffer has been modified");
   6215 
   6216 	addChild(referenceGroup);
   6217 	addChild(functionCallGroup);
   6218 	addChild(modifyAfterUseGroup);
   6219 	addChild(renderAfterUploadGroup);
   6220 
   6221 	// .reference
   6222 	{
   6223 		static const struct BufferSizeRange
   6224 		{
   6225 			const char* name;
   6226 			int			minBufferSize;
   6227 			int			maxBufferSize;
   6228 			int			numSamples;
   6229 			bool		largeBuffersCase;
   6230 		} sizeRanges[] =
   6231 		{
   6232 			{ "small_buffers", 0,		1 << 18,	64,		false	}, // !< 0kB - 256kB
   6233 			{ "large_buffers", 1 << 18,	1 << 24,	32,		true	}, // !< 256kB - 16MB
   6234 		};
   6235 
   6236 		for (int bufferSizeRangeNdx = 0; bufferSizeRangeNdx < DE_LENGTH_OF_ARRAY(sizeRanges); ++bufferSizeRangeNdx)
   6237 		{
   6238 			referenceGroup->addChild(new ReferenceMemcpyCase(m_context,
   6239 															 std::string("memcpy_").append(sizeRanges[bufferSizeRangeNdx].name).c_str(),
   6240 															 "Test memcpy performance",
   6241 															 sizeRanges[bufferSizeRangeNdx].minBufferSize,
   6242 															 sizeRanges[bufferSizeRangeNdx].maxBufferSize,
   6243 															 sizeRanges[bufferSizeRangeNdx].numSamples,
   6244 															 sizeRanges[bufferSizeRangeNdx].largeBuffersCase));
   6245 		}
   6246 	}
   6247 
   6248 	// .function_call
   6249 	{
   6250 		const int minBufferSize		= 0;		// !< 0kiB
   6251 		const int maxBufferSize		= 1 << 24;	// !< 16MiB
   6252 		const int numDataSamples	= 25;
   6253 		const int numMapSamples		= 25;
   6254 
   6255 		tcu::TestCaseGroup* const bufferDataMethodGroup		= new tcu::TestCaseGroup(m_testCtx, "buffer_data", "Use glBufferData");
   6256 		tcu::TestCaseGroup* const bufferSubDataMethodGroup	= new tcu::TestCaseGroup(m_testCtx, "buffer_sub_data", "Use glBufferSubData");
   6257 		tcu::TestCaseGroup* const mapBufferRangeMethodGroup	= new tcu::TestCaseGroup(m_testCtx, "map_buffer_range", "Use glMapBufferRange");
   6258 
   6259 		functionCallGroup->addChild(bufferDataMethodGroup);
   6260 		functionCallGroup->addChild(bufferSubDataMethodGroup);
   6261 		functionCallGroup->addChild(mapBufferRangeMethodGroup);
   6262 
   6263 		// .buffer_data
   6264 		{
   6265 			static const struct TargetCase
   6266 			{
   6267 				tcu::TestCaseGroup*				group;
   6268 				BufferDataUploadCase::CaseType	caseType;
   6269 				bool							allUsages;
   6270 			} targetCases[] =
   6271 			{
   6272 				{ new tcu::TestCaseGroup(m_testCtx, "new_buffer",				"Target new buffer"),							BufferDataUploadCase::CASE_NEW_BUFFER,			true	},
   6273 				{ new tcu::TestCaseGroup(m_testCtx, "unspecified_buffer",		"Target new unspecified buffer"),				BufferDataUploadCase::CASE_UNSPECIFIED_BUFFER,	true	},
   6274 				{ new tcu::TestCaseGroup(m_testCtx, "specified_buffer",			"Target new specified buffer"),					BufferDataUploadCase::CASE_SPECIFIED_BUFFER,	true	},
   6275 				{ new tcu::TestCaseGroup(m_testCtx, "used_buffer",				"Target buffer that was used in draw"),			BufferDataUploadCase::CASE_USED_BUFFER,			true	},
   6276 				{ new tcu::TestCaseGroup(m_testCtx, "larger_used_buffer",		"Target larger buffer that was used in draw"),	BufferDataUploadCase::CASE_USED_LARGER_BUFFER,	false	},
   6277 			};
   6278 
   6279 			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targetCases); ++targetNdx)
   6280 			{
   6281 				bufferDataMethodGroup->addChild(targetCases[targetNdx].group);
   6282 
   6283 				for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(bufferUsages); ++usageNdx)
   6284 					if (bufferUsages[usageNdx].primaryUsage || targetCases[targetNdx].allUsages)
   6285 						targetCases[targetNdx].group->addChild(new BufferDataUploadCase(m_context,
   6286 																						std::string("usage_").append(bufferUsages[usageNdx].name).c_str(),
   6287 																						std::string("Test with usage = ").append(bufferUsages[usageNdx].name).c_str(),
   6288 																						minBufferSize,
   6289 																						maxBufferSize,
   6290 																						numDataSamples,
   6291 																						bufferUsages[usageNdx].usage,
   6292 																						targetCases[targetNdx].caseType));
   6293 			}
   6294 		}
   6295 
   6296 		// .buffer_sub_data
   6297 		{
   6298 			static const struct FlagCase
   6299 			{
   6300 				tcu::TestCaseGroup*					group;
   6301 				BufferSubDataUploadCase::CaseType	parentCase;
   6302 				bool								allUsages;
   6303 				int									flags;
   6304 			} flagCases[] =
   6305 			{
   6306 				{ new tcu::TestCaseGroup(m_testCtx, "used_buffer_full_upload",					    ""),															BufferSubDataUploadCase::CASE_USED_BUFFER,	true,	BufferSubDataUploadCase::FLAG_FULL_UPLOAD															},
   6307 				{ new tcu::TestCaseGroup(m_testCtx, "used_buffer_invalidate_before_full_upload",    "Clear buffer with bufferData(...,NULL) before sub data call"),	BufferSubDataUploadCase::CASE_USED_BUFFER,	false,	BufferSubDataUploadCase::FLAG_FULL_UPLOAD    | BufferSubDataUploadCase::FLAG_INVALIDATE_BEFORE_USE	},
   6308 				{ new tcu::TestCaseGroup(m_testCtx, "used_buffer_partial_upload",                   ""),															BufferSubDataUploadCase::CASE_USED_BUFFER,	true,	BufferSubDataUploadCase::FLAG_PARTIAL_UPLOAD														},
   6309 				{ new tcu::TestCaseGroup(m_testCtx, "used_buffer_invalidate_before_partial_upload", "Clear buffer with bufferData(...,NULL) before sub data call"),	BufferSubDataUploadCase::CASE_USED_BUFFER,	false,	BufferSubDataUploadCase::FLAG_PARTIAL_UPLOAD | BufferSubDataUploadCase::FLAG_INVALIDATE_BEFORE_USE	},
   6310 			};
   6311 
   6312 			for (int flagNdx = 0; flagNdx < DE_LENGTH_OF_ARRAY(flagCases); ++flagNdx)
   6313 			{
   6314 				bufferSubDataMethodGroup->addChild(flagCases[flagNdx].group);
   6315 
   6316 				for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(bufferUsages); ++usageNdx)
   6317 					if (bufferUsages[usageNdx].primaryUsage || flagCases[flagNdx].allUsages)
   6318 							flagCases[flagNdx].group->addChild(new BufferSubDataUploadCase(m_context,
   6319 																						   std::string("usage_").append(bufferUsages[usageNdx].name).c_str(),
   6320 																						   std::string("Test with usage = ").append(bufferUsages[usageNdx].name).c_str(),
   6321 																						   minBufferSize,
   6322 																						   maxBufferSize,
   6323 																						   numDataSamples,
   6324 																						   bufferUsages[usageNdx].usage,
   6325 																						   flagCases[flagNdx].parentCase,
   6326 																						   flagCases[flagNdx].flags));
   6327 			}
   6328 		}
   6329 
   6330 		// .map_buffer_range
   6331 		{
   6332 			static const struct FlagCase
   6333 			{
   6334 				const char*	name;
   6335 				bool		usefulForUnusedBuffers;
   6336 				bool		allUsages;
   6337 				int			glFlags;
   6338 				int			caseFlags;
   6339 			} flagCases[] =
   6340 			{
   6341 				{ "flag_write_full",										true,	true,	GL_MAP_WRITE_BIT,																0																				},
   6342 				{ "flag_write_partial",										true,	true,	GL_MAP_WRITE_BIT,																MapBufferRangeCase::FLAG_PARTIAL												},
   6343 				{ "flag_read_write_full",									true,	true,	GL_MAP_WRITE_BIT | GL_MAP_READ_BIT,												0																				},
   6344 				{ "flag_read_write_partial",								true,	true,	GL_MAP_WRITE_BIT | GL_MAP_READ_BIT,												MapBufferRangeCase::FLAG_PARTIAL												},
   6345 				{ "flag_invalidate_range_full",								true,	false,	GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT,									0																				},
   6346 				{ "flag_invalidate_range_partial",							true,	false,	GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT,									MapBufferRangeCase::FLAG_PARTIAL												},
   6347 				{ "flag_invalidate_buffer_full",							true,	false,	GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT,								0																				},
   6348 				{ "flag_invalidate_buffer_partial",							true,	false,	GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT,								MapBufferRangeCase::FLAG_PARTIAL												},
   6349 				{ "flag_write_full_manual_invalidate_buffer",				false,	false,	GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT,									MapBufferRangeCase::FLAG_MANUAL_INVALIDATION									},
   6350 				{ "flag_write_partial_manual_invalidate_buffer",			false,	false,	GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT,									MapBufferRangeCase::FLAG_PARTIAL | MapBufferRangeCase::FLAG_MANUAL_INVALIDATION	},
   6351 				{ "flag_unsynchronized_full",								true,	false,	GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT,									0																				},
   6352 				{ "flag_unsynchronized_partial",							true,	false,	GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT,									MapBufferRangeCase::FLAG_PARTIAL												},
   6353 				{ "flag_unsynchronized_and_invalidate_buffer_full",			true,	false,	GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT,	0																				},
   6354 				{ "flag_unsynchronized_and_invalidate_buffer_partial",		true,	false,	GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT,	MapBufferRangeCase::FLAG_PARTIAL												},
   6355 			};
   6356 			static const struct FlushCases
   6357 			{
   6358 				const char*	name;
   6359 				int			glFlags;
   6360 				int			caseFlags;
   6361 			} flushCases[] =
   6362 			{
   6363 				{ "flag_flush_explicit_map_full",					GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT,	0												},
   6364 				{ "flag_flush_explicit_map_partial",				GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT,	MapBufferRangeFlushCase::FLAG_PARTIAL			},
   6365 				{ "flag_flush_explicit_map_full_flush_in_parts",	GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT,	MapBufferRangeFlushCase::FLAG_FLUSH_IN_PARTS	},
   6366 				{ "flag_flush_explicit_map_full_flush_partial",		GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT,	MapBufferRangeFlushCase::FLAG_FLUSH_PARTIAL		},
   6367 			};
   6368 			static const struct MapTestGroup
   6369 			{
   6370 				int					flags;
   6371 				bool				unusedBufferCase;
   6372 				tcu::TestCaseGroup* group;
   6373 			} groups[] =
   6374 			{
   6375 				{ MapBufferRangeCase::FLAG_USE_UNUSED_UNSPECIFIED_BUFFER,	true,	new tcu::TestCaseGroup(m_testCtx, "new_unspecified_buffer", "Test with unused, unspecified buffers"),				},
   6376 				{ MapBufferRangeCase::FLAG_USE_UNUSED_SPECIFIED_BUFFER,		true,	new tcu::TestCaseGroup(m_testCtx, "new_specified_buffer", "Test with unused, specified buffers"),					},
   6377 				{ 0,														false,	new tcu::TestCaseGroup(m_testCtx, "used_buffer", "Test with used (data has been sourced from a buffer) buffers")	},
   6378 			};
   6379 
   6380 			// we OR same flags to both range and flushRange cases, make sure it is legal
   6381 			DE_STATIC_ASSERT((int)MapBufferRangeCase::FLAG_USE_UNUSED_SPECIFIED_BUFFER == (int)MapBufferRangeFlushCase::FLAG_USE_UNUSED_SPECIFIED_BUFFER);
   6382 			DE_STATIC_ASSERT((int)MapBufferRangeCase::FLAG_USE_UNUSED_UNSPECIFIED_BUFFER == (int)MapBufferRangeFlushCase::FLAG_USE_UNUSED_UNSPECIFIED_BUFFER);
   6383 
   6384 			for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(groups); ++groupNdx)
   6385 			{
   6386 				tcu::TestCaseGroup* const bufferTypeGroup = groups[groupNdx].group;
   6387 
   6388 				mapBufferRangeMethodGroup->addChild(bufferTypeGroup);
   6389 
   6390 				for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(flagCases); ++caseNdx)
   6391 				{
   6392 					if (groups[groupNdx].unusedBufferCase && !flagCases[caseNdx].usefulForUnusedBuffers)
   6393 						continue;
   6394 
   6395 					tcu::TestCaseGroup* const bufferUsageGroup = new tcu::TestCaseGroup(m_testCtx, flagCases[caseNdx].name, "");
   6396 					bufferTypeGroup->addChild(bufferUsageGroup);
   6397 
   6398 					for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(bufferUsages); ++usageNdx)
   6399 						if (bufferUsages[usageNdx].primaryUsage || flagCases[caseNdx].allUsages)
   6400 							bufferUsageGroup->addChild(new MapBufferRangeCase(m_context,
   6401 																			  bufferUsages[usageNdx].name,
   6402 																			  std::string("Test with usage = ").append(bufferUsages[usageNdx].name).c_str(),
   6403 																			  minBufferSize,
   6404 																			  maxBufferSize,
   6405 																			  numMapSamples,
   6406 																			  bufferUsages[usageNdx].usage,
   6407 																			  flagCases[caseNdx].glFlags,
   6408 																			  flagCases[caseNdx].caseFlags | groups[groupNdx].flags));
   6409 				}
   6410 
   6411 				for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(flushCases); ++caseNdx)
   6412 				{
   6413 					tcu::TestCaseGroup* const bufferUsageGroup = new tcu::TestCaseGroup(m_testCtx, flushCases[caseNdx].name, "");
   6414 					bufferTypeGroup->addChild(bufferUsageGroup);
   6415 
   6416 					for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(bufferUsages); ++usageNdx)
   6417 						if (bufferUsages[usageNdx].primaryUsage)
   6418 							bufferUsageGroup->addChild(new MapBufferRangeFlushCase(m_context,
   6419 																				   bufferUsages[usageNdx].name,
   6420 																				   std::string("Test with usage = ").append(bufferUsages[usageNdx].name).c_str(),
   6421 																				   minBufferSize,
   6422 																				   maxBufferSize,
   6423 																				   numMapSamples,
   6424 																				   bufferUsages[usageNdx].usage,
   6425 																				   flushCases[caseNdx].glFlags,
   6426 																				   flushCases[caseNdx].caseFlags | groups[groupNdx].flags));
   6427 				}
   6428 			}
   6429 		}
   6430 	}
   6431 
   6432 	// .modify_after_use
   6433 	{
   6434 		const int minBufferSize	= 0;		// !< 0kiB
   6435 		const int maxBufferSize	= 1 << 24;	// !< 16MiB
   6436 
   6437 		static const struct Usage
   6438 		{
   6439 			const char* name;
   6440 			const char* description;
   6441 			deUint32	usage;
   6442 		} usages[] =
   6443 		{
   6444 			{ "static_draw",	"Test with GL_STATIC_DRAW",		GL_STATIC_DRAW	},
   6445 			{ "dynamic_draw",	"Test with GL_DYNAMIC_DRAW",	GL_DYNAMIC_DRAW	},
   6446 			{ "stream_draw",	"Test with GL_STREAM_DRAW",		GL_STREAM_DRAW },
   6447 
   6448 		};
   6449 
   6450 		for (int usageNdx = 0; usageNdx < DE_LENGTH_OF_ARRAY(usages); ++usageNdx)
   6451 		{
   6452 			tcu::TestCaseGroup* const usageGroup = new tcu::TestCaseGroup(m_testCtx, usages[usageNdx].name, usages[usageNdx].description);
   6453 			modifyAfterUseGroup->addChild(usageGroup);
   6454 
   6455 			usageGroup->addChild(new ModifyAfterWithBufferDataCase		(m_context, "buffer_data",							"Respecify buffer contents after use",					minBufferSize, maxBufferSize, usages[usageNdx].usage, 0));
   6456 			usageGroup->addChild(new ModifyAfterWithBufferDataCase		(m_context, "buffer_data_different_size",			"Respecify buffer contents and size after use",			minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithBufferDataCase::FLAG_RESPECIFY_SIZE));
   6457 			usageGroup->addChild(new ModifyAfterWithBufferDataCase		(m_context, "buffer_data_repeated",					"Respecify buffer contents after upload and use",		minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithBufferDataCase::FLAG_UPLOAD_REPEATED));
   6458 
   6459 			usageGroup->addChild(new ModifyAfterWithBufferSubDataCase	(m_context, "buffer_sub_data_full",					"Respecify buffer contents after use",					minBufferSize, maxBufferSize, usages[usageNdx].usage, 0));
   6460 			usageGroup->addChild(new ModifyAfterWithBufferSubDataCase	(m_context, "buffer_sub_data_partial",				"Respecify buffer contents partially use",				minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithBufferSubDataCase::FLAG_PARTIAL));
   6461 			usageGroup->addChild(new ModifyAfterWithBufferSubDataCase	(m_context, "buffer_sub_data_full_repeated",		"Respecify buffer contents after upload and use",		minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithBufferSubDataCase::FLAG_UPLOAD_REPEATED));
   6462 			usageGroup->addChild(new ModifyAfterWithBufferSubDataCase	(m_context, "buffer_sub_data_partial_repeated",		"Respecify buffer contents partially upload and use",	minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithBufferSubDataCase::FLAG_UPLOAD_REPEATED | ModifyAfterWithBufferSubDataCase::FLAG_PARTIAL));
   6463 
   6464 			usageGroup->addChild(new ModifyAfterWithMapBufferRangeCase	(m_context, "map_flag_write_full",					"Respecify buffer contents after use",					minBufferSize, maxBufferSize, usages[usageNdx].usage, 0,												GL_MAP_WRITE_BIT));
   6465 			usageGroup->addChild(new ModifyAfterWithMapBufferRangeCase	(m_context, "map_flag_write_partial",				"Respecify buffer contents partially after use",		minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithMapBufferRangeCase::FLAG_PARTIAL,	GL_MAP_WRITE_BIT));
   6466 			usageGroup->addChild(new ModifyAfterWithMapBufferRangeCase	(m_context, "map_flag_read_write_full",				"Respecify buffer contents after use",					minBufferSize, maxBufferSize, usages[usageNdx].usage, 0,												GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
   6467 			usageGroup->addChild(new ModifyAfterWithMapBufferRangeCase	(m_context, "map_flag_read_write_partial",			"Respecify buffer contents partially after use",		minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithMapBufferRangeCase::FLAG_PARTIAL,	GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
   6468 			usageGroup->addChild(new ModifyAfterWithMapBufferRangeCase	(m_context, "map_flag_invalidate_range_full",		"Respecify buffer contents after use",					minBufferSize, maxBufferSize, usages[usageNdx].usage, 0,												GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT));
   6469 			usageGroup->addChild(new ModifyAfterWithMapBufferRangeCase	(m_context, "map_flag_invalidate_range_partial",	"Respecify buffer contents partially after use",		minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithMapBufferRangeCase::FLAG_PARTIAL,	GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT));
   6470 			usageGroup->addChild(new ModifyAfterWithMapBufferRangeCase	(m_context, "map_flag_invalidate_buffer_full",		"Respecify buffer contents after use",					minBufferSize, maxBufferSize, usages[usageNdx].usage, 0,												GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
   6471 			usageGroup->addChild(new ModifyAfterWithMapBufferRangeCase	(m_context, "map_flag_invalidate_buffer_partial",	"Respecify buffer contents partially after use",		minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithMapBufferRangeCase::FLAG_PARTIAL,	GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
   6472 			usageGroup->addChild(new ModifyAfterWithMapBufferRangeCase	(m_context, "map_flag_unsynchronized_full",			"Respecify buffer contents after use",					minBufferSize, maxBufferSize, usages[usageNdx].usage, 0,												GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
   6473 			usageGroup->addChild(new ModifyAfterWithMapBufferRangeCase	(m_context, "map_flag_unsynchronized_partial",		"Respecify buffer contents partially after use",		minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithMapBufferRangeCase::FLAG_PARTIAL,	GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
   6474 
   6475 			usageGroup->addChild(new ModifyAfterWithMapBufferFlushCase	(m_context, "map_flag_flush_explicit_full",			"Respecify buffer contents after use",					minBufferSize, maxBufferSize, usages[usageNdx].usage, 0,												GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
   6476 			usageGroup->addChild(new ModifyAfterWithMapBufferFlushCase	(m_context, "map_flag_flush_explicit_partial",		"Respecify buffer contents partially after use",		minBufferSize, maxBufferSize, usages[usageNdx].usage, ModifyAfterWithMapBufferFlushCase::FLAG_PARTIAL,	GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
   6477 		}
   6478 	}
   6479 
   6480 	// .render_after_upload
   6481 	{
   6482 		// .reference
   6483 		{
   6484 			tcu::TestCaseGroup* const renderReferenceGroup = new tcu::TestCaseGroup(m_testCtx, "reference", "Baseline results");
   6485 			renderAfterUploadGroup->addChild(renderReferenceGroup);
   6486 
   6487 			// .draw
   6488 			{
   6489 				tcu::TestCaseGroup* const drawGroup = new tcu::TestCaseGroup(m_testCtx, "draw", "Time usage of functions with non-modified buffers");
   6490 				renderReferenceGroup->addChild(drawGroup);
   6491 
   6492 				// Time consumed by readPixels
   6493 				drawGroup->addChild(new ReferenceReadPixelsTimeCase	(m_context, "read_pixels",		"Measure time consumed by readPixels() function call"));
   6494 
   6495 				// Time consumed by rendering
   6496 				drawGroup->addChild(new ReferenceRenderTimeCase		(m_context, "draw_arrays",		"Measure time consumed by drawArrays() function call",		DRAWMETHOD_DRAW_ARRAYS));
   6497 				drawGroup->addChild(new ReferenceRenderTimeCase		(m_context, "draw_elements",	"Measure time consumed by drawElements() function call",	DRAWMETHOD_DRAW_ELEMENTS));
   6498 			}
   6499 
   6500 			// .draw_upload_draw
   6501 			{
   6502 				static const struct
   6503 				{
   6504 					const char*		name;
   6505 					const char*		description;
   6506 					DrawMethod		drawMethod;
   6507 					TargetBuffer	targetBuffer;
   6508 					bool			partial;
   6509 				} uploadTargets[] =
   6510 				{
   6511 					{
   6512 						"draw_arrays_upload_vertices",
   6513 						"Measure time consumed by drawArrays, vertex attribute upload, another drawArrays, and readPixels function calls.",
   6514 						DRAWMETHOD_DRAW_ARRAYS,
   6515 						TARGETBUFFER_VERTEX,
   6516 						false
   6517 					},
   6518 					{
   6519 						"draw_arrays_upload_vertices_partial",
   6520 						"Measure time consumed by drawArrays, partial vertex attribute upload, another drawArrays, and readPixels function calls.",
   6521 						DRAWMETHOD_DRAW_ARRAYS,
   6522 						TARGETBUFFER_VERTEX,
   6523 						true
   6524 					},
   6525 					{
   6526 						"draw_elements_upload_vertices",
   6527 						"Measure time consumed by drawElements, vertex attribute upload, another drawElements, and readPixels function calls.",
   6528 						DRAWMETHOD_DRAW_ELEMENTS,
   6529 						TARGETBUFFER_VERTEX,
   6530 						false
   6531 					},
   6532 					{
   6533 						"draw_elements_upload_indices",
   6534 						"Measure time consumed by drawElements, index upload, another drawElements, and readPixels function calls.",
   6535 						DRAWMETHOD_DRAW_ELEMENTS,
   6536 						TARGETBUFFER_INDEX,
   6537 						false
   6538 					},
   6539 					{
   6540 						"draw_elements_upload_indices_partial",
   6541 						"Measure time consumed by drawElements, partial index upload, another drawElements, and readPixels function calls.",
   6542 						DRAWMETHOD_DRAW_ELEMENTS,
   6543 						TARGETBUFFER_INDEX,
   6544 						true
   6545 					},
   6546 				};
   6547 				static const struct
   6548 				{
   6549 					const char*							name;
   6550 					const char*							description;
   6551 					UploadMethod						uploadMethod;
   6552 					BufferInUseRenderTimeCase::MapFlags	mapFlags;
   6553 					bool								supportsPartialUpload;
   6554 				} uploadMethods[] =
   6555 				{
   6556 					{ "buffer_data",						"bufferData",		UPLOADMETHOD_BUFFER_DATA,		BufferInUseRenderTimeCase::MAPFLAG_NONE,				false	},
   6557 					{ "buffer_sub_data",					"bufferSubData",	UPLOADMETHOD_BUFFER_SUB_DATA,	BufferInUseRenderTimeCase::MAPFLAG_NONE,				true	},
   6558 					{ "map_buffer_range_invalidate_range",	"mapBufferRange",	UPLOADMETHOD_MAP_BUFFER_RANGE,	BufferInUseRenderTimeCase::MAPFLAG_INVALIDATE_RANGE,	true	},
   6559 					{ "map_buffer_range_invalidate_buffer",	"mapBufferRange",	UPLOADMETHOD_MAP_BUFFER_RANGE,	BufferInUseRenderTimeCase::MAPFLAG_INVALIDATE_BUFFER,	false	},
   6560 				};
   6561 
   6562 				tcu::TestCaseGroup* const drawUploadDrawGroup = new tcu::TestCaseGroup(m_testCtx, "draw_upload_draw", "Time usage of functions draw, upload and another draw");
   6563 				renderReferenceGroup->addChild(drawUploadDrawGroup);
   6564 
   6565 				for (int uploadTargetNdx = 0; uploadTargetNdx < DE_LENGTH_OF_ARRAY(uploadTargets); ++uploadTargetNdx)
   6566 				for (int uploadMethodNdx = 0; uploadMethodNdx < DE_LENGTH_OF_ARRAY(uploadMethods); ++uploadMethodNdx)
   6567 				{
   6568 					const std::string name = std::string() + uploadTargets[uploadTargetNdx].name + "_with_" + uploadMethods[uploadMethodNdx].name;
   6569 
   6570 					if (uploadTargets[uploadTargetNdx].partial && !uploadMethods[uploadMethodNdx].supportsPartialUpload)
   6571 						continue;
   6572 
   6573 					drawUploadDrawGroup->addChild(new BufferInUseRenderTimeCase(m_context,
   6574 																				name.c_str(),
   6575 																				uploadTargets[uploadTargetNdx].description,
   6576 																				uploadTargets[uploadTargetNdx].drawMethod,
   6577 																				uploadMethods[uploadMethodNdx].mapFlags,
   6578 																				uploadTargets[uploadTargetNdx].targetBuffer,
   6579 																				uploadMethods[uploadMethodNdx].uploadMethod,
   6580 																				(uploadTargets[uploadTargetNdx].partial) ? (UPLOADRANGE_PARTIAL) : (UPLOADRANGE_FULL),
   6581 																				BufferInUseRenderTimeCase::UPLOADBUFFERTARGET_DIFFERENT_BUFFER));
   6582 				}
   6583 			}
   6584 		}
   6585 
   6586 		// .upload_unrelated_and_draw
   6587 		{
   6588 			static const struct
   6589 			{
   6590 				const char*		name;
   6591 				const char*		description;
   6592 				DrawMethod		drawMethod;
   6593 			} drawMethods[] =
   6594 			{
   6595 				{ "draw_arrays",	"drawArrays",	DRAWMETHOD_DRAW_ARRAYS		},
   6596 				{ "draw_elements",	"drawElements",	DRAWMETHOD_DRAW_ELEMENTS	},
   6597 			};
   6598 
   6599 			static const struct
   6600 			{
   6601 				const char*		name;
   6602 				UploadMethod	uploadMethod;
   6603 			} uploadMethods[] =
   6604 			{
   6605 				{ "buffer_data",		UPLOADMETHOD_BUFFER_DATA		},
   6606 				{ "buffer_sub_data",	UPLOADMETHOD_BUFFER_SUB_DATA	},
   6607 				{ "map_buffer_range",	UPLOADMETHOD_MAP_BUFFER_RANGE	},
   6608 			};
   6609 
   6610 			tcu::TestCaseGroup* const uploadUnrelatedGroup = new tcu::TestCaseGroup(m_testCtx, "upload_unrelated_and_draw", "Time usage of functions after an unrelated upload");
   6611 			renderAfterUploadGroup->addChild(uploadUnrelatedGroup);
   6612 
   6613 			for (int drawMethodNdx = 0; drawMethodNdx < DE_LENGTH_OF_ARRAY(drawMethods); ++drawMethodNdx)
   6614 			for (int uploadMethodNdx = 0; uploadMethodNdx < DE_LENGTH_OF_ARRAY(uploadMethods); ++uploadMethodNdx)
   6615 			{
   6616 				const std::string name = std::string() + drawMethods[drawMethodNdx].name + "_upload_unrelated_with_" + uploadMethods[uploadMethodNdx].name;
   6617 				const std::string desc = std::string() + "Measure time consumed by " + drawMethods[drawMethodNdx].description + " function call after an unrelated upload";
   6618 
   6619 				// Time consumed by rendering command after an unrelated upload
   6620 
   6621 				uploadUnrelatedGroup->addChild(new UnrelatedUploadRenderTimeCase(m_context, name.c_str(), desc.c_str(), drawMethods[drawMethodNdx].drawMethod, uploadMethods[uploadMethodNdx].uploadMethod));
   6622 			}
   6623 		}
   6624 
   6625 		// .upload_and_draw
   6626 		{
   6627 			static const struct
   6628 			{
   6629 				const char*			name;
   6630 				const char*			description;
   6631 				BufferState			bufferState;
   6632 				UnrelatedBufferType	unrelatedBuffer;
   6633 				bool				supportsPartialUpload;
   6634 			} bufferConfigs[] =
   6635 			{
   6636 				{ "used_buffer",						"Upload to an used buffer",											BUFFERSTATE_EXISTING,	UNRELATEDBUFFERTYPE_NONE,	true	},
   6637 				{ "new_buffer",							"Upload to a new buffer",											BUFFERSTATE_NEW,		UNRELATEDBUFFERTYPE_NONE,	false	},
   6638 				{ "used_buffer_and_unrelated_upload",	"Upload to an used buffer and an unrelated buffer and then draw",	BUFFERSTATE_EXISTING,	UNRELATEDBUFFERTYPE_VERTEX,	true	},
   6639 				{ "new_buffer_and_unrelated_upload",	"Upload to a new buffer and an unrelated buffer and then draw",		BUFFERSTATE_NEW,		UNRELATEDBUFFERTYPE_VERTEX,	false	},
   6640 			};
   6641 
   6642 			tcu::TestCaseGroup* const uploadAndDrawGroup = new tcu::TestCaseGroup(m_testCtx, "upload_and_draw", "Time usage of rendering functions with modified buffers");
   6643 			renderAfterUploadGroup->addChild(uploadAndDrawGroup);
   6644 
   6645 			// .used_buffer
   6646 			// .new_buffer
   6647 			// .used_buffer_and_unrelated_upload
   6648 			// .new_buffer_and_unrelated_upload
   6649 			for (int stateNdx = 0; stateNdx < DE_LENGTH_OF_ARRAY(bufferConfigs); ++stateNdx)
   6650 			{
   6651 				static const struct
   6652 				{
   6653 					const char*		name;
   6654 					const char*		description;
   6655 					DrawMethod		drawMethod;
   6656 					TargetBuffer	targetBuffer;
   6657 					bool			partial;
   6658 				} uploadTargets[] =
   6659 				{
   6660 					{
   6661 						"draw_arrays_upload_vertices",
   6662 						"Measure time consumed by vertex attribute upload, drawArrays, and readPixels function calls",
   6663 						DRAWMETHOD_DRAW_ARRAYS,
   6664 						TARGETBUFFER_VERTEX,
   6665 						false
   6666 					},
   6667 					{
   6668 						"draw_arrays_upload_vertices_partial",
   6669 						"Measure time consumed by partial vertex attribute upload, drawArrays, and readPixels function calls",
   6670 						DRAWMETHOD_DRAW_ARRAYS,
   6671 						TARGETBUFFER_VERTEX,
   6672 						true
   6673 					},
   6674 					{
   6675 						"draw_elements_upload_vertices",
   6676 						"Measure time consumed by vertex attribute upload, drawElements, and readPixels function calls",
   6677 						DRAWMETHOD_DRAW_ELEMENTS,
   6678 						TARGETBUFFER_VERTEX,
   6679 						false
   6680 					},
   6681 					{
   6682 						"draw_elements_upload_indices",
   6683 						"Measure time consumed by index upload, drawElements, and readPixels function calls",
   6684 						DRAWMETHOD_DRAW_ELEMENTS,
   6685 						TARGETBUFFER_INDEX,
   6686 						false
   6687 					},
   6688 					{
   6689 						"draw_elements_upload_indices_partial",
   6690 						"Measure time consumed by partial index upload, drawElements, and readPixels function calls",
   6691 						DRAWMETHOD_DRAW_ELEMENTS,
   6692 						TARGETBUFFER_INDEX,
   6693 						true
   6694 					},
   6695 				};
   6696 				static const struct
   6697 				{
   6698 					const char*		name;
   6699 					const char*		description;
   6700 					UploadMethod	uploadMethod;
   6701 					bool			supportsPartialUpload;
   6702 				} uploadMethods[] =
   6703 				{
   6704 					{ "buffer_data",		"bufferData",		UPLOADMETHOD_BUFFER_DATA,		false	},
   6705 					{ "buffer_sub_data",	"bufferSubData",	UPLOADMETHOD_BUFFER_SUB_DATA,	true	},
   6706 					{ "map_buffer_range",	"mapBufferRange",	UPLOADMETHOD_MAP_BUFFER_RANGE,	true	},
   6707 				};
   6708 
   6709 				tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, bufferConfigs[stateNdx].name, bufferConfigs[stateNdx].description);
   6710 				uploadAndDrawGroup->addChild(group);
   6711 
   6712 				for (int uploadTargetNdx = 0; uploadTargetNdx < DE_LENGTH_OF_ARRAY(uploadTargets); ++uploadTargetNdx)
   6713 				for (int uploadMethodNdx = 0; uploadMethodNdx < DE_LENGTH_OF_ARRAY(uploadMethods); ++uploadMethodNdx)
   6714 				{
   6715 					const std::string name = std::string() + uploadTargets[uploadTargetNdx].name + "_with_" + uploadMethods[uploadMethodNdx].name;
   6716 
   6717 					if (uploadTargets[uploadTargetNdx].partial && !uploadMethods[uploadMethodNdx].supportsPartialUpload)
   6718 						continue;
   6719 					if (uploadTargets[uploadTargetNdx].partial && !bufferConfigs[stateNdx].supportsPartialUpload)
   6720 						continue;
   6721 
   6722 					// Don't log unrelated buffer information to samples if there is no such buffer
   6723 
   6724 					if (bufferConfigs[stateNdx].unrelatedBuffer == UNRELATEDBUFFERTYPE_NONE)
   6725 					{
   6726 						typedef UploadRenderReadDuration				SampleType;
   6727 						typedef GenericUploadRenderTimeCase<SampleType>	TestType;
   6728 
   6729 						group->addChild(new TestType(m_context,
   6730 													 name.c_str(),
   6731 													 uploadTargets[uploadTargetNdx].description,
   6732 													 uploadTargets[uploadTargetNdx].drawMethod,
   6733 													 uploadTargets[uploadTargetNdx].targetBuffer,
   6734 													 uploadMethods[uploadMethodNdx].uploadMethod,
   6735 													 bufferConfigs[stateNdx].bufferState,
   6736 													 (uploadTargets[uploadTargetNdx].partial) ? (UPLOADRANGE_PARTIAL) : (UPLOADRANGE_FULL),
   6737 													 bufferConfigs[stateNdx].unrelatedBuffer));
   6738 					}
   6739 					else
   6740 					{
   6741 						typedef UploadRenderReadDurationWithUnrelatedUploadSize	SampleType;
   6742 						typedef GenericUploadRenderTimeCase<SampleType>			TestType;
   6743 
   6744 						group->addChild(new TestType(m_context,
   6745 													 name.c_str(),
   6746 													 uploadTargets[uploadTargetNdx].description,
   6747 													 uploadTargets[uploadTargetNdx].drawMethod,
   6748 													 uploadTargets[uploadTargetNdx].targetBuffer,
   6749 													 uploadMethods[uploadMethodNdx].uploadMethod,
   6750 													 bufferConfigs[stateNdx].bufferState,
   6751 													 (uploadTargets[uploadTargetNdx].partial) ? (UPLOADRANGE_PARTIAL) : (UPLOADRANGE_FULL),
   6752 													 bufferConfigs[stateNdx].unrelatedBuffer));
   6753 					}
   6754 				}
   6755 			}
   6756 		}
   6757 
   6758 		// .draw_modify_draw
   6759 		{
   6760 			static const struct
   6761 			{
   6762 				const char*		name;
   6763 				const char*		description;
   6764 				DrawMethod		drawMethod;
   6765 				TargetBuffer	targetBuffer;
   6766 				bool			partial;
   6767 			} uploadTargets[] =
   6768 			{
   6769 				{
   6770 					"draw_arrays_upload_vertices",
   6771 					"Measure time consumed by drawArrays, vertex attribute upload, another drawArrays, and readPixels function calls.",
   6772 					DRAWMETHOD_DRAW_ARRAYS,
   6773 					TARGETBUFFER_VERTEX,
   6774 					false
   6775 				},
   6776 				{
   6777 					"draw_arrays_upload_vertices_partial",
   6778 					"Measure time consumed by drawArrays, partial vertex attribute upload, another drawArrays, and readPixels function calls.",
   6779 					DRAWMETHOD_DRAW_ARRAYS,
   6780 					TARGETBUFFER_VERTEX,
   6781 					true
   6782 				},
   6783 				{
   6784 					"draw_elements_upload_vertices",
   6785 					"Measure time consumed by drawElements, vertex attribute upload, another drawElements, and readPixels function calls.",
   6786 					DRAWMETHOD_DRAW_ELEMENTS,
   6787 					TARGETBUFFER_VERTEX,
   6788 					false
   6789 				},
   6790 				{
   6791 					"draw_elements_upload_indices",
   6792 					"Measure time consumed by drawElements, index upload, another drawElements, and readPixels function calls.",
   6793 					DRAWMETHOD_DRAW_ELEMENTS,
   6794 					TARGETBUFFER_INDEX,
   6795 					false
   6796 				},
   6797 				{
   6798 					"draw_elements_upload_indices_partial",
   6799 					"Measure time consumed by drawElements, partial index upload, another drawElements, and readPixels function calls.",
   6800 					DRAWMETHOD_DRAW_ELEMENTS,
   6801 					TARGETBUFFER_INDEX,
   6802 					true
   6803 				},
   6804 			};
   6805 			static const struct
   6806 			{
   6807 				const char*							name;
   6808 				const char*							description;
   6809 				UploadMethod						uploadMethod;
   6810 				BufferInUseRenderTimeCase::MapFlags	mapFlags;
   6811 				bool								supportsPartialUpload;
   6812 			} uploadMethods[] =
   6813 			{
   6814 				{ "buffer_data",						"bufferData",		UPLOADMETHOD_BUFFER_DATA,		BufferInUseRenderTimeCase::MAPFLAG_NONE,				false	},
   6815 				{ "buffer_sub_data",					"bufferSubData",	UPLOADMETHOD_BUFFER_SUB_DATA,	BufferInUseRenderTimeCase::MAPFLAG_NONE,				true	},
   6816 				{ "map_buffer_range_invalidate_range",	"mapBufferRange",	UPLOADMETHOD_MAP_BUFFER_RANGE,	BufferInUseRenderTimeCase::MAPFLAG_INVALIDATE_RANGE,	true	},
   6817 				{ "map_buffer_range_invalidate_buffer",	"mapBufferRange",	UPLOADMETHOD_MAP_BUFFER_RANGE,	BufferInUseRenderTimeCase::MAPFLAG_INVALIDATE_BUFFER,	false	},
   6818 			};
   6819 
   6820 			tcu::TestCaseGroup* const drawModifyDrawGroup = new tcu::TestCaseGroup(m_testCtx, "draw_modify_draw", "Time used in rendering functions with modified buffers while original buffer is still in use");
   6821 			renderAfterUploadGroup->addChild(drawModifyDrawGroup);
   6822 
   6823 			for (int uploadTargetNdx = 0; uploadTargetNdx < DE_LENGTH_OF_ARRAY(uploadTargets); ++uploadTargetNdx)
   6824 			for (int uploadMethodNdx = 0; uploadMethodNdx < DE_LENGTH_OF_ARRAY(uploadMethods); ++uploadMethodNdx)
   6825 			{
   6826 				const std::string name = std::string() + uploadTargets[uploadTargetNdx].name + "_with_" + uploadMethods[uploadMethodNdx].name;
   6827 
   6828 				if (uploadTargets[uploadTargetNdx].partial && !uploadMethods[uploadMethodNdx].supportsPartialUpload)
   6829 					continue;
   6830 
   6831 				drawModifyDrawGroup->addChild(new BufferInUseRenderTimeCase(m_context,
   6832 																			name.c_str(),
   6833 																			uploadTargets[uploadTargetNdx].description,
   6834 																			uploadTargets[uploadTargetNdx].drawMethod,
   6835 																			uploadMethods[uploadMethodNdx].mapFlags,
   6836 																			uploadTargets[uploadTargetNdx].targetBuffer,
   6837 																			uploadMethods[uploadMethodNdx].uploadMethod,
   6838 																			(uploadTargets[uploadTargetNdx].partial) ? (UPLOADRANGE_PARTIAL) : (UPLOADRANGE_FULL),
   6839 																			BufferInUseRenderTimeCase::UPLOADBUFFERTARGET_SAME_BUFFER));
   6840 			}
   6841 		}
   6842 
   6843 		// .upload_wait_draw
   6844 		{
   6845 			static const struct
   6846 			{
   6847 				const char*	name;
   6848 				const char*	description;
   6849 				BufferState	bufferState;
   6850 			} bufferStates[] =
   6851 			{
   6852 				{ "new_buffer",		"Uploading to just generated name",	BUFFERSTATE_NEW			},
   6853 				{ "used_buffer",	"Uploading to a used buffer",		BUFFERSTATE_EXISTING	},
   6854 			};
   6855 			static const struct
   6856 			{
   6857 				const char*		name;
   6858 				const char*		description;
   6859 				DrawMethod		drawMethod;
   6860 				TargetBuffer	targetBuffer;
   6861 			} uploadTargets[] =
   6862 			{
   6863 				{ "draw_arrays_vertices",	"Upload vertex data, draw with drawArrays",		DRAWMETHOD_DRAW_ARRAYS,		TARGETBUFFER_VERTEX	},
   6864 				{ "draw_elements_vertices",	"Upload vertex data, draw with drawElements",	DRAWMETHOD_DRAW_ELEMENTS,	TARGETBUFFER_VERTEX	},
   6865 				{ "draw_elements_indices",	"Upload index data, draw with drawElements",	DRAWMETHOD_DRAW_ELEMENTS,	TARGETBUFFER_INDEX	},
   6866 			};
   6867 			static const struct
   6868 			{
   6869 				const char*		name;
   6870 				const char*		description;
   6871 				UploadMethod	uploadMethod;
   6872 			} uploadMethods[] =
   6873 			{
   6874 				{ "buffer_data",		"bufferData",		UPLOADMETHOD_BUFFER_DATA		},
   6875 				{ "buffer_sub_data",	"bufferSubData",	UPLOADMETHOD_BUFFER_SUB_DATA	},
   6876 				{ "map_buffer_range",	"mapBufferRange",	UPLOADMETHOD_MAP_BUFFER_RANGE	},
   6877 			};
   6878 
   6879 			tcu::TestCaseGroup* const uploadSwapDrawGroup = new tcu::TestCaseGroup(m_testCtx, "upload_wait_draw", "Time used in rendering functions after a buffer upload N frames ago");
   6880 			renderAfterUploadGroup->addChild(uploadSwapDrawGroup);
   6881 
   6882 			for (int bufferStateNdx = 0; bufferStateNdx < DE_LENGTH_OF_ARRAY(bufferStates); ++bufferStateNdx)
   6883 			{
   6884 				tcu::TestCaseGroup* const bufferGroup = new tcu::TestCaseGroup(m_testCtx, bufferStates[bufferStateNdx].name, bufferStates[bufferStateNdx].description);
   6885 				uploadSwapDrawGroup->addChild(bufferGroup);
   6886 
   6887 				for (int uploadTargetNdx = 0; uploadTargetNdx < DE_LENGTH_OF_ARRAY(uploadTargets); ++uploadTargetNdx)
   6888 				for (int uploadMethodNdx = 0; uploadMethodNdx < DE_LENGTH_OF_ARRAY(uploadMethods); ++uploadMethodNdx)
   6889 				{
   6890 					const std::string name = std::string() + uploadTargets[uploadTargetNdx].name + "_with_" + uploadMethods[uploadMethodNdx].name;
   6891 
   6892 					bufferGroup->addChild(new UploadWaitDrawCase(m_context,
   6893 																 name.c_str(),
   6894 																 uploadTargets[uploadTargetNdx].description,
   6895 																 uploadTargets[uploadTargetNdx].drawMethod,
   6896 																 uploadTargets[uploadTargetNdx].targetBuffer,
   6897 																 uploadMethods[uploadMethodNdx].uploadMethod,
   6898 																 bufferStates[bufferStateNdx].bufferState));
   6899 				}
   6900 			}
   6901 		}
   6902 	}
   6903 }
   6904 
   6905 } // Performance
   6906 } // gles3
   6907 } // deqp
   6908