Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1003)

Unified Diff: components/exo/wayland/clients/motion_events.cc

Issue 2610513006: exo: Implement presentation interface. (Closed)
Patch Set: dcastagna nits Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/exo/wayland/BUILD.gn ('k') | components/exo/wayland/server.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/exo/wayland/clients/motion_events.cc
diff --git a/components/exo/wayland/clients/motion_events.cc b/components/exo/wayland/clients/motion_events.cc
index 92235d9bbf01757fd4f97a8c0e39b94468df99be..806e02a80b827f9aa15aab021400efe551a003ee 100644
--- a/components/exo/wayland/clients/motion_events.cc
+++ b/components/exo/wayland/clients/motion_events.cc
@@ -8,6 +8,7 @@
#include <fcntl.h>
#include <linux-dmabuf-unstable-v1-client-protocol.h>
+#include <presentation-time-client-protocol.h>
#include <wayland-client-core.h>
#include <wayland-client-protocol.h>
@@ -21,6 +22,7 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/shared_memory.h"
#include "base/scoped_generic.h"
#include "base/strings/string_number_conversions.h"
@@ -69,6 +71,9 @@ DEFAULT_DELETER(wl_seat, wl_seat_destroy)
DEFAULT_DELETER(wl_pointer, wl_pointer_destroy)
DEFAULT_DELETER(wl_touch, wl_touch_destroy)
DEFAULT_DELETER(wl_callback, wl_callback_destroy)
+DEFAULT_DELETER(wp_presentation, wp_presentation_destroy)
+DEFAULT_DELETER(struct wp_presentation_feedback,
+ wp_presentation_feedback_destroy)
DEFAULT_DELETER(zwp_linux_buffer_params_v1, zwp_linux_buffer_params_v1_destroy)
DEFAULT_DELETER(zwp_linux_dmabuf_v1, zwp_linux_dmabuf_v1_destroy)
@@ -111,6 +116,7 @@ const int kBenchmarkWarmupFrames = 10;
struct Globals {
std::unique_ptr<wl_compositor> compositor;
std::unique_ptr<wl_shm> shm;
+ std::unique_ptr<wp_presentation> presentation;
std::unique_ptr<zwp_linux_dmabuf_v1> linux_dmabuf;
std::unique_ptr<wl_shell> shell;
std::unique_ptr<wl_seat> seat;
@@ -135,6 +141,9 @@ void RegistryHandler(void* data,
} else if (strcmp(interface, "wl_seat") == 0) {
globals->seat.reset(static_cast<wl_seat*>(
wl_registry_bind(registry, id, &wl_seat_interface, 5)));
+ } else if (strcmp(interface, "wp_presentation") == 0) {
+ globals->presentation.reset(static_cast<wp_presentation*>(
+ wl_registry_bind(registry, id, &wp_presentation_interface, 1)));
} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
globals->linux_dmabuf.reset(static_cast<zwp_linux_dmabuf_v1*>(
wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, 1)));
@@ -271,17 +280,78 @@ void TouchFrame(void* data, wl_touch* touch) {}
void TouchCancel(void* data, wl_touch* touch) {}
-struct Frame {
+struct Schedule {
uint32_t time = 0;
bool callback_pending = false;
};
void FrameCallback(void* data, wl_callback* callback, uint32_t time) {
- Frame* frame = static_cast<Frame*>(data);
+ Schedule* schedule = static_cast<Schedule*>(data);
static uint32_t initial_time = time;
- frame->time = time - initial_time;
- frame->callback_pending = false;
+ schedule->time = time - initial_time;
+ schedule->callback_pending = false;
+}
+
+struct Frame {
+ Buffer* buffer = nullptr;
+ base::TimeDelta wall_time;
+ base::TimeDelta cpu_time;
+ std::vector<base::TimeTicks> event_times;
+ std::unique_ptr<struct wp_presentation_feedback> feedback;
+};
+
+struct Presentation {
+ std::deque<std::unique_ptr<Frame>> scheduled_frames;
+ base::TimeDelta wall_time;
+ base::TimeDelta cpu_time;
+ base::TimeDelta latency_time;
+ uint32_t num_frames_presented = 0;
+ uint32_t num_events_presented = 0;
+};
+
+void FeedbackSyncOutput(void* data,
+ struct wp_presentation_feedback* presentation_feedback,
+ wl_output* output) {}
+
+void FeedbackPresented(void* data,
+ struct wp_presentation_feedback* presentation_feedback,
+ uint32_t tv_sec_hi,
+ uint32_t tv_sec_lo,
+ uint32_t tv_nsec,
+ uint32_t refresh,
+ uint32_t seq_hi,
+ uint32_t seq_lo,
+ uint32_t flags) {
+ Presentation* presentation = static_cast<Presentation*>(data);
+ DCHECK_GT(presentation->scheduled_frames.size(), 0u);
+ std::unique_ptr<Frame> frame =
+ std::move(presentation->scheduled_frames.front());
+ presentation->scheduled_frames.pop_front();
+
+ presentation->wall_time += frame->wall_time;
+ presentation->cpu_time += frame->cpu_time;
+ ++presentation->num_frames_presented;
+
+ int64_t seconds = (static_cast<int64_t>(tv_sec_hi) << 32) + tv_sec_lo;
+ int64_t microseconds = seconds * base::Time::kMicrosecondsPerSecond +
+ tv_nsec / base::Time::kNanosecondsPerMicrosecond;
+ base::TimeTicks presentation_time =
+ base::TimeTicks::FromInternalValue(microseconds);
+ for (const auto& event_time : frame->event_times) {
+ presentation->latency_time += presentation_time - event_time;
+ ++presentation->num_events_presented;
+ }
+}
+
+void FeedbackDiscarded(void* data,
+ struct wp_presentation_feedback* presentation_feedback) {
+ Presentation* presentation = static_cast<Presentation*>(data);
+ DCHECK_GT(presentation->scheduled_frames.size(), 0u);
+ std::unique_ptr<Frame> frame =
+ std::move(presentation->scheduled_frames.front());
+ presentation->scheduled_frames.pop_front();
+ LOG(WARNING) << "Frame discarded";
}
#if defined(OZONE_PLATFORM_GBM)
@@ -385,6 +455,10 @@ int MotionEvents::Run() {
LOG(ERROR) << "Can't find shm interface";
return 1;
}
+ if (!globals_.presentation) {
+ LOG(ERROR) << "Can't find presentation interface";
+ return 1;
+ }
if (use_drm_ && !globals_.linux_dmabuf) {
LOG(ERROR) << "Can't find linux_dmabuf interface";
return 1;
@@ -400,6 +474,7 @@ int MotionEvents::Run() {
#if defined(OZONE_PLATFORM_GBM)
EGLenum egl_sync_type = 0;
+ sk_sp<const GrGLInterface> native_interface;
if (use_drm_) {
// Number of files to look for when discovering DRM devices.
const uint32_t kDrmMaxMinor = 15;
@@ -453,14 +528,14 @@ int MotionEvents::Run() {
if (gl::GLSurfaceEGL::HasEGLExtension("EGL_ANDROID_native_fence_sync")) {
egl_sync_type = EGL_SYNC_NATIVE_FENCE_ANDROID;
}
- }
- sk_sp<const GrGLInterface> native_interface(GrGLCreateNativeInterface());
- DCHECK(native_interface);
- gr_context_ = sk_sp<GrContext>(GrContext::Create(
- kOpenGL_GrBackend,
- reinterpret_cast<GrBackendContext>(native_interface.get())));
- DCHECK(gr_context_);
+ native_interface = sk_sp<const GrGLInterface>(GrGLCreateNativeInterface());
+ DCHECK(native_interface);
+ gr_context_ = sk_sp<GrContext>(GrContext::Create(
+ kOpenGL_GrBackend,
+ reinterpret_cast<GrBackendContext>(native_interface.get())));
+ DCHECK(gr_context_);
+ }
#endif
wl_buffer_listener buffer_listener = {BufferRelease};
@@ -539,18 +614,20 @@ int MotionEvents::Run() {
TouchFrame, TouchCancel};
wl_touch_add_listener(touch.get(), &touch_listener, &event_times);
- Frame frame;
+ Schedule schedule;
std::unique_ptr<wl_callback> frame_callback;
wl_callback_listener frame_listener = {FrameCallback};
- std::deque<Buffer*> pending_frames;
- uint32_t frames = 0;
+ Presentation presentation;
+ std::deque<std::unique_ptr<Frame>> pending_frames;
+
size_t num_benchmark_runs_left = num_benchmark_runs_;
- base::TimeTicks benchmark_time;
- base::TimeDelta benchmark_wall_time;
- base::TimeDelta benchmark_cpu_time;
+ base::TimeTicks benchmark_start_time;
std::string fps_counter_text("??");
+ wp_presentation_feedback_listener feedback_listener = {
+ FeedbackSyncOutput, FeedbackPresented, FeedbackDiscarded};
+
SkPaint text_paint;
text_paint.setTextSize(32.0f);
text_paint.setColor(SK_ColorWHITE);
@@ -558,7 +635,7 @@ int MotionEvents::Run() {
int dispatch_status = 0;
do {
- bool enqueue_frame = frame.callback_pending
+ bool enqueue_frame = schedule.callback_pending
? pending_frames.size() < max_frames_pending_
: pending_frames.empty();
if (enqueue_frame) {
@@ -570,22 +647,28 @@ int MotionEvents::Run() {
return 1;
}
+ auto frame = base::MakeUnique<Frame>();
+ frame->buffer = buffer;
+
base::TimeTicks wall_time_start;
base::ThreadTicks cpu_time_start;
if (num_benchmark_runs_ || show_fps_counter_) {
wall_time_start = base::TimeTicks::Now();
- if (frames <= kBenchmarkWarmupFrames)
- benchmark_time = wall_time_start;
+ if (presentation.num_frames_presented <= kBenchmarkWarmupFrames)
+ benchmark_start_time = wall_time_start;
- if ((wall_time_start - benchmark_time) > benchmark_interval_) {
- uint32_t benchmark_frames = frames - kBenchmarkWarmupFrames;
+ base::TimeDelta benchmark_time = wall_time_start - benchmark_start_time;
+ if (benchmark_time > benchmark_interval_) {
+ uint32_t benchmark_frames =
+ presentation.num_frames_presented - kBenchmarkWarmupFrames;
if (num_benchmark_runs_left) {
- // Print benchmark statistics for the frames produced and exit.
- // Note: frames produced is not necessarily the same as frames
- // displayed.
+ // Print benchmark statistics for the frames presented and exit.
std::cout << benchmark_frames << '\t'
- << benchmark_wall_time.InMilliseconds() << '\t'
- << benchmark_cpu_time.InMilliseconds() << '\t'
+ << benchmark_time.InMilliseconds() << '\t'
+ << presentation.wall_time.InMilliseconds() << '\t'
+ << presentation.cpu_time.InMilliseconds() << '\t'
+ << presentation.num_events_presented << '\t'
+ << presentation.latency_time.InMilliseconds() << '\t'
<< std::endl;
if (!--num_benchmark_runs_left)
return 0;
@@ -595,10 +678,12 @@ int MotionEvents::Run() {
fps_counter_text = base::UintToString(
std::round(benchmark_frames / benchmark_interval_.InSecondsF()));
- frames = kBenchmarkWarmupFrames;
- benchmark_time = wall_time_start;
- benchmark_wall_time = base::TimeDelta();
- benchmark_cpu_time = base::TimeDelta();
+ benchmark_start_time = wall_time_start;
+ presentation.wall_time = base::TimeDelta();
+ presentation.cpu_time = base::TimeDelta();
+ presentation.latency_time = base::TimeDelta();
+ presentation.num_frames_presented = kBenchmarkWarmupFrames;
+ presentation.num_events_presented = 0;
}
cpu_time_start = base::ThreadTicks::Now();
@@ -622,6 +707,8 @@ int MotionEvents::Run() {
canvas->drawIRect(rect, paint);
std::string text = base::UintToString(event_times.back());
canvas->drawText(text.c_str(), text.length(), 8, y + 32, text_paint);
+ frame->event_times.push_back(base::TimeTicks::FromInternalValue(
+ event_times.back() * base::Time::kMicrosecondsPerMillisecond));
event_times.pop_back();
y += h;
}
@@ -633,7 +720,7 @@ int MotionEvents::Run() {
SkIRect rect = SkIRect::MakeXYWH(-SkScalarHalf(half_width),
-SkScalarHalf(half_height), half_width,
half_height);
- SkScalar rotation = SkScalarMulDiv(frame.time, kRotationSpeed, 1000);
+ SkScalar rotation = SkScalarMulDiv(schedule.time, kRotationSpeed, 1000);
canvas->save();
canvas->translate(half_width, half_height);
for (size_t i = 0; i < num_rects_; ++i) {
@@ -668,35 +755,43 @@ int MotionEvents::Run() {
}
buffer->busy = true;
- pending_frames.push_back(buffer);
- if (num_benchmark_runs_ || show_fps_counter_) {
- ++frames;
- benchmark_wall_time += base::TimeTicks::Now() - wall_time_start;
- benchmark_cpu_time += base::ThreadTicks::Now() - cpu_time_start;
+ if (num_benchmark_runs_) {
+ frame->wall_time = base::TimeTicks::Now() - wall_time_start;
+ frame->cpu_time = base::ThreadTicks::Now() - cpu_time_start;
}
+ pending_frames.push_back(std::move(frame));
continue;
}
- if (!frame.callback_pending) {
+ if (!schedule.callback_pending) {
DCHECK_GT(pending_frames.size(), 0u);
- Buffer* buffer = pending_frames.front();
+ std::unique_ptr<Frame> frame = std::move(pending_frames.front());
pending_frames.pop_front();
wl_surface_set_buffer_scale(surface.get(), scale_);
wl_surface_damage(surface.get(), 0, 0, width_ / scale_, height_ / scale_);
- wl_surface_attach(surface.get(), buffer->buffer.get(), 0, 0);
+ wl_surface_attach(surface.get(), frame->buffer->buffer.get(), 0, 0);
#if defined(OZONE_PLATFORM_GBM)
- if (buffer->egl_sync) {
- eglClientWaitSyncKHR(eglGetCurrentDisplay(), buffer->egl_sync->get(),
+ if (frame->buffer->egl_sync) {
+ eglClientWaitSyncKHR(eglGetCurrentDisplay(),
+ frame->buffer->egl_sync->get(),
EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
}
#endif
frame_callback.reset(wl_surface_frame(surface.get()));
- wl_callback_add_listener(frame_callback.get(), &frame_listener, &frame);
- frame.callback_pending = true;
+ wl_callback_add_listener(frame_callback.get(), &frame_listener,
+ &schedule);
+ schedule.callback_pending = true;
+
+ frame->feedback.reset(
+ wp_presentation_feedback(globals_.presentation.get(), surface.get()));
+ wp_presentation_feedback_add_listener(frame->feedback.get(),
+ &feedback_listener, &presentation);
+ presentation.scheduled_frames.push_back(std::move(frame));
+
wl_surface_commit(surface.get());
wl_display_flush(display_.get());
continue;
« no previous file with comments | « components/exo/wayland/BUILD.gn ('k') | components/exo/wayland/server.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698