Bug 1632310 [wpt PR 23186] - Add test for computed versus resolved style., a=testonly
[gecko.git] / gfx / layers / SourceSurfaceSharedData.h
blobd86b37baff9185a2957bd37e34678094a31e43fc
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"
14 namespace mozilla {
15 namespace gfx {
17 class SourceSurfaceSharedData;
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.
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.
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.
34 class SourceSurfaceSharedDataWrapper final : public DataSourceSurface {
35 typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;
37 public:
38 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedDataWrapper,
39 override)
41 SourceSurfaceSharedDataWrapper()
42 : mStride(0),
43 mConsumers(0),
44 mFormat(SurfaceFormat::UNKNOWN),
45 mCreatorPid(0),
46 mCreatorRef(true) {}
48 bool Init(const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat,
49 const SharedMemoryBasic::Handle& aHandle,
50 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 { return SurfaceType::DATA; }
59 IntSize GetSize() const override { return mSize; }
60 SurfaceFormat GetFormat() const override { return mFormat; }
62 uint8_t* GetData() override { return static_cast<uint8_t*>(mBuf->memory()); }
64 bool OnHeap() const override { return false; }
66 bool AddConsumer() { return ++mConsumers == 1; }
68 bool RemoveConsumer(bool aForCreator) {
69 MOZ_ASSERT(mConsumers > 0);
70 if (aForCreator) {
71 if (!mCreatorRef) {
72 MOZ_ASSERT_UNREACHABLE("Already released creator reference!");
73 return false;
75 mCreatorRef = false;
77 return --mConsumers == 0;
80 uint32_t GetConsumers() const {
81 MOZ_ASSERT(mConsumers > 0);
82 return mConsumers;
85 bool HasCreatorRef() const { return mCreatorRef; }
87 private:
88 size_t GetDataLength() const {
89 return static_cast<size_t>(mStride) * mSize.height;
92 size_t GetAlignedDataLength() const {
93 return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
96 int32_t mStride;
97 uint32_t mConsumers;
98 IntSize mSize;
99 RefPtr<SharedMemoryBasic> mBuf;
100 SurfaceFormat mFormat;
101 base::ProcessId mCreatorPid;
102 bool mCreatorRef;
106 * This class is used to wrap shared (as in process) data buffers used by a
107 * source surface.
109 class SourceSurfaceSharedData final : public DataSourceSurface {
110 typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;
112 public:
113 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedData, override)
115 SourceSurfaceSharedData()
116 : mMutex("SourceSurfaceSharedData"),
117 mStride(0),
118 mHandleCount(0),
119 mFormat(SurfaceFormat::UNKNOWN),
120 mClosed(false),
121 mFinalized(false),
122 mShared(false) {}
125 * Initialize the surface by creating a shared memory buffer with a size
126 * determined by aSize, aStride and aFormat. If aShare is true, it will also
127 * immediately attempt to share the surface with the GPU process via
128 * SharedSurfacesChild.
130 bool Init(const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat,
131 bool aShare = true);
133 uint8_t* GetData() override {
134 MutexAutoLock lock(mMutex);
135 return GetDataInternal();
138 int32_t Stride() override { return mStride; }
140 SurfaceType GetType() const override { return SurfaceType::DATA_SHARED; }
141 IntSize GetSize() const override { return mSize; }
142 SurfaceFormat GetFormat() const override { return mFormat; }
144 void GuaranteePersistance() override;
146 void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
147 SizeOfInfo& aInfo) const override;
149 bool OnHeap() const override { return false; }
152 * Although Map (and Moz2D in general) isn't normally threadsafe,
153 * we want to allow it for SourceSurfaceSharedData since it should
154 * always be fine (for reading at least).
156 * This is the same as the base class implementation except using
157 * mMapCount instead of mIsMapped since that breaks for multithread.
159 * Additionally if a reallocation happened while there were active
160 * mappings, then we guarantee that GetData will continue to return
161 * the same data pointer by retaining the old shared buffer until
162 * the last mapping is freed via Unmap.
164 bool Map(MapType, MappedSurface* aMappedSurface) override {
165 MutexAutoLock lock(mMutex);
166 ++mMapCount;
167 aMappedSurface->mData = GetDataInternal();
168 aMappedSurface->mStride = mStride;
169 return true;
172 void Unmap() override {
173 MutexAutoLock lock(mMutex);
174 MOZ_ASSERT(mMapCount > 0);
175 if (--mMapCount == 0) {
176 mOldBuf = nullptr;
181 * Get a handle to share to another process for this buffer. Returns:
182 * NS_OK -- success, aHandle is valid.
183 * NS_ERROR_NOT_AVAILABLE -- handle was closed, need to reallocate.
184 * NS_ERROR_FAILURE -- failed to create a handle to share.
186 nsresult ShareToProcess(base::ProcessId aPid,
187 SharedMemoryBasic::Handle& aHandle);
190 * Indicates the buffer is not expected to be shared with any more processes.
191 * May release the handle if possible (see CloseHandleInternal).
193 void FinishedSharing() {
194 MutexAutoLock lock(mMutex);
195 mShared = true;
196 CloseHandleInternal();
200 * Indicates whether or not the buffer can be shared with another process
201 * without reallocating. Note that this is racy and should only be used for
202 * informational/reporting purposes.
204 bool CanShare() const {
205 MutexAutoLock lock(mMutex);
206 return !mClosed;
210 * Allocate a new shared memory buffer so that we can get a new handle for
211 * sharing to new processes. ShareToProcess must have failed with
212 * NS_ERROR_NOT_AVAILABLE in order for this to be safe to call. Returns true
213 * if the operation succeeds. If it fails, there is no state change.
215 bool ReallocHandle();
218 * Signals we have finished writing to the buffer and it may be marked as
219 * read only.
221 void Finalize();
224 * Indicates whether or not the buffer can change. If this returns true, it is
225 * guaranteed to continue to do so for the remainder of the surface's life.
227 bool IsFinalized() const {
228 MutexAutoLock lock(mMutex);
229 return mFinalized;
233 * Yields a dirty rect of what has changed since it was last called.
235 Maybe<IntRect> TakeDirtyRect() override {
236 MutexAutoLock lock(mMutex);
237 if (mDirtyRect) {
238 Maybe<IntRect> ret = std::move(mDirtyRect);
239 return ret;
241 return Nothing();
245 * Increment the invalidation counter.
247 void Invalidate(const IntRect& aDirtyRect) override {
248 MutexAutoLock lock(mMutex);
249 if (!aDirtyRect.IsEmpty()) {
250 if (mDirtyRect) {
251 mDirtyRect->UnionRect(mDirtyRect.ref(), aDirtyRect);
252 } else {
253 mDirtyRect = Some(aDirtyRect);
255 } else {
256 mDirtyRect = Some(IntRect(IntPoint(0, 0), mSize));
258 MOZ_ASSERT_IF(mDirtyRect, !mDirtyRect->IsEmpty());
262 * While a HandleLock exists for the given surface, the shared memory handle
263 * cannot be released.
265 class MOZ_STACK_CLASS HandleLock final {
266 public:
267 explicit HandleLock(SourceSurfaceSharedData* aSurface)
268 : mSurface(aSurface) {
269 mSurface->LockHandle();
272 ~HandleLock() { mSurface->UnlockHandle(); }
274 private:
275 RefPtr<SourceSurfaceSharedData> mSurface;
278 private:
279 friend class SourceSurfaceSharedDataWrapper;
281 virtual ~SourceSurfaceSharedData() = default;
283 void LockHandle() {
284 MutexAutoLock lock(mMutex);
285 ++mHandleCount;
288 void UnlockHandle() {
289 MutexAutoLock lock(mMutex);
290 MOZ_ASSERT(mHandleCount > 0);
291 --mHandleCount;
292 mShared = true;
293 CloseHandleInternal();
296 uint8_t* GetDataInternal() const;
298 size_t GetDataLength() const {
299 return static_cast<size_t>(mStride) * mSize.height;
302 size_t GetAlignedDataLength() const {
303 return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
307 * Attempt to close the handle. Only if the buffer has been both finalized
308 * and we have completed sharing will it be released.
310 void CloseHandleInternal();
312 mutable Mutex mMutex;
313 int32_t mStride;
314 int32_t mHandleCount;
315 Maybe<IntRect> mDirtyRect;
316 IntSize mSize;
317 RefPtr<SharedMemoryBasic> mBuf;
318 RefPtr<SharedMemoryBasic> mOldBuf;
319 SurfaceFormat mFormat;
320 bool mClosed : 1;
321 bool mFinalized : 1;
322 bool mShared : 1;
325 } // namespace gfx
326 } // namespace mozilla
328 #endif /* MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_ */