Chromium Code Reviews| 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 f32b13059bddc06cbf2560db083b4f30f4592c03..d2c04fbad3a511b95f092f30c64f126225fbbbaf 100644 |
| --- a/components/exo/wayland/clients/motion_events.cc |
| +++ b/components/exo/wayland/clients/motion_events.cc |
| @@ -11,6 +11,7 @@ |
| #include <wayland-client-core.h> |
| #include <wayland-client-protocol.h> |
| +#include <deque> |
| #include <iostream> |
| #include <vector> |
| @@ -95,7 +96,7 @@ const char kDriRenderNode[] = "/dev/dri/renderD128"; |
| #endif |
| // Number of buffers. |
| -const size_t kBuffers = 3; |
| +const size_t kBuffers = 5; |
| // Rotation speed (degrees/second). |
| const double kRotationSpeed = 360.0; |
| @@ -297,14 +298,16 @@ class MotionEvents { |
| size_t height, |
| int scale, |
| size_t num_rects, |
| - bool use_drm, |
| - bool fullscreen) |
| + size_t max_frames_pending, |
| + bool fullscreen, |
| + bool use_drm) |
| : width_(width), |
| height_(height), |
| scale_(scale), |
| num_rects_(num_rects), |
| - use_drm_(use_drm), |
| - fullscreen_(fullscreen) {} |
| + max_frames_pending_(max_frames_pending), |
| + fullscreen_(fullscreen), |
| + use_drm_(use_drm) {} |
| // Initialize and run client main loop. |
| int Run(); |
| @@ -318,8 +321,9 @@ class MotionEvents { |
| const size_t height_; |
| const int scale_; |
| const size_t num_rects_; |
| - const bool use_drm_; |
| + const size_t max_frames_pending_; |
| const bool fullscreen_; |
| + const bool use_drm_; |
| Globals globals_; |
| std::unique_ptr<wl_display> display_; |
| @@ -482,89 +486,117 @@ int MotionEvents::Run() { |
| Frame frame; |
| std::unique_ptr<wl_callback> frame_callback; |
| wl_callback_listener frame_listener = {FrameCallback}; |
| + std::deque<wl_buffer*> pending_frames; |
| uint32_t frames = 0; |
| + base::TimeDelta frames_time; |
| base::TimeTicks benchmark_time = base::TimeTicks::Now(); |
| base::TimeDelta benchmark_interval = |
| base::TimeDelta::FromSeconds(kBenchmarkInterval); |
| + int dispatch_status = 0; |
| do { |
| - if (frame.callback_pending) |
| - continue; |
| + size_t max_frames_pending = max_frames_pending_; |
| + if (!frame.callback_pending) |
| + ++max_frames_pending; |
| + |
| + if (pending_frames.size() < max_frames_pending) { |
| + Buffer* buffer = |
|
Daniele Castagna
2016/11/10 03:32:26
As discussed offline, we can create an helper func
|
| + std::find_if(std::begin(buffers_), std::end(buffers_), |
| + [](const Buffer& buffer) { return !buffer.busy; }); |
| + if (buffer == std::end(buffers_)) { |
| + LOG(WARNING) << "Can't find free buffer"; |
| + return 1; |
| + } |
| - Buffer* buffer = |
| - std::find_if(std::begin(buffers_), std::end(buffers_), |
| - [](const Buffer& buffer) { return !buffer.busy; }); |
| - if (buffer == std::end(buffers_)) |
| - continue; |
| + base::TimeTicks current_time = base::TimeTicks::Now(); |
|
Daniele Castagna
2016/11/10 03:32:26
Can we try re-using the code gpu/perftests/measure
|
| + if ((current_time - benchmark_time) > benchmark_interval) { |
| + std::cout << frames << " frames in " << benchmark_interval.InSeconds() |
| + << " seconds: " |
| + << static_cast<double>(frames) / |
| + benchmark_interval.InSeconds() |
| + << " fps (" |
| + << frames_time.InMilliseconds() / static_cast<double>(frames) |
| + << " ms/frame) " |
| + << std::count_if( |
| + std::begin(buffers_), std::end(buffers_), |
| + [](const Buffer& buffer) { return buffer.busy; }) |
| + << std::endl; |
| + benchmark_time = current_time; |
| + frames = 0; |
| + frames_time = base::TimeDelta(); |
| + } |
| - base::TimeTicks current_time = base::TimeTicks::Now(); |
| - if ((current_time - benchmark_time) > benchmark_interval) { |
| - std::cout << frames << " frames in " << benchmark_interval.InSeconds() |
| - << " seconds: " |
| - << static_cast<double>(frames) / benchmark_interval.InSeconds() |
| - << " fps" << std::endl; |
| - benchmark_time = current_time; |
| - frames = 0; |
| - } |
| + SkCanvas* canvas = buffer->sk_surface->getCanvas(); |
| + canvas->save(); |
| + |
| + if (event_times.empty()) { |
| + canvas->clear(SK_ColorBLACK); |
| + } else { |
| + // Split buffer into one horizontal rectangle for each event received |
| + // since last frame. Latest event at the top. |
| + int y = 0; |
| + // Note: Rounding up to ensure we cover the whole canvas. |
| + int h = (height_ + (event_times.size() / 2)) / event_times.size(); |
| + while (!event_times.empty()) { |
| + SkIRect rect = SkIRect::MakeXYWH(0, y, width_, h); |
| + SkPaint paint; |
| + paint.setColor(SkColorSetRGB((event_times.back() & 0x0000ff) >> 0, |
| + (event_times.back() & 0x00ff00) >> 8, |
| + (event_times.back() & 0xff0000) >> 16)); |
| + canvas->drawIRect(rect, paint); |
| + event_times.pop_back(); |
| + y += h; |
| + } |
| + } |
| - SkCanvas* canvas = buffer->sk_surface->getCanvas(); |
| - canvas->save(); |
| - |
| - if (event_times.empty()) { |
| - canvas->clear(SK_ColorBLACK); |
| - } else { |
| - // Split buffer into one horizontal rectangle for each event received |
| - // since last frame. Latest event at the top. |
| - int y = 0; |
| - // Note: Rounding up to ensure we cover the whole canvas. |
| - int h = (height_ + (event_times.size() / 2)) / event_times.size(); |
| - while (!event_times.empty()) { |
| - SkIRect rect = SkIRect::MakeXYWH(0, y, width_, h); |
| - SkPaint paint; |
| - paint.setColor(SkColorSetRGB((event_times.back() & 0x0000ff) >> 0, |
| - (event_times.back() & 0x00ff00) >> 8, |
| - (event_times.back() & 0xff0000) >> 16)); |
| + // Draw rotating rects. |
| + SkScalar half_width = SkScalarHalf(width_); |
| + SkScalar half_height = SkScalarHalf(height_); |
| + SkIRect rect = SkIRect::MakeXYWH(-SkScalarHalf(half_width), |
| + -SkScalarHalf(half_height), half_width, |
| + half_height); |
| + SkScalar rotation = SkScalarMulDiv(frame.time, kRotationSpeed, 1000); |
| + SkPaint paint; |
| + canvas->translate(half_width, half_height); |
| + for (size_t i = 0; i < num_rects_; ++i) { |
| + const SkColor kColors[] = {SK_ColorBLUE, SK_ColorGREEN, |
| + SK_ColorRED, SK_ColorYELLOW, |
| + SK_ColorCYAN, SK_ColorMAGENTA}; |
| + paint.setColor(SkColorSetA(kColors[i % arraysize(kColors)], 0xA0)); |
| + canvas->rotate(rotation / num_rects_); |
| canvas->drawIRect(rect, paint); |
| - event_times.pop_back(); |
| - y += h; |
| } |
| - } |
| - // Draw rotating rects. |
| - SkScalar half_width = SkScalarHalf(width_); |
| - SkScalar half_height = SkScalarHalf(height_); |
| - SkIRect rect = |
| - SkIRect::MakeXYWH(-SkScalarHalf(half_width), -SkScalarHalf(half_height), |
| - half_width, half_height); |
| - SkScalar rotation = SkScalarMulDiv(frame.time, kRotationSpeed, 1000); |
| - SkPaint paint; |
| - canvas->translate(half_width, half_height); |
| - for (size_t i = 0; i < num_rects_; ++i) { |
| - const SkColor kColors[] = {SK_ColorBLUE, SK_ColorGREEN, |
| - SK_ColorRED, SK_ColorYELLOW, |
| - SK_ColorCYAN, SK_ColorMAGENTA}; |
| - paint.setColor(SkColorSetA(kColors[i % arraysize(kColors)], 0xA0)); |
| - canvas->rotate(rotation / num_rects_); |
| - canvas->drawIRect(rect, paint); |
| - } |
| - canvas->restore(); |
| - if (gr_context_) { |
| - gr_context_->flush(); |
| - glFinish(); |
| - } |
| - wl_surface_set_buffer_scale(surface.get(), scale_); |
| - wl_surface_attach(surface.get(), buffer->buffer.get(), 0, 0); |
| - buffer->busy = true; |
| + canvas->restore(); |
| + if (gr_context_) { |
| + gr_context_->flush(); |
| + glFinish(); |
| + } |
| - frame_callback.reset(wl_surface_frame(surface.get())); |
| - wl_callback_add_listener(frame_callback.get(), &frame_listener, &frame); |
| - frame.callback_pending = true; |
| + buffer->busy = true; |
| + pending_frames.push_back(buffer->buffer.get()); |
| + ++frames; |
| + frames_time += base::TimeTicks::Now() - current_time; |
| + continue; |
| + } |
| - ++frames; |
| + if (!frame.callback_pending) { |
| + DCHECK_GT(pending_frames.size(), 0u); |
| + wl_surface_set_buffer_scale(surface.get(), scale_); |
| + wl_surface_attach(surface.get(), pending_frames.front(), 0, 0); |
| + pending_frames.pop_front(); |
| + |
| + frame_callback.reset(wl_surface_frame(surface.get())); |
| + wl_callback_add_listener(frame_callback.get(), &frame_listener, &frame); |
| + frame.callback_pending = true; |
| + wl_surface_commit(surface.get()); |
| + wl_display_flush(display_.get()); |
| + continue; |
| + } |
| - wl_surface_commit(surface.get()); |
| - } while (wl_display_dispatch(display_.get()) != -1); |
| + dispatch_status = wl_display_dispatch(display_.get()); |
| + } while (dispatch_status != -1); |
| return 0; |
| } |
| @@ -668,12 +700,15 @@ const char kScale[] = "scale"; |
| // Specifies the number of rotating rects to draw. |
| const char kNumRects[] = "num-rects"; |
| -// Use drm buffer instead of shared memory. |
| -const char kUseDrm[] = "use-drm"; |
| +// Specifies the maximum number of pending frames. |
| +const char kMaxFramesPending[] = "max-frames-pending"; |
| // Specifies if client should be fullscreen. |
| const char kFullscreen[] = "fullscreen"; |
| +// Use drm buffer instead of shared memory. |
| +const char kUseDrm[] = "use-drm"; |
| + |
| } // namespace switches |
| int main(int argc, char* argv[]) { |
| @@ -707,10 +742,18 @@ int main(int argc, char* argv[]) { |
| return 1; |
| } |
| - bool use_drm = command_line->HasSwitch(switches::kUseDrm); |
| - bool fullscreen = command_line->HasSwitch(switches::kFullscreen); |
| + size_t max_frames_pending = 0; |
| + if (command_line->HasSwitch(switches::kMaxFramesPending) && |
| + (!base::StringToSizeT( |
| + command_line->GetSwitchValueASCII(switches::kMaxFramesPending), |
| + &max_frames_pending))) { |
| + LOG(ERROR) << "Invalid value for " << switches::kMaxFramesPending; |
| + return 1; |
| + } |
| - exo::wayland::clients::MotionEvents client(width, height, scale, num_rects, |
| - use_drm, fullscreen); |
| + exo::wayland::clients::MotionEvents client( |
| + width, height, scale, num_rects, max_frames_pending, |
| + command_line->HasSwitch(switches::kFullscreen), |
| + command_line->HasSwitch(switches::kUseDrm)); |
| return client.Run(); |
| } |