Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/SourceSurfaceSharedData.h
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
#ifndef MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_
8
#define MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_
9
10
#include "mozilla/gfx/2D.h"
11
#include "mozilla/Mutex.h"
12
#include "mozilla/ipc/SharedMemoryBasic.h"
13
14
namespace mozilla {
15
namespace gfx {
16
17
class SourceSurfaceSharedData;
18
19
/**
20
 * This class is used to wrap shared (as in process) data buffers allocated by
21
 * a SourceSurfaceSharedData object. It may live in the same process or a
22
 * different process from the actual SourceSurfaceSharedData object.
23
 *
24
 * If it is in the same process, mBuf is the same object as that in the surface.
25
 * It is a useful abstraction over just using the surface directly, because it
26
 * can have a different lifetime from the surface; if the surface gets freed,
27
 * consumers may continue accessing the data in the buffer. Releasing the
28
 * original surface is a signal which feeds into SharedSurfacesParent to decide
29
 * to release the SourceSurfaceSharedDataWrapper.
30
 *
31
 * If it is in a different process, mBuf is a new SharedMemoryBasic object which
32
 * mapped in the given shared memory handle as read only memory.
33
 */
34
class SourceSurfaceSharedDataWrapper final : public DataSourceSurface
35
{
36
  typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;
37
38
public:
39
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedDataWrapper, override)
40
41
  SourceSurfaceSharedDataWrapper()
42
    : mStride(0)
43
    , mConsumers(0)
44
    , mFormat(SurfaceFormat::UNKNOWN)
45
    , mCreatorPid(0)
46
  { }
47
48
  bool Init(const IntSize& aSize,
49
            int32_t aStride,
50
            SurfaceFormat aFormat,
51
            const SharedMemoryBasic::Handle& aHandle,
52
            base::ProcessId aCreatorPid);
53
54
  void Init(SourceSurfaceSharedData *aSurface);
55
56
  base::ProcessId GetCreatorPid() const
57
  {
58
    return mCreatorPid;
59
  }
60
61
  int32_t Stride() override { return mStride; }
62
63
  SurfaceType GetType() const override { return SurfaceType::DATA; }
64
  IntSize GetSize() const override { return mSize; }
65
  SurfaceFormat GetFormat() const override { return mFormat; }
66
67
  uint8_t* GetData() override
68
  {
69
    return static_cast<uint8_t*>(mBuf->memory());
70
  }
71
72
  bool OnHeap() const override
73
  {
74
    return false;
75
  }
76
77
  bool AddConsumer()
78
  {
79
    return ++mConsumers == 1;
80
  }
81
82
  bool RemoveConsumer()
83
  {
84
    MOZ_ASSERT(mConsumers > 0);
85
    return --mConsumers == 0;
86
  }
87
88
private:
89
  size_t GetDataLength() const
90
0
  {
91
0
    return static_cast<size_t>(mStride) * mSize.height;
92
0
  }
93
94
  size_t GetAlignedDataLength() const
95
0
  {
96
0
    return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
97
0
  }
98
99
  int32_t mStride;
100
  uint32_t mConsumers;
101
  IntSize mSize;
102
  RefPtr<SharedMemoryBasic> mBuf;
103
  SurfaceFormat mFormat;
104
  base::ProcessId mCreatorPid;
105
};
106
107
/**
108
 * This class is used to wrap shared (as in process) data buffers used by a
109
 * source surface.
110
 */
111
class SourceSurfaceSharedData final : public DataSourceSurface
112
{
113
  typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;
114
115
public:
116
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedData, override)
117
118
  SourceSurfaceSharedData()
119
    : mMutex("SourceSurfaceSharedData")
120
    , mStride(0)
121
    , mMapCount(0)
122
    , mHandleCount(0)
123
    , mFormat(SurfaceFormat::UNKNOWN)
124
    , mClosed(false)
125
    , mFinalized(false)
126
    , mShared(false)
127
  {
128
  }
129
130
  /**
131
   * Initialize the surface by creating a shared memory buffer with a size
132
   * determined by aSize, aStride and aFormat. If aShare is true, it will also
133
   * immediately attempt to share the surface with the GPU process via
134
   * SharedSurfacesChild.
135
   */
136
  bool Init(const IntSize& aSize,
137
            int32_t aStride,
138
            SurfaceFormat aFormat,
139
            bool aShare = true);
140
141
  uint8_t* GetData() override
142
0
  {
143
0
    MutexAutoLock lock(mMutex);
144
0
    return GetDataInternal();
145
0
  }
146
147
0
  int32_t Stride() override { return mStride; }
148
149
0
  SurfaceType GetType() const override { return SurfaceType::DATA_SHARED; }
150
0
  IntSize GetSize() const override { return mSize; }
151
0
  SurfaceFormat GetFormat() const override { return mFormat; }
152
153
  void GuaranteePersistance() override;
154
155
  void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
156
                              size_t& aHeapSizeOut,
157
                              size_t& aNonHeapSizeOut,
158
                              size_t& aExtHandlesOut) const override;
