Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/thebes/SoftwareVsyncSource.cpp
Line
Count
Source (jump to first uncovered line)
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
using namespace mozilla;
13
14
SoftwareVsyncSource::SoftwareVsyncSource()
15
0
{
16
0
  MOZ_ASSERT(NS_IsMainThread());
17
0
  mGlobalDisplay = new SoftwareDisplay();
18
0
}
19
20
SoftwareVsyncSource::~SoftwareVsyncSource()
21
0
{
22
0
  MOZ_ASSERT(NS_IsMainThread());
23
0
  mGlobalDisplay = nullptr;
24
0
}
25
26
SoftwareDisplay::SoftwareDisplay()
27
  : mVsyncEnabled(false)
28
0
{
29
0
  // Mimic 60 fps
30
0
  MOZ_ASSERT(NS_IsMainThread());
31
0
  const double rate = 1000.0 / (double) gfxPlatform::GetSoftwareVsyncRate();
32
0
  mVsyncRate = mozilla::TimeDuration::FromMilliseconds(rate);
33
0
  mVsyncThread = new base::Thread("SoftwareVsyncThread");
34
0
  MOZ_RELEASE_ASSERT(mVsyncThread->Start(), "GFX: Could not start software vsync thread");
35
0
}
36
37
0
SoftwareDisplay::~SoftwareDisplay() {}
38
39
void
40
SoftwareDisplay::EnableVsync()
41
0
{
42
0
  MOZ_ASSERT(mVsyncThread->IsRunning());
43
0
  if (NS_IsMainThread()) {
44
0
    if (mVsyncEnabled) {
45
0
      return;
46
0
    }
47
0
    mVsyncEnabled = true;
48
0
49
0
    mVsyncThread->message_loop()->PostTask(NewRunnableMethod(
50
0
      "SoftwareDisplay::EnableVsync", this, &SoftwareDisplay::EnableVsync));
51
0
    return;
52
0
  }
53
0
54
0
  MOZ_ASSERT(IsInSoftwareVsyncThread());
55
0
  NotifyVsync(mozilla::TimeStamp::Now());
56
0
}
57
58
void
59
SoftwareDisplay::DisableVsync()
60
0
{
61
0
  MOZ_ASSERT(mVsyncThread->IsRunning());
62
0
  if (NS_IsMainThread()) {
63
0
    if (!mVsyncEnabled) {
64
0
      return;
65
0
    }
66
0
    mVsyncEnabled = false;
67
0
68
0
    mVsyncThread->message_loop()->PostTask(NewRunnableMethod(
69
0
      "SoftwareDisplay::DisableVsync", this, &SoftwareDisplay::DisableVsync));
70
0
    return;
71
0
  }
72
0
73
0
  MOZ_ASSERT(IsInSoftwareVsyncThread());
74
0
  if (mCurrentVsyncTask) {
75
0
    mCurrentVsyncTask->Cancel();
76
0
    mCurrentVsyncTask = nullptr;
77
0
  }
78
0
}
79
80
bool
81
SoftwareDisplay::IsVsyncEnabled()
82
0
{
83
0
  MOZ_ASSERT(NS_IsMainThread());
84
0
  return mVsyncEnabled;
85
0
}
86
87
bool
88
SoftwareDisplay::IsInSoftwareVsyncThread()
89
0
{
90
0
  return mVsyncThread->thread_id() == PlatformThread::CurrentId();
91
0
}
92
93
void
94
SoftwareDisplay::NotifyVsync(mozilla::TimeStamp aVsyncTimestamp)
95
0
{
96
0
  MOZ_ASSERT(IsInSoftwareVsyncThread());
97
0
98
0
  mozilla::TimeStamp displayVsyncTime = aVsyncTimestamp;
99
0
  mozilla::TimeStamp now = mozilla::TimeStamp::Now();
100
0
  // Posted tasks can only have integer millisecond delays
101
0
  // whereas TimeDurations can have floating point delays.
102
0
  // Thus the vsync timestamp can be in the future, which large parts
103
0
  // of the system can't handle, including animations. Force the timestamp to be now.
104
0
  if (aVsyncTimestamp > now) {
105
0
    displayVsyncTime = now;
106
0
  }
107
0
108
0
  Display::NotifyVsync(displayVsyncTime);
109
0
110
0
  // Prevent skew by still scheduling based on the original
111
0
  // vsync timestamp
112
0
  ScheduleNextVsync(aVsyncTimestamp);
113
0
}
114
115
mozilla::TimeDuration
116
SoftwareDisplay::GetVsyncRate()
117
0
{
118
0
  return mVsyncRate;
119
0
}
120
121
void
122
SoftwareDisplay::ScheduleNextVsync(mozilla::TimeStamp aVsyncTimestamp)
123
0
{
124
0
  MOZ_ASSERT(IsInSoftwareVsyncThread());
125
0
  mozilla::TimeStamp nextVsync = aVsyncTimestamp + mVsyncRate;
126
0
  mozilla::TimeDuration delay = nextVsync - mozilla::TimeStamp::Now();
127
0
  if (delay.ToMilliseconds() < 0) {
128
0
    delay = mozilla::TimeDuration::FromMilliseconds(0);
129
0
    nextVsync = mozilla::TimeStamp::Now();
130
0
  }
131
0
132
0
  mCurrentVsyncTask = NewCancelableRunnableMethod<mozilla::TimeStamp>(
133
0
    "SoftwareDisplay::NotifyVsync",
134
0
    this,
135
0
    &SoftwareDisplay::NotifyVsync,
136
0
    nextVsync);
137
0
138
0
  RefPtr<Runnable> addrefedTask = mCurrentVsyncTask;
139
0
  mVsyncThread->message_loop()->PostDelayedTask(
140
0
    addrefedTask.forget(),
141
0
    delay.ToMilliseconds());
142
0
}
143
144
void
145
SoftwareDisplay::Shutdown()
146
0
{
147
0
  MOZ_ASSERT(NS_IsMainThread());
148
0
  DisableVsync();
149
0
  mVsyncThread->Stop();
150
0
  delete mVsyncThread;
151
0
}