summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorccameron <ccameron@chromium.org>2015-06-08 15:07:57 -0700
committerCommit bot <commit-bot@chromium.org>2015-06-08 22:09:29 +0000
commit9913d64654735b8c947495d6ead02edf3d6071e2 (patch)
treee6799b7f7cc4b734a641fd317f53b7c013d55a21 /ui
parent39c5af24ab4e14ece3d7c97b7c4d027151ede176 (diff)
downloadchromium_src-9913d64654735b8c947495d6ead02edf3d6071e2.zip
chromium_src-9913d64654735b8c947495d6ead02edf3d6071e2.tar.gz
chromium_src-9913d64654735b8c947495d6ead02edf3d6071e2.tar.bz2
Mac: Move DisplayLinkMac from content to ui
This logically belongs in ui::, because Mac views will need to be synced to their display as well. There is a bit of ugliness in this change in that the task runner for display-link callbacks is provided as an argument to creation. It will be moved to be an argument to a function to add callbacks in an upcoming patch. BUG=496484 Review URL: https://codereview.chromium.org/1163353002 Cr-Commit-Position: refs/heads/master@{#333357}
Diffstat (limited to 'ui')
-rw-r--r--ui/accelerated_widget_mac/BUILD.gn2
-rw-r--r--ui/accelerated_widget_mac/accelerated_widget_mac.gyp6
-rw-r--r--ui/accelerated_widget_mac/display_link_mac.cc185
-rw-r--r--ui/accelerated_widget_mac/display_link_mac.h85
4 files changed, 276 insertions, 2 deletions
diff --git a/ui/accelerated_widget_mac/BUILD.gn b/ui/accelerated_widget_mac/BUILD.gn
index 0c066dd..2ca4299 100644
--- a/ui/accelerated_widget_mac/BUILD.gn
+++ b/ui/accelerated_widget_mac/BUILD.gn
@@ -8,6 +8,8 @@ component("accelerated_widget_mac") {
"accelerated_widget_mac.h",
"accelerated_widget_mac.mm",
"accelerated_widget_mac_export.h",
+ "display_link_mac.cc",
+ "display_link_mac.h",
"io_surface_context.h",
"io_surface_context.mm",
"io_surface_layer.h",
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.gyp b/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
index d46b2e629..2e13b11 100644
--- a/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
+++ b/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
@@ -15,12 +15,14 @@
'accelerated_widget_mac.h',
'accelerated_widget_mac.mm',
'accelerated_widget_mac_export.h',
+ 'display_link_mac.cc',
+ 'display_link_mac.h',
'io_surface_context.h',
'io_surface_context.mm',
'io_surface_layer.h',
'io_surface_layer.mm',
- "io_surface_ns_gl_surface.h",
- "io_surface_ns_gl_surface.mm",
+ 'io_surface_ns_gl_surface.h',
+ 'io_surface_ns_gl_surface.mm',
'io_surface_texture.h',
'io_surface_texture.mm',
'software_layer.h',
diff --git a/ui/accelerated_widget_mac/display_link_mac.cc b/ui/accelerated_widget_mac/display_link_mac.cc
new file mode 100644
index 0000000..94aa454
--- /dev/null
+++ b/ui/accelerated_widget_mac/display_link_mac.cc
@@ -0,0 +1,185 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/accelerated_widget_mac/display_link_mac.h"
+
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+
+template<>
+struct ScopedTypeRefTraits<CVDisplayLinkRef> {
+ static void Retain(CVDisplayLinkRef object) {
+ CVDisplayLinkRetain(object);
+ }
+ static void Release(CVDisplayLinkRef object) {
+ CVDisplayLinkRelease(object);
+ }
+};
+
+} // namespace base
+
+namespace ui {
+
+// static
+scoped_refptr<DisplayLinkMac> DisplayLinkMac::GetForDisplay(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
+ CGDirectDisplayID display_id) {
+ // Return the existing display link for this display, if it exists.
+ DisplayMap::iterator found = display_map_.Get().find(display_id);
+ if (found != display_map_.Get().end()) {
+ return found->second;
+ }
+
+ CVReturn ret = kCVReturnSuccess;
+
+ base::ScopedTypeRef<CVDisplayLinkRef> display_link;
+ ret = CVDisplayLinkCreateWithCGDisplay(
+ display_id,
+ display_link.InitializeInto());
+ if (ret != kCVReturnSuccess) {
+ LOG(ERROR) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret;
+ return NULL;
+ }
+
+ scoped_refptr<DisplayLinkMac> display_link_mac;
+ display_link_mac = new DisplayLinkMac(
+ main_thread_task_runner, display_id, display_link);
+ ret = CVDisplayLinkSetOutputCallback(
+ display_link_mac->display_link_,
+ &DisplayLinkCallback,
+ display_link_mac.get());
+ if (ret != kCVReturnSuccess) {
+ LOG(ERROR) << "CVDisplayLinkSetOutputCallback failed: " << ret;
+ return NULL;
+ }
+
+ return display_link_mac;
+}
+
+DisplayLinkMac::DisplayLinkMac(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
+ CGDirectDisplayID display_id,
+ base::ScopedTypeRef<CVDisplayLinkRef> display_link)
+ : main_thread_task_runner_(main_thread_task_runner),
+ display_id_(display_id),
+ display_link_(display_link),
+ timebase_and_interval_valid_(false) {
+ DCHECK(display_map_.Get().find(display_id) == display_map_.Get().end());
+ if (display_map_.Get().empty()) {
+ CGError register_error = CGDisplayRegisterReconfigurationCallback(
+ DisplayReconfigurationCallBack, nullptr);
+ DPLOG_IF(ERROR, register_error != kCGErrorSuccess)
+ << "CGDisplayRegisterReconfigurationCallback: "
+ << register_error;
+ }
+ display_map_.Get().insert(std::make_pair(display_id_, this));
+}
+
+DisplayLinkMac::~DisplayLinkMac() {
+ StopDisplayLink();
+
+ DisplayMap::iterator found = display_map_.Get().find(display_id_);
+ DCHECK(found != display_map_.Get().end());
+ DCHECK(found->second == this);
+ display_map_.Get().erase(found);
+ if (display_map_.Get().empty()) {
+ CGError remove_error = CGDisplayRemoveReconfigurationCallback(
+ DisplayReconfigurationCallBack, nullptr);
+ DPLOG_IF(ERROR, remove_error != kCGErrorSuccess)
+ << "CGDisplayRemoveReconfigurationCallback: "
+ << remove_error;
+ }
+}
+
+bool DisplayLinkMac::GetVSyncParameters(
+ base::TimeTicks* timebase, base::TimeDelta* interval) {
+ if (!timebase_and_interval_valid_) {
+ StartOrContinueDisplayLink();
+ return false;
+ }
+
+ *timebase = timebase_;
+ *interval = interval_;
+ return true;
+}
+
+void DisplayLinkMac::Tick(const CVTimeStamp& cv_time) {
+ TRACE_EVENT0("ui", "DisplayLinkMac::Tick");
+
+ // Verify that videoRefreshPeriod is 32 bits.
+ DCHECK((cv_time.videoRefreshPeriod & ~0xffffFFFFull) == 0ull);
+
+ // Verify that the numerator and denominator make some sense.
+ uint32 numerator = static_cast<uint32>(cv_time.videoRefreshPeriod);
+ uint32 denominator = cv_time.videoTimeScale;
+ if (numerator <= 0 || denominator <= 0) {
+ LOG(WARNING) << "Unexpected numerator or denominator, bailing.";
+ return;
+ }
+
+ timebase_ = base::TimeTicks::FromInternalValue(
+ cv_time.hostTime / 1000);
+ interval_ = base::TimeDelta::FromMicroseconds(
+ 1000000 * static_cast<int64>(numerator) / denominator);
+ timebase_and_interval_valid_ = true;
+
+ StopDisplayLink();
+}
+
+void DisplayLinkMac::StartOrContinueDisplayLink() {
+ if (CVDisplayLinkIsRunning(display_link_))
+ return;
+
+ CVReturn ret = CVDisplayLinkStart(display_link_);
+ if (ret != kCVReturnSuccess) {
+ LOG(ERROR) << "CVDisplayLinkStart failed: " << ret;
+ }
+}
+
+void DisplayLinkMac::StopDisplayLink() {
+ if (!CVDisplayLinkIsRunning(display_link_))
+ return;
+
+ CVReturn ret = CVDisplayLinkStop(display_link_);
+ if (ret != kCVReturnSuccess) {
+ LOG(ERROR) << "CVDisplayLinkStop failed: " << ret;
+ }
+}
+
+// static
+CVReturn DisplayLinkMac::DisplayLinkCallback(
+ CVDisplayLinkRef display_link,
+ const CVTimeStamp* now,
+ const CVTimeStamp* output_time,
+ CVOptionFlags flags_in,
+ CVOptionFlags* flags_out,
+ void* context) {
+ TRACE_EVENT0("ui", "DisplayLinkMac::DisplayLinkCallback");
+ DisplayLinkMac* display_link_mac = static_cast<DisplayLinkMac*>(context);
+ display_link_mac->main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DisplayLinkMac::Tick, display_link_mac, *output_time));
+ return kCVReturnSuccess;
+}
+
+// static
+void DisplayLinkMac::DisplayReconfigurationCallBack(
+ CGDirectDisplayID display,
+ CGDisplayChangeSummaryFlags flags,
+ void* user_info) {
+ DisplayMap::iterator found = display_map_.Get().find(display);
+ if (found == display_map_.Get().end())
+ return;
+ DisplayLinkMac* display_link_mac = found->second;
+ display_link_mac->timebase_and_interval_valid_ = false;
+}
+
+// static
+base::LazyInstance<DisplayLinkMac::DisplayMap>
+ DisplayLinkMac::display_map_ = LAZY_INSTANCE_INITIALIZER;
+
+} // ui
+
diff --git a/ui/accelerated_widget_mac/display_link_mac.h b/ui/accelerated_widget_mac/display_link_mac.h
new file mode 100644
index 0000000..24aad6e
--- /dev/null
+++ b/ui/accelerated_widget_mac/display_link_mac.h
@@ -0,0 +1,85 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_ACCELERATED_WIDGET_MAC_DISPLAY_LINK_MAC_H_
+#define UI_ACCELERATED_WIDGET_MAC_DISPLAY_LINK_MAC_H_
+
+#include <QuartzCore/CVDisplayLink.h>
+#include <map>
+
+#include "base/lazy_instance.h"
+#include "base/mac/scoped_typeref.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h"
+
+namespace ui {
+
+class ACCELERATED_WIDGET_MAC_EXPORT DisplayLinkMac :
+ public base::RefCounted<DisplayLinkMac> {
+ public:
+ static scoped_refptr<DisplayLinkMac> GetForDisplay(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
+ CGDirectDisplayID display_id);
+
+ // Get vsync scheduling parameters.
+ bool GetVSyncParameters(
+ base::TimeTicks* timebase,
+ base::TimeDelta* interval);
+
+ private:
+ friend class base::RefCounted<DisplayLinkMac>;
+
+ DisplayLinkMac(
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
+ CGDirectDisplayID display_id,
+ base::ScopedTypeRef<CVDisplayLinkRef> display_link);
+ virtual ~DisplayLinkMac();
+
+ void StartOrContinueDisplayLink();
+ void StopDisplayLink();
+ void Tick(const CVTimeStamp& time);
+
+ // Called by the system on the display link thread, and posts a call to Tick
+ // to the UI thread.
+ static CVReturn DisplayLinkCallback(
+ CVDisplayLinkRef display_link,
+ const CVTimeStamp* now,
+ const CVTimeStamp* output_time,
+ CVOptionFlags flags_in,
+ CVOptionFlags* flags_out,
+ void* context);
+
+ // This is called whenever the display is reconfigured, and marks that the
+ // vsync parameters must be recalculated.
+ static void DisplayReconfigurationCallBack(
+ CGDirectDisplayID display,
+ CGDisplayChangeSummaryFlags flags,
+ void* user_info);
+
+ // The task runner from which to post tasks to run on the main thread.
+ scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+
+ // The display that this display link is attached to.
+ CGDirectDisplayID display_id_;
+
+ // CVDisplayLink for querying VSync timing info.
+ base::ScopedTypeRef<CVDisplayLinkRef> display_link_;
+
+ // VSync parameters computed during Tick.
+ bool timebase_and_interval_valid_;
+ base::TimeTicks timebase_;
+ base::TimeDelta interval_;
+
+ // Each display link instance consumes a non-negligible number of cycles, so
+ // make all display links on the same screen share the same object.
+ typedef std::map<CGDirectDisplayID, DisplayLinkMac*> DisplayMap;
+ static base::LazyInstance<DisplayMap> display_map_;
+};
+
+} // ui
+
+#endif // UI_ACCELERATED_WIDGET_MAC_DISPLAY_LINK_MAC_H_