Skip to content

Commit

Permalink
viz: Add AChoreographer vsync id plumbing
Browse files Browse the repository at this point in the history
Get deadline information and store it in optional BeginFrameArgs field.

Bug: 1308459
Change-Id: Ia7f31d189895ad921a6b824053f3e63cdba9254c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3566369
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Commit-Queue: Bo Liu <boliu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#988584}
  • Loading branch information
Bo Liu authored and Chromium LUCI CQ committed Apr 4, 2022
1 parent d7a78bf commit 179283e
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 19 deletions.
31 changes: 31 additions & 0 deletions components/viz/common/frame_sinks/begin_frame_args.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,42 @@ std::string BeginFrameId::ToString() const {
return value.ToJSON();
}

PossibleDeadline::PossibleDeadline(int64_t vsync_id,
base::TimeDelta latch_delta,
base::TimeDelta present_delta)
: vsync_id(vsync_id),
latch_delta(latch_delta),
present_delta(present_delta) {}
PossibleDeadline::PossibleDeadline(const PossibleDeadline& other) = default;
PossibleDeadline::PossibleDeadline(PossibleDeadline&& other) = default;
PossibleDeadline::~PossibleDeadline() = default;
PossibleDeadline& PossibleDeadline::operator=(const PossibleDeadline& other) =
default;
PossibleDeadline& PossibleDeadline::operator=(PossibleDeadline&& other) =
default;

PossibleDeadlines::PossibleDeadlines(size_t preferred_index)
: preferred_index(preferred_index) {}
PossibleDeadlines::PossibleDeadlines(const PossibleDeadlines& other) = default;
PossibleDeadlines::PossibleDeadlines(PossibleDeadlines&& other) = default;
PossibleDeadlines::~PossibleDeadlines() = default;
PossibleDeadlines& PossibleDeadlines::operator=(
const PossibleDeadlines& other) = default;
PossibleDeadlines& PossibleDeadlines::operator=(PossibleDeadlines&& other) =
default;

const PossibleDeadline& PossibleDeadlines::GetPreferredDeadline() const {
return deadlines[preferred_index];
}

BeginFrameArgs::BeginFrameArgs()
: frame_time(base::TimeTicks::Min()),
deadline(base::TimeTicks::Min()),
interval(base::Microseconds(-1)),
frame_id(BeginFrameId(0, kInvalidFrameNumber)) {}

BeginFrameArgs::~BeginFrameArgs() = default;