159
160
  bool OnHeap() const override
161
0
  {
162
0
    return false;
163
0
  }
164
165
  /**
166
   * Although Map (and Moz2D in general) isn't normally threadsafe,
167
   * we want to allow it for SourceSurfaceSharedData since it should
168
   * always be fine (for reading at least).
169
   *
170
   * This is the same as the base class implementation except using
171
   * mMapCount instead of mIsMapped since that breaks for multithread.
172
   *
173
   * Additionally if a reallocation happened while there were active
174
   * mappings, then we guarantee that GetData will continue to return
175
   * the same data pointer by retaining the old shared buffer until
176
   * the last mapping is freed via Unmap.
177
   */
178
  bool Map(MapType, MappedSurface *aMappedSurface) override
179
0
  {
180
0
    MutexAutoLock lock(mMutex);
181
0
    ++mMapCount;
182
0
    aMappedSurface->mData = GetDataInternal();
183
0
    aMappedSurface->mStride = mStride;
184
0
    return true;
185
0
  }
186
187
  void Unmap() override
188
0
  {
189
0
    MutexAutoLock lock(mMutex);
190
0
    MOZ_ASSERT(mMapCount > 0);
191
0
    if (--mMapCount == 0) {
192
0
      mOldBuf = nullptr;
193
0
    }
194
0
  }
195
196
  /**
197
   * Get a handle to share to another process for this buffer. Returns:
198
   *   NS_OK -- success, aHandle is valid.
199
   *   NS_ERROR_NOT_AVAILABLE -- handle was closed, need to reallocate.
200
   *   NS_ERROR_FAILURE -- failed to create a handle to share.
201
   */
202
  nsresult ShareToProcess(base::ProcessId aPid,
203
                          SharedMemoryBasic::Handle& aHandle);
204
205
  /**
206
   * Indicates the buffer is not expected to be shared with any more processes.
207
   * May release the handle if possible (see CloseHandleInternal).
208
   */
209
  void FinishedSharing()
210
  {
211
    MutexAutoLock lock(mMutex);
212
    mShared = true;
213
    CloseHandleInternal();
214
  }
215
216
  /**
217
   * Indicates whether or not the buffer can be shared with another process
218
   * without reallocating. Note that this is racy and should only be used for
219
   * informational/reporting purposes.
220
   */
221
  bool CanShare() const
222
0
  {
223
0
    MutexAutoLock lock(mMutex);
224
0
    return !mClosed;
225
0
  }
226
227
  /**
228
   * Allocate a new shared memory buffer so that we can get a new handle for
229
   * sharing to new processes. ShareToProcess must have failed with
230
   * NS_ERROR_NOT_AVAILABLE in order for this to be safe to call. Returns true
231
   * if the operation succeeds. If it fails, there is no state change.
232
   */
233
  bool ReallocHandle();
234
235
  /**
236
   * Signals we have finished writing to the buffer and it may be marked as
237
   * read only.
238
   */
