widget/android/AndroidGraphicBuffer.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include <dlfcn.h>
     7 #include <android/log.h>
     8 #include <GLES2/gl2.h>
     9 #include <nsTArray.h>
    10 #include "AndroidGraphicBuffer.h"
    11 #include "AndroidBridge.h"
    12 #include "mozilla/Preferences.h"
    14 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "AndroidGraphicBuffer" , ## args)
    16 #define EGL_NATIVE_BUFFER_ANDROID 0x3140
    17 #define EGL_IMAGE_PRESERVED_KHR   0x30D2
    19 typedef void *EGLContext;
    20 typedef void *EGLDisplay;
    21 typedef uint32_t EGLenum;
    22 typedef int32_t EGLint;
    23 typedef uint32_t EGLBoolean;
    25 #define EGL_TRUE 1
    26 #define EGL_FALSE 0
    27 #define EGL_NONE 0x3038
    28 #define EGL_NO_CONTEXT (EGLContext)0
    29 #define EGL_DEFAULT_DISPLAY  (void*)0
    31 #define ANDROID_LIBUI_PATH "libui.so"
    32 #define ANDROID_GLES_PATH "libGLESv2.so"
    33 #define ANDROID_EGL_PATH "libEGL.so"
    35 // Really I have no idea, but this should be big enough
    36 #define GRAPHIC_BUFFER_SIZE 1024
    38 enum {
    39     /* buffer is never read in software */
    40     GRALLOC_USAGE_SW_READ_NEVER   = 0x00000000,
    41     /* buffer is rarely read in software */
    42     GRALLOC_USAGE_SW_READ_RARELY  = 0x00000002,
    43     /* buffer is often read in software */
    44     GRALLOC_USAGE_SW_READ_OFTEN   = 0x00000003,
    45     /* mask for the software read values */
    46     GRALLOC_USAGE_SW_READ_MASK    = 0x0000000F,
    48     /* buffer is never written in software */
    49     GRALLOC_USAGE_SW_WRITE_NEVER  = 0x00000000,
    50     /* buffer is never written in software */
    51     GRALLOC_USAGE_SW_WRITE_RARELY = 0x00000020,
    52     /* buffer is never written in software */
    53     GRALLOC_USAGE_SW_WRITE_OFTEN  = 0x00000030,
    54     /* mask for the software write values */
    55     GRALLOC_USAGE_SW_WRITE_MASK   = 0x000000F0,
    57     /* buffer will be used as an OpenGL ES texture */
    58     GRALLOC_USAGE_HW_TEXTURE      = 0x00000100,
    59     /* buffer will be used as an OpenGL ES render target */
    60     GRALLOC_USAGE_HW_RENDER       = 0x00000200,
    61     /* buffer will be used by the 2D hardware blitter */
    62     GRALLOC_USAGE_HW_2D           = 0x00000400,
    63     /* buffer will be used with the framebuffer device */
    64     GRALLOC_USAGE_HW_FB           = 0x00001000,
    65     /* mask for the software usage bit-mask */
    66     GRALLOC_USAGE_HW_MASK         = 0x00001F00,
    67 };
    69 enum {
    70     HAL_PIXEL_FORMAT_RGBA_8888          = 1,
    71     HAL_PIXEL_FORMAT_RGBX_8888          = 2,
    72     HAL_PIXEL_FORMAT_RGB_888            = 3,
    73     HAL_PIXEL_FORMAT_RGB_565            = 4,
    74     HAL_PIXEL_FORMAT_BGRA_8888          = 5,
    75     HAL_PIXEL_FORMAT_RGBA_5551          = 6,
    76     HAL_PIXEL_FORMAT_RGBA_4444          = 7,
    77 };
    79 typedef struct ARect {
    80     int32_t left;
    81     int32_t top;
    82     int32_t right;
    83     int32_t bottom;
    84 } ARect;
    86 static bool gTryRealloc = true;
    88 static class GLFunctions
    89 {
    90 public:
    91   MOZ_CONSTEXPR GLFunctions() : fGetDisplay(nullptr),
    92                                 fEGLGetError(nullptr),
    93                                 fCreateImageKHR(nullptr),
    94                                 fDestroyImageKHR(nullptr),
    95                                 fImageTargetTexture2DOES(nullptr),
    96                                 fBindTexture(nullptr),
    97                                 fGLGetError(nullptr),
    98                                 fGraphicBufferCtor(nullptr),
    99                                 fGraphicBufferDtor(nullptr),
   100                                 fGraphicBufferLock(nullptr),
   101                                 fGraphicBufferLockRect(nullptr),
   102                                 fGraphicBufferUnlock(nullptr),
   103                                 fGraphicBufferGetNativeBuffer(nullptr),
   104                                 fGraphicBufferReallocate(nullptr),
   105                                 mInitialized(false)
   106   {
   107   }
   109   typedef EGLDisplay (* pfnGetDisplay)(void *display_id);
   110   pfnGetDisplay fGetDisplay;
   111   typedef EGLint (* pfnEGLGetError)(void);
   112   pfnEGLGetError fEGLGetError;
   114   typedef EGLImageKHR (* pfnCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
   115   pfnCreateImageKHR fCreateImageKHR;
   116   typedef EGLBoolean (* pfnDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image);
   117   pfnDestroyImageKHR fDestroyImageKHR;
   119   typedef void (* pfnImageTargetTexture2DOES)(GLenum target, EGLImageKHR image);
   120   pfnImageTargetTexture2DOES fImageTargetTexture2DOES;
   122   typedef void (* pfnBindTexture)(GLenum target, GLuint texture);
   123   pfnBindTexture fBindTexture;
   125   typedef GLenum (* pfnGLGetError)();
   126   pfnGLGetError fGLGetError;
   128   typedef void (*pfnGraphicBufferCtor)(void*, uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
   129   pfnGraphicBufferCtor fGraphicBufferCtor;
   131   typedef void (*pfnGraphicBufferDtor)(void*);
   132   pfnGraphicBufferDtor fGraphicBufferDtor;
   134   typedef int (*pfnGraphicBufferLock)(void*, uint32_t usage, unsigned char **addr);
   135   pfnGraphicBufferLock fGraphicBufferLock;
   137   typedef int (*pfnGraphicBufferLockRect)(void*, uint32_t usage, const ARect&, unsigned char **addr);
   138   pfnGraphicBufferLockRect fGraphicBufferLockRect;
   140   typedef int (*pfnGraphicBufferUnlock)(void*);
   141   pfnGraphicBufferUnlock fGraphicBufferUnlock;
   143   typedef void* (*pfnGraphicBufferGetNativeBuffer)(void*);
   144   pfnGraphicBufferGetNativeBuffer fGraphicBufferGetNativeBuffer;
   146   typedef int (*pfnGraphicBufferReallocate)(void*, uint32_t w, uint32_t h, uint32_t format);
   147   pfnGraphicBufferReallocate fGraphicBufferReallocate;
   149   bool EnsureInitialized()
   150   {
   151     if (mInitialized) {
   152       return true;
   153     }
   155     void *handle = dlopen(ANDROID_EGL_PATH, RTLD_LAZY);
   156     if (!handle) {
   157       LOG("Couldn't load EGL library");
   158       return false;
   159     }
   161     fGetDisplay = (pfnGetDisplay)dlsym(handle, "eglGetDisplay");
   162     fEGLGetError = (pfnEGLGetError)dlsym(handle, "eglGetError");
   163     fCreateImageKHR = (pfnCreateImageKHR)dlsym(handle, "eglCreateImageKHR");
   164     fDestroyImageKHR = (pfnDestroyImageKHR)dlsym(handle, "eglDestroyImageKHR");
   166     if (!fGetDisplay || !fEGLGetError || !fCreateImageKHR || !fDestroyImageKHR) {
   167       LOG("Failed to find some EGL functions");
   168       return false;
   169     }
   171     handle = dlopen(ANDROID_GLES_PATH, RTLD_LAZY);
   172     if (!handle) {
   173       LOG("Couldn't load GL library");
   174       return false;
   175     }
   177     fImageTargetTexture2DOES = (pfnImageTargetTexture2DOES)dlsym(handle, "glEGLImageTargetTexture2DOES");
   178     fBindTexture = (pfnBindTexture)dlsym(handle, "glBindTexture");
   179     fGLGetError = (pfnGLGetError)dlsym(handle, "glGetError");
   181     if (!fImageTargetTexture2DOES || !fBindTexture || !fGLGetError) {
   182       LOG("Failed to find some GL functions");
   183       return false;
   184     }
   186     handle = dlopen(ANDROID_LIBUI_PATH, RTLD_LAZY);
   187     if (!handle) {
   188       LOG("Couldn't load libui.so");
   189       return false;
   190     }
   192     fGraphicBufferCtor = (pfnGraphicBufferCtor)dlsym(handle, "_ZN7android13GraphicBufferC1Ejjij");
   193     fGraphicBufferDtor = (pfnGraphicBufferDtor)dlsym(handle, "_ZN7android13GraphicBufferD1Ev");
   194     fGraphicBufferLock = (pfnGraphicBufferLock)dlsym(handle, "_ZN7android13GraphicBuffer4lockEjPPv");
   195     fGraphicBufferLockRect = (pfnGraphicBufferLockRect)dlsym(handle, "_ZN7android13GraphicBuffer4lockEjRKNS_4RectEPPv");
   196     fGraphicBufferUnlock = (pfnGraphicBufferUnlock)dlsym(handle, "_ZN7android13GraphicBuffer6unlockEv");
   197     fGraphicBufferGetNativeBuffer = (pfnGraphicBufferGetNativeBuffer)dlsym(handle, "_ZNK7android13GraphicBuffer15getNativeBufferEv");
   198     fGraphicBufferReallocate = (pfnGraphicBufferReallocate)dlsym(handle, "_ZN7android13GraphicBuffer10reallocateEjjij");
   200     if (!fGraphicBufferCtor || !fGraphicBufferDtor || !fGraphicBufferLock ||
   201         !fGraphicBufferUnlock || !fGraphicBufferGetNativeBuffer) {
   202       LOG("Failed to lookup some GraphicBuffer functions");
   203       return false;
   204     }
   206     mInitialized = true;
   207     return true;
   208   }
   210 private:
   211   bool mInitialized;
   213 } sGLFunctions;
   215 namespace mozilla {
   217 static void clearGLError()
   218 {
   219   while (glGetError() != GL_NO_ERROR);
   220 }
   222 static bool ensureNoGLError(const char* name)
   223 {
   224   bool result = true;
   225   GLuint error;
   227   while ((error = glGetError()) != GL_NO_ERROR) {
   228     LOG("GL error [%s]: %40x\n", name, error);
   229     result = false;
   230   }
   232   return result;
   233 }
   235 AndroidGraphicBuffer::AndroidGraphicBuffer(uint32_t width, uint32_t height, uint32_t usage,
   236                                            gfxImageFormat format) :
   237     mWidth(width)
   238   , mHeight(height)
   239   , mUsage(usage)
   240   , mFormat(format)
   241   , mHandle(0)
   242   , mEGLImage(0)
   243 {
   244 }
   246 AndroidGraphicBuffer::~AndroidGraphicBuffer()
   247 {
   248   DestroyBuffer();
   249 }
   251 void
   252 AndroidGraphicBuffer::DestroyBuffer()
   253 {
   254   /**
   255    * XXX: eglDestroyImageKHR crashes sometimes due to refcount badness (I think)
   256    *
   257    * If you look at egl.cpp (https://github.com/android/platform_frameworks_base/blob/master/opengl/libagl/egl.cpp#L2002)
   258    * you can see that eglCreateImageKHR just refs the native buffer, and eglDestroyImageKHR
   259    * just unrefs it. Somehow the ref count gets messed up and things are already destroyed
   260    * by the time eglDestroyImageKHR gets called. For now, at least, just not calling
   261    * eglDestroyImageKHR should be fine since we do free the GraphicBuffer below.
   262    *
   263    * Bug 712716
   264    */
   265 #if 0
   266   if (mEGLImage) {
   267     if (sGLFunctions.EnsureInitialized()) {
   268       sGLFunctions.fDestroyImageKHR(sGLFunctions.fGetDisplay(EGL_DEFAULT_DISPLAY), mEGLImage);
   269       mEGLImage = nullptr;
   270     }
   271   }
   272 #endif
   273   mEGLImage = nullptr;
   275   if (mHandle) {
   276     if (sGLFunctions.EnsureInitialized()) {
   277       sGLFunctions.fGraphicBufferDtor(mHandle);
   278     }
   279     free(mHandle);
   280     mHandle = nullptr;
   281   }
   283 }
   285 bool
   286 AndroidGraphicBuffer::EnsureBufferCreated()
   287 {
   288   if (!mHandle) {
   289     mHandle = malloc(GRAPHIC_BUFFER_SIZE);
   290     sGLFunctions.fGraphicBufferCtor(mHandle, mWidth, mHeight, GetAndroidFormat(mFormat), GetAndroidUsage(mUsage));
   291   }
   293   return true;
   294 }
   296 bool
   297 AndroidGraphicBuffer::EnsureInitialized()
   298 {
   299   if (!sGLFunctions.EnsureInitialized()) {
   300     return false;
   301   }
   303   EnsureBufferCreated();
   304   return true;
   305 }
   307 int
   308 AndroidGraphicBuffer::Lock(uint32_t aUsage, unsigned char **bits)
   309 {
   310   if (!EnsureInitialized())
   311     return true;
   313   return sGLFunctions.fGraphicBufferLock(mHandle, GetAndroidUsage(aUsage), bits);
   314 }
   316 int
   317 AndroidGraphicBuffer::Lock(uint32_t aUsage, const nsIntRect& aRect, unsigned char **bits)
   318 {
   319   if (!EnsureInitialized())
   320     return false;
   322   ARect rect;
   323   rect.left = aRect.x;
   324   rect.top = aRect.y;
   325   rect.right = aRect.x + aRect.width;
   326   rect.bottom = aRect.y + aRect.height;
   328   return sGLFunctions.fGraphicBufferLockRect(mHandle, GetAndroidUsage(aUsage), rect, bits);
   329 }
   331 int
   332 AndroidGraphicBuffer::Unlock()
   333 {
   334   if (!EnsureInitialized())
   335     return false;
   337   return sGLFunctions.fGraphicBufferUnlock(mHandle);
   338 }
   340 bool
   341 AndroidGraphicBuffer::Reallocate(uint32_t aWidth, uint32_t aHeight, gfxImageFormat aFormat)
   342 {
   343   if (!EnsureInitialized())
   344     return false;
   346   mWidth = aWidth;
   347   mHeight = aHeight;
   348   mFormat = aFormat;
   350   // Sometimes GraphicBuffer::reallocate just doesn't work. In those cases we'll just allocate a brand
   351   // new buffer. If reallocate fails once, never try it again.
   352   if (!gTryRealloc || sGLFunctions.fGraphicBufferReallocate(mHandle, aWidth, aHeight, GetAndroidFormat(aFormat)) != 0) {
   353     DestroyBuffer();
   354     EnsureBufferCreated();
   356     gTryRealloc = false;
   357   }
   359   return true;
   360 }
   362 uint32_t
   363 AndroidGraphicBuffer::GetAndroidUsage(uint32_t aUsage)
   364 {
   365   uint32_t flags = 0;
   367   if (aUsage & UsageSoftwareRead) {
   368     flags |= GRALLOC_USAGE_SW_READ_OFTEN;
   369   }
   371   if (aUsage & UsageSoftwareWrite) {
   372     flags |= GRALLOC_USAGE_SW_WRITE_OFTEN;
   373   }
   375   if (aUsage & UsageTexture) {
   376     flags |= GRALLOC_USAGE_HW_TEXTURE;
   377   }
   379   if (aUsage & UsageTarget) {
   380     flags |= GRALLOC_USAGE_HW_RENDER;
   381   }
   383   if (aUsage & Usage2D) {
   384     flags |= GRALLOC_USAGE_HW_2D;
   385   }
   387   return flags;
   388 }
   390 uint32_t
   391 AndroidGraphicBuffer::GetAndroidFormat(gfxImageFormat aFormat)
   392 {
   393   switch (aFormat) {
   394     case gfxImageFormat::RGB24:
   395       return HAL_PIXEL_FORMAT_RGBX_8888;
   396     case gfxImageFormat::RGB16_565:
   397       return HAL_PIXEL_FORMAT_RGB_565;
   398     default:
   399       return 0;
   400   }
   401 }
   403 bool
   404 AndroidGraphicBuffer::EnsureEGLImage()
   405 {
   406   if (mEGLImage)
   407     return true;
   410   if (!EnsureInitialized())
   411     return false;
   413   EGLint eglImgAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE };
   414   void* nativeBuffer = sGLFunctions.fGraphicBufferGetNativeBuffer(mHandle);
   416   mEGLImage = sGLFunctions.fCreateImageKHR(sGLFunctions.fGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)nativeBuffer, eglImgAttrs);
   417   return mEGLImage != nullptr;
   418 }
   420 bool
   421 AndroidGraphicBuffer::Bind()
   422 {
   423   if (!EnsureInitialized())
   424     return false;
   426   if (!EnsureEGLImage()) {
   427     LOG("No valid EGLImage!");
   428     return false;
   429   }
   431   clearGLError();
   432   sGLFunctions.fImageTargetTexture2DOES(GL_TEXTURE_2D, mEGLImage);
   433   return ensureNoGLError("glEGLImageTargetTexture2DOES");
   434 }
   436 // Build whitelist to check for board type.
   437 static void InitWhiteList(nsTArray<nsString>& list)
   438 {
   439   nsString ele;
   440   ele.AssignASCII("droid2"); // Motorola Droid 2
   441   list.AppendElement(ele);
   442   ele.AssignASCII("GT-I9100"); // Samsung Galaxy SII
   443   list.AppendElement(ele);
   444   ele.AssignASCII("herring"); // Samsung Nexus S
   445   list.AppendElement(ele);
   446   ele.AssignASCII("omap4sdp"); // Amazon Kindle Fire
   447   list.AppendElement(ele);
   448   ele.AssignASCII("SGH-I897"); // Samsung Galaxy S
   449   list.AppendElement(ele);
   450   ele.AssignASCII("sgh-i997"); // Samsung Infuse 4G
   451   list.AppendElement(ele);
   452   ele.AssignASCII("sgh-t839"); // Samsung Sidekick 4G
   453   list.AppendElement(ele);
   454   ele.AssignASCII("shadow"); // Motorola Droid X
   455   list.AppendElement(ele);
   456   ele.AssignASCII("spyder"); // Motorola Razr
   457   list.AppendElement(ele);
   458   ele.AssignASCII("targa"); // Motorola Droid Bionic
   459   list.AppendElement(ele);
   460   ele.AssignASCII("tuna"); // Galaxy Nexus
   461   list.AppendElement(ele);
   462   ele.AssignASCII("venus2"); // Motorla Droid Pro
   463   list.AppendElement(ele);
   464 }
   466 bool
   467 AndroidGraphicBuffer::IsBlacklisted()
   468 {
   469   nsAutoString board;
   470   if (!AndroidBridge::Bridge()->GetStaticStringField("android/os/Build", "BOARD", board))
   471     return true;
   473   NS_ConvertUTF16toUTF8 boardUtf8(board);
   475   if (Preferences::GetBool("direct-texture.force.enabled", false)) {
   476     LOG("allowing board '%s' due to prefs override", boardUtf8.get());
   477     return false;
   478   }
   480   if (Preferences::GetBool("direct-texture.force.disabled", false)) {
   481     LOG("disallowing board '%s' due to prefs override", boardUtf8.get());
   482     return true;
   483   }
   485   static nsTArray<nsString> sListAllowed;
   486   if (sListAllowed.Length() == 0) {
   487     InitWhiteList(sListAllowed);
   488   }
   490   int i = -1;
   491   if ((i = sListAllowed.BinaryIndexOf(board)) >= 0) {
   492     nsString name = sListAllowed.ElementAt(i);
   493     LOG("allowing board '%s' based on '%s'\n", boardUtf8.get(), NS_ConvertUTF16toUTF8(name).get());
   494     return false;
   495   }
   497   LOG("disallowing board: %s\n", boardUtf8.get());
   498   return true;
   499 }
   501 } /* mozilla */

mercurial