tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SoftwareVsyncSource.cpp (4347B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      5 */
      6 
      7 #include "SoftwareVsyncSource.h"
      8 #include "base/task.h"
      9 #include "gfxPlatform.h"
     10 #include "nsThreadUtils.h"
     11 
     12 namespace mozilla::gfx {
     13 
     14 SoftwareVsyncSource::SoftwareVsyncSource(const TimeDuration& aInitialVsyncRate)
     15    : mVsyncEnabled(false),
     16      mVsyncRate(TimeDuration{aInitialVsyncRate},
     17                 "SoftwareVsyncSource::mVsyncRate") {
     18  MOZ_ASSERT(NS_IsMainThread());
     19  mVsyncThread = new base::Thread("SoftwareVsyncThread");
     20  MOZ_RELEASE_ASSERT(mVsyncThread->Start(),
     21                     "GFX: Could not start software vsync thread");
     22 }
     23 
     24 SoftwareVsyncSource::~SoftwareVsyncSource() {
     25  MOZ_ASSERT(NS_IsMainThread());
     26  if (mVsyncThread) {
     27    mVsyncThread->Stop();
     28    delete mVsyncThread;
     29  }
     30 };
     31 
     32 void SoftwareVsyncSource::EnableVsync() {
     33  MOZ_ASSERT(mVsyncThread->IsRunning());
     34  if (NS_IsMainThread()) {
     35    if (mVsyncEnabled) {
     36      return;
     37    }
     38    mVsyncEnabled = true;
     39 
     40    mVsyncThread->message_loop()->PostTask(
     41        NewRunnableMethod("SoftwareVsyncSource::EnableVsync", this,
     42                          &SoftwareVsyncSource::EnableVsync));
     43    return;
     44  }
     45 
     46  MOZ_ASSERT(IsInSoftwareVsyncThread());
     47  TimeStamp vsyncTime = TimeStamp::Now();
     48  TimeStamp outputTime = vsyncTime + GetVsyncRate();
     49  NotifyVsync(vsyncTime, outputTime);
     50 }
     51 
     52 void SoftwareVsyncSource::DisableVsync() {
     53  MOZ_ASSERT(mVsyncThread->IsRunning());
     54  if (NS_IsMainThread()) {
     55    if (!mVsyncEnabled) {
     56      return;
     57    }
     58    mVsyncEnabled = false;
     59 
     60    mVsyncThread->message_loop()->PostTask(
     61        NewRunnableMethod("SoftwareVsyncSource::DisableVsync", this,
     62                          &SoftwareVsyncSource::DisableVsync));
     63    return;
     64  }
     65 
     66  MOZ_ASSERT(IsInSoftwareVsyncThread());
     67  if (mCurrentVsyncTask) {
     68    mCurrentVsyncTask->Cancel();
     69    mCurrentVsyncTask = nullptr;
     70  }
     71 }
     72 
     73 bool SoftwareVsyncSource::IsVsyncEnabled() {
     74  MOZ_ASSERT(NS_IsMainThread());
     75  return mVsyncEnabled;
     76 }
     77 
     78 bool SoftwareVsyncSource::IsInSoftwareVsyncThread() {
     79  return mVsyncThread->thread_id() == PlatformThread::CurrentId();
     80 }
     81 
     82 void SoftwareVsyncSource::NotifyVsync(const TimeStamp& aVsyncTimestamp,
     83                                      const TimeStamp& aOutputTimestamp) {
     84  MOZ_ASSERT(IsInSoftwareVsyncThread());
     85 
     86  TimeStamp displayVsyncTime = aVsyncTimestamp;
     87  TimeStamp now = TimeStamp::Now();
     88  // Posted tasks can only have integer millisecond delays
     89  // whereas TimeDurations can have floating point delays.
     90  // Thus the vsync timestamp can be in the future, which large parts
     91  // of the system can't handle, including animations. Force the timestamp to be
     92  // now.
     93  if (aVsyncTimestamp > now) {
     94    displayVsyncTime = now;
     95  }
     96 
     97  VsyncSource::NotifyVsync(displayVsyncTime, aOutputTimestamp);
     98 
     99  // Prevent skew by still scheduling based on the original
    100  // vsync timestamp
    101  ScheduleNextVsync(aVsyncTimestamp);
    102 }
    103 
    104 TimeDuration SoftwareVsyncSource::GetVsyncRate() {
    105  auto rate = mVsyncRate.Lock();
    106  return *rate;
    107 }
    108 
    109 void SoftwareVsyncSource::SetVsyncRate(const TimeDuration& aNewRate) {
    110  auto rate = mVsyncRate.Lock();
    111  *rate = aNewRate;
    112 }
    113 
    114 void SoftwareVsyncSource::ScheduleNextVsync(TimeStamp aVsyncTimestamp) {
    115  MOZ_ASSERT(IsInSoftwareVsyncThread());
    116  TimeDuration vsyncRate = GetVsyncRate();
    117  TimeStamp nextVsync = aVsyncTimestamp + vsyncRate;
    118  TimeDuration delay = nextVsync - TimeStamp::Now();
    119  if (delay.ToMilliseconds() < 0) {
    120    delay = TimeDuration::FromMilliseconds(0);
    121    nextVsync = TimeStamp::Now();
    122  }
    123 
    124  TimeStamp outputTime = nextVsync + vsyncRate;
    125 
    126  mCurrentVsyncTask = NewCancelableRunnableMethod<TimeStamp, TimeStamp>(
    127      "SoftwareVsyncSource::NotifyVsync", this,
    128      &SoftwareVsyncSource::NotifyVsync, nextVsync, outputTime);
    129 
    130  RefPtr<Runnable> addrefedTask = mCurrentVsyncTask;
    131  mVsyncThread->message_loop()->PostDelayedTask(addrefedTask.forget(),
    132                                                delay.ToMilliseconds());
    133 }
    134 
    135 void SoftwareVsyncSource::Shutdown() {
    136  MOZ_ASSERT(NS_IsMainThread());
    137  DisableVsync();
    138  mVsyncThread->Stop();
    139  delete mVsyncThread;
    140  mVsyncThread = nullptr;
    141 }
    142 
    143 }  // namespace mozilla::gfx