15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/browser/renderer_host/display_link_mac.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/debug/trace_event.h" 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h" 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace base { 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)template<> 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)struct ScopedTypeRefTraits<CVDisplayLinkRef> { 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static void Retain(CVDisplayLinkRef object) { 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CVDisplayLinkRetain(object); 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static void Release(CVDisplayLinkRef object) { 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CVDisplayLinkRelease(object); 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}; 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace base 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace content { 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_refptr<DisplayLinkMac> DisplayLinkMac::GetForDisplay( 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CGDirectDisplayID display_id) { 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Return the existing display link for this display, if it exists. 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DisplayMap::iterator found = display_map_.Get().find(display_id); 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (found != display_map_.Get().end()) { 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return found->second; 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CVReturn ret = kCVReturnSuccess; 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ScopedTypeRef<CVDisplayLinkRef> display_link; 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ret = CVDisplayLinkCreateWithCGDisplay( 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) display_id, 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) display_link.InitializeInto()); 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (ret != kCVReturnSuccess) { 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(ERROR) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret; 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return NULL; 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_refptr<DisplayLinkMac> display_link_mac; 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) display_link_mac = new DisplayLinkMac(display_id, display_link); 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ret = CVDisplayLinkSetOutputCallback( 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) display_link_mac->display_link_, 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &DisplayLinkCallback, 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) display_link_mac.get()); 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (ret != kCVReturnSuccess) { 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(ERROR) << "CVDisplayLinkSetOutputCallback failed: " << ret; 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return NULL; 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return display_link_mac; 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DisplayLinkMac::DisplayLinkMac( 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CGDirectDisplayID display_id, 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ScopedTypeRef<CVDisplayLinkRef> display_link) 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : display_id_(display_id), 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) display_link_(display_link), 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) stop_timer_( 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, base::TimeDelta::FromSeconds(1), 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this, &DisplayLinkMac::StopDisplayLink), 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) timebase_and_interval_valid_(false) { 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(display_map_.Get().find(display_id) == display_map_.Get().end()); 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) display_map_.Get().insert(std::make_pair(display_id_, this)); 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DisplayLinkMac::~DisplayLinkMac() { 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (CVDisplayLinkIsRunning(display_link_)) 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CVDisplayLinkStop(display_link_); 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DisplayMap::iterator found = display_map_.Get().find(display_id_); 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(found != display_map_.Get().end()); 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(found->second == this); 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) display_map_.Get().erase(found); 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DisplayLinkMac::GetVSyncParameters( 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeTicks* timebase, base::TimeDelta* interval) { 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StartOrContinueDisplayLink(); 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::AutoLock lock(lock_); 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!timebase_and_interval_valid_) 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *timebase = timebase_; 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *interval = interval_; 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DisplayLinkMac::Tick(const CVTimeStamp* cv_time) { 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) TRACE_EVENT0("browser", "DisplayLinkMac::GetVSyncParameters"); 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::AutoLock lock(lock_); 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Verify that videoRefreshPeriod is 32 bits. 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK((cv_time->videoRefreshPeriod & ~0xffffFFFFull) == 0ull); 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Verify that the numerator and denominator make some sense. 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) uint32 numerator = static_cast<uint32>(cv_time->videoRefreshPeriod); 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) uint32 denominator = cv_time->videoTimeScale; 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (numerator <= 0 || denominator <= 0) { 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(WARNING) << "Unexpected numerator or denominator, bailing."; 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) timebase_ = base::TimeTicks::FromInternalValue( 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) cv_time->hostTime / 1000); 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) interval_ = base::TimeDelta::FromMicroseconds( 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1000000 * static_cast<int64>(numerator) / denominator); 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) timebase_and_interval_valid_ = true; 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DisplayLinkMac::StartOrContinueDisplayLink() { 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Reset the timer, so that the display link won't be turned off for another 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // second. 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) stop_timer_.Reset(); 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (CVDisplayLinkIsRunning(display_link_)) 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CVReturn ret = CVDisplayLinkStart(display_link_); 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (ret != kCVReturnSuccess) { 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(ERROR) << "CVDisplayLinkStart failed: " << ret; 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DisplayLinkMac::StopDisplayLink() { 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!CVDisplayLinkIsRunning(display_link_)) 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CVReturn ret = CVDisplayLinkStop(display_link_); 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (ret != kCVReturnSuccess) { 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(ERROR) << "CVDisplayLinkStop failed: " << ret; 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CVReturn DisplayLinkMac::DisplayLinkCallback( 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CVDisplayLinkRef display_link, 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const CVTimeStamp* now, 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const CVTimeStamp* output_time, 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CVOptionFlags flags_in, 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CVOptionFlags* flags_out, 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void* context) { 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DisplayLinkMac* display_link_mac = static_cast<DisplayLinkMac*>(context); 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) display_link_mac->Tick(output_time); 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return kCVReturnSuccess; 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::LazyInstance<DisplayLinkMac::DisplayMap> 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DisplayLinkMac::display_map_ = LAZY_INSTANCE_INITIALIZER; 158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // content 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 161