Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Implementation of a client that produces output in the form of RGBA | 5 // Implementation of a client that produces output in the form of RGBA |
| 6 // buffers when receiving pointer/touch events. RGB contains the lower | 6 // buffers when receiving pointer/touch events. RGB contains the lower |
| 7 // 24 bits of the event timestamp and A is 0xff. | 7 // 24 bits of the event timestamp and A is 0xff. |
| 8 | 8 |
| 9 #include <fcntl.h> | 9 #include <fcntl.h> |
| 10 #include <linux-dmabuf-unstable-v1-client-protocol.h> | 10 #include <linux-dmabuf-unstable-v1-client-protocol.h> |
| 11 #include <presentation-time-client-protocol.h> | |
| 11 #include <wayland-client-core.h> | 12 #include <wayland-client-core.h> |
| 12 #include <wayland-client-protocol.h> | 13 #include <wayland-client-protocol.h> |
| 13 | 14 |
| 14 #include <cmath> | 15 #include <cmath> |
| 15 #include <deque> | 16 #include <deque> |
| 16 #include <iostream> | 17 #include <iostream> |
| 17 #include <string> | 18 #include <string> |
| 18 #include <vector> | 19 #include <vector> |
| 19 | 20 |
| 20 #include "base/at_exit.h" | 21 #include "base/at_exit.h" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 62 DEFAULT_DELETER(wl_shm_pool, wl_shm_pool_destroy) | 63 DEFAULT_DELETER(wl_shm_pool, wl_shm_pool_destroy) |
| 63 DEFAULT_DELETER(wl_buffer, wl_buffer_destroy) | 64 DEFAULT_DELETER(wl_buffer, wl_buffer_destroy) |
| 64 DEFAULT_DELETER(wl_surface, wl_surface_destroy) | 65 DEFAULT_DELETER(wl_surface, wl_surface_destroy) |
| 65 DEFAULT_DELETER(wl_region, wl_region_destroy) | 66 DEFAULT_DELETER(wl_region, wl_region_destroy) |
| 66 DEFAULT_DELETER(wl_shell, wl_shell_destroy) | 67 DEFAULT_DELETER(wl_shell, wl_shell_destroy) |
| 67 DEFAULT_DELETER(wl_shell_surface, wl_shell_surface_destroy) | 68 DEFAULT_DELETER(wl_shell_surface, wl_shell_surface_destroy) |
| 68 DEFAULT_DELETER(wl_seat, wl_seat_destroy) | 69 DEFAULT_DELETER(wl_seat, wl_seat_destroy) |
| 69 DEFAULT_DELETER(wl_pointer, wl_pointer_destroy) | 70 DEFAULT_DELETER(wl_pointer, wl_pointer_destroy) |
| 70 DEFAULT_DELETER(wl_touch, wl_touch_destroy) | 71 DEFAULT_DELETER(wl_touch, wl_touch_destroy) |
| 71 DEFAULT_DELETER(wl_callback, wl_callback_destroy) | 72 DEFAULT_DELETER(wl_callback, wl_callback_destroy) |
| 73 DEFAULT_DELETER(wp_presentation, wp_presentation_destroy) | |
| 74 DEFAULT_DELETER(struct wp_presentation_feedback, | |
| 75 wp_presentation_feedback_destroy) | |
| 72 DEFAULT_DELETER(zwp_linux_buffer_params_v1, zwp_linux_buffer_params_v1_destroy) | 76 DEFAULT_DELETER(zwp_linux_buffer_params_v1, zwp_linux_buffer_params_v1_destroy) |
| 73 DEFAULT_DELETER(zwp_linux_dmabuf_v1, zwp_linux_dmabuf_v1_destroy) | 77 DEFAULT_DELETER(zwp_linux_dmabuf_v1, zwp_linux_dmabuf_v1_destroy) |
| 74 | 78 |
| 75 #if defined(OZONE_PLATFORM_GBM) | 79 #if defined(OZONE_PLATFORM_GBM) |
| 76 DEFAULT_DELETER(gbm_device, gbm_device_destroy) | 80 DEFAULT_DELETER(gbm_device, gbm_device_destroy) |
| 77 DEFAULT_DELETER(gbm_bo, gbm_bo_destroy) | 81 DEFAULT_DELETER(gbm_bo, gbm_bo_destroy) |
| 78 #endif | 82 #endif |
| 79 | 83 |
| 80 namespace exo { | 84 namespace exo { |
| 81 namespace wayland { | 85 namespace wayland { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 104 | 108 |
| 105 // Rotation speed (degrees/second). | 109 // Rotation speed (degrees/second). |
| 106 const double kRotationSpeed = 360.0; | 110 const double kRotationSpeed = 360.0; |
| 107 | 111 |
| 108 // Benchmark warmup frames before starting measurement. | 112 // Benchmark warmup frames before starting measurement. |
| 109 const int kBenchmarkWarmupFrames = 10; | 113 const int kBenchmarkWarmupFrames = 10; |
| 110 | 114 |
| 111 struct Globals { | 115 struct Globals { |
| 112 std::unique_ptr<wl_compositor> compositor; | 116 std::unique_ptr<wl_compositor> compositor; |
| 113 std::unique_ptr<wl_shm> shm; | 117 std::unique_ptr<wl_shm> shm; |
| 118 std::unique_ptr<wp_presentation> presentation; | |
| 114 std::unique_ptr<zwp_linux_dmabuf_v1> linux_dmabuf; | 119 std::unique_ptr<zwp_linux_dmabuf_v1> linux_dmabuf; |
| 115 std::unique_ptr<wl_shell> shell; | 120 std::unique_ptr<wl_shell> shell; |
| 116 std::unique_ptr<wl_seat> seat; | 121 std::unique_ptr<wl_seat> seat; |
| 117 }; | 122 }; |
| 118 | 123 |
| 119 void RegistryHandler(void* data, | 124 void RegistryHandler(void* data, |
| 120 wl_registry* registry, | 125 wl_registry* registry, |
| 121 uint32_t id, | 126 uint32_t id, |
| 122 const char* interface, | 127 const char* interface, |
| 123 uint32_t version) { | 128 uint32_t version) { |
| 124 Globals* globals = static_cast<Globals*>(data); | 129 Globals* globals = static_cast<Globals*>(data); |
| 125 | 130 |
| 126 if (strcmp(interface, "wl_compositor") == 0) { | 131 if (strcmp(interface, "wl_compositor") == 0) { |
| 127 globals->compositor.reset(static_cast<wl_compositor*>( | 132 globals->compositor.reset(static_cast<wl_compositor*>( |
| 128 wl_registry_bind(registry, id, &wl_compositor_interface, 3))); | 133 wl_registry_bind(registry, id, &wl_compositor_interface, 3))); |
| 129 } else if (strcmp(interface, "wl_shm") == 0) { | 134 } else if (strcmp(interface, "wl_shm") == 0) { |
| 130 globals->shm.reset(static_cast<wl_shm*>( | 135 globals->shm.reset(static_cast<wl_shm*>( |
| 131 wl_registry_bind(registry, id, &wl_shm_interface, 1))); | 136 wl_registry_bind(registry, id, &wl_shm_interface, 1))); |
| 132 } else if (strcmp(interface, "wl_shell") == 0) { | 137 } else if (strcmp(interface, "wl_shell") == 0) { |
| 133 globals->shell.reset(static_cast<wl_shell*>( | 138 globals->shell.reset(static_cast<wl_shell*>( |
| 134 wl_registry_bind(registry, id, &wl_shell_interface, 1))); | 139 wl_registry_bind(registry, id, &wl_shell_interface, 1))); |
| 135 } else if (strcmp(interface, "wl_seat") == 0) { | 140 } else if (strcmp(interface, "wl_seat") == 0) { |
| 136 globals->seat.reset(static_cast<wl_seat*>( | 141 globals->seat.reset(static_cast<wl_seat*>( |
| 137 wl_registry_bind(registry, id, &wl_seat_interface, 5))); | 142 wl_registry_bind(registry, id, &wl_seat_interface, 5))); |
| 143 } else if (strcmp(interface, "wp_presentation") == 0) { | |
| 144 globals->presentation.reset(static_cast<wp_presentation*>( | |
| 145 wl_registry_bind(registry, id, &wp_presentation_interface, 1))); | |
| 138 } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) { | 146 } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) { |
| 139 globals->linux_dmabuf.reset(static_cast<zwp_linux_dmabuf_v1*>( | 147 globals->linux_dmabuf.reset(static_cast<zwp_linux_dmabuf_v1*>( |
| 140 wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, 1))); | 148 wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, 1))); |
| 141 } | 149 } |
| 142 } | 150 } |
| 143 | 151 |
| 144 void RegistryRemover(void* data, wl_registry* registry, uint32_t id) { | 152 void RegistryRemover(void* data, wl_registry* registry, uint32_t id) { |
| 145 LOG(WARNING) << "Got a registry losing event for " << id; | 153 LOG(WARNING) << "Got a registry losing event for " << id; |
| 146 } | 154 } |
| 147 | 155 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 264 wl_fixed_t y) { | 272 wl_fixed_t y) { |
| 265 EventTimeStack* stack = static_cast<EventTimeStack*>(data); | 273 EventTimeStack* stack = static_cast<EventTimeStack*>(data); |
| 266 | 274 |
| 267 stack->push_back(time); | 275 stack->push_back(time); |
| 268 } | 276 } |
| 269 | 277 |
| 270 void TouchFrame(void* data, wl_touch* touch) {} | 278 void TouchFrame(void* data, wl_touch* touch) {} |
| 271 | 279 |
| 272 void TouchCancel(void* data, wl_touch* touch) {} | 280 void TouchCancel(void* data, wl_touch* touch) {} |
| 273 | 281 |
| 274 struct Frame { | 282 struct Schedule { |
| 275 uint32_t time = 0; | 283 uint32_t time = 0; |
| 276 bool callback_pending = false; | 284 bool callback_pending = false; |
| 277 }; | 285 }; |
| 278 | 286 |
| 279 void FrameCallback(void* data, wl_callback* callback, uint32_t time) { | 287 void FrameCallback(void* data, wl_callback* callback, uint32_t time) { |
| 280 Frame* frame = static_cast<Frame*>(data); | 288 Schedule* schedule = static_cast<Schedule*>(data); |
| 281 | 289 |
| 282 static uint32_t initial_time = time; | 290 static uint32_t initial_time = time; |
| 283 frame->time = time - initial_time; | 291 schedule->time = time - initial_time; |
| 284 frame->callback_pending = false; | 292 schedule->callback_pending = false; |
| 293 } | |
| 294 | |
| 295 struct Frame { | |
| 296 Buffer* buffer = nullptr; | |
| 297 base::TimeDelta wall_time; | |
| 298 base::TimeDelta cpu_time; | |
| 299 std::vector<base::TimeTicks> event_times; | |
| 300 std::unique_ptr<struct wp_presentation_feedback> feedback; | |
| 301 }; | |
| 302 | |
| 303 struct Presentation { | |
| 304 std::deque<std::unique_ptr<Frame>> scheduled_frames; | |
| 305 base::TimeDelta wall_time; | |
| 306 base::TimeDelta cpu_time; | |
| 307 base::TimeDelta latency_time; | |
| 308 uint32_t num_frames_presented = 0; | |
| 309 uint32_t num_events_presented = 0; | |
| 310 }; | |
| 311 | |
| 312 void FeedbackSyncOutput(void* data, | |
| 313 struct wp_presentation_feedback* presentation_feedback, | |
| 314 wl_output* output) {} | |
| 315 | |
| 316 void FeedbackPresented(void* data, | |
| 317 struct wp_presentation_feedback* presentation_feedback, | |
| 318 uint32_t tv_sec_hi, | |
| 319 uint32_t tv_sec_lo, | |
| 320 uint32_t tv_nsec, | |
| 321 uint32_t refresh, | |
| 322 uint32_t seq_hi, | |
| 323 uint32_t seq_lo, | |
| 324 uint32_t flags) { | |
| 325 Presentation* presentation = static_cast<Presentation*>(data); | |
| 326 DCHECK_GT(presentation->scheduled_frames.size(), 0u); | |
| 327 std::unique_ptr<Frame> frame = | |
| 328 std::move(presentation->scheduled_frames.front()); | |
| 329 presentation->scheduled_frames.pop_front(); | |
| 330 | |
| 331 presentation->wall_time += frame->wall_time; | |
| 332 presentation->cpu_time += frame->cpu_time; | |
| 333 ++presentation->num_frames_presented; | |
| 334 | |
| 335 int64_t seconds = (static_cast<int64_t>(tv_sec_hi) << 32) + tv_sec_lo; | |
| 336 int64_t microseconds = seconds * base::Time::kMicrosecondsPerSecond + | |
| 337 tv_nsec / base::Time::kNanosecondsPerMicrosecond; | |
| 338 base::TimeTicks presentation_time = | |
| 339 base::TimeTicks::FromInternalValue(microseconds); | |
| 340 for (const auto& event_time : frame->event_times) { | |
| 341 presentation->latency_time += presentation_time - event_time; | |
| 342 ++presentation->num_events_presented; | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 void FeedbackDiscarded(void* data, | |
| 347 struct wp_presentation_feedback* presentation_feedback) { | |
| 348 Presentation* presentation = static_cast<Presentation*>(data); | |
| 349 DCHECK_GT(presentation->scheduled_frames.size(), 0u); | |
| 350 std::unique_ptr<Frame> frame = | |
| 351 std::move(presentation->scheduled_frames.front()); | |
| 352 presentation->scheduled_frames.pop_front(); | |
| 353 LOG(WARNING) << "Frame discarded"; | |
| 285 } | 354 } |
| 286 | 355 |
| 287 #if defined(OZONE_PLATFORM_GBM) | 356 #if defined(OZONE_PLATFORM_GBM) |
| 288 void LinuxBufferParamsCreated(void* data, | 357 void LinuxBufferParamsCreated(void* data, |
| 289 zwp_linux_buffer_params_v1* params, | 358 zwp_linux_buffer_params_v1* params, |
| 290 wl_buffer* new_buffer) { | 359 wl_buffer* new_buffer) { |
| 291 Buffer* buffer = static_cast<Buffer*>(data); | 360 Buffer* buffer = static_cast<Buffer*>(data); |
| 292 buffer->buffer.reset(new_buffer); | 361 buffer->buffer.reset(new_buffer); |
| 293 } | 362 } |
| 294 | 363 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 378 wl_display_roundtrip(display_.get()); | 447 wl_display_roundtrip(display_.get()); |
| 379 | 448 |
| 380 if (!globals_.compositor) { | 449 if (!globals_.compositor) { |
| 381 LOG(ERROR) << "Can't find compositor interface"; | 450 LOG(ERROR) << "Can't find compositor interface"; |
| 382 return 1; | 451 return 1; |
| 383 } | 452 } |
| 384 if (!globals_.shm) { | 453 if (!globals_.shm) { |
| 385 LOG(ERROR) << "Can't find shm interface"; | 454 LOG(ERROR) << "Can't find shm interface"; |
| 386 return 1; | 455 return 1; |
| 387 } | 456 } |
| 457 if (!globals_.presentation) { | |
| 458 LOG(ERROR) << "Can't find presentation interface"; | |
| 459 return 1; | |
| 460 } | |
| 388 if (use_drm_ && !globals_.linux_dmabuf) { | 461 if (use_drm_ && !globals_.linux_dmabuf) { |
| 389 LOG(ERROR) << "Can't find linux_dmabuf interface"; | 462 LOG(ERROR) << "Can't find linux_dmabuf interface"; |
| 390 return 1; | 463 return 1; |
| 391 } | 464 } |
| 392 if (!globals_.shell) { | 465 if (!globals_.shell) { |
| 393 LOG(ERROR) << "Can't find shell interface"; | 466 LOG(ERROR) << "Can't find shell interface"; |
| 394 return 1; | 467 return 1; |
| 395 } | 468 } |
| 396 if (!globals_.seat) { | 469 if (!globals_.seat) { |
| 397 LOG(ERROR) << "Can't find seat interface"; | 470 LOG(ERROR) << "Can't find seat interface"; |
| 398 return 1; | 471 return 1; |
| 399 } | 472 } |
| 400 | 473 |
| 401 #if defined(OZONE_PLATFORM_GBM) | 474 #if defined(OZONE_PLATFORM_GBM) |
| 402 EGLenum egl_sync_type = 0; | 475 EGLenum egl_sync_type = 0; |
| 476 sk_sp<const GrGLInterface> native_interface; | |
| 403 if (use_drm_) { | 477 if (use_drm_) { |
| 404 // Number of files to look for when discovering DRM devices. | 478 // Number of files to look for when discovering DRM devices. |
| 405 const uint32_t kDrmMaxMinor = 15; | 479 const uint32_t kDrmMaxMinor = 15; |
| 406 const uint32_t kRenderNodeStart = 128; | 480 const uint32_t kRenderNodeStart = 128; |
| 407 const uint32_t kRenderNodeEnd = kRenderNodeStart + kDrmMaxMinor; | 481 const uint32_t kRenderNodeEnd = kRenderNodeStart + kDrmMaxMinor; |
| 408 | 482 |
| 409 for (uint32_t i = kRenderNodeStart; i < kRenderNodeEnd; i++) { | 483 for (uint32_t i = kRenderNodeStart; i < kRenderNodeEnd; i++) { |
| 410 std::string dri_render_node( | 484 std::string dri_render_node( |
| 411 base::StringPrintf(kDriRenderNodeTemplate, i)); | 485 base::StringPrintf(kDriRenderNodeTemplate, i)); |
| 412 base::ScopedFD drm_fd(open(dri_render_node.c_str(), O_RDWR)); | 486 base::ScopedFD drm_fd(open(dri_render_node.c_str(), O_RDWR)); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 446 make_current_.reset( | 520 make_current_.reset( |
| 447 new ui::ScopedMakeCurrent(gl_context_.get(), gl_surface_.get())); | 521 new ui::ScopedMakeCurrent(gl_context_.get(), gl_surface_.get())); |
| 448 | 522 |
| 449 if (gl::GLSurfaceEGL::HasEGLExtension("EGL_EXT_image_flush_external") || | 523 if (gl::GLSurfaceEGL::HasEGLExtension("EGL_EXT_image_flush_external") || |
| 450 gl::GLSurfaceEGL::HasEGLExtension("EGL_ARM_implicit_external_sync")) { | 524 gl::GLSurfaceEGL::HasEGLExtension("EGL_ARM_implicit_external_sync")) { |
| 451 egl_sync_type = EGL_SYNC_FENCE_KHR; | 525 egl_sync_type = EGL_SYNC_FENCE_KHR; |
| 452 } | 526 } |
| 453 if (gl::GLSurfaceEGL::HasEGLExtension("EGL_ANDROID_native_fence_sync")) { | 527 if (gl::GLSurfaceEGL::HasEGLExtension("EGL_ANDROID_native_fence_sync")) { |
| 454 egl_sync_type = EGL_SYNC_NATIVE_FENCE_ANDROID; | 528 egl_sync_type = EGL_SYNC_NATIVE_FENCE_ANDROID; |
| 455 } | 529 } |
| 530 | |
| 531 native_interface = sk_sp<const GrGLInterface>(GrGLCreateNativeInterface()); | |
| 532 DCHECK(native_interface); | |
| 533 gr_context_ = sk_sp<GrContext>(GrContext::Create( | |
| 534 kOpenGL_GrBackend, | |
| 535 reinterpret_cast<GrBackendContext>(native_interface.get()))); | |
| 536 DCHECK(gr_context_); | |
| 456 } | 537 } |
| 457 | |
| 458 sk_sp<const GrGLInterface> native_interface(GrGLCreateNativeInterface()); | |
| 459 DCHECK(native_interface); | |
| 460 gr_context_ = sk_sp<GrContext>(GrContext::Create( | |
| 461 kOpenGL_GrBackend, | |
| 462 reinterpret_cast<GrBackendContext>(native_interface.get()))); | |
| 463 DCHECK(gr_context_); | |
| 464 #endif | 538 #endif |
| 465 | 539 |
| 466 wl_buffer_listener buffer_listener = {BufferRelease}; | 540 wl_buffer_listener buffer_listener = {BufferRelease}; |
| 467 | 541 |
| 468 for (size_t i = 0; i < kBuffers; ++i) { | 542 for (size_t i = 0; i < kBuffers; ++i) { |
| 469 if (!CreateBuffer(&buffers_[i])) | 543 if (!CreateBuffer(&buffers_[i])) |
| 470 return 1; | 544 return 1; |
| 471 } | 545 } |
| 472 wl_display_roundtrip(display_.get()); | 546 wl_display_roundtrip(display_.get()); |
| 473 for (size_t i = 0; i < kBuffers; ++i) { | 547 for (size_t i = 0; i < kBuffers; ++i) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 532 static_cast<wl_touch*>(wl_seat_get_touch(globals_.seat.get()))); | 606 static_cast<wl_touch*>(wl_seat_get_touch(globals_.seat.get()))); |
| 533 if (!touch) { | 607 if (!touch) { |
| 534 LOG(ERROR) << "Can't get touch"; | 608 LOG(ERROR) << "Can't get touch"; |
| 535 return 1; | 609 return 1; |
| 536 } | 610 } |
| 537 | 611 |
| 538 wl_touch_listener touch_listener = {TouchDown, TouchUp, TouchMotion, | 612 wl_touch_listener touch_listener = {TouchDown, TouchUp, TouchMotion, |
| 539 TouchFrame, TouchCancel}; | 613 TouchFrame, TouchCancel}; |
| 540 wl_touch_add_listener(touch.get(), &touch_listener, &event_times); | 614 wl_touch_add_listener(touch.get(), &touch_listener, &event_times); |
| 541 | 615 |
| 542 Frame frame; | 616 Schedule schedule; |
| 543 std::unique_ptr<wl_callback> frame_callback; | 617 std::unique_ptr<wl_callback> frame_callback; |
| 544 wl_callback_listener frame_listener = {FrameCallback}; | 618 wl_callback_listener frame_listener = {FrameCallback}; |
| 545 std::deque<Buffer*> pending_frames; | |
| 546 | 619 |
| 547 uint32_t frames = 0; | 620 Presentation presentation; |
| 621 std::deque<std::unique_ptr<Frame>> pending_frames; | |
| 622 | |
| 548 size_t num_benchmark_runs_left = num_benchmark_runs_; | 623 size_t num_benchmark_runs_left = num_benchmark_runs_; |
| 549 base::TimeTicks benchmark_time; | 624 base::TimeTicks benchmark_start_time; |
| 550 base::TimeDelta benchmark_wall_time; | |
| 551 base::TimeDelta benchmark_cpu_time; | |
| 552 std::string fps_counter_text("??"); | 625 std::string fps_counter_text("??"); |
| 553 | 626 |
| 627 wp_presentation_feedback_listener feedback_listener = { | |
| 628 FeedbackSyncOutput, FeedbackPresented, FeedbackDiscarded}; | |
| 629 | |
| 554 SkPaint text_paint; | 630 SkPaint text_paint; |
| 555 text_paint.setTextSize(32.0f); | 631 text_paint.setTextSize(32.0f); |
| 556 text_paint.setColor(SK_ColorWHITE); | 632 text_paint.setColor(SK_ColorWHITE); |
| 557 text_paint.setStyle(SkPaint::kFill_Style); | 633 text_paint.setStyle(SkPaint::kFill_Style); |
| 558 | 634 |
| 559 int dispatch_status = 0; | 635 int dispatch_status = 0; |
| 560 do { | 636 do { |
| 561 bool enqueue_frame = frame.callback_pending | 637 bool enqueue_frame = schedule.callback_pending |
| 562 ? pending_frames.size() < max_frames_pending_ | 638 ? pending_frames.size() < max_frames_pending_ |
| 563 : pending_frames.empty(); | 639 : pending_frames.empty(); |
| 564 if (enqueue_frame) { | 640 if (enqueue_frame) { |
| 565 Buffer* buffer = | 641 Buffer* buffer = |
| 566 std::find_if(std::begin(buffers_), std::end(buffers_), | 642 std::find_if(std::begin(buffers_), std::end(buffers_), |
| 567 [](const Buffer& buffer) { return !buffer.busy; }); | 643 [](const Buffer& buffer) { return !buffer.busy; }); |
| 568 if (buffer == std::end(buffers_)) { | 644 if (buffer == std::end(buffers_)) { |
| 569 LOG(ERROR) << "Can't find free buffer"; | 645 LOG(ERROR) << "Can't find free buffer"; |
| 570 return 1; | 646 return 1; |
| 571 } | 647 } |
| 572 | 648 |
| 649 std::unique_ptr<Frame> frame(new Frame); | |
|
Daniele Castagna
2017/01/09 17:01:33
nit: I'd go with auto frame = make_unique
reveman
2017/01/09 17:55:15
Done.
| |
| 650 frame->buffer = buffer; | |
| 651 | |
| 573 base::TimeTicks wall_time_start; | 652 base::TimeTicks wall_time_start; |
| 574 base::ThreadTicks cpu_time_start; | 653 base::ThreadTicks cpu_time_start; |
| 575 if (num_benchmark_runs_ || show_fps_counter_) { | 654 if (num_benchmark_runs_ || show_fps_counter_) { |
| 576 wall_time_start = base::TimeTicks::Now(); | 655 wall_time_start = base::TimeTicks::Now(); |
| 577 if (frames <= kBenchmarkWarmupFrames) | 656 if (presentation.num_frames_presented <= kBenchmarkWarmupFrames) |
| 578 benchmark_time = wall_time_start; | 657 benchmark_start_time = wall_time_start; |
| 579 | 658 |
| 580 if ((wall_time_start - benchmark_time) > benchmark_interval_) { | 659 base::TimeDelta benchmark_time = wall_time_start - benchmark_start_time; |
| 581 uint32_t benchmark_frames = frames - kBenchmarkWarmupFrames; | 660 if (benchmark_time > benchmark_interval_) { |
| 661 uint32_t benchmark_frames = | |
| 662 presentation.num_frames_presented - kBenchmarkWarmupFrames; | |
| 582 if (num_benchmark_runs_left) { | 663 if (num_benchmark_runs_left) { |
| 583 // Print benchmark statistics for the frames produced and exit. | 664 // Print benchmark statistics for the frames presented and exit. |
| 584 // Note: frames produced is not necessarily the same as frames | |
| 585 // displayed. | |
| 586 std::cout << benchmark_frames << '\t' | 665 std::cout << benchmark_frames << '\t' |
| 587 << benchmark_wall_time.InMilliseconds() << '\t' | 666 << benchmark_time.InMilliseconds() << '\t' |
| 588 << benchmark_cpu_time.InMilliseconds() << '\t' | 667 << presentation.wall_time.InMilliseconds() << '\t' |
| 668 << presentation.cpu_time.InMilliseconds() << '\t' | |
| 669 << presentation.num_events_presented << '\t' | |
| 670 << presentation.latency_time.InMilliseconds() << '\t' | |
| 589 << std::endl; | 671 << std::endl; |
| 590 if (!--num_benchmark_runs_left) | 672 if (!--num_benchmark_runs_left) |
| 591 return 0; | 673 return 0; |
| 592 } | 674 } |
| 593 | 675 |
| 594 // Set FPS counter text in case it's being shown. | 676 // Set FPS counter text in case it's being shown. |
| 595 fps_counter_text = base::UintToString( | 677 fps_counter_text = base::UintToString( |
| 596 std::round(benchmark_frames / benchmark_interval_.InSecondsF())); | 678 std::round(benchmark_frames / benchmark_interval_.InSecondsF())); |
| 597 | 679 |
| 598 frames = kBenchmarkWarmupFrames; | 680 benchmark_start_time = wall_time_start; |
| 599 benchmark_time = wall_time_start; | 681 presentation.wall_time = base::TimeDelta(); |
| 600 benchmark_wall_time = base::TimeDelta(); | 682 presentation.cpu_time = base::TimeDelta(); |
| 601 benchmark_cpu_time = base::TimeDelta(); | 683 presentation.latency_time = base::TimeDelta(); |
| 684 presentation.num_frames_presented = kBenchmarkWarmupFrames; | |
| 685 presentation.num_events_presented = 0; | |
| 602 } | 686 } |
| 603 | 687 |
| 604 cpu_time_start = base::ThreadTicks::Now(); | 688 cpu_time_start = base::ThreadTicks::Now(); |
| 605 } | 689 } |
| 606 | 690 |
| 607 SkCanvas* canvas = buffer->sk_surface->getCanvas(); | 691 SkCanvas* canvas = buffer->sk_surface->getCanvas(); |
| 608 if (event_times.empty()) { | 692 if (event_times.empty()) { |
| 609 canvas->clear(SK_ColorBLACK); | 693 canvas->clear(SK_ColorBLACK); |
| 610 } else { | 694 } else { |
| 611 // Split buffer into one horizontal rectangle for each event received | 695 // Split buffer into one horizontal rectangle for each event received |
| 612 // since last frame. Latest event at the top. | 696 // since last frame. Latest event at the top. |
| 613 int y = 0; | 697 int y = 0; |
| 614 // Note: Rounding up to ensure we cover the whole canvas. | 698 // Note: Rounding up to ensure we cover the whole canvas. |
| 615 int h = (height_ + (event_times.size() / 2)) / event_times.size(); | 699 int h = (height_ + (event_times.size() / 2)) / event_times.size(); |
| 616 while (!event_times.empty()) { | 700 while (!event_times.empty()) { |
| 617 SkIRect rect = SkIRect::MakeXYWH(0, y, width_, h); | 701 SkIRect rect = SkIRect::MakeXYWH(0, y, width_, h); |
| 618 SkPaint paint; | 702 SkPaint paint; |
| 619 paint.setColor(SkColorSetRGB((event_times.back() & 0x0000ff) >> 0, | 703 paint.setColor(SkColorSetRGB((event_times.back() & 0x0000ff) >> 0, |
| 620 (event_times.back() & 0x00ff00) >> 8, | 704 (event_times.back() & 0x00ff00) >> 8, |
| 621 (event_times.back() & 0xff0000) >> 16)); | 705 (event_times.back() & 0xff0000) >> 16)); |
| 622 canvas->drawIRect(rect, paint); | 706 canvas->drawIRect(rect, paint); |
| 623 std::string text = base::UintToString(event_times.back()); | 707 std::string text = base::UintToString(event_times.back()); |
| 624 canvas->drawText(text.c_str(), text.length(), 8, y + 32, text_paint); | 708 canvas->drawText(text.c_str(), text.length(), 8, y + 32, text_paint); |
| 709 frame->event_times.push_back(base::TimeTicks::FromInternalValue( | |
| 710 event_times.back() * base::Time::kMicrosecondsPerMillisecond)); | |
| 625 event_times.pop_back(); | 711 event_times.pop_back(); |
| 626 y += h; | 712 y += h; |
| 627 } | 713 } |
| 628 } | 714 } |
| 629 | 715 |
| 630 // Draw rotating rects. | 716 // Draw rotating rects. |
| 631 SkScalar half_width = SkScalarHalf(width_); | 717 SkScalar half_width = SkScalarHalf(width_); |
| 632 SkScalar half_height = SkScalarHalf(height_); | 718 SkScalar half_height = SkScalarHalf(height_); |
| 633 SkIRect rect = SkIRect::MakeXYWH(-SkScalarHalf(half_width), | 719 SkIRect rect = SkIRect::MakeXYWH(-SkScalarHalf(half_width), |
| 634 -SkScalarHalf(half_height), half_width, | 720 -SkScalarHalf(half_height), half_width, |
| 635 half_height); | 721 half_height); |
| 636 SkScalar rotation = SkScalarMulDiv(frame.time, kRotationSpeed, 1000); | 722 SkScalar rotation = SkScalarMulDiv(schedule.time, kRotationSpeed, 1000); |
| 637 canvas->save(); | 723 canvas->save(); |
| 638 canvas->translate(half_width, half_height); | 724 canvas->translate(half_width, half_height); |
| 639 for (size_t i = 0; i < num_rects_; ++i) { | 725 for (size_t i = 0; i < num_rects_; ++i) { |
| 640 const SkColor kColors[] = {SK_ColorBLUE, SK_ColorGREEN, | 726 const SkColor kColors[] = {SK_ColorBLUE, SK_ColorGREEN, |
| 641 SK_ColorRED, SK_ColorYELLOW, | 727 SK_ColorRED, SK_ColorYELLOW, |
| 642 SK_ColorCYAN, SK_ColorMAGENTA}; | 728 SK_ColorCYAN, SK_ColorMAGENTA}; |
| 643 SkPaint paint; | 729 SkPaint paint; |
| 644 paint.setColor(SkColorSetA(kColors[i % arraysize(kColors)], 0xA0)); | 730 paint.setColor(SkColorSetA(kColors[i % arraysize(kColors)], 0xA0)); |
| 645 canvas->rotate(rotation / num_rects_); | 731 canvas->rotate(rotation / num_rects_); |
| 646 canvas->drawIRect(rect, paint); | 732 canvas->drawIRect(rect, paint); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 661 buffer->egl_sync.reset(new ScopedEglSync(eglCreateSyncKHR( | 747 buffer->egl_sync.reset(new ScopedEglSync(eglCreateSyncKHR( |
| 662 eglGetCurrentDisplay(), egl_sync_type, nullptr))); | 748 eglGetCurrentDisplay(), egl_sync_type, nullptr))); |
| 663 DCHECK(buffer->egl_sync->is_valid()); | 749 DCHECK(buffer->egl_sync->is_valid()); |
| 664 } | 750 } |
| 665 #endif | 751 #endif |
| 666 | 752 |
| 667 glFlush(); | 753 glFlush(); |
| 668 } | 754 } |
| 669 | 755 |
| 670 buffer->busy = true; | 756 buffer->busy = true; |
| 671 pending_frames.push_back(buffer); | |
| 672 | 757 |
| 673 if (num_benchmark_runs_ || show_fps_counter_) { | 758 if (num_benchmark_runs_) { |
| 674 ++frames; | 759 frame->wall_time = base::TimeTicks::Now() - wall_time_start; |
| 675 benchmark_wall_time += base::TimeTicks::Now() - wall_time_start; | 760 frame->cpu_time = base::ThreadTicks::Now() - cpu_time_start; |
| 676 benchmark_cpu_time += base::ThreadTicks::Now() - cpu_time_start; | |
| 677 } | 761 } |
| 762 pending_frames.push_back(std::move(frame)); | |
| 678 continue; | 763 continue; |
| 679 } | 764 } |
| 680 | 765 |
| 681 if (!frame.callback_pending) { | 766 if (!schedule.callback_pending) { |
| 682 DCHECK_GT(pending_frames.size(), 0u); | 767 DCHECK_GT(pending_frames.size(), 0u); |
| 683 Buffer* buffer = pending_frames.front(); | 768 std::unique_ptr<Frame> frame = std::move(pending_frames.front()); |
| 684 pending_frames.pop_front(); | 769 pending_frames.pop_front(); |
| 685 | 770 |
| 686 wl_surface_set_buffer_scale(surface.get(), scale_); | 771 wl_surface_set_buffer_scale(surface.get(), scale_); |
| 687 wl_surface_damage(surface.get(), 0, 0, width_ / scale_, height_ / scale_); | 772 wl_surface_damage(surface.get(), 0, 0, width_ / scale_, height_ / scale_); |
| 688 wl_surface_attach(surface.get(), buffer->buffer.get(), 0, 0); | 773 wl_surface_attach(surface.get(), frame->buffer->buffer.get(), 0, 0); |
| 689 | 774 |
| 690 #if defined(OZONE_PLATFORM_GBM) | 775 #if defined(OZONE_PLATFORM_GBM) |
| 691 if (buffer->egl_sync) { | 776 if (frame->buffer->egl_sync) { |
| 692 eglClientWaitSyncKHR(eglGetCurrentDisplay(), buffer->egl_sync->get(), | 777 eglClientWaitSyncKHR(eglGetCurrentDisplay(), |
| 778 frame->buffer->egl_sync->get(), | |
| 693 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); | 779 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); |
| 694 } | 780 } |
| 695 #endif | 781 #endif |
| 696 | 782 |
| 697 frame_callback.reset(wl_surface_frame(surface.get())); | 783 frame_callback.reset(wl_surface_frame(surface.get())); |
| 698 wl_callback_add_listener(frame_callback.get(), &frame_listener, &frame); | 784 wl_callback_add_listener(frame_callback.get(), &frame_listener, |
| 699 frame.callback_pending = true; | 785 &schedule); |
| 786 schedule.callback_pending = true; | |
| 787 | |
| 788 frame->feedback.reset( | |
| 789 wp_presentation_feedback(globals_.presentation.get(), surface.get())); | |
| 790 wp_presentation_feedback_add_listener(frame->feedback.get(), | |
| 791 &feedback_listener, &presentation); | |
| 792 presentation.scheduled_frames.push_back(std::move(frame)); | |
| 793 | |
| 700 wl_surface_commit(surface.get()); | 794 wl_surface_commit(surface.get()); |
| 701 wl_display_flush(display_.get()); | 795 wl_display_flush(display_.get()); |
| 702 continue; | 796 continue; |
| 703 } | 797 } |
| 704 | 798 |
| 705 dispatch_status = wl_display_dispatch(display_.get()); | 799 dispatch_status = wl_display_dispatch(display_.get()); |
| 706 } while (dispatch_status != -1); | 800 } while (dispatch_status != -1); |
| 707 | 801 |
| 708 return 0; | 802 return 0; |
| 709 } | 803 } |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 899 new std::string(command_line->GetSwitchValueASCII(switches::kUseDrm))); | 993 new std::string(command_line->GetSwitchValueASCII(switches::kUseDrm))); |
| 900 } | 994 } |
| 901 | 995 |
| 902 exo::wayland::clients::MotionEvents client( | 996 exo::wayland::clients::MotionEvents client( |
| 903 width, height, scale, num_rects, max_frames_pending, | 997 width, height, scale, num_rects, max_frames_pending, |
| 904 command_line->HasSwitch(switches::kFullscreen), | 998 command_line->HasSwitch(switches::kFullscreen), |
| 905 command_line->HasSwitch(switches::kShowFpsCounter), num_benchmark_runs, | 999 command_line->HasSwitch(switches::kShowFpsCounter), num_benchmark_runs, |
| 906 base::TimeDelta::FromMilliseconds(benchmark_interval_ms), use_drm.get()); | 1000 base::TimeDelta::FromMilliseconds(benchmark_interval_ms), use_drm.get()); |
| 907 return client.Run(); | 1001 return client.Run(); |
| 908 } | 1002 } |
| OLD | NEW |