1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program OpenGL (ES) Module
3e5c31af7Sopenharmony_ci * -----------------------------------------------
4e5c31af7Sopenharmony_ci *
5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project
6e5c31af7Sopenharmony_ci *
7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License.
9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at
10e5c31af7Sopenharmony_ci *
11e5c31af7Sopenharmony_ci *      http://www.apache.org/licenses/LICENSE-2.0
12e5c31af7Sopenharmony_ci *
13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and
17e5c31af7Sopenharmony_ci * limitations under the License.
18e5c31af7Sopenharmony_ci *
19e5c31af7Sopenharmony_ci *//*!
20e5c31af7Sopenharmony_ci * \file
21e5c31af7Sopenharmony_ci * \brief Calibration tools.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "glsCalibration.hpp"
25e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
26e5c31af7Sopenharmony_ci#include "tcuVectorUtil.hpp"
27e5c31af7Sopenharmony_ci#include "deStringUtil.hpp"
28e5c31af7Sopenharmony_ci#include "deMath.h"
29e5c31af7Sopenharmony_ci#include "deClock.h"
30e5c31af7Sopenharmony_ci
31e5c31af7Sopenharmony_ci#include <algorithm>
32e5c31af7Sopenharmony_ci#include <limits>
33e5c31af7Sopenharmony_ci
34e5c31af7Sopenharmony_ciusing std::string;
35e5c31af7Sopenharmony_ciusing std::vector;
36e5c31af7Sopenharmony_ciusing tcu::Vec2;
37e5c31af7Sopenharmony_ciusing tcu::TestLog;
38e5c31af7Sopenharmony_ciusing tcu::TestNode;
39e5c31af7Sopenharmony_ciusing namespace glu;
40e5c31af7Sopenharmony_ci
41e5c31af7Sopenharmony_cinamespace deqp
42e5c31af7Sopenharmony_ci{
43e5c31af7Sopenharmony_cinamespace gls
44e5c31af7Sopenharmony_ci{
45e5c31af7Sopenharmony_ci
46e5c31af7Sopenharmony_ci// Reorders input arbitrarily, linear complexity and no allocations
47e5c31af7Sopenharmony_citemplate<typename T>
48e5c31af7Sopenharmony_cifloat destructiveMedian (vector<T>& data)
49e5c31af7Sopenharmony_ci{
50e5c31af7Sopenharmony_ci	const typename vector<T>::iterator mid = data.begin()+data.size()/2;
51e5c31af7Sopenharmony_ci
52e5c31af7Sopenharmony_ci	std::nth_element(data.begin(), mid, data.end());
53e5c31af7Sopenharmony_ci
54e5c31af7Sopenharmony_ci	if (data.size()%2 == 0) // Even number of elements, need average of two centermost elements
55e5c31af7Sopenharmony_ci		return (*mid + *std::max_element(data.begin(), mid))*0.5f; // Data is partially sorted around mid, mid is half an item after center
56e5c31af7Sopenharmony_ci	else
57e5c31af7Sopenharmony_ci		return *mid;
58e5c31af7Sopenharmony_ci}
59e5c31af7Sopenharmony_ci
60e5c31af7Sopenharmony_ciLineParameters theilSenLinearRegression (const std::vector<tcu::Vec2>& dataPoints)
61e5c31af7Sopenharmony_ci{
62e5c31af7Sopenharmony_ci	const float		epsilon					= 1e-6f;
63e5c31af7Sopenharmony_ci
64e5c31af7Sopenharmony_ci	const int		numDataPoints			= (int)dataPoints.size();
65e5c31af7Sopenharmony_ci	vector<float>	pairwiseCoefficients;
66e5c31af7Sopenharmony_ci	vector<float>	pointwiseOffsets;
67e5c31af7Sopenharmony_ci	LineParameters	result					(0.0f, 0.0f);
68e5c31af7Sopenharmony_ci
69e5c31af7Sopenharmony_ci	// Compute the pairwise coefficients.
70e5c31af7Sopenharmony_ci	for (int i = 0; i < numDataPoints; i++)
71e5c31af7Sopenharmony_ci	{
72e5c31af7Sopenharmony_ci		const Vec2& ptA = dataPoints[i];
73e5c31af7Sopenharmony_ci
74e5c31af7Sopenharmony_ci		for (int j = 0; j < i; j++)
75e5c31af7Sopenharmony_ci		{
76e5c31af7Sopenharmony_ci			const Vec2& ptB = dataPoints[j];
77e5c31af7Sopenharmony_ci
78e5c31af7Sopenharmony_ci			if (de::abs(ptA.x() - ptB.x()) > epsilon)
79e5c31af7Sopenharmony_ci				pairwiseCoefficients.push_back((ptA.y() - ptB.y()) / (ptA.x() - ptB.x()));
80e5c31af7Sopenharmony_ci		}
81e5c31af7Sopenharmony_ci	}
82e5c31af7Sopenharmony_ci
83e5c31af7Sopenharmony_ci	// Find the median of the pairwise coefficients.
84e5c31af7Sopenharmony_ci	// \note If there are no data point pairs with differing x values, the coefficient variable will stay zero as initialized.
85e5c31af7Sopenharmony_ci	if (!pairwiseCoefficients.empty())
86e5c31af7Sopenharmony_ci		result.coefficient = destructiveMedian(pairwiseCoefficients);
87e5c31af7Sopenharmony_ci
88e5c31af7Sopenharmony_ci	// Compute the offsets corresponding to the median coefficient, for all data points.
89e5c31af7Sopenharmony_ci	for (int i = 0; i < numDataPoints; i++)
90e5c31af7Sopenharmony_ci		pointwiseOffsets.push_back(dataPoints[i].y() - result.coefficient*dataPoints[i].x());
91e5c31af7Sopenharmony_ci
92e5c31af7Sopenharmony_ci	// Find the median of the offsets.
93e5c31af7Sopenharmony_ci	// \note If there are no data points, the offset variable will stay zero as initialized.
94e5c31af7Sopenharmony_ci	if (!pointwiseOffsets.empty())
95e5c31af7Sopenharmony_ci		result.offset = destructiveMedian(pointwiseOffsets);
96e5c31af7Sopenharmony_ci
97e5c31af7Sopenharmony_ci	return result;
98e5c31af7Sopenharmony_ci}
99e5c31af7Sopenharmony_ci
100e5c31af7Sopenharmony_ci// Sample from given values using linear interpolation at a given position as if values were laid to range [0, 1]
101e5c31af7Sopenharmony_citemplate <typename T>
102e5c31af7Sopenharmony_cistatic float linearSample (const std::vector<T>& values, float position)
103e5c31af7Sopenharmony_ci{
104e5c31af7Sopenharmony_ci	DE_ASSERT(position >= 0.0f);
105e5c31af7Sopenharmony_ci	DE_ASSERT(position <= 1.0f);
106e5c31af7Sopenharmony_ci
107e5c31af7Sopenharmony_ci	const int	maxNdx				= (int)values.size() - 1;
108e5c31af7Sopenharmony_ci	const float	floatNdx			= (float)maxNdx * position;
109e5c31af7Sopenharmony_ci	const int	lowerNdx			= (int)deFloatFloor(floatNdx);
110e5c31af7Sopenharmony_ci	const int	higherNdx			= lowerNdx + (lowerNdx == maxNdx ? 0 : 1); // Use only last element if position is 1.0
111e5c31af7Sopenharmony_ci	const float	interpolationFactor = floatNdx - (float)lowerNdx;
112e5c31af7Sopenharmony_ci
113e5c31af7Sopenharmony_ci	DE_ASSERT(lowerNdx >= 0 && lowerNdx < (int)values.size());
114e5c31af7Sopenharmony_ci	DE_ASSERT(higherNdx >= 0 && higherNdx < (int)values.size());
115e5c31af7Sopenharmony_ci	DE_ASSERT(interpolationFactor >= 0 && interpolationFactor < 1.0f);
116e5c31af7Sopenharmony_ci
117e5c31af7Sopenharmony_ci	return tcu::mix((float)values[lowerNdx], (float)values[higherNdx], interpolationFactor);
118e5c31af7Sopenharmony_ci}
119e5c31af7Sopenharmony_ci
120e5c31af7Sopenharmony_ciLineParametersWithConfidence theilSenSiegelLinearRegression (const std::vector<tcu::Vec2>& dataPoints, float reportedConfidence)
121e5c31af7Sopenharmony_ci{
122e5c31af7Sopenharmony_ci	DE_ASSERT(!dataPoints.empty());
123e5c31af7Sopenharmony_ci
124e5c31af7Sopenharmony_ci	// Siegel's variation
125e5c31af7Sopenharmony_ci
126e5c31af7Sopenharmony_ci	const float						epsilon				= 1e-6f;
127e5c31af7Sopenharmony_ci	const int						numDataPoints		= (int)dataPoints.size();
128e5c31af7Sopenharmony_ci	std::vector<float>				medianSlopes;
129e5c31af7Sopenharmony_ci	std::vector<float>				pointwiseOffsets;
130e5c31af7Sopenharmony_ci	LineParametersWithConfidence	result;
131e5c31af7Sopenharmony_ci
132e5c31af7Sopenharmony_ci	// Compute the median slope via each element
133e5c31af7Sopenharmony_ci	for (int i = 0; i < numDataPoints; i++)
134e5c31af7Sopenharmony_ci	{
135e5c31af7Sopenharmony_ci		const tcu::Vec2&	ptA		= dataPoints[i];
136e5c31af7Sopenharmony_ci		std::vector<float>	slopes;
137e5c31af7Sopenharmony_ci
138e5c31af7Sopenharmony_ci		slopes.reserve(numDataPoints);
139e5c31af7Sopenharmony_ci
140e5c31af7Sopenharmony_ci		for (int j = 0; j < numDataPoints; j++)
141e5c31af7Sopenharmony_ci		{
142e5c31af7Sopenharmony_ci			const tcu::Vec2& ptB = dataPoints[j];
143e5c31af7Sopenharmony_ci
144e5c31af7Sopenharmony_ci			if (de::abs(ptA.x() - ptB.x()) > epsilon)
145e5c31af7Sopenharmony_ci				slopes.push_back((ptA.y() - ptB.y()) / (ptA.x() - ptB.x()));
146e5c31af7Sopenharmony_ci		}
147e5c31af7Sopenharmony_ci
148e5c31af7Sopenharmony_ci		// Add median of slopes through point i
149e5c31af7Sopenharmony_ci		medianSlopes.push_back(destructiveMedian(slopes));
150e5c31af7Sopenharmony_ci	}
151e5c31af7Sopenharmony_ci
152e5c31af7Sopenharmony_ci	DE_ASSERT(!medianSlopes.empty());
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci	// Find the median of the pairwise coefficients.
155e5c31af7Sopenharmony_ci	std::sort(medianSlopes.begin(), medianSlopes.end());
156e5c31af7Sopenharmony_ci	result.coefficient = linearSample(medianSlopes, 0.5f);
157e5c31af7Sopenharmony_ci
158e5c31af7Sopenharmony_ci	// Compute the offsets corresponding to the median coefficient, for all data points.
159e5c31af7Sopenharmony_ci	for (int i = 0; i < numDataPoints; i++)
160e5c31af7Sopenharmony_ci		pointwiseOffsets.push_back(dataPoints[i].y() - result.coefficient*dataPoints[i].x());
161e5c31af7Sopenharmony_ci
162e5c31af7Sopenharmony_ci	// Find the median of the offsets.
163e5c31af7Sopenharmony_ci	std::sort(pointwiseOffsets.begin(), pointwiseOffsets.end());
164e5c31af7Sopenharmony_ci	result.offset = linearSample(pointwiseOffsets, 0.5f);
165e5c31af7Sopenharmony_ci
166e5c31af7Sopenharmony_ci	// calculate confidence intervals
167e5c31af7Sopenharmony_ci	result.coefficientConfidenceLower = linearSample(medianSlopes, 0.5f - reportedConfidence*0.5f);
168e5c31af7Sopenharmony_ci	result.coefficientConfidenceUpper = linearSample(medianSlopes, 0.5f + reportedConfidence*0.5f);
169e5c31af7Sopenharmony_ci
170e5c31af7Sopenharmony_ci	result.offsetConfidenceLower = linearSample(pointwiseOffsets, 0.5f - reportedConfidence*0.5f);
171e5c31af7Sopenharmony_ci	result.offsetConfidenceUpper = linearSample(pointwiseOffsets, 0.5f + reportedConfidence*0.5f);
172e5c31af7Sopenharmony_ci
173e5c31af7Sopenharmony_ci	result.confidence = reportedConfidence;
174e5c31af7Sopenharmony_ci
175e5c31af7Sopenharmony_ci	return result;
176e5c31af7Sopenharmony_ci}
177e5c31af7Sopenharmony_ci
178e5c31af7Sopenharmony_cibool MeasureState::isDone (void) const
179e5c31af7Sopenharmony_ci{
180e5c31af7Sopenharmony_ci	return (int)frameTimes.size() >= maxNumFrames || (frameTimes.size() >= 2 &&
181e5c31af7Sopenharmony_ci													  frameTimes[frameTimes.size()-2] >= (deUint64)frameShortcutTime &&
182e5c31af7Sopenharmony_ci													  frameTimes[frameTimes.size()-1] >= (deUint64)frameShortcutTime);
183e5c31af7Sopenharmony_ci}
184e5c31af7Sopenharmony_ci
185e5c31af7Sopenharmony_cideUint64 MeasureState::getTotalTime (void) const
186e5c31af7Sopenharmony_ci{
187e5c31af7Sopenharmony_ci	deUint64 time = 0;
188e5c31af7Sopenharmony_ci	for (int i = 0; i < (int)frameTimes.size(); i++)
189e5c31af7Sopenharmony_ci		time += frameTimes[i];
190e5c31af7Sopenharmony_ci	return time;
191e5c31af7Sopenharmony_ci}
192e5c31af7Sopenharmony_ci
193e5c31af7Sopenharmony_civoid MeasureState::clear (void)
194e5c31af7Sopenharmony_ci{
195e5c31af7Sopenharmony_ci	maxNumFrames		= 0;
196e5c31af7Sopenharmony_ci	frameShortcutTime	= std::numeric_limits<float>::infinity();
197e5c31af7Sopenharmony_ci	numDrawCalls		= 0;
198e5c31af7Sopenharmony_ci	frameTimes.clear();
199e5c31af7Sopenharmony_ci}
200e5c31af7Sopenharmony_ci
201e5c31af7Sopenharmony_civoid MeasureState::start (int maxNumFrames_, float frameShortcutTime_, int numDrawCalls_)
202e5c31af7Sopenharmony_ci{
203e5c31af7Sopenharmony_ci	frameTimes.clear();
204e5c31af7Sopenharmony_ci	frameTimes.reserve(maxNumFrames_);
205e5c31af7Sopenharmony_ci	maxNumFrames		= maxNumFrames_;
206e5c31af7Sopenharmony_ci	frameShortcutTime	= frameShortcutTime_;
207e5c31af7Sopenharmony_ci	numDrawCalls		= numDrawCalls_;
208e5c31af7Sopenharmony_ci}
209e5c31af7Sopenharmony_ci
210e5c31af7Sopenharmony_ciTheilSenCalibrator::TheilSenCalibrator (void)
211e5c31af7Sopenharmony_ci	: m_params	(1 /* initial calls */, 10 /* calibrate iter frames */, 2000.0f /* calibrate iter shortcut threshold */, 31 /* max calibration iterations */,
212e5c31af7Sopenharmony_ci				 1000.0f/30.0f /* target frame time */, 1000.0f/60.0f /* frame time cap */, 1000.0f /* target measure duration */)
213e5c31af7Sopenharmony_ci	, m_state	(INTERNALSTATE_LAST)
214e5c31af7Sopenharmony_ci{
215e5c31af7Sopenharmony_ci	clear();
216e5c31af7Sopenharmony_ci}
217e5c31af7Sopenharmony_ci
218e5c31af7Sopenharmony_ciTheilSenCalibrator::TheilSenCalibrator (const CalibratorParameters& params)
219e5c31af7Sopenharmony_ci	: m_params	(params)
220e5c31af7Sopenharmony_ci	, m_state	(INTERNALSTATE_LAST)
221e5c31af7Sopenharmony_ci{
222e5c31af7Sopenharmony_ci	clear();
223e5c31af7Sopenharmony_ci}
224e5c31af7Sopenharmony_ci
225e5c31af7Sopenharmony_ciTheilSenCalibrator::~TheilSenCalibrator()
226e5c31af7Sopenharmony_ci{
227e5c31af7Sopenharmony_ci}
228e5c31af7Sopenharmony_ci
229e5c31af7Sopenharmony_civoid TheilSenCalibrator::clear (void)
230e5c31af7Sopenharmony_ci{
231e5c31af7Sopenharmony_ci	m_measureState.clear();
232e5c31af7Sopenharmony_ci	m_calibrateIterations.clear();
233e5c31af7Sopenharmony_ci	m_state = INTERNALSTATE_CALIBRATING;
234e5c31af7Sopenharmony_ci}
235e5c31af7Sopenharmony_ci
236e5c31af7Sopenharmony_civoid TheilSenCalibrator::clear (const CalibratorParameters& params)
237e5c31af7Sopenharmony_ci{
238e5c31af7Sopenharmony_ci	m_params = params;
239e5c31af7Sopenharmony_ci	clear();
240e5c31af7Sopenharmony_ci}
241e5c31af7Sopenharmony_ci
242e5c31af7Sopenharmony_ciTheilSenCalibrator::State TheilSenCalibrator::getState (void) const
243e5c31af7Sopenharmony_ci{
244e5c31af7Sopenharmony_ci	if (m_state == INTERNALSTATE_FINISHED)
245e5c31af7Sopenharmony_ci		return STATE_FINISHED;
246e5c31af7Sopenharmony_ci	else
247e5c31af7Sopenharmony_ci	{
248e5c31af7Sopenharmony_ci		DE_ASSERT(m_state == INTERNALSTATE_CALIBRATING || !m_measureState.isDone());
249e5c31af7Sopenharmony_ci		return m_measureState.isDone() ? STATE_RECOMPUTE_PARAMS : STATE_MEASURE;
250e5c31af7Sopenharmony_ci	}
251e5c31af7Sopenharmony_ci}
252e5c31af7Sopenharmony_ci
253e5c31af7Sopenharmony_civoid TheilSenCalibrator::recordIteration (deUint64 iterationTime)
254e5c31af7Sopenharmony_ci{
255e5c31af7Sopenharmony_ci	DE_ASSERT((m_state == INTERNALSTATE_CALIBRATING || m_state == INTERNALSTATE_RUNNING) && !m_measureState.isDone());
256e5c31af7Sopenharmony_ci	m_measureState.frameTimes.push_back(iterationTime);
257e5c31af7Sopenharmony_ci
258e5c31af7Sopenharmony_ci	if (m_state == INTERNALSTATE_RUNNING && m_measureState.isDone())
259e5c31af7Sopenharmony_ci		m_state = INTERNALSTATE_FINISHED;
260e5c31af7Sopenharmony_ci}
261e5c31af7Sopenharmony_ci
262e5c31af7Sopenharmony_civoid TheilSenCalibrator::recomputeParameters (void)
263e5c31af7Sopenharmony_ci{
264e5c31af7Sopenharmony_ci	DE_ASSERT(m_state == INTERNALSTATE_CALIBRATING);
265e5c31af7Sopenharmony_ci	DE_ASSERT(m_measureState.isDone());
266e5c31af7Sopenharmony_ci
267e5c31af7Sopenharmony_ci	// Minimum and maximum acceptable frame times.
268e5c31af7Sopenharmony_ci	const float		minGoodFrameTimeUs	= m_params.targetFrameTimeUs * 0.95f;
269e5c31af7Sopenharmony_ci	const float		maxGoodFrameTimeUs	= m_params.targetFrameTimeUs * 1.15f;
270e5c31af7Sopenharmony_ci
271e5c31af7Sopenharmony_ci	const int		numIterations		= (int)m_calibrateIterations.size();
272e5c31af7Sopenharmony_ci
273e5c31af7Sopenharmony_ci	// Record frame time.
274e5c31af7Sopenharmony_ci	if (numIterations > 0)
275e5c31af7Sopenharmony_ci	{
276e5c31af7Sopenharmony_ci		m_calibrateIterations.back().frameTime = (float)((double)m_measureState.getTotalTime() / (double)m_measureState.frameTimes.size());
277e5c31af7Sopenharmony_ci
278e5c31af7Sopenharmony_ci		// Check if we're good enough to stop calibrating.
279e5c31af7Sopenharmony_ci		{
280e5c31af7Sopenharmony_ci			bool endCalibration = false;
281e5c31af7Sopenharmony_ci
282e5c31af7Sopenharmony_ci			// Is the maximum calibration iteration limit reached?
283e5c31af7Sopenharmony_ci			endCalibration = endCalibration || (int)m_calibrateIterations.size() >= m_params.maxCalibrateIterations;
284e5c31af7Sopenharmony_ci
285e5c31af7Sopenharmony_ci			// Do a few past iterations have frame time in acceptable range?
286e5c31af7Sopenharmony_ci			{
287e5c31af7Sopenharmony_ci				const int numRelevantPastIterations = 2;
288e5c31af7Sopenharmony_ci
289e5c31af7Sopenharmony_ci				if (!endCalibration && (int)m_calibrateIterations.size() >= numRelevantPastIterations)
290e5c31af7Sopenharmony_ci				{
291e5c31af7Sopenharmony_ci					const CalibrateIteration* const		past			= &m_calibrateIterations[m_calibrateIterations.size() - numRelevantPastIterations];
292e5c31af7Sopenharmony_ci					bool								allInGoodRange	= true;
293e5c31af7Sopenharmony_ci
294e5c31af7Sopenharmony_ci					for (int i = 0; i < numRelevantPastIterations && allInGoodRange; i++)
295e5c31af7Sopenharmony_ci					{
296e5c31af7Sopenharmony_ci						const float frameTimeUs = past[i].frameTime;
297e5c31af7Sopenharmony_ci						if (!de::inRange(frameTimeUs, minGoodFrameTimeUs, maxGoodFrameTimeUs))
298e5c31af7Sopenharmony_ci							allInGoodRange = false;
299e5c31af7Sopenharmony_ci					}
300e5c31af7Sopenharmony_ci
301e5c31af7Sopenharmony_ci					endCalibration = endCalibration || allInGoodRange;
302e5c31af7Sopenharmony_ci				}
303e5c31af7Sopenharmony_ci			}
304e5c31af7Sopenharmony_ci
305e5c31af7Sopenharmony_ci			// Do a few past iterations have similar-enough call counts?
306e5c31af7Sopenharmony_ci			{
307e5c31af7Sopenharmony_ci				const int numRelevantPastIterations = 3;
308e5c31af7Sopenharmony_ci				if (!endCalibration && (int)m_calibrateIterations.size() >= numRelevantPastIterations)
309e5c31af7Sopenharmony_ci				{
310e5c31af7Sopenharmony_ci					const CalibrateIteration* const		past			= &m_calibrateIterations[m_calibrateIterations.size() - numRelevantPastIterations];
311e5c31af7Sopenharmony_ci					int									minCallCount	= std::numeric_limits<int>::max();
312e5c31af7Sopenharmony_ci					int									maxCallCount	= std::numeric_limits<int>::min();
313e5c31af7Sopenharmony_ci
314e5c31af7Sopenharmony_ci					for (int i = 0; i < numRelevantPastIterations; i++)
315e5c31af7Sopenharmony_ci					{
316e5c31af7Sopenharmony_ci						minCallCount = de::min(minCallCount, past[i].numDrawCalls);
317e5c31af7Sopenharmony_ci						maxCallCount = de::max(maxCallCount, past[i].numDrawCalls);
318e5c31af7Sopenharmony_ci					}
319e5c31af7Sopenharmony_ci
320e5c31af7Sopenharmony_ci					if ((float)(maxCallCount - minCallCount) <= (float)minCallCount * 0.1f)
321e5c31af7Sopenharmony_ci						endCalibration = true;
322e5c31af7Sopenharmony_ci				}
323e5c31af7Sopenharmony_ci			}
324e5c31af7Sopenharmony_ci
325e5c31af7Sopenharmony_ci			// Is call count just 1, and frame time still way too high?
326e5c31af7Sopenharmony_ci			endCalibration = endCalibration || (m_calibrateIterations.back().numDrawCalls == 1 && m_calibrateIterations.back().frameTime > m_params.targetFrameTimeUs*2.0f);
327e5c31af7Sopenharmony_ci
328e5c31af7Sopenharmony_ci			if (endCalibration)
329e5c31af7Sopenharmony_ci			{
330e5c31af7Sopenharmony_ci				const int	minFrames			= 10;
331e5c31af7Sopenharmony_ci				const int	maxFrames			= 60;
332e5c31af7Sopenharmony_ci				int			numMeasureFrames	= deClamp32(deRoundFloatToInt32(m_params.targetMeasureDurationUs / m_calibrateIterations.back().frameTime), minFrames, maxFrames);
333e5c31af7Sopenharmony_ci
334e5c31af7Sopenharmony_ci				m_state = INTERNALSTATE_RUNNING;
335e5c31af7Sopenharmony_ci				m_measureState.start(numMeasureFrames, m_params.calibrateIterationShortcutThreshold, m_calibrateIterations.back().numDrawCalls);
336e5c31af7Sopenharmony_ci				return;
337e5c31af7Sopenharmony_ci			}
338e5c31af7Sopenharmony_ci		}
339e5c31af7Sopenharmony_ci	}
340e5c31af7Sopenharmony_ci
341e5c31af7Sopenharmony_ci	DE_ASSERT(m_state == INTERNALSTATE_CALIBRATING);
342e5c31af7Sopenharmony_ci
343e5c31af7Sopenharmony_ci	// Estimate new call count.
344e5c31af7Sopenharmony_ci	{
345e5c31af7Sopenharmony_ci		int newCallCount;
346e5c31af7Sopenharmony_ci
347e5c31af7Sopenharmony_ci		if (numIterations == 0)
348e5c31af7Sopenharmony_ci			newCallCount = m_params.numInitialCalls;
349e5c31af7Sopenharmony_ci		else
350e5c31af7Sopenharmony_ci		{
351e5c31af7Sopenharmony_ci			vector<Vec2> dataPoints;
352e5c31af7Sopenharmony_ci			for (int i = 0; i < numIterations; i++)
353e5c31af7Sopenharmony_ci			{
354e5c31af7Sopenharmony_ci				if (m_calibrateIterations[i].numDrawCalls == 1 || m_calibrateIterations[i].frameTime > m_params.frameTimeCapUs*1.05f) // Only account for measurements not too near the cap.
355e5c31af7Sopenharmony_ci					dataPoints.push_back(Vec2((float)m_calibrateIterations[i].numDrawCalls, m_calibrateIterations[i].frameTime));
356e5c31af7Sopenharmony_ci			}
357e5c31af7Sopenharmony_ci
358e5c31af7Sopenharmony_ci			if (numIterations == 1)
359e5c31af7Sopenharmony_ci				dataPoints.push_back(Vec2(0.0f, 0.0f)); // If there's just one measurement so far, this will help in getting the next estimate.
360e5c31af7Sopenharmony_ci
361e5c31af7Sopenharmony_ci			{
362e5c31af7Sopenharmony_ci				const float				targetFrameTimeUs	= m_params.targetFrameTimeUs;
363e5c31af7Sopenharmony_ci				const float				coeffEpsilon		= 0.001f; // Coefficient must be large enough (and positive) to be considered sensible.
364e5c31af7Sopenharmony_ci
365e5c31af7Sopenharmony_ci				const LineParameters	estimatorLine		= theilSenLinearRegression(dataPoints);
366e5c31af7Sopenharmony_ci
367e5c31af7Sopenharmony_ci				int						prevMaxCalls		= 0;
368e5c31af7Sopenharmony_ci
369e5c31af7Sopenharmony_ci				// Find the maximum of the past call counts.
370e5c31af7Sopenharmony_ci				for (int i = 0; i < numIterations; i++)
371e5c31af7Sopenharmony_ci					prevMaxCalls = de::max(prevMaxCalls, m_calibrateIterations[i].numDrawCalls);
372e5c31af7Sopenharmony_ci
373e5c31af7Sopenharmony_ci				if (estimatorLine.coefficient < coeffEpsilon) // Coefficient not good for sensible estimation; increase call count enough to get a reasonably different value.
374e5c31af7Sopenharmony_ci					newCallCount = 2*prevMaxCalls;
375e5c31af7Sopenharmony_ci				else
376e5c31af7Sopenharmony_ci				{
377e5c31af7Sopenharmony_ci					// Solve newCallCount such that approximately targetFrameTime = offset + coefficient*newCallCount.
378e5c31af7Sopenharmony_ci					newCallCount = (int)((targetFrameTimeUs - estimatorLine.offset) / estimatorLine.coefficient + 0.5f);
379e5c31af7Sopenharmony_ci
380e5c31af7Sopenharmony_ci					// We should generally prefer FPS counts below the target rather than above (i.e. higher frame times rather than lower).
381e5c31af7Sopenharmony_ci					if (estimatorLine.offset + estimatorLine.coefficient*(float)newCallCount < minGoodFrameTimeUs)
382e5c31af7Sopenharmony_ci						newCallCount++;
383e5c31af7Sopenharmony_ci				}
384e5c31af7Sopenharmony_ci
385e5c31af7Sopenharmony_ci				// Make sure we have at least minimum amount of calls, and don't allow increasing call count too much in one iteration.
386e5c31af7Sopenharmony_ci				newCallCount = de::clamp(newCallCount, 1, prevMaxCalls*10);
387e5c31af7Sopenharmony_ci			}
388e5c31af7Sopenharmony_ci		}
389e5c31af7Sopenharmony_ci
390e5c31af7Sopenharmony_ci		m_measureState.start(m_params.maxCalibrateIterationFrames, m_params.calibrateIterationShortcutThreshold, newCallCount);
391e5c31af7Sopenharmony_ci		m_calibrateIterations.push_back(CalibrateIteration(newCallCount, 0.0f));
392e5c31af7Sopenharmony_ci	}
393e5c31af7Sopenharmony_ci}
394e5c31af7Sopenharmony_ci
395e5c31af7Sopenharmony_civoid logCalibrationInfo (tcu::TestLog& log, const TheilSenCalibrator& calibrator)
396e5c31af7Sopenharmony_ci{
397e5c31af7Sopenharmony_ci	const CalibratorParameters&				params				= calibrator.getParameters();
398e5c31af7Sopenharmony_ci	const std::vector<CalibrateIteration>&	calibrateIterations	= calibrator.getCalibrationInfo();
399e5c31af7Sopenharmony_ci
400e5c31af7Sopenharmony_ci	// Write out default calibration info.
401e5c31af7Sopenharmony_ci
402e5c31af7Sopenharmony_ci	log << TestLog::Section("CalibrationInfo", "Calibration Info")
403e5c31af7Sopenharmony_ci		<< TestLog::Message  << "Target frame time: " << params.targetFrameTimeUs << " us (" << 1000000 / params.targetFrameTimeUs << " fps)" << TestLog::EndMessage;
404e5c31af7Sopenharmony_ci
405e5c31af7Sopenharmony_ci	for (int iterNdx = 0; iterNdx < (int)calibrateIterations.size(); iterNdx++)
406e5c31af7Sopenharmony_ci	{
407e5c31af7Sopenharmony_ci		log << TestLog::Message << "  iteration " << iterNdx << ": " << calibrateIterations[iterNdx].numDrawCalls << " calls => "
408e5c31af7Sopenharmony_ci								<< de::floatToString(calibrateIterations[iterNdx].frameTime, 2) << " us ("
409e5c31af7Sopenharmony_ci								<< de::floatToString(1000000.0f / calibrateIterations[iterNdx].frameTime, 2) << " fps)" << TestLog::EndMessage;
410e5c31af7Sopenharmony_ci	}
411e5c31af7Sopenharmony_ci	log << TestLog::Integer("CallCount",	"Calibrated call count",	"",	QP_KEY_TAG_NONE, calibrator.getMeasureState().numDrawCalls)
412e5c31af7Sopenharmony_ci		<< TestLog::Integer("FrameCount",	"Calibrated frame count",	"", QP_KEY_TAG_NONE, (int)calibrator.getMeasureState().frameTimes.size());
413e5c31af7Sopenharmony_ci	log << TestLog::EndSection;
414e5c31af7Sopenharmony_ci}
415e5c31af7Sopenharmony_ci
416e5c31af7Sopenharmony_ci} // gls
417e5c31af7Sopenharmony_ci} // deqp
418