• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "content/browser/renderer_host/display_link_mac.h"
6 
7 #include "base/debug/trace_event.h"
8 #include "base/logging.h"
9 
10 namespace base {
11 
12 template<>
13 struct ScopedTypeRefTraits<CVDisplayLinkRef> {
Retainbase::ScopedTypeRefTraits14   static void Retain(CVDisplayLinkRef object) {
15     CVDisplayLinkRetain(object);
16   }
Releasebase::ScopedTypeRefTraits17   static void Release(CVDisplayLinkRef object) {
18     CVDisplayLinkRelease(object);
19   }
20 };
21 
22 }  // namespace base
23 
24 namespace content {
25 
26 // static
GetForDisplay(CGDirectDisplayID display_id)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()) {
32     return found->second;
33   }
34 
35   CVReturn ret = kCVReturnSuccess;
36 
37   base::ScopedTypeRef<CVDisplayLinkRef> display_link;
38   ret = CVDisplayLinkCreateWithCGDisplay(
39       display_id,
40       display_link.InitializeInto());
41   if (ret != kCVReturnSuccess) {
42     LOG(ERROR) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret;
43     return NULL;
44   }
45 
46   scoped_refptr<DisplayLinkMac> display_link_mac;
47   display_link_mac = new DisplayLinkMac(display_id, display_link);
48 
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;
56   }
57 
58   return display_link_mac;
59 }
60 
DisplayLinkMac(CGDirectDisplayID display_id,base::ScopedTypeRef<CVDisplayLinkRef> display_link)61 DisplayLinkMac::DisplayLinkMac(
62     CGDirectDisplayID display_id,
63     base::ScopedTypeRef<CVDisplayLinkRef> display_link)
64       : display_id_(display_id),
65         display_link_(display_link),
66         stop_timer_(
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));
72 }
73 
~DisplayLinkMac()74 DisplayLinkMac::~DisplayLinkMac() {
75   if (CVDisplayLinkIsRunning(display_link_))
76     CVDisplayLinkStop(display_link_);
77 
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);
82 }
83 
GetVSyncParameters(base::TimeTicks * timebase,base::TimeDelta * interval)84 bool DisplayLinkMac::GetVSyncParameters(
85     base::TimeTicks* timebase, base::TimeDelta* interval) {
86   StartOrContinueDisplayLink();
87 
88   base::AutoLock lock(lock_);
89   if (!timebase_and_interval_valid_)
90     return false;
91 
92   *timebase = timebase_;
93   *interval = interval_;
94   return true;
95 }
96 
Tick(const CVTimeStamp * cv_time)97 void DisplayLinkMac::Tick(const CVTimeStamp* cv_time) {
98   TRACE_EVENT0("browser", "DisplayLinkMac::GetVSyncParameters");
99   base::AutoLock lock(lock_);
100 
101   // Verify that videoRefreshPeriod is 32 bits.
102   DCHECK((cv_time->videoRefreshPeriod & ~0xffffFFFFull) == 0ull);
103 
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.";
109     return;
110   }
111 
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;
117 }
118 
StartOrContinueDisplayLink()119 void DisplayLinkMac::StartOrContinueDisplayLink() {
120   // Reset the timer, so that the display link won't be turned off for another
121   // second.
122   stop_timer_.Reset();
123 
124   if (CVDisplayLinkIsRunning(display_link_))
125     return;
126 
127   CVReturn ret = CVDisplayLinkStart(display_link_);
128   if (ret != kCVReturnSuccess) {
129     LOG(ERROR) << "CVDisplayLinkStart failed: " << ret;
130   }
131 }
132 
StopDisplayLink()133 void DisplayLinkMac::StopDisplayLink() {
134   if (!CVDisplayLinkIsRunning(display_link_))
135     return;
136 
137   CVReturn ret = CVDisplayLinkStop(display_link_);
138   if (ret != kCVReturnSuccess) {
139     LOG(ERROR) << "CVDisplayLinkStop failed: " << ret;
140   }
141 }
142 
DisplayLinkCallback(CVDisplayLinkRef display_link,const CVTimeStamp * now,const CVTimeStamp * output_time,CVOptionFlags flags_in,CVOptionFlags * flags_out,void * context)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,
149     void* context) {
150   DisplayLinkMac* display_link_mac = static_cast<DisplayLinkMac*>(context);
151   display_link_mac->Tick(output_time);
152   return kCVReturnSuccess;
153 }
154 
155 // static
156 base::LazyInstance<DisplayLinkMac::DisplayMap>
157     DisplayLinkMac::display_map_ = LAZY_INSTANCE_INITIALIZER;
158 
159 }  // content
160 
161