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 "content/browser/renderer_host/display_link_mac.h"
7 #include "base/logging.h"
8 #include "base/trace_event/trace_event.h"
13 struct ScopedTypeRefTraits
<CVDisplayLinkRef
> {
14 static void Retain(CVDisplayLinkRef object
) {
15 CVDisplayLinkRetain(object
);
17 static void Release(CVDisplayLinkRef object
) {
18 CVDisplayLinkRelease(object
);
27 scoped_refptr
<DisplayLinkMac
> DisplayLinkMac::GetForDisplay(
28 CGDirectDisplayID display_id
) {
29 // Return the existing display link for this display, if it exists.
30 DisplayMap::iterator found
= display_map_
.Get().find(display_id
);
31 if (found
!= display_map_
.Get().end()) {
35 CVReturn ret
= kCVReturnSuccess
;
37 base::ScopedTypeRef
<CVDisplayLinkRef
> display_link
;
38 ret
= CVDisplayLinkCreateWithCGDisplay(
40 display_link
.InitializeInto());
41 if (ret
!= kCVReturnSuccess
) {
42 LOG(ERROR
) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret
;
46 scoped_refptr
<DisplayLinkMac
> display_link_mac
;
47 display_link_mac
= new DisplayLinkMac(display_id
, display_link
);
49 ret
= CVDisplayLinkSetOutputCallback(
50 display_link_mac
->display_link_
,
52 display_link_mac
.get());
53 if (ret
!= kCVReturnSuccess
) {
54 LOG(ERROR
) << "CVDisplayLinkSetOutputCallback failed: " << ret
;
58 return display_link_mac
;
61 DisplayLinkMac::DisplayLinkMac(
62 CGDirectDisplayID display_id
,
63 base::ScopedTypeRef
<CVDisplayLinkRef
> display_link
)
64 : display_id_(display_id
),
65 display_link_(display_link
),
67 FROM_HERE
, base::TimeDelta::FromSeconds(1),
68 this, &DisplayLinkMac::StopDisplayLink
),
69 timebase_and_interval_valid_(false) {
70 DCHECK(display_map_
.Get().find(display_id
) == display_map_
.Get().end());
71 display_map_
.Get().insert(std::make_pair(display_id_
, this));
74 DisplayLinkMac::~DisplayLinkMac() {
75 if (CVDisplayLinkIsRunning(display_link_
))
76 CVDisplayLinkStop(display_link_
);
78 DisplayMap::iterator found
= display_map_
.Get().find(display_id_
);
79 DCHECK(found
!= display_map_
.Get().end());
80 DCHECK(found
->second
== this);
81 display_map_
.Get().erase(found
);
84 bool DisplayLinkMac::GetVSyncParameters(
85 base::TimeTicks
* timebase
, base::TimeDelta
* interval
) {
86 StartOrContinueDisplayLink();
88 base::AutoLock
lock(lock_
);
89 if (!timebase_and_interval_valid_
)
92 *timebase
= timebase_
;
93 *interval
= interval_
;
97 void DisplayLinkMac::Tick(const CVTimeStamp
* cv_time
) {
98 TRACE_EVENT0("browser", "DisplayLinkMac::GetVSyncParameters");
99 base::AutoLock
lock(lock_
);
101 // Verify that videoRefreshPeriod is 32 bits.
102 DCHECK((cv_time
->videoRefreshPeriod
& ~0xffffFFFFull
) == 0ull);
104 // Verify that the numerator and denominator make some sense.
105 uint32 numerator
= static_cast<uint32
>(cv_time
->videoRefreshPeriod
);
106 uint32 denominator
= cv_time
->videoTimeScale
;
107 if (numerator
<= 0 || denominator
<= 0) {
108 LOG(WARNING
) << "Unexpected numerator or denominator, bailing.";
112 timebase_
= base::TimeTicks::FromInternalValue(
113 cv_time
->hostTime
/ 1000);
114 interval_
= base::TimeDelta::FromMicroseconds(
115 1000000 * static_cast<int64
>(numerator
) / denominator
);
116 timebase_and_interval_valid_
= true;
119 void DisplayLinkMac::StartOrContinueDisplayLink() {
120 // Reset the timer, so that the display link won't be turned off for another
124 if (CVDisplayLinkIsRunning(display_link_
))
127 CVReturn ret
= CVDisplayLinkStart(display_link_
);
128 if (ret
!= kCVReturnSuccess
) {
129 LOG(ERROR
) << "CVDisplayLinkStart failed: " << ret
;
133 void DisplayLinkMac::StopDisplayLink() {
134 if (!CVDisplayLinkIsRunning(display_link_
))
137 CVReturn ret
= CVDisplayLinkStop(display_link_
);
138 if (ret
!= kCVReturnSuccess
) {
139 LOG(ERROR
) << "CVDisplayLinkStop failed: " << ret
;
143 CVReturn
DisplayLinkMac::DisplayLinkCallback(
144 CVDisplayLinkRef display_link
,
145 const CVTimeStamp
* now
,
146 const CVTimeStamp
* output_time
,
147 CVOptionFlags flags_in
,
148 CVOptionFlags
* flags_out
,
150 DisplayLinkMac
* display_link_mac
= static_cast<DisplayLinkMac
*>(context
);
151 display_link_mac
->Tick(output_time
);
152 return kCVReturnSuccess
;
156 base::LazyInstance
<DisplayLinkMac::DisplayMap
>
157 DisplayLinkMac::display_map_
= LAZY_INSTANCE_INITIALIZER
;