Enable Finch selection of Client Side Detection models.
[chromium-blink-merge.git] / ui / accelerated_widget_mac / display_link_mac.cc
blobc9a30699a06fff31a5b8117c2cfb7f5d7b64e0c6
1 // Copyright 2014 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.
5 #include "ui/accelerated_widget_mac/display_link_mac.h"
7 #include "base/logging.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/trace_event/trace_event.h"
11 namespace base {
13 template<>
14 struct ScopedTypeRefTraits<CVDisplayLinkRef> {
15 static void Retain(CVDisplayLinkRef object) {
16 CVDisplayLinkRetain(object);
18 static void Release(CVDisplayLinkRef object) {
19 CVDisplayLinkRelease(object);
23 } // namespace base
25 namespace ui {
27 // static
28 scoped_refptr<DisplayLinkMac> DisplayLinkMac::GetForDisplay(
29 CGDirectDisplayID display_id) {
30 // Return the existing display link for this display, if it exists.
31 DisplayMap::iterator found = display_map_.Get().find(display_id);
32 if (found != display_map_.Get().end()) {
33 return found->second;
36 CVReturn ret = kCVReturnSuccess;
38 base::ScopedTypeRef<CVDisplayLinkRef> display_link;
39 ret = CVDisplayLinkCreateWithCGDisplay(
40 display_id,
41 display_link.InitializeInto());
42 if (ret != kCVReturnSuccess) {
43 LOG(ERROR) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret;
44 return NULL;
47 scoped_refptr<DisplayLinkMac> display_link_mac;
48 display_link_mac = new DisplayLinkMac(display_id, display_link);
49 ret = CVDisplayLinkSetOutputCallback(
50 display_link_mac->display_link_,
51 &DisplayLinkCallback,
52 display_link_mac.get());
53 if (ret != kCVReturnSuccess) {
54 LOG(ERROR) << "CVDisplayLinkSetOutputCallback failed: " << ret;
55 return NULL;
58 return display_link_mac;
61 DisplayLinkMac::DisplayLinkMac(
62 CGDirectDisplayID display_id,
63 base::ScopedTypeRef<CVDisplayLinkRef> display_link)
64 : main_thread_task_runner_(
65 base::MessageLoop::current()->task_runner()),
66 display_id_(display_id),
67 display_link_(display_link),
68 timebase_and_interval_valid_(false) {
69 DCHECK(display_map_.Get().find(display_id) == display_map_.Get().end());
70 if (display_map_.Get().empty()) {
71 CGError register_error = CGDisplayRegisterReconfigurationCallback(
72 DisplayReconfigurationCallBack, nullptr);
73 DPLOG_IF(ERROR, register_error != kCGErrorSuccess)
74 << "CGDisplayRegisterReconfigurationCallback: "
75 << register_error;
77 display_map_.Get().insert(std::make_pair(display_id_, this));
80 DisplayLinkMac::~DisplayLinkMac() {
81 StopDisplayLink();
83 DisplayMap::iterator found = display_map_.Get().find(display_id_);
84 DCHECK(found != display_map_.Get().end());
85 DCHECK(found->second == this);
86 display_map_.Get().erase(found);
87 if (display_map_.Get().empty()) {
88 CGError remove_error = CGDisplayRemoveReconfigurationCallback(
89 DisplayReconfigurationCallBack, nullptr);
90 DPLOG_IF(ERROR, remove_error != kCGErrorSuccess)
91 << "CGDisplayRemoveReconfigurationCallback: "
92 << remove_error;
96 bool DisplayLinkMac::GetVSyncParameters(
97 base::TimeTicks* timebase, base::TimeDelta* interval) {
98 if (!timebase_and_interval_valid_) {
99 StartOrContinueDisplayLink();
100 return false;
103 *timebase = timebase_;
104 *interval = interval_;
105 return true;
108 void DisplayLinkMac::Tick(const CVTimeStamp& cv_time) {
109 TRACE_EVENT0("ui", "DisplayLinkMac::Tick");
111 // Verify that videoRefreshPeriod is 32 bits.
112 DCHECK((cv_time.videoRefreshPeriod & ~0xffffFFFFull) == 0ull);
114 // Verify that the numerator and denominator make some sense.
115 uint32 numerator = static_cast<uint32>(cv_time.videoRefreshPeriod);
116 uint32 denominator = cv_time.videoTimeScale;
117 if (numerator <= 0 || denominator <= 0) {
118 LOG(WARNING) << "Unexpected numerator or denominator, bailing.";
119 return;
122 timebase_ = base::TimeTicks::FromInternalValue(
123 cv_time.hostTime / 1000);
124 interval_ = base::TimeDelta::FromMicroseconds(
125 1000000 * static_cast<int64>(numerator) / denominator);
126 timebase_and_interval_valid_ = true;
128 StopDisplayLink();
131 void DisplayLinkMac::StartOrContinueDisplayLink() {
132 if (CVDisplayLinkIsRunning(display_link_))
133 return;
135 CVReturn ret = CVDisplayLinkStart(display_link_);
136 if (ret != kCVReturnSuccess) {
137 LOG(ERROR) << "CVDisplayLinkStart failed: " << ret;
141 void DisplayLinkMac::StopDisplayLink() {
142 if (!CVDisplayLinkIsRunning(display_link_))
143 return;
145 CVReturn ret = CVDisplayLinkStop(display_link_);
146 if (ret != kCVReturnSuccess) {
147 LOG(ERROR) << "CVDisplayLinkStop failed: " << ret;
151 // static
152 CVReturn DisplayLinkMac::DisplayLinkCallback(
153 CVDisplayLinkRef display_link,
154 const CVTimeStamp* now,
155 const CVTimeStamp* output_time,
156 CVOptionFlags flags_in,
157 CVOptionFlags* flags_out,
158 void* context) {
159 TRACE_EVENT0("ui", "DisplayLinkMac::DisplayLinkCallback");
160 DisplayLinkMac* display_link_mac = static_cast<DisplayLinkMac*>(context);
161 display_link_mac->main_thread_task_runner_->PostTask(
162 FROM_HERE,
163 base::Bind(&DisplayLinkMac::Tick, display_link_mac, *output_time));
164 return kCVReturnSuccess;
167 // static
168 void DisplayLinkMac::DisplayReconfigurationCallBack(
169 CGDirectDisplayID display,
170 CGDisplayChangeSummaryFlags flags,
171 void* user_info) {
172 DisplayMap::iterator found = display_map_.Get().find(display);
173 if (found == display_map_.Get().end())
174 return;
175 DisplayLinkMac* display_link_mac = found->second;
176 display_link_mac->timebase_and_interval_valid_ = false;
179 // static
180 base::LazyInstance<DisplayLinkMac::DisplayMap>
181 DisplayLinkMac::display_map_ = LAZY_INSTANCE_INITIALIZER;
183 } // ui