root/content/browser/renderer_host/display_link_mac.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetForDisplay
  2. timebase_and_interval_valid_
  3. GetVSyncParameters
  4. Tick
  5. StartOrContinueDisplayLink
  6. StopDisplayLink
  7. DisplayLinkCallback

// 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/debug/trace_event.h"
#include "base/logging.h"

namespace base {

template<>
struct ScopedTypeRefTraits<CVDisplayLinkRef> {
  static void Retain(CVDisplayLinkRef object) {
    CVDisplayLinkRetain(object);
  }
  static void Release(CVDisplayLinkRef object) {
    CVDisplayLinkRelease(object);
  }
};

}  // namespace base

namespace content {

// static
scoped_refptr<DisplayLinkMac> 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<CVDisplayLinkRef> display_link;
  ret = CVDisplayLinkCreateWithCGDisplay(
      display_id,
      display_link.InitializeInto());
  if (ret != kCVReturnSuccess) {
    LOG(ERROR) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret;
    return NULL;
  }

  scoped_refptr<DisplayLinkMac> 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<CVDisplayLinkRef> 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<uint32>(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<int64>(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<DisplayLinkMac*>(context);
  display_link_mac->Tick(output_time);
  return kCVReturnSuccess;
}

// static
base::LazyInstance<DisplayLinkMac::DisplayMap>
    DisplayLinkMac::display_map_ = LAZY_INSTANCE_INITIALIZER;

}  // content


/* [<][>][^][v][top][bottom][index][help] */