Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/layers/ProfilerScreenshots.h"
8
9
#include "mozilla/SystemGroup.h"
10
#include "mozilla/TimeStamp.h"
11
12
#include "GeckoProfiler.h"
13
#include "gfxUtils.h"
14
#include "nsThreadUtils.h"
15
#ifdef MOZ_GECKO_PROFILER
16
# include "ProfilerMarkerPayload.h"
17
#endif
18
19
using namespace mozilla;
20
using namespace mozilla::gfx;
21
using namespace mozilla::layers;
22
23
ProfilerScreenshots::ProfilerScreenshots()
24
: mMutex("ProfilerScreenshots::mMutex"), mLiveSurfaceCount(0) {}
25
26
ProfilerScreenshots::~ProfilerScreenshots() = default;
27
28
/* static */
29
bool ProfilerScreenshots::IsEnabled() {
30
#ifdef MOZ_GECKO_PROFILER
31
return profiler_feature_active(ProfilerFeature::Screenshots);
32
#else
33
return false;
34
#endif
35
}
36
37
void ProfilerScreenshots::SubmitScreenshot(
38
uintptr_t aWindowIdentifier, const gfx::IntSize& aOriginalSize,
39
const IntSize& aScaledSize, const TimeStamp& aTimeStamp,
40
const std::function<bool(DataSourceSurface*)>& aPopulateSurface) {
41
#ifdef MOZ_GECKO_PROFILER
42
RefPtr<DataSourceSurface> backingSurface = TakeNextSurface();
43
if (!backingSurface) {
44
return;
45
}
46
47
MOZ_RELEASE_ASSERT(aScaledSize <= backingSurface->GetSize());
48
49
bool succeeded = aPopulateSurface(backingSurface);
50
51
if (!succeeded) {
52
PROFILER_ADD_MARKER(
53
"NoCompositorScreenshot because aPopulateSurface callback failed",
54
GRAPHICS);
55
ReturnSurface(backingSurface);
56
return;
57
}
58
59
int sourceThread = profiler_current_thread_id();
60
uintptr_t windowIdentifier = aWindowIdentifier;
61
IntSize originalSize = aOriginalSize;
62
IntSize scaledSize = aScaledSize;
63
TimeStamp timeStamp = aTimeStamp;
64
65
RefPtr<ProfilerScreenshots> self = this;
66
67
NS_DispatchBackgroundTask(NS_NewRunnableFunction(
68
"ProfilerScreenshots::SubmitScreenshot",
69
[self{std::move(self)}, backingSurface, sourceThread, windowIdentifier,
70
originalSize, scaledSize, timeStamp]() {
71
// Create a new surface that wraps backingSurface's data but has the
72
// correct size.
73
if (profiler_can_accept_markers()) {
74
DataSourceSurface::ScopedMap scopedMap(backingSurface,
75
DataSourceSurface::READ);
76
RefPtr<DataSourceSurface> surf =
77
Factory::CreateWrappingDataSourceSurface(
78
scopedMap.GetData(), scopedMap.GetStride(), scaledSize,
79
SurfaceFormat::B8G8R8A8);
80
81
// Encode surf to a JPEG data URL.
82
nsCString dataURL;
83
nsresult rv = gfxUtils::EncodeSourceSurface(
84
surf, ImageType::JPEG, NS_LITERAL_STRING("quality=85"),
85
gfxUtils::eDataURIEncode, nullptr, &dataURL);
86
if (NS_SUCCEEDED(rv)) {
87
// Add a marker with the data URL.
88
AUTO_PROFILER_STATS(add_marker_with_ScreenshotPayload);
89
profiler_add_marker_for_thread(
90
sourceThread, JS::ProfilingCategoryPair::GRAPHICS,
91
"CompositorScreenshot",
92
MakeUnique<ScreenshotPayload>(timeStamp, std::move(dataURL),
93
originalSize, windowIdentifier));
94
}
95
}
96
97
// Return backingSurface back to the surface pool.
98
self->ReturnSurface(backingSurface);
99
}));
100
#endif
101
}
102
103
already_AddRefed<DataSourceSurface> ProfilerScreenshots::TakeNextSurface() {
104
MutexAutoLock mon(mMutex);
105
if (!mAvailableSurfaces.IsEmpty()) {
106
RefPtr<DataSourceSurface> surf = mAvailableSurfaces[0];
107
mAvailableSurfaces.RemoveElementAt(0);
108
return surf.forget();
109
}
110
if (mLiveSurfaceCount >= 8) {
111
NS_WARNING(
112
"already 8 surfaces in flight, skipping capture for this composite");
113
return nullptr;
114
}
115
mLiveSurfaceCount++;
116
return Factory::CreateDataSourceSurface(ScreenshotSize(),
117
SurfaceFormat::B8G8R8A8);
118
}
119
120
void ProfilerScreenshots::ReturnSurface(DataSourceSurface* aSurface) {
121
MutexAutoLock mon(this->mMutex);
122
mAvailableSurfaces.AppendElement(aSurface);
123
}