239
  void Finalize();
240
241
  /**
242
   * Indicates whether or not the buffer can change. If this returns true, it is
243
   * guaranteed to continue to do so for the remainder of the surface's life.
244
   */
245
  bool IsFinalized() const
246
0
  {
247
0
    MutexAutoLock lock(mMutex);
248
0
    return mFinalized;
249
0
  }
250
251
  /**
252
   * Yields a dirty rect of what has changed since it was last called.
253
   */
254
  Maybe<IntRect> TakeDirtyRect() override
255
0
  {
256
0
    MutexAutoLock lock(mMutex);
257
0
    if (mDirtyRect) {
258
0
      Maybe<IntRect> ret = std::move(mDirtyRect);
259
0
      return ret;
260
0
    }
261
0
    return Nothing();
262
0
  }
263
264
  /**
265
   * Increment the invalidation counter.
266
   */
267
  void Invalidate(const IntRect& aDirtyRect) override
268
0
  {
269
0
    MutexAutoLock lock(mMutex);
270
0
    if (!aDirtyRect.IsEmpty()) {
271
0
      if (mDirtyRect) {
272
0
        mDirtyRect->UnionRect(mDirtyRect.ref(), aDirtyRect);
273
0
      } else {
274
0
        mDirtyRect = Some(aDirtyRect);
275
0
      }
276
0
    } else {
277
0
      mDirtyRect = Some(IntRect(IntPoint(0, 0), mSize));
278
0
    }
279
0
    MOZ_ASSERT_IF(mDirtyRect, !mDirtyRect->IsEmpty());
280
0
  }
281
282
  /**
283
   * While a HandleLock exists for the given surface, the shared memory handle
284
   * cannot be released.
285
   */
286
  class MOZ_STACK_CLASS HandleLock final {
287
  public:
288
    explicit HandleLock(SourceSurfaceSharedData* aSurface)
289
      : mSurface(aSurface)
290
    {
291
      mSurface->LockHandle();
292
    }
293
294
    ~HandleLock()
295
    {
296
      mSurface->UnlockHandle();
297
    }
298
299
  private:
300
    RefPtr<SourceSurfaceSharedData> mSurface;
301
  };
302
303
private:
304
  friend class SourceSurfaceSharedDataWrapper;
305
306
  ~SourceSurfaceSharedData() override
307
0
  {
308
0
    MOZ_ASSERT(mMapCount == 0);
309
0
  }
310
311
  void LockHandle()
312
  {
313
    MutexAutoLock lock(mMutex);
314
    ++mHandleCount;
315
  }
316
317
  void UnlockHandle()
318
  {
319
    MutexAutoLock lock(mMutex);
320
    MOZ_ASSERT(mHandleCount > 0);
321
    --mHandleCount;
322
    mShared = true;
323
    CloseHandleInternal();
324
  }
325
326
  uint8_t* GetDataInternal() const;
327
328
  size_t GetDataLength() const
329
0
  {
330
0
    return static_cast<size_t>(mStride) * mSize.height;
331
0
  }
332
333
  size_t GetAlignedDataLength() const
334
0
  {
335
0
    return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
336
0
  }
337
338
  /**
339
   * Attempt to close the handle. Only if the buffer has been both finalized
340
   * and we have completed sharing will it be released.
341
   */
342
  void CloseHandleInternal();
343
344
  mutable Mutex mMutex;
345
  int32_t mStride;
346
  int32_t mMapCount;
347
  int32_t mHandleCount;
348
  Maybe<IntRect> mDirtyRect;
349
  IntSize mSize;
350
  RefPtr<SharedMemoryBasic> mBuf;
351
  RefPtr<SharedMemoryBasic> mOldBuf;
352
  SurfaceFormat mFormat;
353
  bool mClosed : 1;
354
  bool mFinalized : 1;
355
  bool mShared : 1;
356
};
357
358
} // namespace gfx
359
} // namespace mozilla
360
361
#endif /* MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_ */