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"
18 class SourceSurfaceSharedData
;
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
;
39 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedDataWrapper
,
42 SourceSurfaceSharedDataWrapper()
45 mFormat(SurfaceFormat::UNKNOWN
),
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
;
74 bool AddConsumer() { return ++mConsumers
== 1; }
76 bool RemoveConsumer(bool aForCreator
) {
77 MOZ_ASSERT(mConsumers
> 0);
80 MOZ_ASSERT_UNREACHABLE("Already released creator reference!");
85 return --mConsumers
== 0;
88 uint32_t GetConsumers() const {
89 MOZ_ASSERT(mConsumers
> 0);
93 bool HasCreatorRef() const { return mCreatorRef
; }
95 nsExpirationState
* GetExpirationState() { return &mExpirationState
; }
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
;
114 RefPtr
<SharedMemoryBasic
> mBuf
;
115 SurfaceFormat mFormat
;
116 base::ProcessId mCreatorPid
;
121 * This class is used to wrap shared (as in process) data buffers used by a
124 class SourceSurfaceSharedData
: public DataSourceSurface
{
125 typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic
;
128 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedData
, override
)
130 SourceSurfaceSharedData()
131 : mMutex("SourceSurfaceSharedData"),
134 mFormat(SurfaceFormat::UNKNOWN
),
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
,
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
184 aMappedSurface
->mData
= GetDataInternal();
185 aMappedSurface
->mStride
= mStride
;
190 MutexAutoLock
lock(mMutex
);
191 MOZ_ASSERT(mMapCount
> 0);
192 if (--mMapCount
== 0) {
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
);
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
);
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
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
);
249 * Yields a dirty rect of what has changed since it was last called.
251 Maybe
<IntRect
> TakeDirtyRect() final
{
252 MutexAutoLock
lock(mMutex
);
254 Maybe
<IntRect
> ret
= std::move(mDirtyRect
);
261 * Increment the invalidation counter.
263 void Invalidate(const IntRect
& aDirtyRect
) final
{
264 MutexAutoLock
lock(mMutex
);
265 if (!aDirtyRect
.IsEmpty()) {
267 mDirtyRect
->UnionRect(mDirtyRect
.ref(), aDirtyRect
);
269 mDirtyRect
= Some(aDirtyRect
);
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
{
283 explicit HandleLock(SourceSurfaceSharedData
* aSurface
)
284 : mSurface(aSurface
) {
285 mSurface
->LockHandle();
288 ~HandleLock() { mSurface
->UnlockHandle(); }
291 RefPtr
<SourceSurfaceSharedData
> mSurface
;
295 virtual ~SourceSurfaceSharedData() = default;
298 friend class SourceSurfaceSharedDataWrapper
;
301 MutexAutoLock
lock(mMutex
);
305 void UnlockHandle() {
306 MutexAutoLock
lock(mMutex
);
307 MOZ_ASSERT(mHandleCount
> 0);
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
;
331 int32_t mHandleCount
;
332 Maybe
<IntRect
> mDirtyRect
;
334 RefPtr
<SharedMemoryBasic
> mBuf
;
335 RefPtr
<SharedMemoryBasic
> mOldBuf
;
336 SurfaceFormat mFormat
;
343 } // namespace mozilla
345 #endif /* MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_ */