DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (014c61389f0b)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
/* -*- 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/SystemGroup.h"
#include "mozilla/TimeStamp.h"

#include "GeckoProfiler.h"
#include "gfxUtils.h"
#include "nsThreadUtils.h"
#ifdef MOZ_GECKO_PROFILER
#  include "ProfilerMarkerPayload.h"
#endif

using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;

ProfilerScreenshots::ProfilerScreenshots()
    : mMutex("ProfilerScreenshots::mMutex"), mLiveSurfaceCount(0) {}

ProfilerScreenshots::~ProfilerScreenshots() {}

/* 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_ADD_MARKER(
        "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_DispatchToBackgroundThread(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, NS_LITERAL_STRING("quality=85"),
              gfxUtils::eDataURIEncode, nullptr, &dataURL);
          if (NS_SUCCEEDED(rv)) {
            // Add a marker with the data URL.
            AUTO_PROFILER_STATS(add_marker_with_ScreenshotPayload);
            profiler_add_marker_for_thread(
                sourceThread, JS::ProfilingCategoryPair::GRAPHICS,
                "CompositorScreenshot",
                MakeUnique<ScreenshotPayload>(timeStamp, std::move(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);
}