tor-browser

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

ProfilerScreenshots.cpp (5033B)


      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/TimeStamp.h"
     10 
     11 #include "GeckoProfiler.h"
     12 #include "gfxUtils.h"
     13 #include "nsThreadUtils.h"
     14 
     15 using namespace mozilla;
     16 using namespace mozilla::gfx;
     17 using namespace mozilla::layers;
     18 
     19 struct ScreenshotMarker {
     20  static constexpr mozilla::Span<const char> MarkerTypeName() {
     21    return mozilla::MakeStringSpan("CompositorScreenshot");
     22  }
     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);
     29    }
     30 
     31    aWriter.IntProperty("windowID", aWindowIdentifier);
     32 
     33    if (!aWindowSize.IsEmpty()) {
     34      aWriter.DoubleProperty("windowWidth", aWindowSize.width);
     35      aWriter.DoubleProperty("windowHeight", aWindowSize.height);
     36    }
     37  }
     38  static mozilla::MarkerSchema MarkerTypeDisplay() {
     39    return mozilla::MarkerSchema::SpecialFrontendLocation{};
     40  }
     41 };
     42 
     43 uint32_t ProfilerScreenshots::sWindowCounter = 0;
     44 
     45 ProfilerScreenshots::ProfilerScreenshots()
     46    : mMutex("ProfilerScreenshots::mMutex"),
     47      mLiveSurfaceCount(0),
     48      mWindowIdentifier(++sWindowCounter) {}
     49 
     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);
     57  }
     58 }
     59 
     60 /* static */
     61 bool ProfilerScreenshots::IsEnabled() {
     62  return profiler_feature_active(ProfilerFeature::Screenshots);
     63 }
     64 
     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;
     72  }
     73 
     74  MOZ_RELEASE_ASSERT(aScaledSize <= backingSurface->GetSize());
     75 
     76  bool succeeded = aPopulateSurface(backingSurface);
     77 
     78  if (!succeeded) {
     79    PROFILER_MARKER_UNTYPED(
     80        "NoCompositorScreenshot because aPopulateSurface callback failed",
     81        GRAPHICS);
     82    ReturnSurface(backingSurface);
     83    return;
     84  }
     85 
     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);
    100 
    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);
    113        }
    114 
    115        // Return backingSurface back to the surface pool.
    116        self->ReturnSurface(backingSurface);
    117      }));
    118 }
    119 
    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();
    126  }
    127  if (mLiveSurfaceCount >= 8) {
    128    NS_WARNING(
    129        "already 8 surfaces in flight, skipping capture for this composite");
    130    return nullptr;
    131  }
    132  mLiveSurfaceCount++;
    133  return Factory::CreateDataSourceSurface(ScreenshotSize(),
    134                                          SurfaceFormat::B8G8R8A8);
    135 }
    136 
    137 void ProfilerScreenshots::ReturnSurface(DataSourceSurface* aSurface) {
    138  MutexAutoLock mon(this->mMutex);
    139  mAvailableSurfaces.AppendElement(aSurface);
    140 }