// 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 "content/browser/renderer_host/display_link_mac.h" #include "base/logging.h" #include "base/trace_event/trace_event.h" namespace base { template<> struct ScopedTypeRefTraits { static void Retain(CVDisplayLinkRef object) { CVDisplayLinkRetain(object); } static void Release(CVDisplayLinkRef object) { CVDisplayLinkRelease(object); } }; } // namespace base namespace content { // static scoped_refptr DisplayLinkMac::GetForDisplay( 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 display_link; ret = CVDisplayLinkCreateWithCGDisplay( display_id, display_link.InitializeInto()); if (ret != kCVReturnSuccess) { LOG(ERROR) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret; return NULL; } scoped_refptr display_link_mac; display_link_mac = new DisplayLinkMac(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( CGDirectDisplayID display_id, base::ScopedTypeRef display_link) : display_id_(display_id), display_link_(display_link), stop_timer_( FROM_HERE, base::TimeDelta::FromSeconds(1), this, &DisplayLinkMac::StopDisplayLink), timebase_and_interval_valid_(false) { DCHECK(display_map_.Get().find(display_id) == display_map_.Get().end()); display_map_.Get().insert(std::make_pair(display_id_, this)); } DisplayLinkMac::~DisplayLinkMac() { if (CVDisplayLinkIsRunning(display_link_)) CVDisplayLinkStop(display_link_); DisplayMap::iterator found = display_map_.Get().find(display_id_); DCHECK(found != display_map_.Get().end()); DCHECK(found->second == this); display_map_.Get().erase(found); } bool DisplayLinkMac::GetVSyncParameters( base::TimeTicks* timebase, base::TimeDelta* interval) { StartOrContinueDisplayLink(); base::AutoLock lock(lock_); if (!timebase_and_interval_valid_) return false; *timebase = timebase_; *interval = interval_; return true; } void DisplayLinkMac::Tick(const CVTimeStamp* cv_time) { TRACE_EVENT0("browser", "DisplayLinkMac::GetVSyncParameters"); base::AutoLock lock(lock_); // 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(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(numerator) / denominator); timebase_and_interval_valid_ = true; } void DisplayLinkMac::StartOrContinueDisplayLink() { // Reset the timer, so that the display link won't be turned off for another // second. stop_timer_.Reset(); 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; } } CVReturn DisplayLinkMac::DisplayLinkCallback( CVDisplayLinkRef display_link, const CVTimeStamp* now, const CVTimeStamp* output_time, CVOptionFlags flags_in, CVOptionFlags* flags_out, void* context) { DisplayLinkMac* display_link_mac = static_cast(context); display_link_mac->Tick(output_time); return kCVReturnSuccess; } // static base::LazyInstance DisplayLinkMac::display_map_ = LAZY_INSTANCE_INITIALIZER; } // content