summaryrefslogtreecommitdiffstats
path: root/gfx/layers/ProfilerScreenshots.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/layers/ProfilerScreenshots.cpp
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/layers/ProfilerScreenshots.cpp')
-rw-r--r--gfx/layers/ProfilerScreenshots.cpp139
1 files changed, 139 insertions, 0 deletions
diff --git a/gfx/layers/ProfilerScreenshots.cpp b/gfx/layers/ProfilerScreenshots.cpp
new file mode 100644
index 0000000000..648326150d
--- /dev/null
+++ b/gfx/layers/ProfilerScreenshots.cpp
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/layers/ProfilerScreenshots.h"
+
+#include "mozilla/TimeStamp.h"
+
+#include "GeckoProfiler.h"
+#include "gfxUtils.h"
+#include "nsThreadUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::layers;
+
+ProfilerScreenshots::ProfilerScreenshots()
+ : mMutex("ProfilerScreenshots::mMutex"), mLiveSurfaceCount(0) {}
+
+ProfilerScreenshots::~ProfilerScreenshots() = default;
+
+/* static */
+bool ProfilerScreenshots::IsEnabled() {
+#ifdef MOZ_GECKO_PROFILER
+ return profiler_feature_active(ProfilerFeature::Screenshots);
+#else
+ return false;
+#endif
+}
+
+void ProfilerScreenshots::SubmitScreenshot(
+ uintptr_t aWindowIdentifier, const gfx::IntSize& aOriginalSize,
+ const IntSize& aScaledSize, const TimeStamp& aTimeStamp,
+ const std::function<bool(DataSourceSurface*)>& aPopulateSurface) {
+#ifdef MOZ_GECKO_PROFILER
+ RefPtr<DataSourceSurface> backingSurface = TakeNextSurface();
+ if (!backingSurface) {
+ return;
+ }
+
+ MOZ_RELEASE_ASSERT(aScaledSize <= backingSurface->GetSize());
+
+ bool succeeded = aPopulateSurface(backingSurface);
+
+ if (!succeeded) {
+ PROFILER_MARKER_UNTYPED(
+ "NoCompositorScreenshot because aPopulateSurface callback failed",
+ GRAPHICS);
+ ReturnSurface(backingSurface);
+ return;
+ }
+
+ int sourceThread = profiler_current_thread_id();
+ uintptr_t windowIdentifier = aWindowIdentifier;
+ IntSize originalSize = aOriginalSize;
+ IntSize scaledSize = aScaledSize;
+ TimeStamp timeStamp = aTimeStamp;
+
+ RefPtr<ProfilerScreenshots> self = this;
+
+ NS_DispatchBackgroundTask(NS_NewRunnableFunction(
+ "ProfilerScreenshots::SubmitScreenshot",
+ [self{std::move(self)}, backingSurface, sourceThread, windowIdentifier,
+ originalSize, scaledSize, timeStamp]() {
+ // Create a new surface that wraps backingSurface's data but has the
+ // correct size.
+ if (profiler_can_accept_markers()) {
+ DataSourceSurface::ScopedMap scopedMap(backingSurface,
+ DataSourceSurface::READ);
+ RefPtr<DataSourceSurface> surf =
+ Factory::CreateWrappingDataSourceSurface(
+ scopedMap.GetData(), scopedMap.GetStride(), scaledSize,
+ SurfaceFormat::B8G8R8A8);
+
+ // Encode surf to a JPEG data URL.
+ nsCString dataURL;
+ nsresult rv = gfxUtils::EncodeSourceSurface(
+ surf, ImageType::JPEG, u"quality=85"_ns, gfxUtils::eDataURIEncode,
+ nullptr, &dataURL);
+ if (NS_SUCCEEDED(rv)) {
+ // Add a marker with the data URL.
+ struct ScreenshotMarker {
+ static constexpr mozilla::Span<const char> MarkerTypeName() {
+ return mozilla::MakeStringSpan("CompositorScreenshot");
+ }
+ static void StreamJSONMarkerData(
+ mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
+ const mozilla::ProfilerString8View& aScreenshotDataURL,
+ const mozilla::gfx::IntSize& aWindowSize,
+ uintptr_t aWindowIdentifier) {
+ aWriter.UniqueStringProperty("url", aScreenshotDataURL);
+
+ char hexWindowID[32];
+ SprintfLiteral(hexWindowID, "0x%" PRIXPTR, aWindowIdentifier);
+ aWriter.StringProperty("windowID", hexWindowID);
+ aWriter.DoubleProperty("windowWidth", aWindowSize.width);
+ aWriter.DoubleProperty("windowHeight", aWindowSize.height);
+ }
+ static mozilla::MarkerSchema MarkerTypeDisplay() {
+ return mozilla::MarkerSchema::SpecialFrontendLocation{};
+ }
+ };
+ profiler_add_marker(
+ "CompositorScreenshot", geckoprofiler::category::GRAPHICS,
+ {MarkerThreadId(sourceThread),
+ MarkerTiming::InstantAt(timeStamp)},
+ ScreenshotMarker{}, dataURL, originalSize, windowIdentifier);
+ }
+ }
+
+ // Return backingSurface back to the surface pool.
+ self->ReturnSurface(backingSurface);
+ }));
+#endif
+}
+
+already_AddRefed<DataSourceSurface> ProfilerScreenshots::TakeNextSurface() {
+ MutexAutoLock mon(mMutex);
+ if (!mAvailableSurfaces.IsEmpty()) {
+ RefPtr<DataSourceSurface> surf = mAvailableSurfaces[0];
+ mAvailableSurfaces.RemoveElementAt(0);
+ return surf.forget();
+ }
+ if (mLiveSurfaceCount >= 8) {
+ NS_WARNING(
+ "already 8 surfaces in flight, skipping capture for this composite");
+ return nullptr;
+ }
+ mLiveSurfaceCount++;
+ return Factory::CreateDataSourceSurface(ScreenshotSize(),
+ SurfaceFormat::B8G8R8A8);
+}
+
+void ProfilerScreenshots::ReturnSurface(DataSourceSurface* aSurface) {
+ MutexAutoLock mon(this->mMutex);
+ mAvailableSurfaces.AppendElement(aSurface);
+}