/src/mozilla-central/gfx/layers/SourceSurfaceSharedData.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 "SourceSurfaceSharedData.h" |
8 | | |
9 | | #include "mozilla/Likely.h" |
10 | | #include "mozilla/Types.h" // for decltype |
11 | | #include "mozilla/layers/SharedSurfacesChild.h" |
12 | | |
13 | | #include "base/process_util.h" |
14 | | |
15 | | #ifdef DEBUG |
16 | | /** |
17 | | * If defined, this makes SourceSurfaceSharedData::Finalize memory protect the |
18 | | * underlying shared buffer in the producing process (the content or UI |
19 | | * process). Given flushing the page table is expensive, and its utility is |
20 | | * predominantly diagnostic (in case of overrun), turn it off by default. |
21 | | */ |
22 | | #define SHARED_SURFACE_PROTECT_FINALIZED |
23 | | #endif |
24 | | |
25 | | namespace mozilla { |
26 | | namespace gfx { |
27 | | |
28 | | bool |
29 | | SourceSurfaceSharedDataWrapper::Init(const IntSize& aSize, |
30 | | int32_t aStride, |
31 | | SurfaceFormat aFormat, |
32 | | const SharedMemoryBasic::Handle& aHandle, |
33 | | base::ProcessId aCreatorPid) |
34 | 0 | { |
35 | 0 | MOZ_ASSERT(!mBuf); |
36 | 0 | mSize = aSize; |
37 | 0 | mStride = aStride; |
38 | 0 | mFormat = aFormat; |
39 | 0 | mCreatorPid = aCreatorPid; |
40 | 0 |
|
41 | 0 | size_t len = GetAlignedDataLength(); |
42 | 0 | mBuf = MakeAndAddRef<SharedMemoryBasic>(); |
43 | 0 | if (NS_WARN_IF(!mBuf->SetHandle(aHandle, ipc::SharedMemory::RightsReadOnly)) || |
44 | 0 | NS_WARN_IF(!mBuf->Map(len))) { |
45 | 0 | mBuf = nullptr; |
46 | 0 | return false; |
47 | 0 | } |
48 | 0 | |
49 | 0 | mBuf->CloseHandle(); |
50 | 0 | return true; |
51 | 0 | } |
52 | | |
53 | | void |
54 | | SourceSurfaceSharedDataWrapper::Init(SourceSurfaceSharedData* aSurface) |
55 | 0 | { |
56 | 0 | MOZ_ASSERT(!mBuf); |
57 | 0 | MOZ_ASSERT(aSurface); |
58 | 0 | mSize = aSurface->mSize; |
59 | 0 | mStride = aSurface->mStride; |
60 | 0 | mFormat = aSurface->mFormat; |
61 | 0 | mCreatorPid = base::GetCurrentProcId(); |
62 | 0 | mBuf = aSurface->mBuf; |
63 | 0 | } |
64 | | |
65 | | bool |
66 | | SourceSurfaceSharedData::Init(const IntSize &aSize, |
67 | | int32_t aStride, |
68 | | SurfaceFormat aFormat, |
69 | | bool aShare /* = true */) |
70 | 0 | { |
71 | 0 | mSize = aSize; |
72 | 0 | mStride = aStride; |
73 | 0 | mFormat = aFormat; |
74 | 0 |
|
75 | 0 | size_t len = GetAlignedDataLength(); |
76 | 0 | mBuf = new SharedMemoryBasic(); |
77 | 0 | if (NS_WARN_IF(!mBuf->Create(len)) || |
78 | 0 | NS_WARN_IF(!mBuf->Map(len))) { |
79 | 0 | mBuf = nullptr; |
80 | 0 | return false; |
81 | 0 | } |
82 | 0 | |
83 | 0 | if (aShare) { |
84 | 0 | layers::SharedSurfacesChild::Share(this); |
85 | 0 | } |
86 | 0 |
|
87 | 0 | return true; |
88 | 0 | } |
89 | | |
90 | | void |
91 | | SourceSurfaceSharedData::GuaranteePersistance() |
92 | 0 | { |
93 | 0 | // Shared memory is not unmapped until we release SourceSurfaceSharedData. |
94 | 0 | } |
95 | | |
96 | | void |
97 | | SourceSurfaceSharedData::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, |
98 | | size_t& aHeapSizeOut, |
99 | | size_t& aNonHeapSizeOut, |
100 | | size_t& aExtHandlesOut) const |
101 | 0 | { |
102 | 0 | MutexAutoLock lock(mMutex); |
103 | 0 | if (mBuf) { |
104 | 0 | aNonHeapSizeOut += GetAlignedDataLength(); |
105 | 0 | } |
106 | 0 | if (!mClosed) { |
107 | 0 | ++aExtHandlesOut; |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | uint8_t* |
112 | | SourceSurfaceSharedData::GetDataInternal() const |
113 | 0 | { |
114 | 0 | mMutex.AssertCurrentThreadOwns(); |
115 | 0 |
|
116 | 0 | // If we have an old buffer lingering, it is because we get reallocated to |
117 | 0 | // get a new handle to share, but there were still active mappings. |
118 | 0 | if (MOZ_UNLIKELY(mOldBuf)) { |
119 | 0 | MOZ_ASSERT(mMapCount > 0); |
120 | 0 | MOZ_ASSERT(mFinalized); |
121 | 0 | return static_cast<uint8_t*>(mOldBuf->memory()); |
122 | 0 | } |
123 | 0 | return static_cast<uint8_t*>(mBuf->memory()); |
124 | 0 | } |
125 | | |
126 | | nsresult |
127 | | SourceSurfaceSharedData::ShareToProcess(base::ProcessId aPid, |
128 | | SharedMemoryBasic::Handle& aHandle) |
129 | 0 | { |
130 | 0 | MutexAutoLock lock(mMutex); |
131 | 0 | MOZ_ASSERT(mHandleCount > 0); |
132 | 0 |
|
133 | 0 | if (mClosed) { |
134 | 0 | return NS_ERROR_NOT_AVAILABLE; |
135 | 0 | } |
136 | 0 | |
137 | 0 | bool shared = mBuf->ShareToProcess(aPid, &aHandle); |
138 | 0 | if (MOZ_UNLIKELY(!shared)) { |
139 | 0 | return NS_ERROR_FAILURE; |
140 | 0 | } |
141 | 0 | |
142 | 0 | return NS_OK; |
143 | 0 | } |
144 | | |
145 | | void |
146 | | SourceSurfaceSharedData::CloseHandleInternal() |
147 | 0 | { |
148 | 0 | mMutex.AssertCurrentThreadOwns(); |
149 | 0 |
|
150 | 0 | if (mClosed) { |
151 | 0 | MOZ_ASSERT(mHandleCount == 0); |
152 | 0 | MOZ_ASSERT(mShared); |
153 | 0 | return; |
154 | 0 | } |
155 | 0 |
|
156 | 0 | if (mShared) { |
157 | 0 | mBuf->CloseHandle(); |
158 | 0 | mClosed = true; |
159 | 0 | } |
160 | 0 | } |
161 | | |
162 | | bool |
163 | | SourceSurfaceSharedData::ReallocHandle() |
164 | 0 | { |
165 | 0 | MutexAutoLock lock(mMutex); |
166 | 0 | MOZ_ASSERT(mHandleCount > 0); |
167 | 0 | MOZ_ASSERT(mClosed); |
168 | 0 |
|
169 | 0 | if (NS_WARN_IF(!mFinalized)) { |
170 | 0 | // We haven't finished populating the surface data yet, which means we are |
171 | 0 | // out of luck, as we have no means of synchronizing with the producer to |
172 | 0 | // write new data to a new buffer. This should be fairly rare, caused by a |
173 | 0 | // crash in the GPU process, while we were decoding an image. |
174 | 0 | return false; |
175 | 0 | } |
176 | 0 | |
177 | 0 | size_t len = GetAlignedDataLength(); |
178 | 0 | RefPtr<SharedMemoryBasic> buf = new SharedMemoryBasic(); |
179 | 0 | if (NS_WARN_IF(!buf->Create(len)) || |
180 | 0 | NS_WARN_IF(!buf->Map(len))) { |
181 | 0 | return false; |
182 | 0 | } |
183 | 0 | |
184 | 0 | size_t copyLen = GetDataLength(); |
185 | 0 | memcpy(buf->memory(), mBuf->memory(), copyLen); |
186 | | #ifdef SHARED_SURFACE_PROTECT_FINALIZED |
187 | | buf->Protect(static_cast<char*>(buf->memory()), len, RightsRead); |
188 | | #endif |
189 | |
|
190 | 0 | if (mMapCount > 0 && !mOldBuf) { |
191 | 0 | mOldBuf = std::move(mBuf); |
192 | 0 | } |
193 | 0 | mBuf = std::move(buf); |
194 | 0 | mClosed = false; |
195 | 0 | mShared = false; |
196 | 0 | return true; |
197 | 0 | } |
198 | | |
199 | | void |
200 | | SourceSurfaceSharedData::Finalize() |
201 | 0 | { |
202 | 0 | MutexAutoLock lock(mMutex); |
203 | 0 | MOZ_ASSERT(!mFinalized); |
204 | 0 |
|
205 | | #ifdef SHARED_SURFACE_PROTECT_FINALIZED |
206 | | size_t len = GetAlignedDataLength(); |
207 | | mBuf->Protect(static_cast<char*>(mBuf->memory()), len, RightsRead); |
208 | | #endif |
209 | |
|
210 | 0 | mFinalized = true; |
211 | 0 | } |
212 | | |
213 | | } // namespace gfx |
214 | | } // namespace mozilla |