3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-12 13:32:53 +02:00

filter time-cost drivers for region regulation

This commit is contained in:
Andrew Meadows 2018-08-29 11:17:11 -07:00
parent 4ab45e70a4
commit f9d14e1351
5 changed files with 73 additions and 30 deletions
interface/src
libraries

View file

@ -5795,15 +5795,13 @@ void Application::update(float deltaTime) {
auto t5 = std::chrono::high_resolution_clock::now();
workload::Timings timings(6);
timings[0] = (t4 - t0);
timings[1] = (t5 - t4);
timings[2] = (t4 - t3);
timings[3] = (t3 - t2);
timings[4] = (t2 - t1);
timings[5] = (t1 - t0);
timings[0] = t1 - t0; // prePhysics entities
timings[1] = t2 - t1; // prePhysics avatars
timings[2] = t3 - t2; // stepPhysics
timings[3] = t4 - t3; // postPhysics
timings[4] = t5 - t4; // non-physical kinematics
timings[5] = workload::Timing_ns((int32_t)(NSECS_PER_SECOND * deltaTime)); // game loop duration
_gameWorkload.updateSimulationTimings(timings);
}
}
} else {

View file

@ -36,6 +36,7 @@ const float METERS_PER_MILLIMETER = 0.001f;
const float MILLIMETERS_PER_METER = 1000.0f;
const quint64 NSECS_PER_USEC = 1000;
const quint64 NSECS_PER_MSEC = 1000000;
const quint64 NSECS_PER_SECOND = 1e9;
const quint64 USECS_PER_MSEC = 1000;
const quint64 MSECS_PER_SECOND = 1000;
const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND;

View file

@ -70,7 +70,8 @@ private:
using SpacePointer = std::shared_ptr<Space>;
using Changes = std::vector<Space::Change>;
using IndexVectors = std::vector<IndexVector>;
using Timings = std::vector<std::chrono::nanoseconds>;
using Timing_ns = std::chrono::nanoseconds;
using Timings = std::vector<Timing_ns>;
} // namespace workload

View file

