|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * vim: sw=2 ts=8 et : |
|
3 */ |
|
4 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #include "mozilla/DebugOnly.h" |
|
9 |
|
10 #include "mozilla/gfx/Point.h" |
|
11 #include "mozilla/layers/PGrallocBufferChild.h" |
|
12 #include "mozilla/layers/PGrallocBufferParent.h" |
|
13 #include "mozilla/layers/LayerTransactionChild.h" |
|
14 #include "mozilla/layers/ShadowLayers.h" |
|
15 #include "mozilla/layers/LayerManagerComposite.h" |
|
16 #include "mozilla/layers/CompositorTypes.h" |
|
17 #include "mozilla/layers/TextureHost.h" |
|
18 #include "mozilla/unused.h" |
|
19 #include "nsXULAppAPI.h" |
|
20 |
|
21 #include "ShadowLayerUtilsGralloc.h" |
|
22 |
|
23 #include "nsIMemoryReporter.h" |
|
24 |
|
25 #include "gfxPlatform.h" |
|
26 #include "gfx2DGlue.h" |
|
27 #include "GLContext.h" |
|
28 |
|
29 #include "GeckoProfiler.h" |
|
30 |
|
31 #include "cutils/properties.h" |
|
32 |
|
33 #include "MainThreadUtils.h" |
|
34 |
|
35 using namespace android; |
|
36 using namespace base; |
|
37 using namespace mozilla::layers; |
|
38 using namespace mozilla::gl; |
|
39 |
|
40 namespace IPC { |
|
41 |
|
42 void |
|
43 ParamTraits<MagicGrallocBufferHandle>::Write(Message* aMsg, |
|
44 const paramType& aParam) |
|
45 { |
|
46 #if ANDROID_VERSION >= 19 |
|
47 sp<GraphicBuffer> flattenable = aParam.mGraphicBuffer; |
|
48 #else |
|
49 Flattenable *flattenable = aParam.mGraphicBuffer.get(); |
|
50 #endif |
|
51 size_t nbytes = flattenable->getFlattenedSize(); |
|
52 size_t nfds = flattenable->getFdCount(); |
|
53 |
|
54 char data[nbytes]; |
|
55 int fds[nfds]; |
|
56 |
|
57 #if ANDROID_VERSION >= 19 |
|
58 // Make a copy of "data" and "fds" for flatten() to avoid casting problem |
|
59 void *pdata = (void *)data; |
|
60 int *pfds = fds; |
|
61 |
|
62 flattenable->flatten(pdata, nbytes, pfds, nfds); |
|
63 |
|
64 // In Kitkat, flatten() will change the value of nbytes and nfds, which dues |
|
65 // to multiple parcelable object consumption. The actual size and fd count |
|
66 // which returned by getFlattenedSize() and getFdCount() are not changed. |
|
67 // So we change nbytes and nfds back by call corresponding calls. |
|
68 nbytes = flattenable->getFlattenedSize(); |
|
69 nfds = flattenable->getFdCount(); |
|
70 #else |
|
71 flattenable->flatten(data, nbytes, fds, nfds); |
|
72 #endif |
|
73 |
|
74 aMsg->WriteSize(nbytes); |
|
75 aMsg->WriteSize(nfds); |
|
76 |
|
77 aMsg->WriteBytes(data, nbytes); |
|
78 for (size_t n = 0; n < nfds; ++n) { |
|
79 // These buffers can't die in transit because they're created |
|
80 // synchonously and the parent-side buffer can only be dropped if |
|
81 // there's a crash. |
|
82 aMsg->WriteFileDescriptor(FileDescriptor(fds[n], false)); |
|
83 } |
|
84 } |
|
85 |
|
86 bool |
|
87 ParamTraits<MagicGrallocBufferHandle>::Read(const Message* aMsg, |
|
88 void** aIter, paramType* aResult) |
|
89 { |
|
90 size_t nbytes; |
|
91 size_t nfds; |
|
92 const char* data; |
|
93 |
|
94 if (!aMsg->ReadSize(aIter, &nbytes) || |
|
95 !aMsg->ReadSize(aIter, &nfds) || |
|
96 !aMsg->ReadBytes(aIter, &data, nbytes)) { |
|
97 return false; |
|
98 } |
|
99 |
|
100 int fds[nfds]; |
|
101 |
|
102 for (size_t n = 0; n < nfds; ++n) { |
|
103 FileDescriptor fd; |
|
104 if (!aMsg->ReadFileDescriptor(aIter, &fd)) { |
|
105 return false; |
|
106 } |
|
107 // If the GraphicBuffer was shared cross-process, SCM_RIGHTS does |
|
108 // the right thing and dup's the fd. If it's shared cross-thread, |
|
109 // SCM_RIGHTS doesn't dup the fd. That's surprising, but we just |
|
110 // deal with it here. NB: only the "default" (master) process can |
|
111 // alloc gralloc buffers. |
|
112 bool sameProcess = (XRE_GetProcessType() == GeckoProcessType_Default); |
|
113 int dupFd = sameProcess ? dup(fd.fd) : fd.fd; |
|
114 fds[n] = dupFd; |
|
115 } |
|
116 |
|
117 sp<GraphicBuffer> buffer(new GraphicBuffer()); |
|
118 #if ANDROID_VERSION >= 19 |
|
119 // Make a copy of "data" and "fds" for unflatten() to avoid casting problem |
|
120 void const *pdata = (void const *)data; |
|
121 int const *pfds = fds; |
|
122 |
|
123 if (NO_ERROR == buffer->unflatten(pdata, nbytes, pfds, nfds)) { |
|
124 #else |
|
125 Flattenable *flattenable = buffer.get(); |
|
126 |
|
127 if (NO_ERROR == flattenable->unflatten(data, nbytes, fds, nfds)) { |
|
128 #endif |
|
129 aResult->mGraphicBuffer = buffer; |
|
130 return true; |
|
131 } |
|
132 return false; |
|
133 } |
|
134 |
|
135 } // namespace IPC |
|
136 |
|
137 namespace mozilla { |
|
138 namespace layers { |
|
139 |
|
140 MagicGrallocBufferHandle::MagicGrallocBufferHandle(const sp<GraphicBuffer>& aGraphicBuffer) |
|
141 : mGraphicBuffer(aGraphicBuffer) |
|
142 { |
|
143 } |
|
144 |
|
145 //----------------------------------------------------------------------------- |
|
146 // Parent process |
|
147 |
|
148 static gfxImageFormat |
|
149 ImageFormatForPixelFormat(android::PixelFormat aFormat) |
|
150 { |
|
151 switch (aFormat) { |
|
152 case PIXEL_FORMAT_RGBA_8888: |
|
153 return gfxImageFormat::ARGB32; |
|
154 case PIXEL_FORMAT_RGBX_8888: |
|
155 return gfxImageFormat::RGB24; |
|
156 case PIXEL_FORMAT_RGB_565: |
|
157 return gfxImageFormat::RGB16_565; |
|
158 default: |
|
159 MOZ_CRASH("Unknown gralloc pixel format"); |
|
160 } |
|
161 return gfxImageFormat::ARGB32; |
|
162 } |
|
163 |
|
164 static android::PixelFormat |
|
165 PixelFormatForImageFormat(gfxImageFormat aFormat) |
|
166 { |
|
167 switch (aFormat) { |
|
168 case gfxImageFormat::ARGB32: |
|
169 return android::PIXEL_FORMAT_RGBA_8888; |
|
170 case gfxImageFormat::RGB24: |
|
171 return android::PIXEL_FORMAT_RGBX_8888; |
|
172 case gfxImageFormat::RGB16_565: |
|
173 return android::PIXEL_FORMAT_RGB_565; |
|
174 case gfxImageFormat::A8: |
|
175 NS_WARNING("gralloc does not support gfxImageFormat::A8"); |
|
176 return android::PIXEL_FORMAT_UNKNOWN; |
|
177 default: |
|
178 MOZ_CRASH("Unknown gralloc pixel format"); |
|
179 } |
|
180 return android::PIXEL_FORMAT_RGBA_8888; |
|
181 } |
|
182 |
|
183 static size_t |
|
184 BytesPerPixelForPixelFormat(android::PixelFormat aFormat) |
|
185 { |
|
186 switch (aFormat) { |
|
187 case PIXEL_FORMAT_RGBA_8888: |
|
188 case PIXEL_FORMAT_RGBX_8888: |
|
189 case PIXEL_FORMAT_BGRA_8888: |
|
190 return 4; |
|
191 case PIXEL_FORMAT_RGB_888: |
|
192 return 3; |
|
193 case PIXEL_FORMAT_RGB_565: |
|
194 case PIXEL_FORMAT_RGBA_5551: |
|
195 case PIXEL_FORMAT_RGBA_4444: |
|
196 return 2; |
|
197 default: |
|
198 return 0; |
|
199 } |
|
200 return 0; |
|
201 } |
|
202 |
|
203 static android::PixelFormat |
|
204 PixelFormatForContentType(gfxContentType aContentType) |
|
205 { |
|
206 return PixelFormatForImageFormat( |
|
207 gfxPlatform::GetPlatform()->OptimalFormatForContent(aContentType)); |
|
208 } |
|
209 |
|
210 static gfxContentType |
|
211 ContentTypeFromPixelFormat(android::PixelFormat aFormat) |
|
212 { |
|
213 return gfxASurface::ContentFromFormat(ImageFormatForPixelFormat(aFormat)); |
|
214 } |
|
215 |
|
216 class GrallocReporter MOZ_FINAL : public nsIMemoryReporter |
|
217 { |
|
218 friend class GrallocBufferActor; |
|
219 |
|
220 public: |
|
221 NS_DECL_ISUPPORTS |
|
222 |
|
223 GrallocReporter() |
|
224 { |
|
225 #ifdef DEBUG |
|
226 // There must be only one instance of this class, due to |sAmount| |
|
227 // being static. Assert this. |
|
228 static bool hasRun = false; |
|
229 MOZ_ASSERT(!hasRun); |
|
230 hasRun = true; |
|
231 #endif |
|
232 } |
|
233 |
|
234 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, |
|
235 nsISupports* aData) |
|
236 { |
|
237 return MOZ_COLLECT_REPORT( |
|
238 "gralloc", KIND_OTHER, UNITS_BYTES, sAmount, |
|
239 "Special RAM that can be shared between processes and directly accessed by " |
|
240 "both the CPU and GPU. Gralloc memory is usually a relatively precious " |
|
241 "resource, with much less available than generic RAM. When it's exhausted, " |
|
242 "graphics performance can suffer. This value can be incorrect because of race " |
|
243 "conditions."); |
|
244 } |
|
245 |
|
246 private: |
|
247 static int64_t sAmount; |
|
248 }; |
|
249 |
|
250 NS_IMPL_ISUPPORTS(GrallocReporter, nsIMemoryReporter) |
|
251 |
|
252 int64_t GrallocReporter::sAmount = 0; |
|
253 |
|
254 void InitGralloc() { |
|
255 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); |
|
256 RegisterStrongMemoryReporter(new GrallocReporter()); |
|
257 } |
|
258 |
|
259 GrallocBufferActor::GrallocBufferActor() |
|
260 : mAllocBytes(0) |
|
261 , mTextureHost(nullptr) |
|
262 { |
|
263 } |
|
264 |
|
265 GrallocBufferActor::~GrallocBufferActor() |
|
266 { |
|
267 if (mAllocBytes > 0) { |
|
268 GrallocReporter::sAmount -= mAllocBytes; |
|
269 } |
|
270 } |
|
271 |
|
272 /*static*/ PGrallocBufferParent* |
|
273 GrallocBufferActor::Create(const gfx::IntSize& aSize, |
|
274 const uint32_t& aFormat, |
|
275 const uint32_t& aUsage, |
|
276 MaybeMagicGrallocBufferHandle* aOutHandle) |
|
277 { |
|
278 PROFILER_LABEL("GrallocBufferActor", "Create"); |
|
279 GrallocBufferActor* actor = new GrallocBufferActor(); |
|
280 *aOutHandle = null_t(); |
|
281 uint32_t format = aFormat; |
|
282 uint32_t usage = aUsage; |
|
283 |
|
284 if (format == 0 || usage == 0) { |
|
285 printf_stderr("GrallocBufferActor::Create -- format and usage must be non-zero"); |
|
286 return actor; |
|
287 } |
|
288 |
|
289 // If the requested size is too big (i.e. exceeds the commonly used max GL texture size) |
|
290 // then we risk OOMing the parent process. It's better to just deny the allocation and |
|
291 // kill the child process, which is what the following code does. |
|
292 // TODO: actually use GL_MAX_TEXTURE_SIZE instead of hardcoding 4096 |
|
293 if (aSize.width > 4096 || aSize.height > 4096) { |
|
294 printf_stderr("GrallocBufferActor::Create -- requested gralloc buffer is too big. Killing child instead."); |
|
295 delete actor; |
|
296 return nullptr; |
|
297 } |
|
298 |
|
299 sp<GraphicBuffer> buffer(new GraphicBuffer(aSize.width, aSize.height, format, usage)); |
|
300 if (buffer->initCheck() != OK) |
|
301 return actor; |
|
302 |
|
303 size_t bpp = BytesPerPixelForPixelFormat(format); |
|
304 actor->mAllocBytes = aSize.width * aSize.height * bpp; |
|
305 GrallocReporter::sAmount += actor->mAllocBytes; |
|
306 |
|
307 actor->mGraphicBuffer = buffer; |
|
308 *aOutHandle = MagicGrallocBufferHandle(buffer); |
|
309 |
|
310 return actor; |
|
311 } |
|
312 |
|
313 void GrallocBufferActor::ActorDestroy(ActorDestroyReason) |
|
314 { |
|
315 // Used only for hacky fix for bug 966446. |
|
316 if (mTextureHost) { |
|
317 mTextureHost->ForgetBufferActor(); |
|
318 mTextureHost = nullptr; |
|
319 } |
|
320 } |
|
321 |
|
322 void GrallocBufferActor::AddTextureHost(TextureHost* aTextureHost) |
|
323 { |
|
324 mTextureHost = aTextureHost; |
|
325 } |
|
326 |
|
327 void GrallocBufferActor::RemoveTextureHost() |
|
328 { |
|
329 mTextureHost = nullptr; |
|
330 } |
|
331 |
|
332 /*static*/ bool |
|
333 LayerManagerComposite::SupportsDirectTexturing() |
|
334 { |
|
335 return true; |
|
336 } |
|
337 |
|
338 /*static*/ void |
|
339 LayerManagerComposite::PlatformSyncBeforeReplyUpdate() |
|
340 { |
|
341 // Nothing to be done for gralloc. |
|
342 } |
|
343 |
|
344 //----------------------------------------------------------------------------- |
|
345 // Child process |
|
346 |
|
347 /*static*/ PGrallocBufferChild* |
|
348 GrallocBufferActor::Create() |
|
349 { |
|
350 return new GrallocBufferActor(); |
|
351 } |
|
352 |
|
353 void |
|
354 GrallocBufferActor::InitFromHandle(const MagicGrallocBufferHandle& aHandle) |
|
355 { |
|
356 MOZ_ASSERT(!mGraphicBuffer.get()); |
|
357 MOZ_ASSERT(aHandle.mGraphicBuffer.get()); |
|
358 |
|
359 mGraphicBuffer = aHandle.mGraphicBuffer; |
|
360 } |
|
361 |
|
362 PGrallocBufferChild* |
|
363 ShadowLayerForwarder::AllocGrallocBuffer(const gfx::IntSize& aSize, |
|
364 uint32_t aFormat, |
|
365 uint32_t aUsage, |
|
366 MaybeMagicGrallocBufferHandle* aHandle) |
|
367 { |
|
368 if (!mShadowManager->IPCOpen()) { |
|
369 return nullptr; |
|
370 } |
|
371 return mShadowManager->SendPGrallocBufferConstructor(aSize, aFormat, aUsage, aHandle); |
|
372 } |
|
373 |
|
374 void |
|
375 ShadowLayerForwarder::DeallocGrallocBuffer(PGrallocBufferChild* aChild) |
|
376 { |
|
377 MOZ_ASSERT(aChild); |
|
378 PGrallocBufferChild::Send__delete__(aChild); |
|
379 } |
|
380 |
|
381 //----------------------------------------------------------------------------- |
|
382 // Both processes |
|
383 |
|
384 android::GraphicBuffer* |
|
385 GrallocBufferActor::GetGraphicBuffer() |
|
386 { |
|
387 return mGraphicBuffer.get(); |
|
388 } |
|
389 |
|
390 /*static*/ void |
|
391 ShadowLayerForwarder::PlatformSyncBeforeUpdate() |
|
392 { |
|
393 // Nothing to be done for gralloc. |
|
394 } |
|
395 |
|
396 } // namespace layers |
|
397 } // namespace mozilla |