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