Bug 1839315: part 4) Link from `SheetLoadData::mWasAlternate` to spec. r=emilio DONTBUILD
[gecko.git] / gfx / layers / SourceSurfaceSharedData.h
blob73743a839dbf16b82b95645730f463f529104462
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/. */
7 #ifndef MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_
8 #define MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_
10 #include "mozilla/gfx/2D.h"
11 #include "mozilla/Mutex.h"
12 #include "mozilla/ipc/SharedMemoryBasic.h"
13 #include "nsExpirationTracker.h"
15 namespace mozilla {
16 namespace gfx {
18 class SourceSurfaceSharedData;
20 /**
21 * This class is used to wrap shared (as in process) data buffers allocated by
22 * a SourceSurfaceSharedData object. It may live in the same process or a
23 * different process from the actual SourceSurfaceSharedData object.
25 * If it is in the same process, mBuf is the same object as that in the surface.
26 * It is a useful abstraction over just using the surface directly, because it
27 * can have a different lifetime from the surface; if the surface gets freed,
28 * consumers may continue accessing the data in the buffer. Releasing the
29 * original surface is a signal which feeds into SharedSurfacesParent to decide
30 * to release the SourceSurfaceSharedDataWrapper.
32 * If it is in a different process, mBuf is a new SharedMemoryBasic object which
33 * mapped in the given shared memory handle as read only memory.
35 class SourceSurfaceSharedDataWrapper final : public DataSourceSurface {
36 typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;
38 public:
39 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedDataWrapper,
40 override)
42 SourceSurfaceSharedDataWrapper()
43 : mStride(0),
44 mConsumers(0),
45 mFormat(SurfaceFormat::UNKNOWN),
46 mCreatorPid(0),
47 mCreatorRef(true) {}
49 void Init(const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat,
50 SharedMemoryBasic::Handle aHandle, base::ProcessId aCreatorPid);
52 void Init(SourceSurfaceSharedData* aSurface);
54 base::ProcessId GetCreatorPid() const { return mCreatorPid; }
56 int32_t Stride() override { return mStride; }
58 SurfaceType GetType() const override {
59 return SurfaceType::DATA_SHARED_WRAPPER;
61 IntSize GetSize() const override { return mSize; }
62 SurfaceFormat GetFormat() const override { return mFormat; }
64 uint8_t* GetData() override { return static_cast<uint8_t*>(mBuf->memory()); }
66 bool OnHeap() const override { return false; }
68 bool Map(MapType aMapType, MappedSurface* aMappedSurface) final;
70 void Unmap() final;
72 void ExpireMap();
74 bool AddConsumer() { return ++mConsumers == 1; }
76 bool RemoveConsumer(bool aForCreator) {
77 MOZ_ASSERT(mConsumers > 0);
78 if (aForCreator) {
79 if (!mCreatorRef) {
80 MOZ_ASSERT_UNREACHABLE("Already released creator reference!");
81 return false;
83 mCreatorRef = false;
85 return --mConsumers == 0;
88 uint32_t GetConsumers() const {
89 MOZ_ASSERT(mConsumers > 0);
90 return mConsumers;
93 bool HasCreatorRef() const { return mCreatorRef; }
95 nsExpirationState* GetExpirationState() { return &mExpirationState; }
97 private:
98 size_t GetDataLength() const {
99 return static_cast<size_t>(mStride) * mSize.height;
102 size_t GetAlignedDataLength() const {
103 return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
106 bool EnsureMapped(size_t aLength);
108 // Protects mapping and unmapping of mBuf.
109 Maybe<Mutex> mHandleLock;
110 nsExpirationState mExpirationState;
111 int32_t mStride;
112 uint32_t mConsumers;
113 IntSize mSize;
114 RefPtr<SharedMemoryBasic> mBuf;
115 SurfaceFormat mFormat;
116 base::ProcessId mCreatorPid;
117 bool mCreatorRef;
121 * This class is used to wrap shared (as in process) data buffers used by a
122 * source surface.
124 class SourceSurfaceSharedData : public DataSourceSurface {
125 typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;
127 public:
128 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedData, override)
130 SourceSurfaceSharedData()
131 : mMutex("SourceSurfaceSharedData"),
132 mStride(0),
133 mHandleCount(0),
134 mFormat(SurfaceFormat::UNKNOWN),
135 mClosed(false),
136 mFinalized(false),
137 mShared(false) {}
140 * Initialize the surface by creating a shared memory buffer with a size
141 * determined by aSize, aStride and aFormat. If aShare is true, it will also
142 * immediately attempt to share the surface with the GPU process via
143 * SharedSurfacesChild.
145 bool Init(const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat,
146 bool aShare = true);
148 uint8_t* GetData() final {
149 MutexAutoLock lock(mMutex);
150 return GetDataInternal();
153 int32_t Stride() final { return mStride; }
155 SurfaceType GetType() const override { return SurfaceType::DATA_SHARED; }
156 IntSize GetSize() const final { return mSize; }
157 SurfaceFormat GetFormat() const final { return mFormat; }
159 void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
160 SizeOfInfo& aInfo) const final;
162 bool OnHeap() const final { return false; }
165 * Although Map (and Moz2D in general) isn't normally threadsafe,
166 * we want to allow it for SourceSurfaceSharedData since it should
167 * always be fine (for reading at least).
169 * This is the same as the base class implementation except using
170 * mMapCount instead of mIsMapped since that breaks for multithread.
172 * Additionally if a reallocation happened while there were active
173 * mappings, then we guarantee that GetData will continue to return
174 * the same data pointer by retaining the old shared buffer until
175 * the last mapping is freed via Unmap.
177 bool Map(MapType aMapType, MappedSurface* aMappedSurface) final {
178 MutexAutoLock lock(mMutex);
179 if (mFinalized && aMapType != MapType::READ) {
180 // Once finalized the data may be write-protected
181 return false;
183 ++mMapCount;
184 aMappedSurface->mData = GetDataInternal();
185 aMappedSurface->mStride = mStride;
186 return true;
189 void Unmap() final {
190 MutexAutoLock lock(mMutex);
191 MOZ_ASSERT(mMapCount > 0);
192 if (--mMapCount == 0) {
193 mOldBuf = nullptr;
198 * Get a handle to share to another process for this buffer. Returns:
199 * NS_OK -- success, aHandle is valid.
200 * NS_ERROR_NOT_AVAILABLE -- handle was closed, need to reallocate.
201 * NS_ERROR_FAILURE -- failed to create a handle to share.
203 nsresult CloneHandle(SharedMemoryBasic::Handle& aHandle);
206 * Indicates the buffer is not expected to be shared with any more processes.
207 * May release the handle if possible (see CloseHandleInternal).
209 void FinishedSharing() {
210 MutexAutoLock lock(mMutex);
211 mShared = true;
212 CloseHandleInternal();
216 * Indicates whether or not the buffer can be shared with another process
217 * without reallocating. Note that this is racy and should only be used for
218 * informational/reporting purposes.
220 bool CanShare() const {
221 MutexAutoLock lock(mMutex);
222 return !mClosed;
226 * Allocate a new shared memory buffer so that we can get a new handle for
227 * sharing to new processes. CloneHandle must have failed with
228 * NS_ERROR_NOT_AVAILABLE in order for this to be safe to call. Returns true
229 * if the operation succeeds. If it fails, there is no state change.
231 bool ReallocHandle();
234 * Signals we have finished writing to the buffer and it may be marked as
235 * read only.
237 void Finalize();
240 * Indicates whether or not the buffer can change. If this returns true, it is
241 * guaranteed to continue to do so for the remainder of the surface's life.
243 bool IsFinalized() const {
244 MutexAutoLock lock(mMutex);
245 return mFinalized;
249 * Yields a dirty rect of what has changed since it was last called.
251 Maybe<IntRect> TakeDirtyRect() final {
252 MutexAutoLock lock(mMutex);
253 if (mDirtyRect) {
254 Maybe<IntRect> ret = std::move(mDirtyRect);
255 return ret;
257 return Nothing();
261 * Increment the invalidation counter.
263 void Invalidate(const IntRect& aDirtyRect) final {
264 MutexAutoLock lock(mMutex);
265 if (!aDirtyRect.IsEmpty()) {
266 if (mDirtyRect) {
267 mDirtyRect->UnionRect(mDirtyRect.ref(), aDirtyRect);
268 } else {
269 mDirtyRect = Some(aDirtyRect);
271 } else {
272 mDirtyRect = Some(IntRect(IntPoint(0, 0), mSize));
274 MOZ_ASSERT_IF(mDirtyRect, !mDirtyRect->IsEmpty());
278 * While a HandleLock exists for the given surface, the shared memory handle
279 * cannot be released.
281 class MOZ_STACK_CLASS HandleLock final {
282 public:
283 explicit HandleLock(SourceSurfaceSharedData* aSurface)
284 : mSurface(aSurface) {
285 mSurface->LockHandle();
288 ~HandleLock() { mSurface->UnlockHandle(); }
290 private:
291 RefPtr<SourceSurfaceSharedData> mSurface;
294 protected:
295 virtual ~SourceSurfaceSharedData() = default;
297 private:
298 friend class SourceSurfaceSharedDataWrapper;
300 void LockHandle() {
301 MutexAutoLock lock(mMutex);
302 ++mHandleCount;
305 void UnlockHandle() {
306 MutexAutoLock lock(mMutex);
307 MOZ_ASSERT(mHandleCount > 0);
308 --mHandleCount;
309 mShared = true;
310 CloseHandleInternal();
313 uint8_t* GetDataInternal() const;
315 size_t GetDataLength() const {
316 return static_cast<size_t>(mStride) * mSize.height;
319 size_t GetAlignedDataLength() const {
320 return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
324 * Attempt to close the handle. Only if the buffer has been both finalized
325 * and we have completed sharing will it be released.
327 void CloseHandleInternal();
329 mutable Mutex mMutex MOZ_UNANNOTATED;
330 int32_t mStride;
331 int32_t mHandleCount;
332 Maybe<IntRect> mDirtyRect;
333 IntSize mSize;
334 RefPtr<SharedMemoryBasic> mBuf;
335 RefPtr<SharedMemoryBasic> mOldBuf;
336 SurfaceFormat mFormat;
337 bool mClosed : 1;
338 bool mFinalized : 1;
339 bool mShared : 1;
342 } // namespace gfx
343 } // namespace mozilla
345 #endif /* MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_ */