x11_xrandr_interval_only_vsync_provider.cc 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/base/x/x11_xrandr_interval_only_vsync_provider.h"
  5. #include "base/bind.h"
  6. #include "base/no_destructor.h"
  7. #include "base/threading/thread_task_runner_handle.h"
  8. #include "ui/base/x/x11_display_util.h"
  9. #include "ui/gfx/x/connection.h"
  10. #include "ui/gfx/x/event.h"
  11. #include "ui/gfx/x/future.h"
  12. #include "ui/gfx/x/randr.h"
  13. namespace ui {
  14. namespace {
  15. bool IsXrandrAvailable() {
  16. constexpr int kMinXrandrVersion = 103; // Need at least xrandr version 1.3
  17. return GetXrandrVersion() >= kMinXrandrVersion;
  18. }
  19. class XRandrHelper : public x11::EventObserver {
  20. public:
  21. XRandrHelper() {
  22. DCHECK(IsXrandrAvailable());
  23. auto* connection = x11::Connection::Get();
  24. auto root_window = connection->default_screen().root;
  25. auto& randr = connection->randr();
  26. auto randr_event_mask = x11::RandR::NotifyMask::OutputChange;
  27. randr.SelectInput({root_window, randr_event_mask});
  28. connection->AddEventObserver(this);
  29. }
  30. ~XRandrHelper() override {
  31. auto* connection = x11::Connection::Get();
  32. connection->RemoveEventObserver(this);
  33. }
  34. // x11::EventObserver:
  35. void OnEvent(const x11::Event& xevent) override {
  36. if (xevent.As<x11::RandR::NotifyEvent>()) {
  37. interval_ = {};
  38. }
  39. }
  40. static base::TimeDelta GetInterval() {
  41. if (IsXrandrAvailable()) {
  42. static base::NoDestructor<XRandrHelper> helper;
  43. return helper->GetIntervalInternal();
  44. }
  45. constexpr auto kDefaultInterval = base::Seconds(1) / 60;
  46. return kDefaultInterval;
  47. }
  48. private:
  49. base::TimeDelta GetIntervalInternal() {
  50. if (interval_.is_zero()) {
  51. interval_ = GetPrimaryDisplayRefreshIntervalFromXrandr();
  52. }
  53. return interval_;
  54. }
  55. base::TimeDelta interval_;
  56. };
  57. } // namespace
  58. XrandrIntervalOnlyVSyncProvider::XrandrIntervalOnlyVSyncProvider() = default;
  59. XrandrIntervalOnlyVSyncProvider::~XrandrIntervalOnlyVSyncProvider() = default;
  60. void XrandrIntervalOnlyVSyncProvider::GetVSyncParameters(
  61. UpdateVSyncCallback callback) {
  62. base::ThreadTaskRunnerHandle::Get()->PostTask(
  63. FROM_HERE, base::BindOnce(std::move(callback), base::TimeTicks(),
  64. XRandrHelper::GetInterval()));
  65. }
  66. bool XrandrIntervalOnlyVSyncProvider::GetVSyncParametersIfAvailable(
  67. base::TimeTicks* timebase,
  68. base::TimeDelta* interval) {
  69. *interval = XRandrHelper::GetInterval();
  70. return true;
  71. }
  72. bool XrandrIntervalOnlyVSyncProvider::SupportGetVSyncParametersIfAvailable()
  73. const {
  74. return true;
  75. }
  76. bool XrandrIntervalOnlyVSyncProvider::IsHWClock() const {
  77. return false;
  78. }
  79. } // namespace ui