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:
UnmapFailureError(void)502 UnmapFailureError (void) : std::exception() {}
503 };
504
getHumanReadableByteSize(int numBytes)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
medianTimeMemcpy(void * dst,const void * src,int numBytes)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
dummyCalculation(float initial,int workSize)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
busyWait(int microseconds)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>
linearSample(const std::vector<T> & values,float position)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>
calculateSingleOperationStatistics(const std::vector<T> & samples,deUint64 T::SampleType::* target)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>
calculateBasicStatistics(StatisticsType & stats,const LineParametersWithConfidence & fit,const std::vector<SampleType> & samples,int SampleType::* predictor)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>
calculateBasicTransferStatistics(StatisticsType & stats,const LineParametersWithConfidence & fit,const std::vector<SampleType> & samples)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>
calculateBasicRenderStatistics(StatisticsType & stats,const LineParametersWithConfidence & fit,const std::vector<SampleType> & samples)769 void calculateBasicRenderStatistics (StatisticsType& stats, const LineParametersWithConfidence& fit, const std::vector<SampleType>& samples)
770 {
771 calculateBasicStatistics(stats, fit, samples, &SampleType::renderDataSize);
772 }
773
calculateSampleStatistics(const LineParametersWithConfidence & fit,const std::vector<UploadSampleResult<SingleOperationDuration>> & samples)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
calculateSampleStatistics(const LineParametersWithConfidence & fit,const std::vector<UploadSampleResult<MapBufferRangeDuration>> & samples)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
calculateSampleStatistics(const LineParametersWithConfidence & fit,const std::vector<UploadSampleResult<MapBufferRangeFlushDuration>> & samples)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
calculateSampleStatistics(const LineParametersWithConfidence & fit,const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc>> & samples)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
calculateSampleStatistics(const LineParametersWithConfidence & fit,const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc>> & samples)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
calculateSampleStatistics(const LineParametersWithConfidence & fit,const std::vector<RenderSampleResult<RenderReadDuration>> & samples)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
calculateSampleStatistics(const LineParametersWithConfidence & fit,const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration>> & samples)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
calculateSampleStatistics(const LineParametersWithConfidence & fit,const std::vector<RenderSampleResult<UploadRenderReadDuration>> & samples)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
calculateSampleStatistics(const LineParametersWithConfidence & fit,const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize>> & samples)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
calculateSampleStatistics(const LineParametersWithConfidence & fit,const std::vector<RenderSampleResult<RenderUploadRenderReadDuration>> & samples)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>
fitLineToSamples(const std::vector<UploadSampleResult<DurationType>> & samples,int beginNdx,int endNdx,int step,deUint64 DurationType::* target=& DurationType::fitResponseDuration)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>
fitLineToSamples(const std::vector<RenderSampleResult<DurationType>> & samples,int beginNdx,int endNdx,int step,deUint64 DurationType::* target=& DurationType::fitResponseDuration)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>
fitLineToSamples(const std::vector<T> & samples,int beginNdx,int endNdx,deUint64 T::SampleType::* target=& T::SampleType::fitResponseDuration)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>
fitLineToSamples(const std::vector<T> & samples,deUint64 T::SampleType::* target=& T::SampleType::fitResponseDuration)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
getAreaBetweenLines(float xmin,float xmax,float lineAOffset,float lineACoefficient,float lineBOffset,float lineBCoefficient)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>
calculateSampleFitLinearity(const std::vector<T> & samples,int T::* predictor)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>
calculateSampleFitLinearity(const std::vector<UploadSampleResult<DurationType>> & samples)1020 static float calculateSampleFitLinearity (const std::vector<UploadSampleResult<DurationType> >& samples)
1021 {
1022 return calculateSampleFitLinearity(samples, &UploadSampleResult<DurationType>::writtenSize);
1023 }
1024
1025 template <typename DurationType>
calculateSampleFitLinearity(const std::vector<RenderSampleResult<DurationType>> & samples)1026 static float calculateSampleFitLinearity (const std::vector<RenderSampleResult<DurationType> >& samples)
1027 {
1028 return calculateSampleFitLinearity(samples, &RenderSampleResult<DurationType>::renderDataSize);
1029 }
1030
1031 template <typename T>
calculateSampleTemporalStability(const std::vector<T> & samples,int T::* predictor)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>
calculateSampleTemporalStability(const std::vector<UploadSampleResult<DurationType>> & samples)1056 static float calculateSampleTemporalStability (const std::vector<UploadSampleResult<DurationType> >& samples)
1057 {
1058 return calculateSampleTemporalStability(samples, &UploadSampleResult<DurationType>::writtenSize);
1059 }
1060
1061 template <typename DurationType>
calculateSampleTemporalStability(const std::vector<RenderSampleResult<DurationType>> & samples)1062 static float calculateSampleTemporalStability (const std::vector<RenderSampleResult<DurationType> >& samples)
1063 {
1064 return calculateSampleTemporalStability(samples, &RenderSampleResult<DurationType>::renderDataSize);
1065 }
1066
1067 template <typename DurationType>
bucketizeSamplesUniformly(const std::vector<UploadSampleResult<DurationType>> & samples,std::vector<UploadSampleResult<DurationType>> * buckets,int numBuckets,int & minBufferSize,int & maxBufferSize)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>
logMapRangeStats(tcu::TestLog & log,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logUnmapStats(tcu::TestLog & log,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logWriteStats(tcu::TestLog & log,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logFlushStats(tcu::TestLog & log,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logAllocStats(tcu::TestLog & log,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logMapRangeStats(tcu::TestLog & log,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logUnmapStats(tcu::TestLog & log,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logWriteStats(tcu::TestLog & log,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logFlushStats(tcu::TestLog & log,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logAllocStats(tcu::TestLog & log,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logMapContribution(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logUnmapContribution(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logWriteContribution(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logFlushContribution(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logAllocContribution(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logRenderContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logReadContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logUploadContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logTotalContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logFirstRenderContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logSecondRenderContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logMapContribution(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logUnmapContribution(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logWriteContribution(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logFlushContribution(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logAllocContribution(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logRenderContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logReadContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logUploadContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logTotalContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logFirstRenderContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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>
logSecondRenderContribution(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples,const typename SampleTypeTraits<SampleType>::StatsType & stats)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
logSampleList(tcu::TestLog & log,const LineParametersWithConfidence & theilSenFitting,const std::vector<UploadSampleResult<SingleOperationDuration>> & samples)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
logSampleList(tcu::TestLog & log,const LineParametersWithConfidence & theilSenFitting,const std::vector<UploadSampleResult<MapBufferRangeDuration>> & samples)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
logSampleList(tcu::TestLog & log,const LineParametersWithConfidence & theilSenFitting,const std::vector<UploadSampleResult<MapBufferRangeDurationNoAlloc>> & samples)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
logSampleList(tcu::TestLog & log,const LineParametersWithConfidence & theilSenFitting,const std::vector<UploadSampleResult<MapBufferRangeFlushDuration>> & samples)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
logSampleList(tcu::TestLog & log,const LineParametersWithConfidence & theilSenFitting,const std::vector<UploadSampleResult<MapBufferRangeFlushDurationNoAlloc>> & samples)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
logSampleList(tcu::TestLog & log,const LineParametersWithConfidence & theilSenFitting,const std::vector<RenderSampleResult<RenderReadDuration>> & samples)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
logSampleList(tcu::TestLog & log,const LineParametersWithConfidence & theilSenFitting,const std::vector<RenderSampleResult<UnrelatedUploadRenderReadDuration>> & samples)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
logSampleList(tcu::TestLog & log,const LineParametersWithConfidence & theilSenFitting,const std::vector<RenderSampleResult<UploadRenderReadDuration>> & samples)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
logSampleList(tcu::TestLog & log,const LineParametersWithConfidence & theilSenFitting,const std::vector<RenderSampleResult<UploadRenderReadDurationWithUnrelatedUploadSize>> & samples)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
logSampleList(tcu::TestLog & log,const LineParametersWithConfidence & theilSenFitting,const std::vector<RenderSampleResult<RenderUploadRenderReadDuration>> & samples)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>
analyzeSampleResults(tcu::TestLog & log,const std::vector<UploadSampleResult<SampleType>> & samples,bool logBucketPerformance)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>
analyzeSampleResults(tcu::TestLog & log,const std::vector<RenderSampleResult<SampleType>> & samples)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
generateTwoPassRandomIterationOrder(std::vector<int> & iterationOrder,int numSamples)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>
BasicBufferCase(Context & context,const char * name,const char * desc,int bufferSizeMin,int bufferSizeMax,int numSamples,int flags)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>
~BasicBufferCase(void)1959 BasicBufferCase<SampleType>::~BasicBufferCase (void)
1960 {
1961 deinit();
1962 }
1963
1964 template <typename SampleType>
init(void)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>
deinit(void)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>
iterate(void)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>
disableGLWarmup(void)2156 void BasicBufferCase<SampleType>::disableGLWarmup (void)
2157 {
2158 m_useGL = false;
2159 }
2160
2161 template <typename SampleType>
waitGLResults(void)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>
BasicUploadCase(Context & context,const char * name,const char * desc,int bufferSizeMin,int bufferSizeMax,int numSamples,deUint32 bufferUsage,CaseType caseType,ResultType resultType,int flags)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>
~BasicUploadCase(void)2259 BasicUploadCase<SampleType>::~BasicUploadCase (void)
2260 {
2261 deinit();
2262 }
2263
2264 template <typename SampleType>
init(void)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>
deinit(void)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>
runSample(int iteration,UploadSampleResult<SampleType> & sample)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>
createBuffer(int iteration,int bufferSize)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>
deleteBuffer(int bufferSize)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>
useBuffer(int bufferSize)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>
logAndSetTestResult(const std::vector<UploadSampleResult<SampleType>> & results)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
ReferenceMemcpyCase(Context & ctx,const char * name,const char * desc,int minBufferSize,int maxBufferSize,int numSamples,bool largeBuffersCase)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
~ReferenceMemcpyCase(void)2521 ReferenceMemcpyCase::~ReferenceMemcpyCase (void)
2522 {
2523 }
2524
init(void)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
deinit(void)2535 void ReferenceMemcpyCase::deinit (void)
2536 {
2537 m_dstBuf = std::vector<deUint8>();
2538 BasicUploadCase<SingleOperationDuration>::deinit();
2539 }
2540
testBufferUpload(UploadSampleResult<SingleOperationDuration> & result,int bufferSize)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
BufferDataUploadCase(Context & ctx,const char * name,const char * desc,int minBufferSize,int maxBufferSize,int numSamples,deUint32 bufferUsage,CaseType caseType)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
~BufferDataUploadCase(void)2566 BufferDataUploadCase::~BufferDataUploadCase (void)
2567 {
2568 }
2569
init(void)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
testBufferUpload(UploadSampleResult<SingleOperationDuration> & result,int bufferSize)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
BufferSubDataUploadCase(Context & ctx,const char * name,const char * desc,int minBufferSize,int maxBufferSize,int numSamples,deUint32 bufferUsage,CaseType parentCase,int flags)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
~BufferSubDataUploadCase(void)2629 BufferSubDataUploadCase::~BufferSubDataUploadCase (void)
2630 {
2631 }
2632
init(void)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
testBufferUpload(UploadSampleResult<SingleOperationDuration> & result,int bufferSize)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
MapBufferRangeCase(Context & ctx,const char * name,const char * desc,int minBufferSize,int maxBufferSize,int numSamples,deUint32 bufferUsage,deUint32 mapFlags,int caseFlags)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
~MapBufferRangeCase(void)2726 MapBufferRangeCase::~MapBufferRangeCase (void)
2727 {
2728 }
2729
init(void)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
getBaseCaseType(int caseFlags)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
getBaseFlags(deUint32 mapFlags,int caseFlags)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
testBufferUpload(UploadSampleResult<MapBufferRangeDuration> & result,int bufferSize)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
attemptBufferMap(UploadSampleResult<MapBufferRangeDuration> & result,int bufferSize)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
MapBufferRangeFlushCase(Context & ctx,const char * name,const char * desc,int minBufferSize,int maxBufferSize,int numSamples,deUint32 bufferUsage,deUint32 mapFlags,int caseFlags)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
~MapBufferRangeFlushCase(void)2940 MapBufferRangeFlushCase::~MapBufferRangeFlushCase (void)
2941 {
2942 }
2943
init(void)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
getBaseCaseType(int caseFlags)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
getBaseFlags(deUint32 mapFlags,int caseFlags)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
testBufferUpload(UploadSampleResult<MapBufferRangeFlushDuration> & result,int bufferSize)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
attemptBufferMap(UploadSampleResult<MapBufferRangeFlushDuration> & result,int bufferSize)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>
ModifyAfterBasicCase(Context & context,const char * name,const char * description,int bufferSizeMin,int bufferSizeMax,deUint32 usage,bool bufferUnspecifiedAfterTest)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>
~ModifyAfterBasicCase(void)3205 ModifyAfterBasicCase<SampleType>::~ModifyAfterBasicCase (void)
3206 {
3207 BasicBufferCase<SampleType>::deinit();
3208 }
3209
3210 template <typename SampleType>
init(void)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>
deinit(void)3247 void ModifyAfterBasicCase<SampleType>::deinit (void)
3248 {
3249 m_zeroData = std::vector<deUint8>();
3250
3251 BasicBufferCase<SampleType>::deinit();
3252 }
3253
3254 template <typename SampleType>
drawBufferRange(int begin,int end)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>
runSample(int iteration,UploadSampleResult<SampleType> & sample)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>
prepareAndRunTest(int iteration,UploadSampleResult<SampleType> & result,int bufferSize)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>
logAndSetTestResult(const std::vector<UploadSampleResult<SampleType>> & results)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
ModifyAfterWithBufferDataCase(Context & context,const char * name,const char * desc,int bufferSizeMin,int bufferSizeMax,deUint32 usage,int flags)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
~ModifyAfterWithBufferDataCase(void)3411 ModifyAfterWithBufferDataCase::~ModifyAfterWithBufferDataCase (void)
3412 {
3413 deinit();
3414 }
3415
init(void)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
deinit(void)3443 void ModifyAfterWithBufferDataCase::deinit (void)
3444 {
3445 ModifyAfterBasicCase<SingleOperationDuration>::deinit();
3446 }
3447
testWithBufferSize(UploadSampleResult<SingleOperationDuration> & result,int bufferSize)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
ModifyAfterWithBufferSubDataCase(Context & context,const char * name,const char * desc,int bufferSizeMin,int bufferSizeMax,deUint32 usage,int flags)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
~ModifyAfterWithBufferSubDataCase(void)3514 ModifyAfterWithBufferSubDataCase::~ModifyAfterWithBufferSubDataCase (void)
3515 {
3516 deinit();
3517 }
3518
init(void)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
deinit(void)3538 void ModifyAfterWithBufferSubDataCase::deinit (void)
3539 {
3540 ModifyAfterBasicCase<SingleOperationDuration>::deinit();
3541 }
3542
testWithBufferSize(UploadSampleResult<SingleOperationDuration> & result,int bufferSize)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
ModifyAfterWithMapBufferRangeCase(Context & context,const char * name,const char * desc,int bufferSizeMin,int bufferSizeMax,deUint32 usage,int flags,deUint32 glMapFlags)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
~ModifyAfterWithMapBufferRangeCase(void)3604 ModifyAfterWithMapBufferRangeCase::~ModifyAfterWithMapBufferRangeCase (void)
3605 {
3606 deinit();
3607 }
3608
init(void)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
deinit(void)3631 void ModifyAfterWithMapBufferRangeCase::deinit (void)
3632 {
3633 ModifyAfterBasicCase<MapBufferRangeDurationNoAlloc>::deinit();
3634 }
3635
isBufferUnspecifiedAfterUpload(int flags,deUint32 mapFlags)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
testWithBufferSize(UploadSampleResult<MapBufferRangeDurationNoAlloc> & result,int bufferSize)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
ModifyAfterWithMapBufferFlushCase(Context & context,const char * name,const char * desc,int bufferSizeMin,int bufferSizeMax,deUint32 usage,int flags,deUint32 glMapFlags)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
~ModifyAfterWithMapBufferFlushCase(void)3721 ModifyAfterWithMapBufferFlushCase::~ModifyAfterWithMapBufferFlushCase (void)
3722 {
3723 deinit();
3724 }
3725
init(void)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
deinit(void)3748 void ModifyAfterWithMapBufferFlushCase::deinit (void)
3749 {
3750 ModifyAfterBasicCase<MapBufferRangeFlushDurationNoAlloc>::deinit();
3751 }
3752
isBufferUnspecifiedAfterUpload(int flags,deUint32 mapFlags)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
testWithBufferSize(UploadSampleResult<MapBufferRangeFlushDurationNoAlloc> & result,int bufferSize)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
getLayeredGridNumVertices(const LayeredGridSpec & scene)3877 static int getLayeredGridNumVertices (const LayeredGridSpec& scene)
3878 {
3879 return scene.gridWidth * scene.gridHeight * scene.gridLayers * 6;
3880 }
3881
generateLayeredGridVertexAttribData4C4V(std::vector<tcu::Vec4> & vertexData,const LayeredGridSpec & scene)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
generateLayeredGridIndexData(std::vector<deUint32> & indexData,const LayeredGridSpec & scene)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
RenderPerformanceTestBase(Context & context,const char * name,const char * description)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
~RenderPerformanceTestBase(void)3960 RenderPerformanceTestBase::~RenderPerformanceTestBase (void)
3961 {
3962 deinit();
3963 }
3964
init(void)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
deinit(void)3985 void RenderPerformanceTestBase::deinit (void)
3986 {
3987 delete m_renderProgram;
3988 m_renderProgram = DE_NULL;
3989 }
3990
setupVertexAttribs(void) const3991 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)), glu::BufferOffsetAsPointer(0 * sizeof(tcu::Vec4)));
4001 gl.vertexAttribPointer(m_positionLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(8 * sizeof(float)), glu::BufferOffsetAsPointer(1 * sizeof(tcu::Vec4)));
4002
4003 gl.useProgram(m_renderProgram->getProgram());
4004
4005 GLU_EXPECT_NO_ERROR(gl.getError(), "set up rendering");
4006 }
4007
waitGLResults(void) const4008 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>
RenderCase(Context & context,const char * name,const char * description,DrawMethod drawMethod)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>
~RenderCase(void)4072 RenderCase<SampleType>::~RenderCase (void)
4073 {
4074 deinit();
4075 }
4076
4077 template <typename SampleType>
init(void)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>
deinit(void)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>
iterate(void)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>
getMinWorkloadSize(void) const4176 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>
getMaxWorkloadSize(void) const4190 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>
getMinWorkloadDataSize(void) const4204 int RenderCase<SampleType>::getMinWorkloadDataSize (void) const
4205 {
4206 return getMinWorkloadSize() * getVertexDataSize();
4207 }
4208
4209 template <typename SampleType>
getMaxWorkloadDataSize(void) const4210 int RenderCase<SampleType>::getMaxWorkloadDataSize (void) const
4211 {
4212 return getMaxWorkloadSize() * getVertexDataSize();
4213 }
4214
4215 template <typename SampleType>
getVertexDataSize(void) const4216 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>
getNumSamples(void) const4225 int RenderCase<SampleType>::getNumSamples (void) const
4226 {
4227 return (int)m_results.size();
4228 }
4229
4230 template <typename SampleType>
uploadScene(const LayeredGridSpec & scene)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>
logAndSetTestResult(const std::vector<SampleResult> & results)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>
mapResultsToRenderRateFormat(std::vector<RenderSampleResult<SampleType>> & dst,const std::vector<SampleResult> & src) const4288 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
ReferenceRenderTimeCase(Context & context,const char * name,const char * description,DrawMethod drawMethod)4306 ReferenceRenderTimeCase::ReferenceRenderTimeCase (Context& context, const char* name, const char* description, DrawMethod drawMethod)
4307 : RenderCase<RenderReadDuration> (context, name, description, drawMethod)
4308 {
4309 }
4310
init(void)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
runSample(SampleResult & sample)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
UnrelatedUploadRenderTimeCase(Context & context,const char * name,const char * description,DrawMethod drawMethod,UploadMethod unrelatedUploadMethod)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
init(void)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
runSample(SampleResult & sample)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
ReferenceReadPixelsTimeCase(Context & context,const char * name,const char * description)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
init(void)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
iterate(void)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
logAndSetTestResult(void)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>
GenericUploadRenderTimeCase(Context & context,const char * name,const char * description,DrawMethod method,TargetBuffer targetBuffer,UploadMethod uploadMethod,BufferState bufferState,UploadRange uploadRange,UnrelatedBufferType unrelatedBufferType)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>
init(void)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>
runSample(SampleResult & sample)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
BufferInUseRenderTimeCase(Context & context,const char * name,const char * description,DrawMethod method,MapFlags mapFlags,TargetBuffer targetBuffer,UploadMethod uploadMethod,UploadRange uploadRange,UploadBufferTarget uploadTarget)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
init(void)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
runSample(SampleResult & sample)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
UploadWaitDrawCase(Context & context,const char * name,const char * description,DrawMethod drawMethod,TargetBuffer targetBuffer,UploadMethod uploadMethod,BufferState bufferState)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
~UploadWaitDrawCase(void)5456 UploadWaitDrawCase::~UploadWaitDrawCase (void)
5457 {
5458 deinit();
5459 }
5460
init(void)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
deinit(void)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
iterate(void)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
uploadBuffer(Sample & sample,Result & result)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
drawFromBuffer(Sample & sample,Result & result)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
reuseAndDeleteBuffer(void)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
logAndSetTestResult(void)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
logSamples(void)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
drawMisc(void)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>
sumOfRanks(const std::vector<deUint64> & testSamples,const std::vector<deUint64> & allSamples,const Comparer & 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>
distributionCompare(const std::vector<deUint64> & orderedObservationsA,const std::vector<deUint64> & orderedObservationsB,const Comparer & 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
operator ()deqp::gles3::Performance::__anon3d4c17010111::ThresholdComparer6059 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
findStabilizationSample(deUint64 (UploadWaitDrawCase::Result::* target),const char * description)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
checkSampleTemporalStability(deUint64 (UploadWaitDrawCase::Result::* target),const char * description)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
BufferDataUploadTests(Context & context)6182 BufferDataUploadTests::BufferDataUploadTests (Context& context)
6183 : TestCaseGroup(context, "data_upload", "Buffer data upload performance tests")
6184 {
6185 }
6186
~BufferDataUploadTests(void)6187 BufferDataUploadTests::~BufferDataUploadTests (void)
6188 {
6189 }
6190
init(void)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