1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,397 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: sw=2 ts=8 et : 1.6 + */ 1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#include "mozilla/DebugOnly.h" 1.12 + 1.13 +#include "mozilla/gfx/Point.h" 1.14 +#include "mozilla/layers/PGrallocBufferChild.h" 1.15 +#include "mozilla/layers/PGrallocBufferParent.h" 1.16 +#include "mozilla/layers/LayerTransactionChild.h" 1.17 +#include "mozilla/layers/ShadowLayers.h" 1.18 +#include "mozilla/layers/LayerManagerComposite.h" 1.19 +#include "mozilla/layers/CompositorTypes.h" 1.20 +#include "mozilla/layers/TextureHost.h" 1.21 +#include "mozilla/unused.h" 1.22 +#include "nsXULAppAPI.h" 1.23 + 1.24 +#include "ShadowLayerUtilsGralloc.h" 1.25 + 1.26 +#include "nsIMemoryReporter.h" 1.27 + 1.28 +#include "gfxPlatform.h" 1.29 +#include "gfx2DGlue.h" 1.30 +#include "GLContext.h" 1.31 + 1.32 +#include "GeckoProfiler.h" 1.33 + 1.34 +#include "cutils/properties.h" 1.35 + 1.36 +#include "MainThreadUtils.h" 1.37 + 1.38 +using namespace android; 1.39 +using namespace base; 1.40 +using namespace mozilla::layers; 1.41 +using namespace mozilla::gl; 1.42 + 1.43 +namespace IPC { 1.44 + 1.45 +void 1.46 +ParamTraits<MagicGrallocBufferHandle>::Write(Message* aMsg, 1.47 + const paramType& aParam) 1.48 +{ 1.49 +#if ANDROID_VERSION >= 19 1.50 + sp<GraphicBuffer> flattenable = aParam.mGraphicBuffer; 1.51 +#else 1.52 + Flattenable *flattenable = aParam.mGraphicBuffer.get(); 1.53 +#endif 1.54 + size_t nbytes = flattenable->getFlattenedSize(); 1.55 + size_t nfds = flattenable->getFdCount(); 1.56 + 1.57 + char data[nbytes]; 1.58 + int fds[nfds]; 1.59 + 1.60 +#if ANDROID_VERSION >= 19 1.61 + // Make a copy of "data" and "fds" for flatten() to avoid casting problem 1.62 + void *pdata = (void *)data; 1.63 + int *pfds = fds; 1.64 + 1.65 + flattenable->flatten(pdata, nbytes, pfds, nfds); 1.66 + 1.67 + // In Kitkat, flatten() will change the value of nbytes and nfds, which dues 1.68 + // to multiple parcelable object consumption. The actual size and fd count 1.69 + // which returned by getFlattenedSize() and getFdCount() are not changed. 1.70 + // So we change nbytes and nfds back by call corresponding calls. 1.71 + nbytes = flattenable->getFlattenedSize(); 1.72 + nfds = flattenable->getFdCount(); 1.73 +#else 1.74 + flattenable->flatten(data, nbytes, fds, nfds); 1.75 +#endif 1.76 + 1.77 + aMsg->WriteSize(nbytes); 1.78 + aMsg->WriteSize(nfds); 1.79 + 1.80 + aMsg->WriteBytes(data, nbytes); 1.81 + for (size_t n = 0; n < nfds; ++n) { 1.82 + // These buffers can't die in transit because they're created 1.83 + // synchonously and the parent-side buffer can only be dropped if 1.84 + // there's a crash. 1.85 + aMsg->WriteFileDescriptor(FileDescriptor(fds[n], false)); 1.86 + } 1.87 +} 1.88 + 1.89 +bool 1.90 +ParamTraits<MagicGrallocBufferHandle>::Read(const Message* aMsg, 1.91 + void** aIter, paramType* aResult) 1.92 +{ 1.93 + size_t nbytes; 1.94 + size_t nfds; 1.95 + const char* data; 1.96 + 1.97 + if (!aMsg->ReadSize(aIter, &nbytes) || 1.98 + !aMsg->ReadSize(aIter, &nfds) || 1.99 + !aMsg->ReadBytes(aIter, &data, nbytes)) { 1.100 + return false; 1.101 + } 1.102 + 1.103 + int fds[nfds]; 1.104 + 1.105 + for (size_t n = 0; n < nfds; ++n) { 1.106 + FileDescriptor fd; 1.107 + if (!aMsg->ReadFileDescriptor(aIter, &fd)) { 1.108 + return false; 1.109 + } 1.110 + // If the GraphicBuffer was shared cross-process, SCM_RIGHTS does 1.111 + // the right thing and dup's the fd. If it's shared cross-thread, 1.112 + // SCM_RIGHTS doesn't dup the fd. That's surprising, but we just 1.113 + // deal with it here. NB: only the "default" (master) process can 1.114 + // alloc gralloc buffers. 1.115 + bool sameProcess = (XRE_GetProcessType() == GeckoProcessType_Default); 1.116 + int dupFd = sameProcess ? dup(fd.fd) : fd.fd; 1.117 + fds[n] = dupFd; 1.118 + } 1.119 + 1.120 + sp<GraphicBuffer> buffer(new GraphicBuffer()); 1.121 +#if ANDROID_VERSION >= 19 1.122 + // Make a copy of "data" and "fds" for unflatten() to avoid casting problem 1.123 + void const *pdata = (void const *)data; 1.124 + int const *pfds = fds; 1.125 + 1.126 + if (NO_ERROR == buffer->unflatten(pdata, nbytes, pfds, nfds)) { 1.127 +#else 1.128 + Flattenable *flattenable = buffer.get(); 1.129 + 1.130 + if (NO_ERROR == flattenable->unflatten(data, nbytes, fds, nfds)) { 1.131 +#endif 1.132 + aResult->mGraphicBuffer = buffer; 1.133 + return true; 1.134 + } 1.135 + return false; 1.136 +} 1.137 + 1.138 +} // namespace IPC 1.139 + 1.140 +namespace mozilla { 1.141 +namespace layers { 1.142 + 1.143 +MagicGrallocBufferHandle::MagicGrallocBufferHandle(const sp<GraphicBuffer>& aGraphicBuffer) 1.144 + : mGraphicBuffer(aGraphicBuffer) 1.145 +{ 1.146 +} 1.147 + 1.148 +//----------------------------------------------------------------------------- 1.149 +// Parent process 1.150 + 1.151 +static gfxImageFormat 1.152 +ImageFormatForPixelFormat(android::PixelFormat aFormat) 1.153 +{ 1.154 + switch (aFormat) { 1.155 + case PIXEL_FORMAT_RGBA_8888: 1.156 + return gfxImageFormat::ARGB32; 1.157 + case PIXEL_FORMAT_RGBX_8888: 1.158 + return gfxImageFormat::RGB24; 1.159 + case PIXEL_FORMAT_RGB_565: 1.160 + return gfxImageFormat::RGB16_565; 1.161 + default: 1.162 + MOZ_CRASH("Unknown gralloc pixel format"); 1.163 + } 1.164 + return gfxImageFormat::ARGB32; 1.165 +} 1.166 + 1.167 +static android::PixelFormat 1.168 +PixelFormatForImageFormat(gfxImageFormat aFormat) 1.169 +{ 1.170 + switch (aFormat) { 1.171 + case gfxImageFormat::ARGB32: 1.172 + return android::PIXEL_FORMAT_RGBA_8888; 1.173 + case gfxImageFormat::RGB24: 1.174 + return android::PIXEL_FORMAT_RGBX_8888; 1.175 + case gfxImageFormat::RGB16_565: 1.176 + return android::PIXEL_FORMAT_RGB_565; 1.177 + case gfxImageFormat::A8: 1.178 + NS_WARNING("gralloc does not support gfxImageFormat::A8"); 1.179 + return android::PIXEL_FORMAT_UNKNOWN; 1.180 + default: 1.181 + MOZ_CRASH("Unknown gralloc pixel format"); 1.182 + } 1.183 + return android::PIXEL_FORMAT_RGBA_8888; 1.184 +} 1.185 + 1.186 +static size_t 1.187 +BytesPerPixelForPixelFormat(android::PixelFormat aFormat) 1.188 +{ 1.189 + switch (aFormat) { 1.190 + case PIXEL_FORMAT_RGBA_8888: 1.191 + case PIXEL_FORMAT_RGBX_8888: 1.192 + case PIXEL_FORMAT_BGRA_8888: 1.193 + return 4; 1.194 + case PIXEL_FORMAT_RGB_888: 1.195 + return 3; 1.196 + case PIXEL_FORMAT_RGB_565: 1.197 + case PIXEL_FORMAT_RGBA_5551: 1.198 + case PIXEL_FORMAT_RGBA_4444: 1.199 + return 2; 1.200 + default: 1.201 + return 0; 1.202 + } 1.203 + return 0; 1.204 +} 1.205 + 1.206 +static android::PixelFormat 1.207 +PixelFormatForContentType(gfxContentType aContentType) 1.208 +{ 1.209 + return PixelFormatForImageFormat( 1.210 + gfxPlatform::GetPlatform()->OptimalFormatForContent(aContentType)); 1.211 +} 1.212 + 1.213 +static gfxContentType 1.214 +ContentTypeFromPixelFormat(android::PixelFormat aFormat) 1.215 +{ 1.216 + return gfxASurface::ContentFromFormat(ImageFormatForPixelFormat(aFormat)); 1.217 +} 1.218 + 1.219 +class GrallocReporter MOZ_FINAL : public nsIMemoryReporter 1.220 +{ 1.221 + friend class GrallocBufferActor; 1.222 + 1.223 +public: 1.224 + NS_DECL_ISUPPORTS 1.225 + 1.226 + GrallocReporter() 1.227 + { 1.228 +#ifdef DEBUG 1.229 + // There must be only one instance of this class, due to |sAmount| 1.230 + // being static. Assert this. 1.231 + static bool hasRun = false; 1.232 + MOZ_ASSERT(!hasRun); 1.233 + hasRun = true; 1.234 +#endif 1.235 + } 1.236 + 1.237 + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, 1.238 + nsISupports* aData) 1.239 + { 1.240 + return MOZ_COLLECT_REPORT( 1.241 + "gralloc", KIND_OTHER, UNITS_BYTES, sAmount, 1.242 +"Special RAM that can be shared between processes and directly accessed by " 1.243 +"both the CPU and GPU. Gralloc memory is usually a relatively precious " 1.244 +"resource, with much less available than generic RAM. When it's exhausted, " 1.245 +"graphics performance can suffer. This value can be incorrect because of race " 1.246 +"conditions."); 1.247 + } 1.248 + 1.249 +private: 1.250 + static int64_t sAmount; 1.251 +}; 1.252 + 1.253 +NS_IMPL_ISUPPORTS(GrallocReporter, nsIMemoryReporter) 1.254 + 1.255 +int64_t GrallocReporter::sAmount = 0; 1.256 + 1.257 +void InitGralloc() { 1.258 + NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); 1.259 + RegisterStrongMemoryReporter(new GrallocReporter()); 1.260 +} 1.261 + 1.262 +GrallocBufferActor::GrallocBufferActor() 1.263 +: mAllocBytes(0) 1.264 +, mTextureHost(nullptr) 1.265 +{ 1.266 +} 1.267 + 1.268 +GrallocBufferActor::~GrallocBufferActor() 1.269 +{ 1.270 + if (mAllocBytes > 0) { 1.271 + GrallocReporter::sAmount -= mAllocBytes; 1.272 + } 1.273 +} 1.274 + 1.275 +/*static*/ PGrallocBufferParent* 1.276 +GrallocBufferActor::Create(const gfx::IntSize& aSize, 1.277 + const uint32_t& aFormat, 1.278 + const uint32_t& aUsage, 1.279 + MaybeMagicGrallocBufferHandle* aOutHandle) 1.280 +{ 1.281 + PROFILER_LABEL("GrallocBufferActor", "Create"); 1.282 + GrallocBufferActor* actor = new GrallocBufferActor(); 1.283 + *aOutHandle = null_t(); 1.284 + uint32_t format = aFormat; 1.285 + uint32_t usage = aUsage; 1.286 + 1.287 + if (format == 0 || usage == 0) { 1.288 + printf_stderr("GrallocBufferActor::Create -- format and usage must be non-zero"); 1.289 + return actor; 1.290 + } 1.291 + 1.292 + // If the requested size is too big (i.e. exceeds the commonly used max GL texture size) 1.293 + // then we risk OOMing the parent process. It's better to just deny the allocation and 1.294 + // kill the child process, which is what the following code does. 1.295 + // TODO: actually use GL_MAX_TEXTURE_SIZE instead of hardcoding 4096 1.296 + if (aSize.width > 4096 || aSize.height > 4096) { 1.297 + printf_stderr("GrallocBufferActor::Create -- requested gralloc buffer is too big. Killing child instead."); 1.298 + delete actor; 1.299 + return nullptr; 1.300 + } 1.301 + 1.302 + sp<GraphicBuffer> buffer(new GraphicBuffer(aSize.width, aSize.height, format, usage)); 1.303 + if (buffer->initCheck() != OK) 1.304 + return actor; 1.305 + 1.306 + size_t bpp = BytesPerPixelForPixelFormat(format); 1.307 + actor->mAllocBytes = aSize.width * aSize.height * bpp; 1.308 + GrallocReporter::sAmount += actor->mAllocBytes; 1.309 + 1.310 + actor->mGraphicBuffer = buffer; 1.311 + *aOutHandle = MagicGrallocBufferHandle(buffer); 1.312 + 1.313 + return actor; 1.314 +} 1.315 + 1.316 +void GrallocBufferActor::ActorDestroy(ActorDestroyReason) 1.317 +{ 1.318 + // Used only for hacky fix for bug 966446. 1.319 + if (mTextureHost) { 1.320 + mTextureHost->ForgetBufferActor(); 1.321 + mTextureHost = nullptr; 1.322 + } 1.323 +} 1.324 + 1.325 +void GrallocBufferActor::AddTextureHost(TextureHost* aTextureHost) 1.326 +{ 1.327 + mTextureHost = aTextureHost; 1.328 +} 1.329 + 1.330 +void GrallocBufferActor::RemoveTextureHost() 1.331 +{ 1.332 + mTextureHost = nullptr; 1.333 +} 1.334 + 1.335 +/*static*/ bool 1.336 +LayerManagerComposite::SupportsDirectTexturing() 1.337 +{ 1.338 + return true; 1.339 +} 1.340 + 1.341 +/*static*/ void 1.342 +LayerManagerComposite::PlatformSyncBeforeReplyUpdate() 1.343 +{ 1.344 + // Nothing to be done for gralloc. 1.345 +} 1.346 + 1.347 +//----------------------------------------------------------------------------- 1.348 +// Child process 1.349 + 1.350 +/*static*/ PGrallocBufferChild* 1.351 +GrallocBufferActor::Create() 1.352 +{ 1.353 + return new GrallocBufferActor(); 1.354 +} 1.355 + 1.356 +void 1.357 +GrallocBufferActor::InitFromHandle(const MagicGrallocBufferHandle& aHandle) 1.358 +{ 1.359 + MOZ_ASSERT(!mGraphicBuffer.get()); 1.360 + MOZ_ASSERT(aHandle.mGraphicBuffer.get()); 1.361 + 1.362 + mGraphicBuffer = aHandle.mGraphicBuffer; 1.363 +} 1.364 + 1.365 +PGrallocBufferChild* 1.366 +ShadowLayerForwarder::AllocGrallocBuffer(const gfx::IntSize& aSize, 1.367 + uint32_t aFormat, 1.368 + uint32_t aUsage, 1.369 + MaybeMagicGrallocBufferHandle* aHandle) 1.370 +{ 1.371 + if (!mShadowManager->IPCOpen()) { 1.372 + return nullptr; 1.373 + } 1.374 + return mShadowManager->SendPGrallocBufferConstructor(aSize, aFormat, aUsage, aHandle); 1.375 +} 1.376 + 1.377 +void 1.378 +ShadowLayerForwarder::DeallocGrallocBuffer(PGrallocBufferChild* aChild) 1.379 +{ 1.380 + MOZ_ASSERT(aChild); 1.381 + PGrallocBufferChild::Send__delete__(aChild); 1.382 +} 1.383 + 1.384 +//----------------------------------------------------------------------------- 1.385 +// Both processes 1.386 + 1.387 +android::GraphicBuffer* 1.388 +GrallocBufferActor::GetGraphicBuffer() 1.389 +{ 1.390 + return mGraphicBuffer.get(); 1.391 +} 1.392 + 1.393 +/*static*/ void 1.394 +ShadowLayerForwarder::PlatformSyncBeforeUpdate() 1.395 +{ 1.396 + // Nothing to be done for gralloc. 1.397 +} 1.398 + 1.399 +} // namespace layers 1.400 +} // namespace mozilla