Home | History | Annotate | Download | only in renderer_host
      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> {
     14   static void Retain(CVDisplayLinkRef object) {
     15     CVDisplayLinkRetain(object);
     16   }
     17   static void Release(CVDisplayLinkRef object) {
     18     CVDisplayLinkRelease(object);
     19   }
     20 };
     21 
     22 }  // namespace base
     23 
     24 namespace content {
     25 
     26 // static
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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