BeginFrameArgs::BeginFrameArgs(uint64_t source_id,
uint64_t sequence_number,
base::TimeTicks frame_time,
Expand Down Expand Up @@ -150,6 +180,7 @@ void BeginFrameArgs::AsValueInto(base::trace_event::TracedValue* state) const {
#endif
state->SetBoolean("on_critical_path", on_critical_path);
state->SetBoolean("animate_only", animate_only);
state->SetBoolean("has_possible_deadlines", !!possible_deadlines);
}

void BeginFrameArgs::AsProtozeroInto(
Expand Down
50 changes: 50 additions & 0 deletions components/viz/common/frame_sinks/begin_frame_args.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@

#include <memory>
#include <string>
#include <vector>

#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "components/viz/common/viz_common_export.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

namespace perfetto {
class EventContext;
Expand Down Expand Up @@ -71,6 +73,47 @@ struct VIZ_COMMON_EXPORT BeginFrameId {
std::string ToString() const;
};

struct VIZ_COMMON_EXPORT PossibleDeadline {
PossibleDeadline(int64_t vsync_id,
base::TimeDelta latch_delta,
base::TimeDelta present_delta);
~PossibleDeadline();

// Out-of-line copy and assignment operators.
PossibleDeadline(const PossibleDeadline& other);
PossibleDeadline(PossibleDeadline&& other);
PossibleDeadline& operator=(const PossibleDeadline& other);
PossibleDeadline& operator=(PossibleDeadline&& other);

// Passed during swap to select the deadline.
int64_t vsync_id;
// Time delta from `BeginFrameArgs::frame_time` when the receiving pipeline
// stage starts to do its work. All viz CPU and GPU work need to be complete
// by this time to not miss a frame.
base::TimeDelta latch_delta;
// Time delta from `BeginFrameArgs::frame_time` when the frame is expected to
// be presented to the user. This would be the present time if viz finished
// its work before `latch_delta` and subsequent stages were also on time.
base::TimeDelta present_delta;
};

struct VIZ_COMMON_EXPORT PossibleDeadlines {
explicit PossibleDeadlines(size_t preferred_index);
~PossibleDeadlines();

// Out-of-line copy and assignment operators.
PossibleDeadlines(const PossibleDeadlines& other);
PossibleDeadlines(PossibleDeadlines&& other);
PossibleDeadlines& operator=(const PossibleDeadlines& other);
PossibleDeadlines& operator=(PossibleDeadlines&& other);

const PossibleDeadline& GetPreferredDeadline() const;

// Index into to `deadlines` vector picked by the OS as the default.
size_t preferred_index;
std::vector<PossibleDeadline> deadlines;
};

struct VIZ_COMMON_EXPORT BeginFrameArgs {
enum BeginFrameArgsType {
INVALID,
Expand All @@ -90,6 +133,7 @@ struct VIZ_COMMON_EXPORT BeginFrameArgs {

// Creates an invalid set of values.
BeginFrameArgs();
~BeginFrameArgs();

BeginFrameArgs(const BeginFrameArgs& args);
BeginFrameArgs& operator=(const BeginFrameArgs& args);
Expand Down Expand Up @@ -189,6 +233,12 @@ struct VIZ_COMMON_EXPORT BeginFrameArgs {
// sent.
uint64_t frames_throttled_since_last = 0;

// This is not serialized for mojo as it should only be used internal to viz.
// Note `deadline` is not yet updated to one of these deadline since some
// code still assumes `deadline` is a multiple of `interval` from
// `frame_time`.
absl::optional<PossibleDeadlines> possible_deadlines;

private:
BeginFrameArgs(uint64_t source_id,
uint64_t sequence_number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <dlfcn.h>
#include <sys/types.h>
#include <utility>

#include "base/android/build_info.h"
#include "base/android/jni_android.h"
Expand All @@ -25,6 +26,28 @@ using pAChoreographer_registerRefreshRateCallback =
void (*)(AChoreographer*, AChoreographer_refreshRateCallback, void*);
using pAChoreographer_unregisterRefreshRateCallback =
void (*)(AChoreographer*, AChoreographer_refreshRateCallback, void*);

typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData;
typedef void (*AChoreographer_vsyncCallback)(
const AChoreographerFrameCallbackData*,
void*);

using pAChoreographer_postVsyncCallback =
void (*)(AChoreographer* choreographer,
AChoreographer_vsyncCallback callback,
void* data);
using pAChoreographerFrameCallbackData_getFrameTimeNanos =
int64_t (*)(const AChoreographerFrameCallbackData*);
using pAChoreographerFrameCallbackData_getFrameTimelinesLength =
size_t (*)(const AChoreographerFrameCallbackData*);
using pAChoreographerFrameCallbackData_getPreferredFrameTimelineIndex =
size_t (*)(const AChoreographerFrameCallbackData*);
using pAChoreographerFrameCallbackData_getFrameTimelineVsyncId =
int64_t (*)(const AChoreographerFrameCallbackData*, size_t);
using pAChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos =
int64_t (*)(const AChoreographerFrameCallbackData*, size_t);
using pAChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos =
int64_t (*)(const AChoreographerFrameCallbackData*, size_t);
}

namespace {
Expand All @@ -45,12 +68,13 @@ struct AChoreographerMethods {
}

bool supported = true;
pAChoreographer_getInstance AChoreographer_getInstanceFn;
pAChoreographer_postFrameCallback64 AChoreographer_postFrameCallback64Fn;
pAChoreographer_getInstance AChoreographer_getInstanceFn = nullptr;
pAChoreographer_postFrameCallback64 AChoreographer_postFrameCallback64Fn =
nullptr;
pAChoreographer_registerRefreshRateCallback
AChoreographer_registerRefreshRateCallbackFn;
AChoreographer_registerRefreshRateCallbackFn = nullptr;
pAChoreographer_unregisterRefreshRateCallback
AChoreographer_unregisterRefreshRateCallbackFn;
AChoreographer_unregisterRefreshRateCallbackFn = nullptr;

private:
AChoreographerMethods() {
Expand All @@ -69,6 +93,69 @@ struct AChoreographerMethods {
~AChoreographerMethods() = default;
};

struct AChoreographerMethods33 {
static const AChoreographerMethods33& Get() {
static AChoreographerMethods33 instance;
return instance;
}

bool supported = true;
pAChoreographer_postVsyncCallback AChoreographer_postVsyncCallbackFn =
nullptr;
pAChoreographerFrameCallbackData_getFrameTimeNanos
AChoreographerFrameCallbackData_getFrameTimeNanosFn = nullptr;
pAChoreographerFrameCallbackData_getFrameTimelinesLength
AChoreographerFrameCallbackData_getFrameTimelinesLengthFn = nullptr;
pAChoreographerFrameCallbackData_getPreferredFrameTimelineIndex
AChoreographerFrameCallbackData_getPreferredFrameTimelineIndexFn =
nullptr;
pAChoreographerFrameCallbackData_getFrameTimelineVsyncId
AChoreographerFrameCallbackData_getFrameTimelineVsyncIdFn = nullptr;
pAChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos
AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanosFn =
nullptr;
pAChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos
AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanosFn = nullptr;

private:
AChoreographerMethods33() {
void* main_dl_handle = dlopen("libandroid.so", RTLD_NOW);
if (!main_dl_handle) {
LOG(ERROR) << "Couldnt load libandroid.so";
supported = false;
return;
}

LOAD_FUNCTION(main_dl_handle, AChoreographer_postVsyncCallback);
LOAD_FUNCTION(main_dl_handle,
AChoreographerFrameCallbackData_getFrameTimeNanos);
LOAD_FUNCTION(main_dl_handle,
AChoreographerFrameCallbackData_getFrameTimelinesLength);
LOAD_FUNCTION(
main_dl_handle,
AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex);
LOAD_FUNCTION(main_dl_handle,
AChoreographerFrameCallbackData_getFrameTimelineVsyncId);
LOAD_FUNCTION(
main_dl_handle,
AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos);
LOAD_FUNCTION(
main_dl_handle,
AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos);
}
~AChoreographerMethods33() = default;
};

base::TimeTicks ToTimeTicks(int64_t time_nanos) {
// Warning: It is generally unsafe to manufacture TimeTicks values. The
// following assumption is being made, AND COULD EASILY BREAK AT ANY TIME:
// Upstream, Java code is providing "System.nanos() / 1000," and this is the
// same timestamp that would be provided by the CLOCK_MONOTONIC POSIX clock.
DCHECK_EQ(base::TimeTicks::GetClock(),
base::TimeTicks::Clock::LINUX_CLOCK_MONOTONIC);
return base::TimeTicks() + base::Nanoseconds(time_nanos);
}

} // namespace

namespace viz {
Expand All @@ -87,8 +174,12 @@ class ExternalBeginFrameSourceAndroid::AChoreographerImpl {
private:
static void FrameCallback64(int64_t frame_time_nanos, void* data);
static void RefershRateCallback(int64_t vsync_period_nanos, void* data);
static void VsyncCallback(
const AChoreographerFrameCallbackData* callback_data,
void* data);

void OnVSync(int64_t frame_time_nanos,
absl::optional<PossibleDeadlines> possible_deadlines,
base::WeakPtr<AChoreographerImpl>* self);
void SetVsyncPeriod(int64_t vsync_period_nanos);
void RequestVsyncIfNeeded();
Expand Down Expand Up @@ -165,7 +256,53 @@ void ExternalBeginFrameSourceAndroid::AChoreographerImpl::FrameCallback64(
delete self;
return;
}
(*self)->OnVSync(frame_time_nanos, self);
(*self)->OnVSync(frame_time_nanos, /*possible_deadlines=*/absl::nullopt,
self);
}

// static
void ExternalBeginFrameSourceAndroid::AChoreographerImpl::VsyncCallback(
const AChoreographerFrameCallbackData* callback_data,
void* data) {
TRACE_EVENT0("toplevel", "Extend_VSync");
auto* self = static_cast<base::WeakPtr<AChoreographerImpl>*>(data);
if (!(*self)) {
delete self;
return;
}
DCHECK(AChoreographerMethods33::Get().supported);
int64_t frame_time_nanos =
AChoreographerMethods33::Get()
.AChoreographerFrameCallbackData_getFrameTimeNanosFn(callback_data);
size_t preferred_index =
AChoreographerMethods33::Get()
.AChoreographerFrameCallbackData_getPreferredFrameTimelineIndexFn(
callback_data);
size_t size = AChoreographerMethods33::Get()
.AChoreographerFrameCallbackData_getFrameTimelinesLengthFn(
callback_data);
CHECK_LT(preferred_index, size);

PossibleDeadlines possible_deadlines(preferred_index);
for (size_t i = 0; i < size; ++i) {
int64_t vsync_id =
AChoreographerMethods33::Get()
.AChoreographerFrameCallbackData_getFrameTimelineVsyncIdFn(
callback_data, i);
int64_t deadline =
AChoreographerMethods33::Get()
.AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanosFn(
callback_data, i);
int64_t present_time =
AChoreographerMethods33::Get()
.AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanosFn(
callback_data, i);
possible_deadlines.deadlines.emplace_back(
vsync_id, base::Nanoseconds(deadline - frame_time_nanos),
base::Nanoseconds(present_time - frame_time_nanos));
}

(*self)->OnVSync(frame_time_nanos, std::move(possible_deadlines), self);
}

// static
Expand All @@ -177,12 +314,18 @@ void ExternalBeginFrameSourceAndroid::AChoreographerImpl::RefershRateCallback(

void ExternalBeginFrameSourceAndroid::AChoreographerImpl::OnVSync(
int64_t frame_time_nanos,
absl::optional<PossibleDeadlines> possible_deadlines,
base::WeakPtr<AChoreographerImpl>* self) {
DCHECK(!self_for_frame_callback_);
DCHECK(self);
self_for_frame_callback_.reset(self);
if (vsync_notification_enabled_) {
client_->OnVSyncImpl(frame_time_nanos, vsync_period_);
// TODO(crbug.com/1308459): If `possible_deadlines` is present, should
// really pick a deadline from `possible_deadlines`. However some code
// still assume the deadline is a multiple of interval from frame time.
int64_t deadline = frame_time_nanos + vsync_period_.InNanoseconds();
client_->OnVSyncImpl(frame_time_nanos, deadline, vsync_period_,
std::move(possible_deadlines));
RequestVsyncIfNeeded();
}
}
Expand All @@ -196,8 +339,13 @@ void ExternalBeginFrameSourceAndroid::AChoreographerImpl::
RequestVsyncIfNeeded() {
if (!vsync_notification_enabled_ || !self_for_frame_callback_)
return;
AChoreographerMethods::Get().AChoreographer_postFrameCallback64Fn(
achoreographer_, &FrameCallback64, self_for_frame_callback_.release());
if (AChoreographerMethods33::Get().supported) {
AChoreographerMethods33::Get().AChoreographer_postVsyncCallbackFn(
achoreographer_, &VsyncCallback, self_for_frame_callback_.release());
} else {
AChoreographerMethods::Get().AChoreographer_postFrameCallback64Fn(
achoreographer_, &FrameCallback64, self_for_frame_callback_.release());
}
}

// ============================================================================
Expand Down Expand Up @@ -231,25 +379,24 @@ void ExternalBeginFrameSourceAndroid::OnVSync(
const base::android::JavaParamRef<jobject>& obj,
jlong time_micros,
jlong period_micros) {
OnVSyncImpl(time_micros * 1000, base::Microseconds(period_micros));
OnVSyncImpl(time_micros * 1000, (time_micros + period_micros) * 1000,
base::Microseconds(period_micros),
/*possible_deadlines=*/absl::nullopt);
}

void ExternalBeginFrameSourceAndroid::OnVSyncImpl(
int64_t time_nanos,
base::TimeDelta vsync_period) {
// Warning: It is generally unsafe to manufacture TimeTicks values. The
// following assumption is being made, AND COULD EASILY BREAK AT ANY TIME:
// Upstream, Java code is providing "System.nanos() / 1000," and this is the
// same timestamp that would be provided by the CLOCK_MONOTONIC POSIX clock.
int64_t deadline_nanos,
base::TimeDelta vsync_period,
absl::optional<PossibleDeadlines> possible_deadlines) {
DCHECK_EQ(base::TimeTicks::GetClock(),
base::TimeTicks::Clock::LINUX_CLOCK_MONOTONIC);
base::TimeTicks frame_time =
base::TimeTicks() + base::Nanoseconds(time_nanos);
// Calculate the next frame deadline:
base::TimeTicks deadline = frame_time + vsync_period;
base::TimeTicks frame_time = ToTimeTicks(time_nanos);
base::TimeTicks deadline = ToTimeTicks(deadline_nanos);

auto begin_frame_args = begin_frame_args_generator_.GenerateBeginFrameArgs(
source_id(), frame_time, deadline, vsync_period);
begin_frame_args.possible_deadlines = std::move(possible_deadlines);
OnBeginFrame(begin_frame_args);
}

Expand Down

0 comments on commit 179283e

Please sign in to comment.