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 <wayland-client-core.h> | 11 #include <wayland-client-core.h> |
| 12 #include <wayland-client-protocol.h> | 12 #include <wayland-client-protocol.h> |
| 13 | 13 |
| 14 #include <deque> | |
| 14 #include <iostream> | 15 #include <iostream> |
| 15 #include <vector> | 16 #include <vector> |
| 16 | 17 |
| 17 #include "base/at_exit.h" | 18 #include "base/at_exit.h" |
| 18 #include "base/command_line.h" | 19 #include "base/command_line.h" |
| 19 #include "base/logging.h" | 20 #include "base/logging.h" |
| 20 #include "base/macros.h" | 21 #include "base/macros.h" |
| 21 #include "base/memory/shared_memory.h" | 22 #include "base/memory/shared_memory.h" |
| 22 #include "base/scoped_generic.h" | 23 #include "base/scoped_generic.h" |
| 23 #include "base/strings/string_number_conversions.h" | 24 #include "base/strings/string_number_conversions.h" |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 const int32_t kDrmFormat = DRM_FORMAT_ABGR8888; | 89 const int32_t kDrmFormat = DRM_FORMAT_ABGR8888; |
| 89 #endif | 90 #endif |
| 90 const size_t kBytesPerPixel = 4; | 91 const size_t kBytesPerPixel = 4; |
| 91 | 92 |
| 92 #if defined(OZONE_PLATFORM_GBM) | 93 #if defined(OZONE_PLATFORM_GBM) |
| 93 // DRI render node path. | 94 // DRI render node path. |
| 94 const char kDriRenderNode[] = "/dev/dri/renderD128"; | 95 const char kDriRenderNode[] = "/dev/dri/renderD128"; |
| 95 #endif | 96 #endif |
| 96 | 97 |
| 97 // Number of buffers. | 98 // Number of buffers. |
| 98 const size_t kBuffers = 3; | 99 const size_t kBuffers = 5; |
| 99 | 100 |
| 100 // Rotation speed (degrees/second). | 101 // Rotation speed (degrees/second). |
| 101 const double kRotationSpeed = 360.0; | 102 const double kRotationSpeed = 360.0; |
| 102 | 103 |
| 103 // Benchmark interval in seconds. | 104 // Benchmark interval in seconds. |
| 104 const int kBenchmarkInterval = 5; | 105 const int kBenchmarkInterval = 5; |
| 105 | 106 |
| 106 struct Globals { | 107 struct Globals { |
| 107 std::unique_ptr<wl_compositor> compositor; | 108 std::unique_ptr<wl_compositor> compositor; |
| 108 std::unique_ptr<wl_shm> shm; | 109 std::unique_ptr<wl_shm> shm; |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 #endif | 291 #endif |
| 291 | 292 |
| 292 } // namespace | 293 } // namespace |
| 293 | 294 |
| 294 class MotionEvents { | 295 class MotionEvents { |
| 295 public: | 296 public: |
| 296 MotionEvents(size_t width, | 297 MotionEvents(size_t width, |
| 297 size_t height, | 298 size_t height, |
| 298 int scale, | 299 int scale, |
| 299 size_t num_rects, | 300 size_t num_rects, |
| 300 bool use_drm, | 301 size_t max_frames_pending, |
| 301 bool fullscreen) | 302 bool fullscreen, |
| 303 bool use_drm) | |
| 302 : width_(width), | 304 : width_(width), |
| 303 height_(height), | 305 height_(height), |
| 304 scale_(scale), | 306 scale_(scale), |
| 305 num_rects_(num_rects), | 307 num_rects_(num_rects), |
| 306 use_drm_(use_drm), | 308 max_frames_pending_(max_frames_pending), |
| 307 fullscreen_(fullscreen) {} | 309 fullscreen_(fullscreen), |
| 310 use_drm_(use_drm) {} | |
| 308 | 311 |
| 309 // Initialize and run client main loop. | 312 // Initialize and run client main loop. |
| 310 int Run(); | 313 int Run(); |
| 311 | 314 |
| 312 private: | 315 private: |
| 313 bool CreateBuffer(Buffer* buffer); | 316 bool CreateBuffer(Buffer* buffer); |
| 314 size_t stride() const { return width_ * kBytesPerPixel; } | 317 size_t stride() const { return width_ * kBytesPerPixel; } |
| 315 size_t buffer_size() const { return stride() * height_; } | 318 size_t buffer_size() const { return stride() * height_; } |
| 316 | 319 |
| 317 const size_t width_; | 320 const size_t width_; |
| 318 const size_t height_; | 321 const size_t height_; |
| 319 const int scale_; | 322 const int scale_; |
| 320 const size_t num_rects_; | 323 const size_t num_rects_; |
| 324 const size_t max_frames_pending_; | |
| 325 const bool fullscreen_; | |
| 321 const bool use_drm_; | 326 const bool use_drm_; |
| 322 const bool fullscreen_; | |
| 323 | 327 |
| 324 Globals globals_; | 328 Globals globals_; |
| 325 std::unique_ptr<wl_display> display_; | 329 std::unique_ptr<wl_display> display_; |
| 326 | 330 |
| 327 #if defined(OZONE_PLATFORM_GBM) | 331 #if defined(OZONE_PLATFORM_GBM) |
| 328 base::ScopedFD drm_fd_; | 332 base::ScopedFD drm_fd_; |
| 329 std::unique_ptr<gbm_device> device_; | 333 std::unique_ptr<gbm_device> device_; |
| 330 #endif | 334 #endif |
| 331 | 335 |
| 332 scoped_refptr<gl::GLSurface> gl_surface_; | 336 scoped_refptr<gl::GLSurface> gl_surface_; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 475 return 1; | 479 return 1; |
| 476 } | 480 } |
| 477 | 481 |
| 478 wl_touch_listener touch_listener = {TouchDown, TouchUp, TouchMotion, | 482 wl_touch_listener touch_listener = {TouchDown, TouchUp, TouchMotion, |
| 479 TouchFrame, TouchCancel}; | 483 TouchFrame, TouchCancel}; |
| 480 wl_touch_add_listener(touch.get(), &touch_listener, &event_times); | 484 wl_touch_add_listener(touch.get(), &touch_listener, &event_times); |
| 481 | 485 |
| 482 Frame frame; | 486 Frame frame; |
| 483 std::unique_ptr<wl_callback> frame_callback; | 487 std::unique_ptr<wl_callback> frame_callback; |
| 484 wl_callback_listener frame_listener = {FrameCallback}; | 488 wl_callback_listener frame_listener = {FrameCallback}; |
| 489 std::deque<wl_buffer*> pending_frames; | |
| 485 | 490 |
| 486 uint32_t frames = 0; | 491 uint32_t frames = 0; |
| 492 base::TimeDelta frames_time; | |
| 487 base::TimeTicks benchmark_time = base::TimeTicks::Now(); | 493 base::TimeTicks benchmark_time = base::TimeTicks::Now(); |
| 488 base::TimeDelta benchmark_interval = | 494 base::TimeDelta benchmark_interval = |
| 489 base::TimeDelta::FromSeconds(kBenchmarkInterval); | 495 base::TimeDelta::FromSeconds(kBenchmarkInterval); |
| 490 | 496 |
| 497 int dispatch_status = 0; | |
| 491 do { | 498 do { |
| 492 if (frame.callback_pending) | 499 size_t max_frames_pending = max_frames_pending_; |
| 500 if (!frame.callback_pending) | |
| 501 ++max_frames_pending; | |
| 502 | |
| 503 if (pending_frames.size() < max_frames_pending) { | |
| 504 Buffer* buffer = | |
|
Daniele Castagna
2016/11/10 03:32:26
As discussed offline, we can create an helper func
| |
| 505 std::find_if(std::begin(buffers_), std::end(buffers_), | |
| 506 [](const Buffer& buffer) { return !buffer.busy; }); | |
| 507 if (buffer == std::end(buffers_)) { | |
| 508 LOG(WARNING) << "Can't find free buffer"; | |
| 509 return 1; | |
| 510 } | |
| 511 | |
| 512 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
| |
| 513 if ((current_time - benchmark_time) > benchmark_interval) { | |
| 514 std::cout << frames << " frames in " << benchmark_interval.InSeconds() | |
| 515 << " seconds: " | |
| 516 << static_cast<double>(frames) / | |
| 517 benchmark_interval.InSeconds() | |
| 518 << " fps (" | |
| 519 << frames_time.InMilliseconds() / static_cast<double>(frames) | |
| 520 << " ms/frame) " | |
| 521 << std::count_if( | |
| 522 std::begin(buffers_), std::end(buffers_), | |
| 523 [](const Buffer& buffer) { return buffer.busy; }) | |
| 524 << std::endl; | |
| 525 benchmark_time = current_time; | |
| 526 frames = 0; | |
| 527 frames_time = base::TimeDelta(); | |
| 528 } | |
| 529 | |
| 530 SkCanvas* canvas = buffer->sk_surface->getCanvas(); | |
| 531 canvas->save(); | |
| 532 | |
| 533 if (event_times.empty()) { | |
| 534 canvas->clear(SK_ColorBLACK); | |
| 535 } else { | |
| 536 // Split buffer into one horizontal rectangle for each event received | |
| 537 // since last frame. Latest event at the top. | |
| 538 int y = 0; | |
| 539 // Note: Rounding up to ensure we cover the whole canvas. | |
| 540 int h = (height_ + (event_times.size() / 2)) / event_times.size(); | |
| 541 while (!event_times.empty()) { | |
| 542 SkIRect rect = SkIRect::MakeXYWH(0, y, width_, h); | |
| 543 SkPaint paint; | |
| 544 paint.setColor(SkColorSetRGB((event_times.back() & 0x0000ff) >> 0, | |
| 545 (event_times.back() & 0x00ff00) >> 8, | |
| 546 (event_times.back() & 0xff0000) >> 16)); | |
| 547 canvas->drawIRect(rect, paint); | |
| 548 event_times.pop_back(); | |
| 549 y += h; | |
| 550 } | |
| 551 } | |
| 552 | |
| 553 // Draw rotating rects. | |
| 554 SkScalar half_width = SkScalarHalf(width_); | |
| 555 SkScalar half_height = SkScalarHalf(height_); | |
| 556 SkIRect rect = SkIRect::MakeXYWH(-SkScalarHalf(half_width), | |
| 557 -SkScalarHalf(half_height), half_width, | |
| 558 half_height); | |
| 559 SkScalar rotation = SkScalarMulDiv(frame.time, kRotationSpeed, 1000); | |
| 560 SkPaint paint; | |
| 561 canvas->translate(half_width, half_height); | |
| 562 for (size_t i = 0; i < num_rects_; ++i) { | |
| 563 const SkColor kColors[] = {SK_ColorBLUE, SK_ColorGREEN, | |
| 564 SK_ColorRED, SK_ColorYELLOW, | |
| 565 SK_ColorCYAN, SK_ColorMAGENTA}; | |
| 566 paint.setColor(SkColorSetA(kColors[i % arraysize(kColors)], 0xA0)); | |
| 567 canvas->rotate(rotation / num_rects_); | |
| 568 canvas->drawIRect(rect, paint); | |
| 569 } | |
| 570 | |
| 571 canvas->restore(); | |
| 572 if (gr_context_) { | |
| 573 gr_context_->flush(); | |
| 574 glFinish(); | |
| 575 } | |
| 576 | |
| 577 buffer->busy = true; | |
| 578 pending_frames.push_back(buffer->buffer.get()); | |
| 579 ++frames; | |
| 580 frames_time += base::TimeTicks::Now() - current_time; | |
| 493 continue; | 581 continue; |
| 494 | |
| 495 Buffer* buffer = | |
| 496 std::find_if(std::begin(buffers_), std::end(buffers_), | |
| 497 [](const Buffer& buffer) { return !buffer.busy; }); | |
| 498 if (buffer == std::end(buffers_)) | |
| 499 continue; | |
| 500 | |
| 501 base::TimeTicks current_time = base::TimeTicks::Now(); | |
| 502 if ((current_time - benchmark_time) > benchmark_interval) { | |
| 503 std::cout << frames << " frames in " << benchmark_interval.InSeconds() | |
| 504 << " seconds: " | |
| 505 << static_cast<double>(frames) / benchmark_interval.InSeconds() | |
| 506 << " fps" << std::endl; | |
| 507 benchmark_time = current_time; | |
| 508 frames = 0; | |
| 509 } | 582 } |
| 510 | 583 |
| 511 SkCanvas* canvas = buffer->sk_surface->getCanvas(); | 584 if (!frame.callback_pending) { |
| 512 canvas->save(); | 585 DCHECK_GT(pending_frames.size(), 0u); |
| 586 wl_surface_set_buffer_scale(surface.get(), scale_); | |
| 587 wl_surface_attach(surface.get(), pending_frames.front(), 0, 0); | |
| 588 pending_frames.pop_front(); | |
| 513 | 589 |
| 514 if (event_times.empty()) { | 590 frame_callback.reset(wl_surface_frame(surface.get())); |
| 515 canvas->clear(SK_ColorBLACK); | 591 wl_callback_add_listener(frame_callback.get(), &frame_listener, &frame); |
| 516 } else { | 592 frame.callback_pending = true; |
| 517 // Split buffer into one horizontal rectangle for each event received | 593 wl_surface_commit(surface.get()); |
| 518 // since last frame. Latest event at the top. | 594 wl_display_flush(display_.get()); |
| 519 int y = 0; | 595 continue; |
| 520 // Note: Rounding up to ensure we cover the whole canvas. | |
| 521 int h = (height_ + (event_times.size() / 2)) / event_times.size(); | |
| 522 while (!event_times.empty()) { | |
| 523 SkIRect rect = SkIRect::MakeXYWH(0, y, width_, h); | |
| 524 SkPaint paint; | |
| 525 paint.setColor(SkColorSetRGB((event_times.back() & 0x0000ff) >> 0, | |
| 526 (event_times.back() & 0x00ff00) >> 8, | |
| 527 (event_times.back() & 0xff0000) >> 16)); | |
| 528 canvas->drawIRect(rect, paint); | |
| 529 event_times.pop_back(); | |
| 530 y += h; | |
| 531 } | |
| 532 } | 596 } |
| 533 | 597 |
| 534 // Draw rotating rects. | 598 dispatch_status = wl_display_dispatch(display_.get()); |
| 535 SkScalar half_width = SkScalarHalf(width_); | 599 } while (dispatch_status != -1); |
| 536 SkScalar half_height = SkScalarHalf(height_); | |
| 537 SkIRect rect = | |
| 538 SkIRect::MakeXYWH(-SkScalarHalf(half_width), -SkScalarHalf(half_height), | |
| 539 half_width, half_height); | |
| 540 SkScalar rotation = SkScalarMulDiv(frame.time, kRotationSpeed, 1000); | |
| 541 SkPaint paint; | |
| 542 canvas->translate(half_width, half_height); | |
| 543 for (size_t i = 0; i < num_rects_; ++i) { | |
| 544 const SkColor kColors[] = {SK_ColorBLUE, SK_ColorGREEN, | |
| 545 SK_ColorRED, SK_ColorYELLOW, | |
| 546 SK_ColorCYAN, SK_ColorMAGENTA}; | |
| 547 paint.setColor(SkColorSetA(kColors[i % arraysize(kColors)], 0xA0)); | |
| 548 canvas->rotate(rotation / num_rects_); | |
| 549 canvas->drawIRect(rect, paint); | |
| 550 } | |
| 551 canvas->restore(); | |
| 552 if (gr_context_) { | |
| 553 gr_context_->flush(); | |
| 554 glFinish(); | |
| 555 } | |
| 556 wl_surface_set_buffer_scale(surface.get(), scale_); | |
| 557 wl_surface_attach(surface.get(), buffer->buffer.get(), 0, 0); | |
| 558 buffer->busy = true; | |
| 559 | |
| 560 frame_callback.reset(wl_surface_frame(surface.get())); | |
| 561 wl_callback_add_listener(frame_callback.get(), &frame_listener, &frame); | |
| 562 frame.callback_pending = true; | |
| 563 | |
| 564 ++frames; | |
| 565 | |
| 566 wl_surface_commit(surface.get()); | |
| 567 } while (wl_display_dispatch(display_.get()) != -1); | |
| 568 | 600 |
| 569 return 0; | 601 return 0; |
| 570 } | 602 } |
| 571 | 603 |
| 572 bool MotionEvents::CreateBuffer(Buffer* buffer) { | 604 bool MotionEvents::CreateBuffer(Buffer* buffer) { |
| 573 #if defined(OZONE_PLATFORM_GBM) | 605 #if defined(OZONE_PLATFORM_GBM) |
| 574 if (use_drm_) { | 606 if (use_drm_) { |
| 575 buffer->bo.reset(gbm_bo_create(device_.get(), width_, height_, kDrmFormat, | 607 buffer->bo.reset(gbm_bo_create(device_.get(), width_, height_, kDrmFormat, |
| 576 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING)); | 608 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING)); |
| 577 if (!buffer->bo) { | 609 if (!buffer->bo) { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 661 | 693 |
| 662 // Specifies the client buffer size. | 694 // Specifies the client buffer size. |
| 663 const char kSize[] = "size"; | 695 const char kSize[] = "size"; |
| 664 | 696 |
| 665 // Specifies the client scale factor (ie. number of physical pixels per DIP). | 697 // Specifies the client scale factor (ie. number of physical pixels per DIP). |
| 666 const char kScale[] = "scale"; | 698 const char kScale[] = "scale"; |
| 667 | 699 |
| 668 // Specifies the number of rotating rects to draw. | 700 // Specifies the number of rotating rects to draw. |
| 669 const char kNumRects[] = "num-rects"; | 701 const char kNumRects[] = "num-rects"; |
| 670 | 702 |
| 703 // Specifies the maximum number of pending frames. | |
| 704 const char kMaxFramesPending[] = "max-frames-pending"; | |
| 705 | |
| 706 // Specifies if client should be fullscreen. | |
| 707 const char kFullscreen[] = "fullscreen"; | |
| 708 | |
| 671 // Use drm buffer instead of shared memory. | 709 // Use drm buffer instead of shared memory. |
| 672 const char kUseDrm[] = "use-drm"; | 710 const char kUseDrm[] = "use-drm"; |
| 673 | 711 |
| 674 // Specifies if client should be fullscreen. | |
| 675 const char kFullscreen[] = "fullscreen"; | |
| 676 | |
| 677 } // namespace switches | 712 } // namespace switches |
| 678 | 713 |
| 679 int main(int argc, char* argv[]) { | 714 int main(int argc, char* argv[]) { |
| 680 base::AtExitManager exit_manager; | 715 base::AtExitManager exit_manager; |
| 681 base::CommandLine::Init(argc, argv); | 716 base::CommandLine::Init(argc, argv); |
| 682 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 717 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| 683 | 718 |
| 684 int width = 256; | 719 int width = 256; |
| 685 int height = 256; | 720 int height = 256; |
| 686 if (command_line->HasSwitch(switches::kSize)) { | 721 if (command_line->HasSwitch(switches::kSize)) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 700 } | 735 } |
| 701 | 736 |
| 702 size_t num_rects = 1; | 737 size_t num_rects = 1; |
| 703 if (command_line->HasSwitch(switches::kNumRects) && | 738 if (command_line->HasSwitch(switches::kNumRects) && |
| 704 !base::StringToSizeT( | 739 !base::StringToSizeT( |
| 705 command_line->GetSwitchValueASCII(switches::kNumRects), &num_rects)) { | 740 command_line->GetSwitchValueASCII(switches::kNumRects), &num_rects)) { |
| 706 LOG(ERROR) << "Invalid value for " << switches::kNumRects; | 741 LOG(ERROR) << "Invalid value for " << switches::kNumRects; |
| 707 return 1; | 742 return 1; |
| 708 } | 743 } |
| 709 | 744 |
| 710 bool use_drm = command_line->HasSwitch(switches::kUseDrm); | 745 size_t max_frames_pending = 0; |
| 711 bool fullscreen = command_line->HasSwitch(switches::kFullscreen); | 746 if (command_line->HasSwitch(switches::kMaxFramesPending) && |
| 747 (!base::StringToSizeT( | |
| 748 command_line->GetSwitchValueASCII(switches::kMaxFramesPending), | |
| 749 &max_frames_pending))) { | |
| 750 LOG(ERROR) << "Invalid value for " << switches::kMaxFramesPending; | |
| 751 return 1; | |
| 752 } | |
| 712 | 753 |
| 713 exo::wayland::clients::MotionEvents client(width, height, scale, num_rects, | 754 exo::wayland::clients::MotionEvents client( |
| 714 use_drm, fullscreen); | 755 width, height, scale, num_rects, max_frames_pending, |
| 756 command_line->HasSwitch(switches::kFullscreen), | |
| 757 command_line->HasSwitch(switches::kUseDrm)); | |
| 715 return client.Run(); | 758 return client.Run(); |
| 716 } | 759 } |
| OLD | NEW |