Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions nativelib/src/main/cpp/presentation_scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
namespace {
constexpr int64_t kNanosecondsPerSecond = 1000000000LL;
constexpr int64_t kNanosecondsPerMicrosecond = 1000LL;
constexpr int64_t kMinSubmitLeadNs = 1000000LL;
constexpr int64_t kMaxSubmitLeadNs = 2000000LL;
constexpr int64_t kSubmitLeadNs = 2000000LL;
constexpr int64_t kPtsQuantizationSlackNs = kNanosecondsPerMicrosecond;
constexpr int64_t kDriftDeadbandNs = 2000000LL;
constexpr int64_t kMaxDriftCorrectionPerFrameNs = 20000LL;
constexpr int kSevereLateFramesBeforeRebuffer = 2;
Expand All @@ -28,13 +28,16 @@ void PtsPresentationScheduler::Configure(double fps) {
frameIntervalNs_ = static_cast<int64_t>(
std::llround(static_cast<double>(kNanosecondsPerSecond) / safeFps));
frameIntervalNs_ = std::max<int64_t>(frameIntervalNs_, 1000000LL);
submitLeadNs_ = std::clamp(frameIntervalNs_ / 8,
kMinSubmitLeadNs, kMaxSubmitLeadNs);
// RenderOutputBufferAtTime only needs a small submission margin. A full
// frame of fixed lead makes the next VSync become the following VSync on
// part of every refresh cycle, adding latency even in steady state.
// RenderService needs an absolute latch margin that does not shrink with
// the stream frame interval. Keep steady-state lead small, but large enough
// for 120 Hz submission overhead.
submitLeadNs_ = kSubmitLeadNs;
initialLeadNs_ = submitLeadNs_;
maxFutureLeadNs_ = initialLeadNs_ + frameIntervalNs_ / 2;
// Decoder callbacks commonly arrive in pairs. Preserve one frame of PTS
// spacing before treating future lead as backlog. The extra microsecond
// covers integer PTS quantization at rates such as 120 and 59.94 FPS.
maxFutureLeadNs_ = initialLeadNs_ + frameIntervalNs_ +
kPtsQuantizationSlackNs;
discontinuityNs_ = std::max<int64_t>(250000000LL, frameIntervalNs_ * 12);
Reset();
}
Expand Down
2 changes: 1 addition & 1 deletion nativelib/src/main/cpp/presentation_scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class PtsPresentationScheduler {
int64_t frameIntervalNs_ = 16666667LL;
int64_t initialLeadNs_ = 2000000LL;
int64_t submitLeadNs_ = 2000000LL;
int64_t maxFutureLeadNs_ = 10333333LL;
int64_t maxFutureLeadNs_ = 18667667LL;
int64_t discontinuityNs_ = 250000000LL;

bool initialized_ = false;
Expand Down
18 changes: 10 additions & 8 deletions nativelib/src/test/cpp/presentation_scheduler_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,22 @@
namespace {
constexpr int64_t kMs = 1000000LL;

void TestBurstCollapsesToLatestWithinLatencyBudget() {
void Test120FpsPairBurstKeepsPtsCadence() {
PtsPresentationScheduler scheduler;
scheduler.Configure(60.0);
scheduler.Configure(120.0);

const PresentationPlan first = scheduler.PlanFrame(0, 1000 * kMs);
const PresentationPlan second = scheduler.PlanFrame(16667, 1000 * kMs);
const PresentationPlan third = scheduler.PlanFrame(33333, 1001 * kMs);
const PresentationPlan second = scheduler.PlanFrame(8334, 1000 * kMs);
const PresentationPlan third = scheduler.PlanFrame(16667, 1001 * kMs);

assert(first.action == PresentationAction::SCHEDULE);
assert(second.action == PresentationAction::SCHEDULE);
assert(third.action == PresentationAction::SCHEDULE);
assert(second.event == PresentationEvent::CATCH_UP);
assert(second.event == PresentationEvent::NONE);
assert(third.event == PresentationEvent::CATCH_UP);
assert(first.targetTimeNs - 1000 * kMs == scheduler.GetInitialLeadNs());
assert(second.targetTimeNs - 1000 * kMs == scheduler.GetInitialLeadNs());
assert(scheduler.GetInitialLeadNs() == 2 * kMs);
assert(second.targetTimeNs - first.targetTimeNs == 8334 * 1000LL);
assert(third.targetTimeNs - 1001 * kMs == scheduler.GetInitialLeadNs());
}

Expand Down Expand Up @@ -151,7 +152,8 @@ void TestFractionalFpsLatencyBudget() {

assert(first.action == PresentationAction::SCHEDULE);
assert(first.targetTimeNs - decodedAtNs == expectedLeadNs);
assert(scheduler.GetMaxFutureLeadNs() == expectedLeadNs + frameIntervalNs / 2);
assert(scheduler.GetMaxFutureLeadNs() ==
expectedLeadNs + frameIntervalNs + 1000LL);
}

void TestSlowClockDriftStaysBounded() {
Expand Down Expand Up @@ -179,7 +181,7 @@ void TestSlowClockDriftStaysBounded() {
} // namespace

int main() {
TestBurstCollapsesToLatestWithinLatencyBudget();
Test120FpsPairBurstKeepsPtsCadence();
TestSmallLateFrameShiftsWholeTimeline();
TestSevereLateDropThenRebuffer();
TestAccumulatedPhaseShiftRecoversQuickly();
Expand Down
Loading