Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/ProfilerScreenshots.cpp
Line
Count
Source (jump to first uncovered line)
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
#ifdef MOZ_GECKO_PROFILER
15
#include "ProfilerMarkerPayload.h"
16
#endif
17
18
using namespace mozilla;
19
using namespace mozilla::layers;
20
21
ProfilerScreenshots::ProfilerScreenshots()
22
  : mMutex("ProfilerScreenshots::mMutex")
23
  , mLiveSurfaceCount(0)
24
0
{
25
0
}
26
27
ProfilerScreenshots::~ProfilerScreenshots()
28
0
{
29
0
  if (mThread) {
30
0
    mThread->Shutdown();
31
0
    mThread = nullptr;
32
0
  }
33
0
}
34
35
/* static */ bool
36
ProfilerScreenshots::IsEnabled()
37
0
{
38
0
#ifdef MOZ_GECKO_PROFILER
39
0
  return profiler_feature_active(ProfilerFeature::Screenshots);
40
#else
41
  return false;
42
#endif
43
}
44
45
void
46
ProfilerScreenshots::SubmitScreenshot(uintptr_t aWindowIdentifier,
47
                                      const gfx::IntSize& aOriginalSize,
48
                                      const IntSize& aScaledSize,
49
                                      const TimeStamp& aTimeStamp,
50
                                      const std::function<bool(DataSourceSurface*)>& aPopulateSurface)
51
0
{
52
0
#ifdef MOZ_GECKO_PROFILER
53
0
  RefPtr<DataSourceSurface> backingSurface = TakeNextSurface();
54
0
  if (!backingSurface) {
55
0
    return;
56
0
  }
57
0
58
0
  MOZ_RELEASE_ASSERT(aScaledSize <= backingSurface->GetSize());
59
0
60
0
  bool succeeded = aPopulateSurface(backingSurface);
61
0
62
0
  if (!succeeded) {
63
0
    PROFILER_ADD_MARKER("NoCompositorScreenshot because aPopulateSurface callback failed");
64
0
    ReturnSurface(backingSurface);
65
0
    return;
66
0
  }
67
0
68
0
  if (!mThread) {
69
0
    nsresult rv =
70
0
      NS_NewNamedThread("ProfScreenshot", getter_AddRefs(mThread));
71
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
72
0
      PROFILER_ADD_MARKER("NoCompositorScreenshot because ProfilerScreenshots thread creation failed");
73
0
      ReturnSurface(backingSurface);
74
0
      return;
75
0
    }
76
0
  }
77
0
78
0
  int sourceThread = profiler_current_thread_id();
79
0
  uintptr_t windowIdentifier = aWindowIdentifier;
80
0
  IntSize originalSize = aOriginalSize;
81
0
  IntSize scaledSize = aScaledSize;
82
0
  TimeStamp timeStamp = aTimeStamp;
83
0
84
0
  mThread->Dispatch(
85
0
    NS_NewRunnableFunction("ProfilerScreenshots::SubmitScreenshot",
86
0
                           [this, backingSurface, sourceThread, windowIdentifier,
87
0
                            originalSize, scaledSize, timeStamp]() {
88
0
    // Create a new surface that wraps backingSurface's data but has the correct
89
0
    // size.
90
0
    {
91
0
      DataSourceSurface::ScopedMap scopedMap(backingSurface, DataSourceSurface::READ);
92
0
      RefPtr<DataSourceSurface> surf =
93
0
        Factory::CreateWrappingDataSourceSurface(
94
0
          scopedMap.GetData(), scopedMap.GetStride(), scaledSize, SurfaceFormat::B8G8R8A8);
95
0
96
0
      // Encode surf to a JPEG data URL.
97
0
      nsCString dataURL;
98
0
      nsresult rv =
99
0
        gfxUtils::EncodeSourceSurface(surf, NS_LITERAL_CSTRING("image/jpeg"),
100
0
                                      NS_LITERAL_STRING("quality=85"),
101
0
                                      gfxUtils::eDataURIEncode,
102
0
                                      nullptr, &dataURL);
103
0
      if (NS_SUCCEEDED(rv)) {
104
0
        // Add a marker with the data URL.
105
0
        profiler_add_marker_for_thread(
106
0
          sourceThread,
107
0
          "CompositorScreenshot",
108
0
          MakeUnique<ScreenshotPayload>(timeStamp, std::move(dataURL),
109
0
                                        originalSize, windowIdentifier));
110
0
      }
111
0
    }
112
0
113
0
    // Return backingSurface back to the surface pool.
114
0
    ReturnSurface(backingSurface);
115
0
  }));
116
0
#endif
117
0
}
118
119
already_AddRefed<DataSourceSurface>
120
ProfilerScreenshots::TakeNextSurface()
121
0
{
122
0
  MutexAutoLock mon(mMutex);
123
0
  if (!mAvailableSurfaces.IsEmpty()) {
124
0
    RefPtr<DataSourceSurface> surf = mAvailableSurfaces[0];
125
0
    mAvailableSurfaces.RemoveElementAt(0);
126
0
    return surf.forget();
127
0
  }
128
0
  if (mLiveSurfaceCount >= 8) {
129
0
    NS_WARNING("already 8 surfaces in flight, skipping capture for this composite");
130
0
    return nullptr;
131
0
  }
132
0
  mLiveSurfaceCount++;
133
0
  return Factory::CreateDataSourceSurface(ScreenshotSize(),
134
0
                                          SurfaceFormat::B8G8R8A8);
135
0
}
136
137
void
138
ProfilerScreenshots::ReturnSurface(DataSourceSurface* aSurface)
139
0
{
140
0
  MutexAutoLock mon(this->mMutex);
141
0
  mAvailableSurfaces.AppendElement(aSurface);
142
0
}