diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 6ce81de2bf98..8d326e1c202f 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -1229,17 +1229,32 @@ public class GeckoAppShell return accessibilityManager.isEnabled(); } - public static void addPluginView(View view, - double x, double y, - double w, double h) - { + public static void addPluginView(final View view, + final double x, final double y, + final double w, final double h) { Log.i(LOGTAG, "addPluginView:" + view + " @ x:" + x + " y:" + y + " w:" + w + " h:" + h ) ; - GeckoApp.mAppContext.addPluginView(view, x, y, w, h); + getMainHandler().post(new Runnable() { + public void run() { + try { + GeckoApp.mAppContext.addPluginView(view, x, y, w, h); + } catch (Exception e) { + Log.e(LOGTAG, "Failed to add plugin view: ", e); + } + } + }); } - public static void removePluginView(View view) { - Log.i(LOGTAG, "remove view:" + view); - GeckoApp.mAppContext.removePluginView(view); + public static void removePluginView(final View view) { + Log.i(LOGTAG, "removePluginView:" + view); + getMainHandler().post(new Runnable() { + public void run() { + try { + GeckoApp.mAppContext.removePluginView(view); + } catch (Exception e) { + Log.e(LOGTAG, "Failed to remove plugin view: ", e); + } + } + }); } public static Class loadPluginClass(String className, String libName) { diff --git a/widget/src/android/AndroidDirectTexture.cpp b/widget/src/android/AndroidDirectTexture.cpp new file mode 100644 index 000000000000..5a118e4bf4c8 --- /dev/null +++ b/widget/src/android/AndroidDirectTexture.cpp @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "AndroidDirectTexture.h" + +typedef gfxASurface::gfxImageFormat gfxImageFormat; + +namespace mozilla { + +AndroidDirectTexture::AndroidDirectTexture(PRUint32 width, PRUint32 height, PRUint32 usage, + gfxImageFormat format) : + mLock("AndroidDirectTexture.mLock") + , mNeedFlip(false) + , mWidth(width) + , mHeight(height) + , mFormat(format) + , mPendingReallocBuffer(NULL) +{ + mFrontBuffer = new AndroidGraphicBuffer(width, height, usage, format); + mBackBuffer = new AndroidGraphicBuffer(width, height, usage, format); +} + +AndroidDirectTexture::~AndroidDirectTexture() +{ + if (mFrontBuffer) { + delete mFrontBuffer; + mFrontBuffer = NULL; + } + + if (mBackBuffer) { + delete mBackBuffer; + mBackBuffer = NULL; + } +} + +void +AndroidDirectTexture::ReallocPendingBuffer() +{ + // We may have reallocated while the current back buffer was being + // used as the front buffer. If we have such a reallocation pending + // and the current back buffer is the target buffer, do it now. + // + // It is assumed that mLock is already acquired + if (mPendingReallocBuffer == mBackBuffer) { + mBackBuffer->Reallocate(mWidth, mHeight, mFormat); + mPendingReallocBuffer = NULL; + } +} + +bool +AndroidDirectTexture::Lock(PRUint32 aUsage, unsigned char **bits) +{ + mLock.Lock(); + ReallocPendingBuffer(); + return mBackBuffer->Lock(aUsage, bits); +} + +bool +AndroidDirectTexture::Lock(PRUint32 aUsage, const nsIntRect& aRect, unsigned char **bits) +{ + mLock.Lock(); + ReallocPendingBuffer(); + return mBackBuffer->Lock(aUsage, aRect, bits); +} + +bool +AndroidDirectTexture::Unlock(bool aFlip) +{ + if (aFlip) { + mNeedFlip = true; + } + + bool result = mBackBuffer->Unlock(); + mLock.Unlock(); + + return result; +} + +bool +AndroidDirectTexture::Reallocate(PRUint32 aWidth, PRUint32 aHeight) { + return Reallocate(aWidth, aHeight, mFormat); +} + +bool +AndroidDirectTexture::Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat) +{ + MutexAutoLock lock(mLock); + + // We only reallocate the current back buffer. The front buffer is likely + // in use, so we'll reallocate it on the first Lock() after it is rotated + // to the back. + bool result = mBackBuffer->Reallocate(aWidth, aHeight, aFormat); + if (result) { + mPendingReallocBuffer = mFrontBuffer; + } + + return result; +} + +bool +AndroidDirectTexture::Bind() +{ + MutexAutoLock lock(mLock); + + if (mNeedFlip) { + AndroidGraphicBuffer* tmp = mBackBuffer; + mBackBuffer = mFrontBuffer; + mFrontBuffer = tmp; + mNeedFlip = false; + } + + return mFrontBuffer->Bind(); +} + +} /* mozilla */ diff --git a/widget/src/android/AndroidDirectTexture.h b/widget/src/android/AndroidDirectTexture.h new file mode 100644 index 000000000000..f4914e1aae66 --- /dev/null +++ b/widget/src/android/AndroidDirectTexture.h @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef AndroidDirectTexture_h_ +#define AndroidDirectTexture_h_ + +#include "gfxASurface.h" +#include "nsRect.h" +#include "mozilla/Mutex.h" +#include "AndroidGraphicBuffer.h" + +namespace mozilla { + +/** + * This is a thread safe wrapper around AndroidGraphicBuffer that handles + * double buffering. Each call to Bind() flips the buffer when necessary. + * + * You need to be careful when destroying an instance of this class. If either + * buffer is locked by the application of the driver/hardware, bad things will + * happen. Be sure that the OpenGL texture is no longer on the screen. + */ +class AndroidDirectTexture +{ +public: + AndroidDirectTexture(PRUint32 width, PRUint32 height, PRUint32 usage, gfxASurface::gfxImageFormat format); + virtual ~AndroidDirectTexture(); + + bool Lock(PRUint32 usage, unsigned char **bits); + bool Lock(PRUint32 usage, const nsIntRect& rect, unsigned char **bits); + bool Unlock(bool aFlip = true); + + bool Reallocate(PRUint32 aWidth, PRUint32 aHeight); + bool Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat); + + PRUint32 Width() { return mWidth; } + PRUint32 Height() { return mHeight; } + + bool Bind(); + +private: + mozilla::Mutex mLock; + bool mNeedFlip; + + PRUint32 mWidth; + PRUint32 mHeight; + gfxASurface::gfxImageFormat mFormat; + + AndroidGraphicBuffer* mFrontBuffer; + AndroidGraphicBuffer* mBackBuffer; + + AndroidGraphicBuffer* mPendingReallocBuffer; + void ReallocPendingBuffer(); +}; + +} /* mozilla */ +#endif /* AndroidDirectTexture_h_ */ diff --git a/widget/src/android/AndroidGraphicBuffer.cpp b/widget/src/android/AndroidGraphicBuffer.cpp new file mode 100644 index 000000000000..91e6b8fec334 --- /dev/null +++ b/widget/src/android/AndroidGraphicBuffer.cpp @@ -0,0 +1,433 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include "AndroidGraphicBuffer.h" + +#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AndroidGraphicBuffer" , ## args) + +#define EGL_NATIVE_BUFFER_ANDROID 0x3140 +#define EGL_IMAGE_PRESERVED_KHR 0x30D2 + +typedef void* EGLContext; +typedef void* EGLImageKHR; +typedef void* EGLClientBuffer; +typedef void* EGLDisplay; + +typedef PRUint32 EGLenum; +typedef PRInt32 EGLint; +typedef PRUint32 EGLBoolean; + +typedef gfxASurface::gfxImageFormat gfxImageFormat; + +#define EGL_TRUE 1 +#define EGL_FALSE 0 +#define EGL_NONE 0x3038 +#define EGL_NO_CONTEXT (EGLContext)0 +#define EGL_DEFAULT_DISPLAY (void*)0 +#define ANDROID_LIBUI_PATH "/system/lib/libui.so" +#define ANDROID_GLES_PATH "/system/lib/libGLESv2.so" +#define ANDROID_EGL_PATH "/system/lib/libEGL.so" + +// Really I have no idea, but this should be big enough +#define GRAPHIC_BUFFER_SIZE 1024 + +enum { + /* buffer is never read in software */ + GRALLOC_USAGE_SW_READ_NEVER = 0x00000000, + /* buffer is rarely read in software */ + GRALLOC_USAGE_SW_READ_RARELY = 0x00000002, + /* buffer is often read in software */ + GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003, + /* mask for the software read values */ + GRALLOC_USAGE_SW_READ_MASK = 0x0000000F, + + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_NEVER = 0x00000000, + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_RARELY = 0x00000020, + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_OFTEN = 0x00000030, + /* mask for the software write values */ + GRALLOC_USAGE_SW_WRITE_MASK = 0x000000F0, + + /* buffer will be used as an OpenGL ES texture */ + GRALLOC_USAGE_HW_TEXTURE = 0x00000100, + /* buffer will be used as an OpenGL ES render target */ + GRALLOC_USAGE_HW_RENDER = 0x00000200, + /* buffer will be used by the 2D hardware blitter */ + GRALLOC_USAGE_HW_2D = 0x00000400, + /* buffer will be used with the framebuffer device */ + GRALLOC_USAGE_HW_FB = 0x00001000, + /* mask for the software usage bit-mask */ + GRALLOC_USAGE_HW_MASK = 0x00001F00, +}; + +enum { + HAL_PIXEL_FORMAT_RGBA_8888 = 1, + HAL_PIXEL_FORMAT_RGBX_8888 = 2, + HAL_PIXEL_FORMAT_RGB_888 = 3, + HAL_PIXEL_FORMAT_RGB_565 = 4, + HAL_PIXEL_FORMAT_BGRA_8888 = 5, + HAL_PIXEL_FORMAT_RGBA_5551 = 6, + HAL_PIXEL_FORMAT_RGBA_4444 = 7, +}; + +typedef struct AndroidRect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} AndroidRect; + +static bool gTryRealloc = true; + +static class GLFunctions +{ +public: + GLFunctions() : mInitialized(false) + { + } + + typedef EGLDisplay (* pfnGetDisplay)(void *display_id); + pfnGetDisplay fGetDisplay; + typedef EGLint (* pfnEGLGetError)(void); + pfnEGLGetError fEGLGetError; + + typedef EGLImageKHR (* pfnCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); + pfnCreateImageKHR fCreateImageKHR; + typedef EGLBoolean (* pfnDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image); + pfnDestroyImageKHR fDestroyImageKHR; + + typedef void (* pfnImageTargetTexture2DOES)(GLenum target, EGLImageKHR image); + pfnImageTargetTexture2DOES fImageTargetTexture2DOES; + + typedef void (* pfnBindTexture)(GLenum target, GLuint texture); + pfnBindTexture fBindTexture; + + typedef GLenum (* pfnGLGetError)(); + pfnGLGetError fGLGetError; + + typedef void (*pfnGraphicBufferCtor)(void*, PRUint32 w, PRUint32 h, PRUint32 format, PRUint32 usage); + pfnGraphicBufferCtor fGraphicBufferCtor; + + typedef void (*pfnGraphicBufferDtor)(void*); + pfnGraphicBufferDtor fGraphicBufferDtor; + + typedef int (*pfnGraphicBufferLock)(void*, PRUint32 usage, unsigned char **addr); + pfnGraphicBufferLock fGraphicBufferLock; + + typedef int (*pfnGraphicBufferLockRect)(void*, PRUint32 usage, const AndroidRect&, unsigned char **addr); + pfnGraphicBufferLockRect fGraphicBufferLockRect; + + typedef int (*pfnGraphicBufferUnlock)(void*); + pfnGraphicBufferUnlock fGraphicBufferUnlock; + + typedef void* (*pfnGraphicBufferGetNativeBuffer)(void*); + pfnGraphicBufferGetNativeBuffer fGraphicBufferGetNativeBuffer; + + typedef int (*pfnGraphicBufferReallocate)(void*, PRUint32 w, PRUint32 h, PRUint32 format); + pfnGraphicBufferReallocate fGraphicBufferReallocate; + + bool EnsureInitialized() + { + if (mInitialized) { + return true; + } + + void *handle = dlopen(ANDROID_EGL_PATH, RTLD_LAZY); + if (!handle) { + LOG("Couldn't load EGL library"); + return false; + } + + fGetDisplay = (pfnGetDisplay)dlsym(handle, "eglGetDisplay"); + fEGLGetError = (pfnEGLGetError)dlsym(handle, "eglGetError"); + fCreateImageKHR = (pfnCreateImageKHR)dlsym(handle, "eglCreateImageKHR"); + fDestroyImageKHR = (pfnDestroyImageKHR)dlsym(handle, "eglDestroyImageKHR"); + + if (!fGetDisplay || !fEGLGetError || !fCreateImageKHR || !fDestroyImageKHR) { + LOG("Failed to find some EGL functions"); + return false; + } + + handle = dlopen(ANDROID_GLES_PATH, RTLD_LAZY); + if (!handle) { + LOG("Couldn't load GL library"); + return false; + } + + fImageTargetTexture2DOES = (pfnImageTargetTexture2DOES)dlsym(handle, "glEGLImageTargetTexture2DOES"); + fBindTexture = (pfnBindTexture)dlsym(handle, "glBindTexture"); + fGLGetError = (pfnGLGetError)dlsym(handle, "glGetError"); + + if (!fImageTargetTexture2DOES || !fBindTexture || !fGLGetError) { + LOG("Failed to find some GL functions"); + return false; + } + + handle = dlopen(ANDROID_LIBUI_PATH, RTLD_LAZY); + if (!handle) { + LOG("Couldn't load libui.so"); + return false; + } + + fGraphicBufferCtor = (pfnGraphicBufferCtor)dlsym(handle, "_ZN7android13GraphicBufferC1Ejjij"); + fGraphicBufferDtor = (pfnGraphicBufferDtor)dlsym(handle, "_ZN7android13GraphicBufferD1Ev"); + fGraphicBufferLock = (pfnGraphicBufferLock)dlsym(handle, "_ZN7android13GraphicBuffer4lockEjPPv"); + fGraphicBufferLockRect = (pfnGraphicBufferLockRect)dlsym(handle, "_ZN7android13GraphicBuffer4lockEjRKNS_4RectEPPv"); + fGraphicBufferUnlock = (pfnGraphicBufferUnlock)dlsym(handle, "_ZN7android13GraphicBuffer6unlockEv"); + fGraphicBufferGetNativeBuffer = (pfnGraphicBufferGetNativeBuffer)dlsym(handle, "_ZNK7android13GraphicBuffer15getNativeBufferEv"); + fGraphicBufferReallocate = (pfnGraphicBufferReallocate)dlsym(handle, "_ZN7android13GraphicBuffer10reallocateEjjij"); + + if (!fGraphicBufferCtor || !fGraphicBufferDtor || !fGraphicBufferLock || + !fGraphicBufferUnlock || !fGraphicBufferGetNativeBuffer) { + LOG("Failed to lookup some GraphicBuffer functions"); + return false; + } + + mInitialized = true; + return true; + } + +private: + bool mInitialized; + +} sGLFunctions; + +namespace mozilla { + +static bool ensureNoGLError(const char* name) +{ + bool result = true; + GLuint error; + + while ((error = glGetError()) != GL_NO_ERROR) { + LOG("GL error [%s]: %40x\n", name, error); + result = false; + } + + return result; +} + +AndroidGraphicBuffer::AndroidGraphicBuffer(PRUint32 width, PRUint32 height, PRUint32 usage, + gfxImageFormat format) : + mWidth(width) + , mHeight(height) + , mUsage(usage) + , mFormat(format) + , mHandle(0) + , mEGLImage(0) +{ +} + +AndroidGraphicBuffer::~AndroidGraphicBuffer() +{ + DestroyBuffer(); +} + +void +AndroidGraphicBuffer::DestroyBuffer() +{ + if (mHandle) { + if (sGLFunctions.EnsureInitialized()) { + sGLFunctions.fGraphicBufferDtor(mHandle); + } + free(mHandle); + mHandle = NULL; + } + + if (mEGLImage) { + if (sGLFunctions.EnsureInitialized()) { + sGLFunctions.fDestroyImageKHR(sGLFunctions.fGetDisplay(EGL_DEFAULT_DISPLAY), mEGLImage); + mEGLImage = NULL; + } + } +} + +bool +AndroidGraphicBuffer::EnsureBufferCreated(PRUint32 aWidth, PRUint32 aHeight, PRUint32 aUsage, gfxImageFormat aFormat) +{ + if (!mHandle) { + mHandle = malloc(GRAPHIC_BUFFER_SIZE); + sGLFunctions.fGraphicBufferCtor(mHandle, mWidth, mHeight, GetAndroidFormat(aFormat), GetAndroidUsage(aUsage)); + } + + return true; +} + +bool +AndroidGraphicBuffer::EnsureInitialized() +{ + if (!sGLFunctions.EnsureInitialized()) { + return false; + } + + EnsureBufferCreated(mWidth, mHeight, mUsage, mFormat); + return true; +} + +bool +AndroidGraphicBuffer::Lock(PRUint32 aUsage, unsigned char **bits) +{ + if (!EnsureInitialized()) + return true; + + return sGLFunctions.fGraphicBufferLock(mHandle, GetAndroidUsage(aUsage), bits) == 0; +} + +bool +AndroidGraphicBuffer::Lock(PRUint32 aUsage, const nsIntRect& aRect, unsigned char **bits) +{ + if (!EnsureInitialized()) + return false; + + AndroidRect rect; + rect.left = aRect.x; + rect.top = aRect.y; + rect.right = aRect.x + aRect.width; + rect.bottom = aRect.y + aRect.height; + + return sGLFunctions.fGraphicBufferLockRect(mHandle, GetAndroidUsage(aUsage), rect, bits) == 0; +} + +bool +AndroidGraphicBuffer::Unlock() +{ + if (!EnsureInitialized()) + return false; + + return sGLFunctions.fGraphicBufferUnlock(mHandle) == 0; +} + +bool +AndroidGraphicBuffer::Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxImageFormat aFormat) +{ + if (!EnsureInitialized()) + return false; + + // Sometimes GraphicBuffer::reallocate just doesn't work. In those cases we'll just allocate a brand + // new buffer. If reallocate fails once, never try it again. + if (!gTryRealloc || sGLFunctions.fGraphicBufferReallocate(mHandle, aWidth, aHeight, GetAndroidFormat(aFormat)) != 0) { + DestroyBuffer(); + EnsureBufferCreated(aWidth, aHeight, mUsage, aFormat); + + gTryRealloc = false; + } + + mWidth = aWidth; + mHeight = aHeight; + mFormat = aFormat; + + return true; +} + +PRUint32 +AndroidGraphicBuffer::GetAndroidUsage(PRUint32 aUsage) +{ + PRUint32 flags = 0; + + if (aUsage & UsageSoftwareRead) { + flags |= GRALLOC_USAGE_SW_READ_OFTEN; + } + + if (aUsage & UsageSoftwareWrite) { + flags |= GRALLOC_USAGE_SW_WRITE_OFTEN; + } + + if (aUsage & UsageTexture) { + flags |= GRALLOC_USAGE_HW_TEXTURE; + } + + if (aUsage & UsageTarget) { + flags |= GRALLOC_USAGE_HW_RENDER; + } + + if (aUsage & Usage2D) { + flags |= GRALLOC_USAGE_HW_2D; + } + + return flags; +} + +PRUint32 +AndroidGraphicBuffer::GetAndroidFormat(gfxImageFormat aFormat) +{ + switch (aFormat) { + case gfxImageFormat::ImageFormatRGB24: + return HAL_PIXEL_FORMAT_RGBX_8888; + case gfxImageFormat::ImageFormatRGB16_565: + return HAL_PIXEL_FORMAT_RGB_565; + default: + return 0; + } +} + +bool +AndroidGraphicBuffer::EnsureEGLImage() +{ + if (mEGLImage) + return true; + + if (!EnsureInitialized()) + return false; + + EGLint eglImgAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE }; + void* nativeBuffer = sGLFunctions.fGraphicBufferGetNativeBuffer(mHandle); + + mEGLImage = sGLFunctions.fCreateImageKHR(sGLFunctions.fGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)nativeBuffer, eglImgAttrs); + return mEGLImage != NULL; +} + +bool +AndroidGraphicBuffer::Bind() +{ + if (!EnsureInitialized()) + return false; + + if (!EnsureEGLImage()) { + LOG("No valid EGLImage!"); + return false; + } + + sGLFunctions.fImageTargetTexture2DOES(GL_TEXTURE_2D, mEGLImage); + return ensureNoGLError("glEGLImageTargetTexture2DOES"); +} + +} /* mozilla */ diff --git a/widget/src/android/AndroidGraphicBuffer.h b/widget/src/android/AndroidGraphicBuffer.h new file mode 100644 index 000000000000..961c7e29d3bf --- /dev/null +++ b/widget/src/android/AndroidGraphicBuffer.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef AndroidGraphicBuffer_h_ +#define AndroidGraphicBuffer_h_ + +#include "gfxASurface.h" +#include "nsRect.h" + +namespace mozilla { + +/** + * This class allows access to Android's direct texturing mechanism. Locking + * the buffer gives you a pointer you can read/write to directly. It is fully + * threadsafe, but you probably really want to use the AndroidDirectTexture + * class which will handle double buffering. + * + * In order to use the buffer in OpenGL, just call Bind() and it will attach + * to whatever texture is bound to GL_TEXTURE_2D. + */ +class AndroidGraphicBuffer +{ +public: + enum { + UsageSoftwareRead = 1, + UsageSoftwareWrite = 1 << 1, + UsageTexture = 1 << 2, + UsageTarget = 1 << 3, + Usage2D = 1 << 4 + }; + + AndroidGraphicBuffer(PRUint32 width, PRUint32 height, PRUint32 usage, gfxASurface::gfxImageFormat format); + virtual ~AndroidGraphicBuffer(); + + bool Lock(PRUint32 usage, unsigned char **bits); + bool Lock(PRUint32 usage, const nsIntRect& rect, unsigned char **bits); + bool Unlock(); + bool Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat); + + PRUint32 Width() { return mWidth; } + PRUint32 Height() { return mHeight; } + + bool Bind(); + +private: + PRUint32 mWidth; + PRUint32 mHeight; + PRUint32 mUsage; + gfxASurface::gfxImageFormat mFormat; + + bool EnsureInitialized(); + bool EnsureEGLImage(); + + void DestroyBuffer(); + bool EnsureBufferCreated(PRUint32 aWidth, PRUint32 aHeight, PRUint32 aUsage, gfxASurface::gfxImageFormat aFormat); + + PRUint32 GetAndroidUsage(PRUint32 aUsage); + PRUint32 GetAndroidFormat(gfxASurface::gfxImageFormat aFormat); + + void *mHandle; + void *mEGLImage; +}; + +} /* mozilla */ +#endif /* AndroidGraphicBuffer_h_ */