@ -102,9 +102,16 @@ void ControlViews::run(const workload::WorkloadContextPointer& runContext, const
// Export the ranges and timings for debuging
if (inTimings.size()) {
_dataExport.timings[workload::Region::R1] = std::chrono::duration<float, std::milli>(inTimings[0]).count();
// NOTE for reference:
// inTimings[0] = prePhysics entities
// inTimings[1] = prePhysics avatars
// inTimings[2] = stepPhysics
// inTimings[3] = postPhysics
// inTimings[4] = non-physical kinematics
// inTimings[5] = game loop
_dataExport.timings[workload::Region::R1] = std::chrono::duration<float, std::milli>(inTimings[2] + inTimings[3]).count();
_dataExport.timings[workload::Region::R2] = _dataExport.timings[workload::Region::R1];
_dataExport.timings[workload::Region::R3] = std::chrono::duration<float, std::milli>(inTimings[1]).count();
_dataExport.timings[workload::Region::R3] = std::chrono::duration<float, std::milli>(inTimings[4]).count();
doExport = true;
}
@ -115,11 +122,29 @@ void ControlViews::run(const workload::WorkloadContextPointer& runContext, const
}
}
glm::vec2 Regulator::run(const Timing_ns& regulationDuration, const Timing_ns& measured, const glm::vec2& current) {
// Regulate next value based on current moving toward the goal budget
float error_ms = std::chrono::duration<float, std::milli>(_budget - measured).count();
float coef = glm::clamp(error_ms / std::chrono::duration<float, std::milli>(regulationDuration).count(), -1.0f, 1.0f);
return current * (1.0f + coef * (error_ms < 0.0f ? _relativeStepDown : _relativeStepUp));
glm::vec2 Regulator::run(const Timing_ns& deltaTime, const Timing_ns& measuredTime, const glm::vec2& currentFrontBack) {
// measure signal: average and noise
const float FILTER_TIMESCALE = 0.5f * (float)NSECS_PER_SECOND;
float del = deltaTime.count() / FILTER_TIMESCALE;
if (del > 1.0f) {
del = 1.0f; // clamp for stability
}
_measuredTimeAverage = (1.0f - del) * _measuredTimeAverage + del * measuredTime.count();
float diff = measuredTime.count() - _measuredTimeAverage;
_measuredTimeNoiseSquared = (1.0f - del) * _measuredTimeNoiseSquared + del * diff * diff;
float noise = sqrtf(_measuredTimeNoiseSquared);
// check budget
float budgetDelta = _budget.count() - _measuredTimeAverage;
if (abs(budgetDelta) < noise) {
// budget is within the noise
return currentFrontBack;
}
// clamp the step factor
del = budgetDelta < 0.0f ? -_relativeStepDown: _relativeStepUp;
return currentFrontBack * (1.0f + del);
}
glm::vec2 Regulator::clamp(const glm::vec2& backFront) const {
@ -128,17 +153,24 @@ glm::vec2 Regulator::clamp(const glm::vec2& backFront) const {
}
void ControlViews::regulateViews(workload::Views& outViews, const workload::Timings& timings) {
for (auto& outView : outViews) {
for (int32_t r = 0; r < workload::Region::NUM_VIEW_REGIONS; r++) {
outView.regionBackFronts[r] = regionBackFronts[r];
}
}
auto loopDuration = std::chrono::nanoseconds{ std::chrono::milliseconds(16) };
regionBackFronts[workload::Region::R1] = regionRegulators[workload::Region::R1].run(loopDuration, timings[0], regionBackFronts[workload::Region::R1]);
regionBackFronts[workload::Region::R2] = regionRegulators[workload::Region::R2].run(loopDuration, timings[0], regionBackFronts[workload::Region::R2]);
regionBackFronts[workload::Region::R3] = regionRegulators[workload::Region::R3].run(loopDuration, timings[1], regionBackFronts[workload::Region::R3]);
// Note: for reference:
// timings[0] = prePhysics entities
// timings[1] = prePhysics avatars
// timings[2] = stepPhysics
// timings[3] = postPhysics
// timings[4] = non-physical kinematics
// timings[5] = game loop
auto loopDuration = timings[5];
regionBackFronts[workload::Region::R1] = regionRegulators[workload::Region::R1].run(loopDuration, timings[2] + timings[3], regionBackFronts[workload::Region::R1]);
regionBackFronts[workload::Region::R2] = regionRegulators[workload::Region::R2].run(loopDuration, timings[2] + timings[3], regionBackFronts[workload::Region::R2]);
regionBackFronts[workload::Region::R3] = regionRegulators[workload::Region::R3].run(loopDuration, timings[4], regionBackFronts[workload::Region::R3]);
enforceRegionContainment();
for (auto& outView : outViews) {

View file

@ -37,8 +37,8 @@ namespace workload {
{ 250.0f, 16000.0f }
};
const float RELATIVE_STEP_DOWN = 0.05f;
const float RELATIVE_STEP_UP = 0.04f;
const float RELATIVE_STEP_DOWN = 0.11f;
const float RELATIVE_STEP_UP = 0.09f;
class SetupViewsConfig : public Job::Config{
Q_OBJECT
@ -212,20 +212,31 @@ namespace workload {
};
struct Regulator {
using Timing_ns = std::chrono::nanoseconds;
Timing_ns _budget{ std::chrono::milliseconds(2) };
glm::vec2 _minRange{ MIN_VIEW_BACK_FRONTS[0] };
glm::vec2 _maxRange{ MAX_VIEW_BACK_FRONTS[0] };
glm::vec2 _relativeStepDown{ RELATIVE_STEP_DOWN };
glm::vec2 _relativeStepUp{ RELATIVE_STEP_UP };
Timing_ns _budget{ std::chrono::milliseconds(2) };
float _measuredTimeAverage { 0.0f };
float _measuredTimeNoiseSquared { 0.0f };
Regulator() {}
Regulator(const Timing_ns& budget_ns, const glm::vec2& minRange, const glm::vec2& maxRange, const glm::vec2& relativeStepDown, const glm::vec2& relativeStepUp) :
_budget(budget_ns), _minRange(minRange), _maxRange(maxRange), _relativeStepDown(relativeStepDown), _relativeStepUp(relativeStepUp) {}
Regulator(const Timing_ns& budget_ns,
const glm::vec2& minRange,
const glm::vec2& maxRange,
const glm::vec2& relativeStepDown,
const glm::vec2& relativeStepUp) :
_minRange(minRange),
_maxRange(maxRange),
_relativeStepDown(relativeStepDown),
_relativeStepUp(relativeStepUp),
_budget(budget_ns),
_measuredTimeAverage(budget_ns.count()),
_measuredTimeNoiseSquared(0.0f)
{}
glm::vec2 run(const Timing_ns& regulationDuration, const Timing_ns& measured, const glm::vec2& current);
void setBudget(const Timing_ns& budget) { _budget = budget; }
glm::vec2 run(const Timing_ns& deltaTime, const Timing_ns& measuredTime, const glm::vec2& currentFrontBack);
glm::vec2 clamp(const glm::vec2& backFront) const;
};