Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
8 #include "mozilla/DebugOnly.h"
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"
21 #include "ShadowLayerUtilsGralloc.h"
23 #include "nsIMemoryReporter.h"
25 #include "gfxPlatform.h"
26 #include "gfx2DGlue.h"
27 #include "GLContext.h"
29 #include "GeckoProfiler.h"
31 #include "cutils/properties.h"
33 #include "MainThreadUtils.h"
35 using namespace android;
36 using namespace base;
37 using namespace mozilla::layers;
38 using namespace mozilla::gl;
40 namespace IPC {
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();
54 char data[nbytes];
55 int fds[nfds];
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;
62 flattenable->flatten(pdata, nbytes, pfds, nfds);
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
74 aMsg->WriteSize(nbytes);
75 aMsg->WriteSize(nfds);
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 }
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;
94 if (!aMsg->ReadSize(aIter, &nbytes) ||
95 !aMsg->ReadSize(aIter, &nfds) ||
96 !aMsg->ReadBytes(aIter, &data, nbytes)) {
97 return false;
98 }
100 int fds[nfds];
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 }
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;
123 if (NO_ERROR == buffer->unflatten(pdata, nbytes, pfds, nfds)) {
124 #else
125 Flattenable *flattenable = buffer.get();
127 if (NO_ERROR == flattenable->unflatten(data, nbytes, fds, nfds)) {
128 #endif
129 aResult->mGraphicBuffer = buffer;
130 return true;
131 }
132 return false;
133 }
135 } // namespace IPC
137 namespace mozilla {
138 namespace layers {
140 MagicGrallocBufferHandle::MagicGrallocBufferHandle(const sp<GraphicBuffer>& aGraphicBuffer)
141 : mGraphicBuffer(aGraphicBuffer)
142 {
143 }
145 //-----------------------------------------------------------------------------
146 // Parent process
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 }
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 }
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 }
203 static android::PixelFormat
204 PixelFormatForContentType(gfxContentType aContentType)
205 {
206 return PixelFormatForImageFormat(
207 gfxPlatform::GetPlatform()->OptimalFormatForContent(aContentType));
208 }
210 static gfxContentType
211 ContentTypeFromPixelFormat(android::PixelFormat aFormat)
212 {
213 return gfxASurface::ContentFromFormat(ImageFormatForPixelFormat(aFormat));
214 }
216 class GrallocReporter MOZ_FINAL : public nsIMemoryReporter
217 {
218 friend class GrallocBufferActor;
220 public:
221 NS_DECL_ISUPPORTS
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 }
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 }
246 private:
247 static int64_t sAmount;
248 };
250 NS_IMPL_ISUPPORTS(GrallocReporter, nsIMemoryReporter)
252 int64_t GrallocReporter::sAmount = 0;
254 void InitGralloc() {
255 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
256 RegisterStrongMemoryReporter(new GrallocReporter());
257 }
259 GrallocBufferActor::GrallocBufferActor()
260 : mAllocBytes(0)
261 , mTextureHost(nullptr)
262 {
263 }
265 GrallocBufferActor::~GrallocBufferActor()
266 {
267 if (mAllocBytes > 0) {
268 GrallocReporter::sAmount -= mAllocBytes;
269 }
270 }
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;
284 if (format == 0 || usage == 0) {
285 printf_stderr("GrallocBufferActor::Create -- format and usage must be non-zero");
286 return actor;
287 }
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 }
299 sp<GraphicBuffer> buffer(new GraphicBuffer(aSize.width, aSize.height, format, usage));
300 if (buffer->initCheck() != OK)
301 return actor;
303 size_t bpp = BytesPerPixelForPixelFormat(format);
304 actor->mAllocBytes = aSize.width * aSize.height * bpp;
305 GrallocReporter::sAmount += actor->mAllocBytes;
307 actor->mGraphicBuffer = buffer;
308 *aOutHandle = MagicGrallocBufferHandle(buffer);
310 return actor;
311 }
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 }
322 void GrallocBufferActor::AddTextureHost(TextureHost* aTextureHost)
323 {
324 mTextureHost = aTextureHost;
325 }
327 void GrallocBufferActor::RemoveTextureHost()
328 {
329 mTextureHost = nullptr;
330 }
332 /*static*/ bool
333 LayerManagerComposite::SupportsDirectTexturing()
334 {
335 return true;
336 }
338 /*static*/ void
339 LayerManagerComposite::PlatformSyncBeforeReplyUpdate()
340 {
341 // Nothing to be done for gralloc.
342 }
344 //-----------------------------------------------------------------------------
345 // Child process
347 /*static*/ PGrallocBufferChild*
348 GrallocBufferActor::Create()
349 {
350 return new GrallocBufferActor();
351 }
353 void
354 GrallocBufferActor::InitFromHandle(const MagicGrallocBufferHandle& aHandle)
355 {
356 MOZ_ASSERT(!mGraphicBuffer.get());
357 MOZ_ASSERT(aHandle.mGraphicBuffer.get());
359 mGraphicBuffer = aHandle.mGraphicBuffer;
360 }
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 }
374 void
375 ShadowLayerForwarder::DeallocGrallocBuffer(PGrallocBufferChild* aChild)
376 {
377 MOZ_ASSERT(aChild);
378 PGrallocBufferChild::Send__delete__(aChild);
379 }
381 //-----------------------------------------------------------------------------
382 // Both processes
384 android::GraphicBuffer*
385 GrallocBufferActor::GetGraphicBuffer()
386 {
387 return mGraphicBuffer.get();
388 }
390 /*static*/ void
391 ShadowLayerForwarder::PlatformSyncBeforeUpdate()
392 {
393 // Nothing to be done for gralloc.
394 }
396 } // namespace layers
397 } // namespace mozilla