Bug 1885580 - Add a MenuGroup component for the menu redesign r=android-reviewers,007
[gecko.git] / gfx / layers / ProfilerScreenshots.cpp
blob44bef9e410532fe68b41374eeccb15bd155d37e1
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/. */
7 #include "mozilla/layers/ProfilerScreenshots.h"
9 #include "mozilla/TimeStamp.h"
11 #include "GeckoProfiler.h"
12 #include "gfxUtils.h"
13 #include "nsThreadUtils.h"
15 using namespace mozilla;
16 using namespace mozilla::gfx;
17 using namespace mozilla::layers;
19 struct ScreenshotMarker {
20 static constexpr mozilla::Span<const char> MarkerTypeName() {
21 return mozilla::MakeStringSpan("CompositorScreenshot");
23 static void StreamJSONMarkerData(
24 mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
25 const mozilla::ProfilerString8View& aScreenshotDataURL,
26 const mozilla::gfx::IntSize& aWindowSize, uint32_t aWindowIdentifier) {
27 if (aScreenshotDataURL.Length() != 0) {
28 aWriter.UniqueStringProperty("url", aScreenshotDataURL);
31 aWriter.IntProperty("windowID", aWindowIdentifier);
33 if (!aWindowSize.IsEmpty()) {
34 aWriter.DoubleProperty("windowWidth", aWindowSize.width);
35 aWriter.DoubleProperty("windowHeight", aWindowSize.height);
38 static mozilla::MarkerSchema MarkerTypeDisplay() {
39 return mozilla::MarkerSchema::SpecialFrontendLocation{};
43 uint32_t ProfilerScreenshots::sWindowCounter = 0;
45 ProfilerScreenshots::ProfilerScreenshots()
46 : mMutex("ProfilerScreenshots::mMutex"),
47 mLiveSurfaceCount(0),
48 mWindowIdentifier(++sWindowCounter) {}
50 ProfilerScreenshots::~ProfilerScreenshots() {
51 if (mWindowIdentifier) {
52 profiler_add_marker("CompositorScreenshotWindowDestroyed",
53 geckoprofiler::category::GRAPHICS,
54 MarkerThreadId::MainThread(), ScreenshotMarker{},
55 /* aScreenshotDataURL */ "", mozilla::gfx::IntSize{},
56 mWindowIdentifier);
60 /* static */
61 bool ProfilerScreenshots::IsEnabled() {
62 return profiler_feature_active(ProfilerFeature::Screenshots);
65 void ProfilerScreenshots::SubmitScreenshot(
66 const gfx::IntSize& aOriginalSize, const IntSize& aScaledSize,
67 const TimeStamp& aTimeStamp,
68 const std::function<bool(DataSourceSurface*)>& aPopulateSurface) {
69 RefPtr<DataSourceSurface> backingSurface = TakeNextSurface();
70 if (!backingSurface) {
71 return;
74 MOZ_RELEASE_ASSERT(aScaledSize <= backingSurface->GetSize());
76 bool succeeded = aPopulateSurface(backingSurface);
78 if (!succeeded) {
79 PROFILER_MARKER_UNTYPED(
80 "NoCompositorScreenshot because aPopulateSurface callback failed",
81 GRAPHICS);
82 ReturnSurface(backingSurface);
83 return;
86 NS_DispatchBackgroundTask(NS_NewRunnableFunction(
87 "ProfilerScreenshots::SubmitScreenshot",
88 [self = RefPtr<ProfilerScreenshots>{this},
89 backingSurface = std::move(backingSurface),
90 windowIdentifier = mWindowIdentifier, originalSize = aOriginalSize,
91 scaledSize = aScaledSize, timeStamp = aTimeStamp]() {
92 // Create a new surface that wraps backingSurface's data but has the
93 // correct size.
94 DataSourceSurface::ScopedMap scopedMap(backingSurface,
95 DataSourceSurface::READ);
96 RefPtr<DataSourceSurface> surf =
97 Factory::CreateWrappingDataSourceSurface(
98 scopedMap.GetData(), scopedMap.GetStride(), scaledSize,
99 SurfaceFormat::B8G8R8A8);
101 // Encode surf to a JPEG data URL.
102 nsCString dataURL;
103 nsresult rv = gfxUtils::EncodeSourceSurface(
104 surf, ImageType::JPEG, u"quality=85"_ns, gfxUtils::eDataURIEncode,
105 nullptr, &dataURL);
106 if (NS_SUCCEEDED(rv)) {
107 // Add a marker with the data URL.
108 profiler_add_marker(
109 "CompositorScreenshot", geckoprofiler::category::GRAPHICS,
110 {MarkerThreadId::MainThread(),
111 MarkerTiming::InstantAt(timeStamp)},
112 ScreenshotMarker{}, dataURL, originalSize, windowIdentifier);
115 // Return backingSurface back to the surface pool.
116 self->ReturnSurface(backingSurface);
117 }));
120 already_AddRefed<DataSourceSurface> ProfilerScreenshots::TakeNextSurface() {
121 MutexAutoLock mon(mMutex);
122 if (!mAvailableSurfaces.IsEmpty()) {
123 RefPtr<DataSourceSurface> surf = mAvailableSurfaces[0];
124 mAvailableSurfaces.RemoveElementAt(0);
125 return surf.forget();
127 if (mLiveSurfaceCount >= 8) {
128 NS_WARNING(
129 "already 8 surfaces in flight, skipping capture for this composite");
130 return nullptr;
132 mLiveSurfaceCount++;
133 return Factory::CreateDataSourceSurface(ScreenshotSize(),
134 SurfaceFormat::B8G8R8A8);
137 void ProfilerScreenshots::ReturnSurface(DataSourceSurface* aSurface) {
138 MutexAutoLock mon(this->mMutex);
139 mAvailableSurfaces.AppendElement(aSurface);