From 30e0f551ce9d37d37f077e157d0051a56f9bf4d6 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Fri, 20 Jul 2012 15:20:51 -0400 Subject: [PATCH] Bug 687267 - Initial support for Flash on Honeycomb r=bgirard,vlad,jgilbert,blassey --- dom/plugins/base/android/ANPNativeWindow.cpp | 24 +- dom/plugins/base/android/ANPOpenGL.cpp | 47 ++- dom/plugins/base/android/ANPVideo.cpp | 50 +--- dom/plugins/base/nsNPAPIPluginInstance.cpp | 243 ++++++++++++++- dom/plugins/base/nsNPAPIPluginInstance.h | 73 ++++- dom/plugins/base/nsPluginInstanceOwner.cpp | 121 +++++--- dom/plugins/base/nsPluginInstanceOwner.h | 31 +- embedding/android/GeckoAppShell.java | 8 +- gfx/gl/GLContext.h | 34 +++ gfx/gl/GLContextProviderEGL.cpp | 230 +++++++++++++-- gfx/gl/GLDefs.h | 4 + gfx/layers/ImageLayers.cpp | 3 + gfx/layers/ImageLayers.h | 5 + gfx/layers/Makefile.in | 3 + gfx/layers/SharedTextureImage.h | 44 +++ gfx/layers/basic/BasicCanvasLayer.cpp | 2 +- gfx/layers/basic/BasicImageLayer.cpp | 12 + gfx/layers/ipc/LayersSurfaces.ipdlh | 1 + gfx/layers/opengl/CanvasLayerOGL.cpp | 2 +- gfx/layers/opengl/ImageLayerOGL.cpp | 118 ++++++-- gfx/layers/opengl/ImageLayerOGL.h | 7 + gfx/layers/opengl/LayerManagerOGL.cpp | 5 + gfx/layers/opengl/LayerManagerOGLProgram.cpp | 17 ++ gfx/layers/opengl/LayerManagerOGLProgram.h | 11 +- gfx/layers/opengl/LayerManagerOGLShaders.h | 85 ++++++ gfx/layers/opengl/LayerManagerOGLShaders.txt | 14 + gfx/layers/opengl/TexturePoolOGL.cpp | 115 ++++++++ gfx/layers/opengl/TexturePoolOGL.h | 38 +++ gfx/thebes/Makefile.in | 2 + gfx/thebes/gfxPlatform.cpp | 14 + gfx/thebes/nsSurfaceTexture.cpp | 263 +++++++++++++++++ gfx/thebes/nsSurfaceTexture.h | 64 ++++ layout/base/nsDisplayItemTypes.h | 1 + layout/generic/nsObjectFrame.cpp | 118 ++++++++ mobile/android/base/GeckoApp.java | 67 ----- mobile/android/base/GeckoAppShell.java | 41 +-- mobile/android/base/Makefile.in | 1 - .../android/base/gfx/SurfaceTextureLayer.java | 279 ------------------ mozglue/android/APKOpen.cpp | 2 + widget/android/AndroidBridge.cpp | 164 +++++----- widget/android/AndroidBridge.h | 21 +- widget/android/AndroidJNI.cpp | 13 + widget/android/AndroidMediaLayer.cpp | 148 ---------- widget/android/AndroidMediaLayer.h | 73 ----- widget/android/Makefile.in | 2 +- widget/android/android/StrongPointer.h | 239 +++++++++++++++ 46 files changed, 1981 insertions(+), 878 deletions(-) create mode 100644 gfx/layers/SharedTextureImage.h create mode 100644 gfx/layers/opengl/TexturePoolOGL.cpp create mode 100644 gfx/layers/opengl/TexturePoolOGL.h create mode 100644 gfx/thebes/nsSurfaceTexture.cpp create mode 100644 gfx/thebes/nsSurfaceTexture.h delete mode 100644 mobile/android/base/gfx/SurfaceTextureLayer.java delete mode 100644 widget/android/AndroidMediaLayer.cpp delete mode 100644 widget/android/AndroidMediaLayer.h create mode 100644 widget/android/android/StrongPointer.h diff --git a/dom/plugins/base/android/ANPNativeWindow.cpp b/dom/plugins/base/android/ANPNativeWindow.cpp index b2b948e47e18..c66d5eb8d3f3 100644 --- a/dom/plugins/base/android/ANPNativeWindow.cpp +++ b/dom/plugins/base/android/ANPNativeWindow.cpp @@ -6,7 +6,6 @@ // must include config.h first for webkit to fiddle with new/delete #include #include "AndroidBridge.h" -#include "AndroidMediaLayer.h" #include "ANPBase.h" #include "nsIPluginInstanceOwner.h" #include "nsPluginInstanceOwner.h" @@ -19,29 +18,14 @@ using namespace mozilla; #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) #define ASSIGN(obj, name) (obj)->name = anp_native_window_##name -static nsresult GetOwner(NPP instance, nsPluginInstanceOwner** owner) { +static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) { nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); - - return pinst->GetOwner((nsIPluginInstanceOwner**)owner); -} - -static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) { - nsRefPtr owner; - if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) - return NULL; - - ANPNativeWindow window = owner->Layer()->GetNativeWindowForContent(); - owner->Invalidate(); - - return window; + return pinst->AcquireContentWindow(); } static void anp_native_window_invertPluginContent(NPP instance, bool isContentInverted) { - nsRefPtr owner; - if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) - return; - - owner->Layer()->SetInverted(isContentInverted); + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); + pinst->SetInverted(isContentInverted); } diff --git a/dom/plugins/base/android/ANPOpenGL.cpp b/dom/plugins/base/android/ANPOpenGL.cpp index aaa98615c359..598720fa3ed7 100644 --- a/dom/plugins/base/android/ANPOpenGL.cpp +++ b/dom/plugins/base/android/ANPOpenGL.cpp @@ -8,6 +8,8 @@ #include "ANPBase.h" #include "GLContextProvider.h" #include "nsNPAPIPluginInstance.h" +#include "nsPluginInstanceOwner.h" +#include "GLContextProvider.h" #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) #define ASSIGN(obj, name) (obj)->name = anp_opengl_##name @@ -15,24 +17,53 @@ using namespace mozilla; using namespace mozilla::gl; -static ANPEGLContext anp_opengl_acquireContext(NPP inst) { - // Bug 687267 - NOT_IMPLEMENTED(); - return NULL; +typedef nsNPAPIPluginInstance::TextureInfo TextureInfo; + +static ANPEGLContext anp_opengl_acquireContext(NPP instance) { + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); + + GLContext* context = pinst->GLContext(); + if (!context) + return NULL; + + context->MakeCurrent(); + return context->GetNativeData(GLContext::NativeGLContext); } static ANPTextureInfo anp_opengl_lockTexture(NPP instance) { - ANPTextureInfo info = { 0, 0, 0, 0 }; - NOT_IMPLEMENTED(); + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); + + TextureInfo pluginInfo = pinst->LockContentTexture(); + + ANPTextureInfo info; + info.textureId = pluginInfo.mTexture; + info.width = pluginInfo.mWidth; + info.height = pluginInfo.mHeight; + + // It looks like we should be passing whatever + // internal format Flash told us it used previously + // (e.g., the value of pluginInfo.mInternalFormat), + // but if we do that it doesn't upload to the texture + // for some reason. + info.internalFormat = 0; + return info; } static void anp_opengl_releaseTexture(NPP instance, const ANPTextureInfo* info) { - NOT_IMPLEMENTED(); + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); + + TextureInfo pluginInfo(info->textureId, info->width, info->height, info->internalFormat); + pinst->ReleaseContentTexture(pluginInfo); + pinst->RedrawPlugin(); } static void anp_opengl_invertPluginContent(NPP instance, bool isContentInverted) { - NOT_IMPLEMENTED(); + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); + + // Our definition of inverted is the opposite of the plugin's + pinst->SetInverted(!isContentInverted); + pinst->RedrawPlugin(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/dom/plugins/base/android/ANPVideo.cpp b/dom/plugins/base/android/ANPVideo.cpp index 0f561a4e7621..584ad25607bb 100644 --- a/dom/plugins/base/android/ANPVideo.cpp +++ b/dom/plugins/base/android/ANPVideo.cpp @@ -3,8 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include "AndroidBridge.h" #include "ANPBase.h" -#include "AndroidMediaLayer.h" #include "nsIPluginInstanceOwner.h" #include "nsPluginInstanceOwner.h" #include "nsNPAPIPluginInstance.h" @@ -15,58 +15,30 @@ using namespace mozilla; -static nsresult GetOwner(NPP instance, nsPluginInstanceOwner** owner) { - nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); - - return pinst->GetOwner((nsIPluginInstanceOwner**)owner); -} - -static AndroidMediaLayer* GetLayerForInstance(NPP instance) { - nsRefPtr owner; - if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) - return NULL; - - return owner->Layer(); -} - -static void Invalidate(NPP instance) { - nsRefPtr owner; - if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) - return; - - owner->Invalidate(); -} +typedef nsNPAPIPluginInstance::VideoInfo VideoInfo; static ANPNativeWindow anp_video_acquireNativeWindow(NPP instance) { - AndroidMediaLayer* layer = GetLayerForInstance(instance); - if (!layer) - return NULL; + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); - return layer->RequestNativeWindowForVideo(); + return pinst->AcquireVideoWindow(); } static void anp_video_setWindowDimensions(NPP instance, const ANPNativeWindow window, - const ANPRectF* dimensions) { - AndroidMediaLayer* layer = GetLayerForInstance(instance); - if (!layer) - return; + const ANPRectF* dimensions) { + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); gfxRect rect(dimensions->left, dimensions->top, dimensions->right - dimensions->left, dimensions->bottom - dimensions->top); - layer->SetNativeWindowDimensions(window, rect); - Invalidate(instance); + pinst->SetVideoDimensions(window, rect); + pinst->RedrawPlugin(); } - static void anp_video_releaseNativeWindow(NPP instance, ANPNativeWindow window) { - AndroidMediaLayer* layer = GetLayerForInstance(instance); - if (!layer) - return; - - layer->ReleaseNativeWindowForVideo(window); - Invalidate(instance); + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); + pinst->ReleaseVideoWindow(window); + pinst->RedrawPlugin(); } static void anp_video_setFramerateCallback(NPP instance, const ANPNativeWindow window, ANPVideoFrameCallbackProc callback) { diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 843f7e049d45..981b14923bf5 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -42,6 +42,14 @@ #include "AndroidBridge.h" #include "mozilla/dom/ScreenOrientation.h" #include "mozilla/Hal.h" +#include "GLContextProvider.h" +#include "TexturePoolOGL.h" + +using namespace mozilla; +using namespace mozilla::gl; + +typedef nsNPAPIPluginInstance::TextureInfo TextureInfo; +typedef nsNPAPIPluginInstance::VideoInfo VideoInfo; class PluginEventRunnable : public nsRunnable { @@ -65,6 +73,89 @@ private: bool mCanceled; }; +static nsRefPtr sPluginContext = nsnull; + +static bool EnsureGLContext() +{ + if (!sPluginContext) { + sPluginContext = GLContextProvider::CreateOffscreen(gfxIntSize(16, 16)); + } + + return sPluginContext != nsnull; +} + +class SharedPluginTexture { +public: + NS_INLINE_DECL_REFCOUNTING(SharedPluginTexture) + + SharedPluginTexture() : + mCurrentHandle(0), mNeedNewImage(false), mLock("SharedPluginTexture.mLock") + { + } + + ~SharedPluginTexture() + { + // This will be destroyed in the compositor (as it normally is) + mCurrentHandle = nsnull; + } + + TextureInfo Lock() + { + if (!EnsureGLContext()) { + mTextureInfo.mTexture = 0; + return mTextureInfo; + } + + if (!mTextureInfo.mTexture && sPluginContext->MakeCurrent()) { + sPluginContext->fGenTextures(1, &mTextureInfo.mTexture); + } + + mLock.Lock(); + return mTextureInfo; + } + + void Release(TextureInfo& aTextureInfo) + { + mNeedNewImage = true; + + mTextureInfo = aTextureInfo; + mLock.Unlock(); + } + + SharedTextureHandle CreateSharedHandle() + { + MutexAutoLock lock(mLock); + + if (!mNeedNewImage) + return mCurrentHandle; + + if (!EnsureGLContext()) + return nsnull; + + mNeedNewImage = false; + + if (mTextureInfo.mWidth == 0 || mTextureInfo.mHeight == 0) + return nsnull; + + mCurrentHandle = sPluginContext->CreateSharedHandle(TextureImage::ThreadShared, (void*)mTextureInfo.mTexture, GLContext::TextureID); + + // We want forget about this now, so delete the texture. Assigning it to zero + // ensures that we create a new one in Lock() + sPluginContext->fDeleteTextures(1, &mTextureInfo.mTexture); + mTextureInfo.mTexture = 0; + + return mCurrentHandle; + } + +private: + TextureInfo mTextureInfo; + SharedTextureHandle mCurrentHandle; + + bool mNeedNewImage; + + Mutex mLock; +}; + #endif using namespace mozilla; @@ -78,12 +169,12 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance() : mDrawingModel(kDefaultDrawingModel), #ifdef MOZ_WIDGET_ANDROID - mSurface(nsnull), mANPDrawingModel(0), mOnScreen(true), mFullScreenOrientation(dom::eScreenOrientation_LandscapePrimary), mWakeLocked(false), mFullScreen(false), + mInverted(false), #endif mRunning(NOT_STARTED), mWindowless(false), @@ -118,10 +209,6 @@ nsNPAPIPluginInstance::~nsNPAPIPluginInstance() PR_Free((void *)mMIMEType); mMIMEType = nsnull; } - -#if MOZ_WIDGET_ANDROID - SetWakeLock(false); -#endif } void @@ -129,6 +216,18 @@ nsNPAPIPluginInstance::Destroy() { Stop(); mPlugin = nsnull; + +#if MOZ_WIDGET_ANDROID + mContentTexture = nsnull; + mContentSurface = nsnull; + + std::map::iterator it; + for (it = mVideos.begin(); it != mVideos.end(); it++) { + delete it->second; + } + mVideos.clear(); + SetWakeLock(false); +#endif } TimeStamp @@ -772,6 +871,24 @@ void nsNPAPIPluginInstance::NotifyFullScreen(bool aFullScreen) } } +void nsNPAPIPluginInstance::NotifySize(nsIntSize size) +{ + if (kOpenGL_ANPDrawingModel != GetANPDrawingModel() || + size == mCurrentSize) + return; + + mCurrentSize = size; + + ANPEvent event; + event.inSize = sizeof(ANPEvent); + event.eventType = kDraw_ANPEventType; + event.data.draw.model = kOpenGL_ANPDrawingModel; + event.data.draw.data.surfaceSize.width = size.width; + event.data.draw.data.surfaceSize.height = size.height; + + HandleEvent(&event, nsnull); +} + void nsNPAPIPluginInstance::SetANPDrawingModel(PRUint32 aModel) { mANPDrawingModel = aModel; @@ -832,6 +949,122 @@ void nsNPAPIPluginInstance::SetWakeLock(bool aLocked) hal::WAKE_LOCK_NO_CHANGE); } +void nsNPAPIPluginInstance::EnsureSharedTexture() +{ + if (!mContentTexture) + mContentTexture = new SharedPluginTexture(); +} + +GLContext* nsNPAPIPluginInstance::GLContext() +{ + if (!EnsureGLContext()) + return nsnull; + + return sPluginContext; +} + +TextureInfo nsNPAPIPluginInstance::LockContentTexture() +{ + EnsureSharedTexture(); + return mContentTexture->Lock(); +} + +void nsNPAPIPluginInstance::ReleaseContentTexture(TextureInfo& aTextureInfo) +{ + EnsureSharedTexture(); + mContentTexture->Release(aTextureInfo); +} + +nsSurfaceTexture* nsNPAPIPluginInstance::CreateSurfaceTexture() +{ + if (!EnsureGLContext()) + return nsnull; + + GLuint texture = TexturePoolOGL::AcquireTexture(); + if (!texture) + return nsnull; + + nsSurfaceTexture* surface = nsSurfaceTexture::Create(texture); + if (!surface) + return nsnull; + + nsCOMPtr frameCallback = NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::RedrawPlugin); + surface->SetFrameAvailableCallback(frameCallback); + return surface; +} + +void* nsNPAPIPluginInstance::AcquireContentWindow() +{ + if (!mContentSurface) { + mContentSurface = CreateSurfaceTexture(); + + if (!mContentSurface) + return nsnull; + } + + return mContentSurface->GetNativeWindow(); +} + +SharedTextureHandle nsNPAPIPluginInstance::CreateSharedHandle() +{ + if (mContentTexture) { + return mContentTexture->CreateSharedHandle(); + } else if (mContentSurface) { + EnsureGLContext(); + return sPluginContext->CreateSharedHandle(TextureImage::ThreadShared, mContentSurface, GLContext::SurfaceTexture); + } else return nsnull; +} + +void* nsNPAPIPluginInstance::AcquireVideoWindow() +{ + nsSurfaceTexture* surface = CreateSurfaceTexture(); + if (!surface) + return nsnull; + + VideoInfo* info = new VideoInfo(surface); + + void* window = info->mSurfaceTexture->GetNativeWindow(); + mVideos.insert(std::pair(window, info)); + + return window; +} + +void nsNPAPIPluginInstance::ReleaseVideoWindow(void* window) +{ + std::map::iterator it = mVideos.find(window); + if (it == mVideos.end()) + return; + + delete it->second; + mVideos.erase(window); +} + +void nsNPAPIPluginInstance::SetVideoDimensions(void* window, gfxRect aDimensions) +{ + std::map::iterator it; + + it = mVideos.find(window); + if (it == mVideos.end()) + return; + + it->second->mDimensions = aDimensions; +} + +void nsNPAPIPluginInstance::GetVideos(nsTArray& aVideos) +{ + std::map::iterator it; + for (it = mVideos.begin(); it != mVideos.end(); it++) + aVideos.AppendElement(it->second); +} + +void nsNPAPIPluginInstance::SetInverted(bool aInverted) +{ + if (aInverted == mInverted) + return; + + mInverted = aInverted; +} + #endif nsresult nsNPAPIPluginInstance::GetDrawingModel(PRInt32* aModel) diff --git a/dom/plugins/base/nsNPAPIPluginInstance.h b/dom/plugins/base/nsNPAPIPluginInstance.h index 9fd8ddda50e8..281a03b4d26f 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.h +++ b/dom/plugins/base/nsNPAPIPluginInstance.h @@ -16,8 +16,13 @@ #include "nsInterfaceHashtable.h" #include "nsHashKeys.h" #ifdef MOZ_WIDGET_ANDROID +#include "nsAutoPtr.h" #include "nsIRunnable.h" +#include "GLContext.h" +#include "nsSurfaceTexture.h" +#include class PluginEventRunnable; +class SharedPluginTexture; #endif #include "mozilla/TimeStamp.h" @@ -124,6 +129,7 @@ public: void NotifyOnScreen(bool aOnScreen); void MemoryPressure(); void NotifyFullScreen(bool aFullScreen); + void NotifySize(nsIntSize size); bool IsOnScreen() { return mOnScreen; @@ -142,6 +148,61 @@ public: void SetFullScreenOrientation(PRUint32 orientation); void SetWakeLock(bool aLock); + + mozilla::gl::GLContext* GLContext(); + + // For ANPOpenGL + class TextureInfo { + public: + TextureInfo() : + mTexture(0), mWidth(0), mHeight(0), mInternalFormat(0) + { + } + + TextureInfo(GLuint aTexture, PRInt32 aWidth, PRInt32 aHeight, GLuint aInternalFormat) : + mTexture(aTexture), mWidth(aWidth), mHeight(aHeight), mInternalFormat(aInternalFormat) + { + } + + GLuint mTexture; + PRInt32 mWidth; + PRInt32 mHeight; + GLuint mInternalFormat; + }; + + TextureInfo LockContentTexture(); + void ReleaseContentTexture(TextureInfo& aTextureInfo); + + // For ANPNativeWindow + void* AcquireContentWindow(); + + mozilla::gl::SharedTextureHandle CreateSharedHandle(); + + // For ANPVideo + class VideoInfo { + public: + VideoInfo(nsSurfaceTexture* aSurfaceTexture) : + mSurfaceTexture(aSurfaceTexture) + { + } + + ~VideoInfo() + { + mSurfaceTexture = nsnull; + } + + nsRefPtr mSurfaceTexture; + gfxRect mDimensions; + }; + + void* AcquireVideoWindow(); + void ReleaseVideoWindow(void* aWindow); + void SetVideoDimensions(void* aWindow, gfxRect aDimensions); + + void GetVideos(nsTArray& aVideos); + + void SetInverted(bool aInverted); + bool Inverted() { return mInverted; } #endif nsresult NewStreamListener(const char* aURL, void* notifyData, @@ -220,7 +281,6 @@ protected: #ifdef MOZ_WIDGET_ANDROID PRUint32 mANPDrawingModel; - nsCOMPtr mSurfaceGetter; friend class PluginEventRunnable; @@ -230,6 +290,10 @@ protected: PRUint32 mFullScreenOrientation; bool mWakeLocked; bool mFullScreen; + bool mInverted; + + nsRefPtr mContentTexture; + nsRefPtr mContentSurface; #endif enum { @@ -278,8 +342,13 @@ private: bool mUsePluginLayersPref; #ifdef MOZ_WIDGET_ANDROID - void* mSurface; + void EnsureSharedTexture(); + nsSurfaceTexture* CreateSurfaceTexture(); + + std::map mVideos; bool mOnScreen; + + nsIntSize mCurrentSize; #endif }; diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index ba58799e665a..e4adb2a189ca 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -36,6 +36,7 @@ using mozilla::DefaultXDisplay; #include "nsSize.h" #include "nsDisplayList.h" #include "ImageLayers.h" +#include "SharedTextureImage.h" #include "nsIDOMEventTarget.h" #include "nsObjectFrame.h" #include "nsIPluginDocument.h" @@ -84,7 +85,6 @@ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); #ifdef MOZ_WIDGET_ANDROID #include "ANPBase.h" #include "AndroidBridge.h" -#include "AndroidMediaLayer.h" #include "nsWindow.h" static nsPluginInstanceOwner* sFullScreenInstance = nsnull; @@ -170,6 +170,38 @@ static void OnDestroyImage(void* aPluginInstanceOwner) already_AddRefed nsPluginInstanceOwner::GetImageContainer() { +#if MOZ_WIDGET_ANDROID + // Right now we only draw with Gecko layers on Honeycomb and higher. See Paint() + // for what we do on other versions. + if (AndroidBridge::Bridge()->GetAPIVersion() < 11) + return NULL; + + nsRefPtr container = LayerManager::CreateImageContainer(); + + Image::Format format = Image::SHARED_TEXTURE; + nsRefPtr img = container->CreateImage(&format, 1); + + SharedTextureImage::Data data; + data.mHandle = mInstance->CreateSharedHandle(); + data.mShareType = mozilla::gl::TextureImage::ThreadShared; + data.mInverted = mInstance->Inverted(); + + gfxRect r = GetPluginRect(); + data.mSize = gfxIntSize(r.width, r.height); + + SharedTextureImage* pluginImage = static_cast(img.get()); + pluginImage->SetData(data); + + container->SetCurrentImage(img); + + float xResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetXResolution(); + float yResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetYResolution(); + r.Scale(xResolution, yResolution); + mInstance->NotifySize(nsIntSize(r.width, r.height)); + + return container.forget(); +#endif + if (mInstance) { nsRefPtr container; // Every call to nsIPluginInstance::GetImage() creates @@ -306,9 +338,7 @@ nsPluginInstanceOwner::nsPluginInstanceOwner() mWaitingForPaint = false; #ifdef MOZ_WIDGET_ANDROID - mInverted = false; mFullScreen = false; - mLayer = nsnull; mJavaView = nsnull; #endif } @@ -1724,26 +1754,6 @@ gfxRect nsPluginInstanceOwner::GetPluginRect() return gfxRect(intBounds); } -void nsPluginInstanceOwner::SendSize(int width, int height) -{ - if (!mInstance) - return; - - PRInt32 model = mInstance->GetANPDrawingModel(); - - if (model != kOpenGL_ANPDrawingModel) - return; - - ANPEvent event; - event.inSize = sizeof(ANPEvent); - event.eventType = kDraw_ANPEventType; - event.data.draw.model = kOpenGL_ANPDrawingModel; - event.data.draw.data.surfaceSize.width = width; - event.data.draw.data.surfaceSize.height = height; - - mInstance->HandleEvent(&event, nsnull); -} - bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect /* = gfxRect(0, 0, 0, 0) */) { if (!mJavaView) { @@ -1779,6 +1789,46 @@ void nsPluginInstanceOwner::RemovePluginView() sFullScreenInstance = nsnull; } +void nsPluginInstanceOwner::GetVideos(nsTArray& aVideos) +{ + if (!mInstance) + return; + + mInstance->GetVideos(aVideos); +} + +already_AddRefed nsPluginInstanceOwner::GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo* aVideoInfo) +{ + nsRefPtr container = LayerManager::CreateImageContainer(); + + Image::Format format = Image::SHARED_TEXTURE; + nsRefPtr img = container->CreateImage(&format, 1); + + SharedTextureImage::Data data; + + data.mHandle = mInstance->GLContext()->CreateSharedHandle(gl::TextureImage::ThreadShared, aVideoInfo->mSurfaceTexture, gl::GLContext::SurfaceTexture); + data.mShareType = mozilla::gl::TextureImage::ThreadShared; + data.mInverted = mInstance->Inverted(); + data.mSize = gfxIntSize(aVideoInfo->mDimensions.width, aVideoInfo->mDimensions.height); + + SharedTextureImage* pluginImage = static_cast(img.get()); + pluginImage->SetData(data); + container->SetCurrentImage(img); + + return container.forget(); +} + +nsIntRect nsPluginInstanceOwner::GetVisibleRect() +{ + gfxRect r = nsIntRect(0, 0, mPluginWindow->width, mPluginWindow->height); + + float xResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetXResolution(); + float yResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetYResolution(); + r.Scale(xResolution, yResolution); + + return nsIntRect(r.x, r.y, r.width, r.height); +} + void nsPluginInstanceOwner::Invalidate() { NPRect rect; rect.left = rect.top = 0; @@ -2756,10 +2806,6 @@ nsPluginInstanceOwner::Destroy() #if MOZ_WIDGET_ANDROID RemovePluginView(); - - if (mLayer) - mLayer->SetVisible(false); - #endif if (mWidget) { @@ -2875,29 +2921,13 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext, PRInt32 model = mInstance->GetANPDrawingModel(); - gfxRect pluginRect = GetPluginRect(); - if (model == kSurface_ANPDrawingModel) { - if (!AddPluginView(pluginRect)) { + if (!AddPluginView(GetPluginRect())) { Invalidate(); } return; } - if (model == kOpenGL_ANPDrawingModel) { - if (!mLayer) - mLayer = new AndroidMediaLayer(); - - mLayer->UpdatePosition(pluginRect); - - float xResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetXResolution(); - float yResolution = mObjectFrame->PresContext()->GetRootPresContext()->PresShell()->GetYResolution(); - pluginRect.Scale(xResolution, yResolution); - - SendSize((int)pluginRect.width, (int)pluginRect.height); - return; - } - if (model != kBitmap_ANPDrawingModel) return; @@ -3634,9 +3664,6 @@ nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive) #ifdef MOZ_WIDGET_ANDROID if (mInstance) { - if (mLayer) - mLayer->SetVisible(mPluginDocumentActiveState); - if (!mPluginDocumentActiveState) RemovePluginView(); diff --git a/dom/plugins/base/nsPluginInstanceOwner.h b/dom/plugins/base/nsPluginInstanceOwner.h index f68089f9fb8e..a1bdb44088ea 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.h +++ b/dom/plugins/base/nsPluginInstanceOwner.h @@ -51,12 +51,6 @@ class gfxXlibSurface; #include #endif -#ifdef MOZ_WIDGET_ANDROID -namespace mozilla { - class AndroidMediaLayer; -} -#endif - // X.h defines KeyPress #ifdef KeyPress #undef KeyPress @@ -260,21 +254,11 @@ public: bool UseAsyncRendering(); #ifdef MOZ_WIDGET_ANDROID - nsIntRect GetVisibleRect() { - return nsIntRect(0, 0, mPluginWindow->width, mPluginWindow->height); - } + // Returns the image container for the specified VideoInfo + void GetVideos(nsTArray& aVideos); + already_AddRefed GetImageContainerForVideo(nsNPAPIPluginInstance::VideoInfo* aVideoInfo); - void SetInverted(bool aInverted) { - mInverted = aInverted; - } - - bool Inverted() { - return mInverted; - } - - mozilla::AndroidMediaLayer* Layer() { - return mLayer; - } + nsIntRect GetVisibleRect(); void Invalidate(); @@ -297,19 +281,12 @@ private: void FixUpURLS(const nsString &name, nsAString &value); #ifdef MOZ_WIDGET_ANDROID - void SendSize(int width, int height); - gfxRect GetPluginRect(); bool AddPluginView(const gfxRect& aRect = gfxRect(0, 0, 0, 0)); void RemovePluginView(); - bool mInverted; bool mFullScreen; - void* mJavaView; - - // For kOpenGL_ANPDrawingModel - nsRefPtr mLayer; #endif nsPluginNativeWindow *mPluginWindow; diff --git a/embedding/android/GeckoAppShell.java b/embedding/android/GeckoAppShell.java index 752c28c78860..d2bfca791e9e 100644 --- a/embedding/android/GeckoAppShell.java +++ b/embedding/android/GeckoAppShell.java @@ -102,7 +102,7 @@ public class GeckoAppShell public static native void notifyListCreated(int aListId, int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId); public static native void notifyGotNextMessage(int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId); public static native void notifyReadingMessageListFailed(int aError, int aRequestId, long aProcessId); - public static native void onSurfaceTextureFrameAvailable(SurfaceTexture surfaceTexture, int id); + public static native void onSurfaceTextureFrameAvailable(Object surfaceTexture, int id); // A looper thread, accessed by GeckoAppShell.getHandler private static class LooperThread extends Thread { @@ -1848,4 +1848,10 @@ public class GeckoAppShell public static String getGfxInfoData() { return null; } + + public static void registerSurfaceTextureFrameListener(Object surfaceTexture, final int id) { + } + + public static void unregisterSurfaceTextureFrameListener(Object surfaceTexture) { + } } diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 999572548e03..34b573bf2cd6 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -23,6 +23,7 @@ #include "gfxImageSurface.h" #include "gfxContext.h" #include "gfxRect.h" +#include "gfx3DMatrix.h" #include "nsISupportsImpl.h" #include "prlink.h" @@ -51,6 +52,7 @@ typedef uintptr_t SharedTextureHandle; enum ShaderProgramType { RGBALayerProgramType, + RGBALayerExternalProgramType, BGRALayerProgramType, RGBXLayerProgramType, BGRXLayerProgramType, @@ -856,10 +858,26 @@ public: return IsExtensionSupported(EXT_framebuffer_blit) || IsExtensionSupported(ANGLE_framebuffer_blit); } + enum SharedTextureBufferType { + TextureID +#ifdef MOZ_WIDGET_ANDROID + , SurfaceTexture +#endif + }; + /** * Create new shared GLContext content handle, must be released by ReleaseSharedHandle. */ virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType) { return 0; } + /* + * Create a new shared GLContext content handle, using the passed buffer as a source. + * Must be released by ReleaseSharedHandle. UpdateSharedHandle will have no effect + * on handles created with this method, as the caller owns the source (the passed buffer) + * and is responsible for updating it accordingly. + */ + virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType, + void* aBuffer, + SharedTextureBufferType aBufferType) { return 0; } /** * Publish GLContext content to intermediate buffer attached to shared handle. * Shared handle content is ready to be used after call returns, and no need extra Flush/Finish are required. @@ -882,12 +900,28 @@ public: */ virtual void ReleaseSharedHandle(TextureImage::TextureShareType aType, SharedTextureHandle aSharedHandle) { } + + + typedef struct { + GLenum mTarget; + ShaderProgramType mProgramType; + gfx3DMatrix mTextureTransform; + } SharedHandleDetails; + + /** + * Returns information necessary for rendering a shared handle. + * These values change depending on what sharing mechanism is in use + */ + virtual bool GetSharedHandleDetails(TextureImage::TextureShareType aType, + SharedTextureHandle aSharedHandle, + SharedHandleDetails& aDetails) { return false; } /** * Attach Shared GL Handle to GL_TEXTURE_2D target * GLContext must be current before this call */ virtual bool AttachSharedHandle(TextureImage::TextureShareType aType, SharedTextureHandle aSharedHandle) { return false; } + /** * Detach Shared GL Handle from GL_TEXTURE_2D target */ diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index 43096964bfe5..1d7111612353 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -32,6 +32,7 @@ /* from widget */ #if defined(MOZ_WIDGET_ANDROID) #include "AndroidBridge.h" +#include "nsSurfaceTexture.h" #endif #include #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) @@ -119,6 +120,7 @@ public: #include "gfxCrashReporterUtils.h" + #if defined(MOZ_PLATFORM_MAEMO) || defined(MOZ_WIDGET_GONK) static bool gUseBackingSurface = true; #else @@ -625,10 +627,16 @@ public: } virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType); + virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType, + void* aBuffer, + SharedTextureBufferType aBufferType); virtual void UpdateSharedHandle(TextureImage::TextureShareType aType, SharedTextureHandle aSharedHandle); virtual void ReleaseSharedHandle(TextureImage::TextureShareType aType, SharedTextureHandle aSharedHandle); + virtual bool GetSharedHandleDetails(TextureImage::TextureShareType aType, + SharedTextureHandle aSharedHandle, + SharedHandleDetails& aDetails); virtual bool AttachSharedHandle(TextureImage::TextureShareType aType, SharedTextureHandle aSharedHandle); protected: @@ -690,14 +698,61 @@ protected: } }; -class EGLTextureWrapper +typedef enum { + Image +#ifdef MOZ_WIDGET_ANDROID + , SurfaceTexture +#endif +} SharedHandleType; + +class SharedTextureHandleWrapper { public: - EGLTextureWrapper(GLContext* aContext, GLuint aTexture) - : mContext(aContext) + SharedTextureHandleWrapper(SharedHandleType aHandleType) : mHandleType(aHandleType) + { + } + + virtual ~SharedTextureHandleWrapper() + { + } + + SharedHandleType Type() { return mHandleType; } + + SharedHandleType mHandleType; +}; + +#ifdef MOZ_WIDGET_ANDROID + +class SurfaceTextureWrapper: public SharedTextureHandleWrapper +{ +public: + SurfaceTextureWrapper(nsSurfaceTexture* aSurfaceTexture) : + SharedTextureHandleWrapper(SharedHandleType::SurfaceTexture) + , mSurfaceTexture(aSurfaceTexture) + { + } + + virtual ~SurfaceTextureWrapper() { + mSurfaceTexture = nsnull; + } + + nsSurfaceTexture* SurfaceTexture() { return mSurfaceTexture; } + + nsRefPtr mSurfaceTexture; +}; + +#endif // MOZ_WIDGET_ANDROID + +class EGLTextureWrapper : public SharedTextureHandleWrapper +{ +public: + EGLTextureWrapper(GLContext* aContext, GLuint aTexture, bool aOwnsTexture) : + SharedTextureHandleWrapper(SharedHandleType::Image) + , mContext(aContext) , mTexture(aTexture) , mEGLImage(nsnull) , mSyncObject(nsnull) + , mOwnsTexture(aOwnsTexture) { } @@ -772,11 +827,16 @@ public: return result == LOCAL_EGL_CONDITION_SATISFIED; } + bool OwnsTexture() { + return mOwnsTexture; + } + private: nsRefPtr mContext; GLuint mTexture; EGLImage mEGLImage; EGLSync mSyncObject; + bool mOwnsTexture; }; void @@ -788,9 +848,12 @@ GLContextEGL::UpdateSharedHandle(TextureImage::TextureShareType aType, return; } + SharedTextureHandleWrapper* wrapper = reinterpret_cast(aSharedHandle); + + NS_ASSERTION(wrapper->Type() == SharedHandleType::Image, "Expected EGLImage shared handle"); NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); - EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle; + EGLTextureWrapper* wrap = reinterpret_cast(wrapper); // We need to copy the current GLContext drawing buffer to the texture // exported by the EGLImage. Need to save both the read FBO and the texture // binding, because we're going to munge them to do this. @@ -830,19 +893,56 @@ GLContextEGL::CreateSharedHandle(TextureImage::TextureShareType aType) CreateTextureForOffscreen(ChooseGLFormats(fmt, GLContext::ForceRGBA), mOffscreenSize, texture); // texture ownership moved to EGLTextureWrapper after this point // and texture will be deleted in EGLTextureWrapper dtor - EGLTextureWrapper* tex = new EGLTextureWrapper(this, texture); + EGLTextureWrapper* tex = new EGLTextureWrapper(this, texture, true); if (!tex->CreateEGLImage()) { NS_ERROR("EGLImage creation for EGLTextureWrapper failed"); ReleaseSharedHandle(aType, (SharedTextureHandle)tex); - - // Stop trying to create shared image Handle - mShareWithEGLImage = false; return nsnull; } // Raw pointer shared across threads return (SharedTextureHandle)tex; } +SharedTextureHandle +GLContextEGL::CreateSharedHandle(TextureImage::TextureShareType aType, + void* aBuffer, + SharedTextureBufferType aBufferType) +{ + // Both EGLImage and SurfaceTexture only support ThreadShared currently, but + // it's possible to make SurfaceTexture work across processes. We should do that. + if (aType != TextureImage::ThreadShared) + return nsnull; + + switch (aBufferType) { +#ifdef MOZ_WIDGET_ANDROID + case SharedTextureBufferType::SurfaceTexture: + if (!IsExtensionSupported(GLContext::OES_EGL_image_external)) { + NS_WARNING("Missing GL_OES_EGL_image_external"); + return nsnull; + } + + return (SharedTextureHandle) new SurfaceTextureWrapper(reinterpret_cast(aBuffer)); +#endif + case SharedTextureBufferType::TextureID: { + if (!mShareWithEGLImage) + return nsnull; + + GLuint texture = (GLuint)aBuffer; + EGLTextureWrapper* tex = new EGLTextureWrapper(this, texture, false); + if (!tex->CreateEGLImage()) { + NS_ERROR("EGLImage creation for EGLTextureWrapper failed"); + delete tex; + return nsnull; + } + + return (SharedTextureHandle)tex; + } + default: + NS_ERROR("Unknown shared texture buffer type"); + return nsnull; + } +} + void GLContextEGL::ReleaseSharedHandle(TextureImage::TextureShareType aType, SharedTextureHandle aSharedHandle) { @@ -851,22 +951,72 @@ void GLContextEGL::ReleaseSharedHandle(TextureImage::TextureShareType aType, return; } - NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); + SharedTextureHandleWrapper* wrapper = reinterpret_cast(aSharedHandle); - EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle; - GLContext *ctx = wrap->GetContext(); - if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) { - ctx = ctx->GetSharedContext(); + switch (wrapper->Type()) { +#ifdef MOZ_WIDGET_ANDROID + case SharedHandleType::SurfaceTexture: + delete wrapper; + break; +#endif + + case SharedHandleType::Image: { + NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); + + EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle; + GLContext *ctx = wrap->GetContext(); + if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) { + ctx = ctx->GetSharedContext(); + } + // If we have a context, then we need to delete the texture; + // if we don't have a context (either real or shared), + // then they went away when the contex was deleted, because it + // was the only one that had access to it. + if (wrap->OwnsTexture() && ctx && !ctx->IsDestroyed() && ctx->MakeCurrent()) { + GLuint texture = wrap->GetTextureID(); + ctx->fDeleteTextures(1, &texture); + } + delete wrap; + break; } - // If we have a context, then we need to delete the texture; - // if we don't have a context (either real or shared), - // then they went away when the contex was deleted, because it - // was the only one that had access to it. - if (ctx && !ctx->IsDestroyed() && ctx->MakeCurrent()) { - GLuint texture = wrap->GetTextureID(); - ctx->fDeleteTextures(1, &texture); + + default: + NS_ERROR("Unknown shared handle type"); } - delete wrap; +} + +bool GLContextEGL::GetSharedHandleDetails(TextureImage::TextureShareType aType, + SharedTextureHandle aSharedHandle, + SharedHandleDetails& aDetails) +{ + if (aType != TextureImage::ThreadShared) + return false; + + SharedTextureHandleWrapper* wrapper = reinterpret_cast(aSharedHandle); + + switch (wrapper->Type()) { +#ifdef MOZ_WIDGET_ANDROID + case SharedHandleType::SurfaceTexture: { + SurfaceTextureWrapper* surfaceWrapper = reinterpret_cast(wrapper); + + aDetails.mTarget = LOCAL_GL_TEXTURE_EXTERNAL; + aDetails.mProgramType = RGBALayerExternalProgramType; + surfaceWrapper->SurfaceTexture()->GetTransformMatrix(aDetails.mTextureTransform); + break; + } +#endif + + case SharedHandleType::Image: + aDetails.mTarget = LOCAL_GL_TEXTURE_2D; + aDetails.mProgramType = RGBALayerProgramType; + break; + + default: + NS_ERROR("Unknown shared handle type"); + return false; + } + + return true; } bool GLContextEGL::AttachSharedHandle(TextureImage::TextureShareType aType, @@ -875,11 +1025,41 @@ bool GLContextEGL::AttachSharedHandle(TextureImage::TextureShareType aType, if (aType != TextureImage::ThreadShared) return false; - NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); + SharedTextureHandleWrapper* wrapper = reinterpret_cast(aSharedHandle); + + switch (wrapper->Type()) { +#ifdef MOZ_WIDGET_ANDROID + case SharedHandleType::SurfaceTexture: { +#ifndef DEBUG + /** + * NOTE: SurfaceTexture spams us if there are any existing GL errors, so we'll clear + * them here in order to avoid that. + */ + GetAndClearError(); +#endif + SurfaceTextureWrapper* surfaceTextureWrapper = reinterpret_cast(wrapper); + + // FIXME: SurfaceTexture provides a transform matrix which is supposed to + // be applied to the texture coordinates. We should return that here + // so we can render correctly. Bug 775083 + surfaceTextureWrapper->SurfaceTexture()->UpdateTexImage(); + break; + } +#endif // MOZ_WIDGET_ANDROID + + case SharedHandleType::Image: { + NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); + + EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle; + fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage()); + break; + } + + default: + NS_ERROR("Unknown shared handle type"); + return false; + } - EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle; - wrap->WaitSync(); - fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage()); return true; } diff --git a/gfx/gl/GLDefs.h b/gfx/gl/GLDefs.h index 01a0552fe375..9555c94404df 100644 --- a/gfx/gl/GLDefs.h +++ b/gfx/gl/GLDefs.h @@ -3252,6 +3252,7 @@ typedef void* GLeglImage; #define LOCAL_EGL_CORE_NATIVE_ENGINE 0x305B #define LOCAL_EGL_READ 0x305A #define LOCAL_EGL_DRAW 0x3059 +#define LOCAL_EGL_BAD_PARAMETER 0x300C #define LOCAL_EGL_CONTEXT_LOST 0x300E // EGL_KHR_image_base (not supplied by EGL_KHR_image!) @@ -3263,6 +3264,9 @@ typedef void* GLeglImage; // EGL_KHR_gl_texture_2D_image #define LOCAL_EGL_GL_TEXTURE_2D 0x30B1 +// OES_EGL_image_external +#define LOCAL_GL_TEXTURE_EXTERNAL 0x8D65 + // EGL_KHR_fence_sync #define LOCAL_EGL_SYNC_FENCE 0x30F9 #define LOCAL_EGL_SYNC_TYPE 0x30F7 diff --git a/gfx/layers/ImageLayers.cpp b/gfx/layers/ImageLayers.cpp index 0c012a6220bb..3685a9bff93a 100644 --- a/gfx/layers/ImageLayers.cpp +++ b/gfx/layers/ImageLayers.cpp @@ -6,6 +6,7 @@ #include "mozilla/ipc/Shmem.h" #include "mozilla/ipc/CrossProcessMutex.h" #include "ImageLayers.h" +#include "SharedTextureImage.h" #include "gfxImageSurface.h" #include "gfxSharedImageSurface.h" #include "yuv_convert.h" @@ -43,6 +44,8 @@ ImageFactory::CreateImage(const Image::Format *aFormats, img = new PlanarYCbCrImage(aRecycleBin); } else if (FormatInList(aFormats, aNumFormats, Image::CAIRO_SURFACE)) { img = new CairoImage(); + } else if (FormatInList(aFormats, aNumFormats, Image::SHARED_TEXTURE)) { + img = new SharedTextureImage(); #ifdef XP_MACOSX } else if (FormatInList(aFormats, aNumFormats, Image::MAC_IO_SURFACE)) { img = new MacIOSurfaceImage(); diff --git a/gfx/layers/ImageLayers.h b/gfx/layers/ImageLayers.h index a519ab5857e2..ca9ec30ac71e 100644 --- a/gfx/layers/ImageLayers.h +++ b/gfx/layers/ImageLayers.h @@ -122,6 +122,11 @@ public: */ REMOTE_IMAGE_BITMAP, + /** + * A OpenGL texture that can be shared across threads or processes + */ + SHARED_TEXTURE, + /** * An DXGI shared surface handle that can be shared with a remote process. */ diff --git a/gfx/layers/Makefile.in b/gfx/layers/Makefile.in index af9451aa26ef..42906f6cef08 100644 --- a/gfx/layers/Makefile.in +++ b/gfx/layers/Makefile.in @@ -39,6 +39,8 @@ EXPORTS = \ LayerManagerOGLProgram.h \ ReadbackLayer.h \ LayerSorter.h \ + TexturePoolOGL.h \ + SharedTextureImage.h \ $(NULL) CPPSRCS = \ @@ -67,6 +69,7 @@ CPPSRCS = \ LayerManagerOGLProgram.cpp \ LayerSorter.cpp \ ImageLayers.cpp \ + TexturePoolOGL.cpp \ $(NULL) ifeq ($(MOZ_WIDGET_TOOLKIT),windows) diff --git a/gfx/layers/SharedTextureImage.h b/gfx/layers/SharedTextureImage.h new file mode 100644 index 000000000000..bae0c75d96b8 --- /dev/null +++ b/gfx/layers/SharedTextureImage.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_SHAREDTEXTUREIMAGE_H +#define GFX_SHAREDTEXTUREIMAGE_H + +#include "ImageLayers.h" +#include "GLContext.h" + +// Split into a separate header from ImageLayers.h due to GLContext.h dependence +// Implementation remains in ImageLayers.cpp + +namespace mozilla { + +namespace layers { + +class THEBES_API SharedTextureImage : public Image { +public: + struct Data { + gl::SharedTextureHandle mHandle; + gl::TextureImage::TextureShareType mShareType; + gfxIntSize mSize; + bool mInverted; + }; + + void SetData(const Data& aData) { mData = aData; } + const Data* GetData() { return &mData; } + + gfxIntSize GetSize() { return mData.mSize; } + + virtual already_AddRefed GetAsSurface() { return NULL; } + + SharedTextureImage() : Image(NULL, SHARED_TEXTURE) {} + +private: + Data mData; +}; + +} // layers +} // mozilla + +#endif // GFX_SHAREDTEXTUREIMAGE_H \ No newline at end of file diff --git a/gfx/layers/basic/BasicCanvasLayer.cpp b/gfx/layers/basic/BasicCanvasLayer.cpp index 6fcdc093130b..b7dee5077612 100644 --- a/gfx/layers/basic/BasicCanvasLayer.cpp +++ b/gfx/layers/basic/BasicCanvasLayer.cpp @@ -387,7 +387,7 @@ BasicShadowableCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) if (!handle) { handle = mGLContext->CreateSharedHandle(flags); if (handle) { - mBackBuffer = SharedTextureDescriptor(flags, handle, mBounds.Size()); + mBackBuffer = SharedTextureDescriptor(flags, handle, mBounds.Size(), false); } } if (handle) { diff --git a/gfx/layers/basic/BasicImageLayer.cpp b/gfx/layers/basic/BasicImageLayer.cpp index f22ff2ffa4f3..b24df2ac69b0 100644 --- a/gfx/layers/basic/BasicImageLayer.cpp +++ b/gfx/layers/basic/BasicImageLayer.cpp @@ -5,6 +5,7 @@ #include "mozilla/layers/PLayersParent.h" #include "BasicLayersImpl.h" +#include "SharedTextureImage.h" #include "gfxUtils.h" #include "gfxSharedImageSurface.h" #include "mozilla/layers/ImageContainerChild.h" @@ -277,6 +278,17 @@ BasicShadowableImageLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) ->Paint(aContext, nsnull); } + if (image->GetFormat() == Image::SHARED_TEXTURE && + BasicManager()->GetParentBackendType() == mozilla::layers::LAYERS_OPENGL) { + SharedTextureImage *sharedImage = static_cast(image); + const SharedTextureImage::Data *data = sharedImage->GetData(); + + SharedTextureDescriptor texture(data->mShareType, data->mHandle, data->mSize, data->mInverted); + SurfaceDescriptor descriptor(texture); + BasicManager()->PaintedImage(BasicManager()->Hold(this), descriptor); + return; + } + if (image->GetFormat() == Image::PLANAR_YCBCR && BasicManager()->IsCompositingCheap()) { PlanarYCbCrImage *YCbCrImage = static_cast(image); const PlanarYCbCrImage::Data *data = YCbCrImage->GetData(); diff --git a/gfx/layers/ipc/LayersSurfaces.ipdlh b/gfx/layers/ipc/LayersSurfaces.ipdlh index 0043d0471c51..6798b1de030c 100644 --- a/gfx/layers/ipc/LayersSurfaces.ipdlh +++ b/gfx/layers/ipc/LayersSurfaces.ipdlh @@ -40,6 +40,7 @@ struct SharedTextureDescriptor { TextureShareType shareType; SharedTextureHandle handle; nsIntSize size; + bool inverted; }; struct SurfaceDescriptorGralloc { diff --git a/gfx/layers/opengl/CanvasLayerOGL.cpp b/gfx/layers/opengl/CanvasLayerOGL.cpp index 565511d08834..a6b3150b4b32 100644 --- a/gfx/layers/opengl/CanvasLayerOGL.cpp +++ b/gfx/layers/opengl/CanvasLayerOGL.cpp @@ -335,7 +335,7 @@ ShadowCanvasLayerOGL::Swap(const CanvasSurface& aNewFront, if (IsValidSharedTexDescriptor(aNewFront)) { MakeTextureIfNeeded(gl(), mTexture); if (!IsValidSharedTexDescriptor(mFrontBufferDescriptor)) { - mFrontBufferDescriptor = SharedTextureDescriptor(TextureImage::ThreadShared, 0, nsIntSize(0, 0)); + mFrontBufferDescriptor = SharedTextureDescriptor(TextureImage::ThreadShared, 0, nsIntSize(0, 0), false); } *aNewBack = mFrontBufferDescriptor; mFrontBufferDescriptor = aNewFront; diff --git a/gfx/layers/opengl/ImageLayerOGL.cpp b/gfx/layers/opengl/ImageLayerOGL.cpp index a5262f8b66ad..bca828d5f37c 100644 --- a/gfx/layers/opengl/ImageLayerOGL.cpp +++ b/gfx/layers/opengl/ImageLayerOGL.cpp @@ -18,12 +18,32 @@ # include "mozilla/X11Util.h" #endif +#ifdef MOZ_WIDGET_ANDROID +#include "nsSurfaceTexture.h" +#endif + using namespace mozilla::gfx; using namespace mozilla::gl; namespace mozilla { namespace layers { +static void +MakeTextureIfNeeded(GLContext* gl, GLuint& aTexture) +{ + if (aTexture != 0) + return; + + gl->fGenTextures(1, &aTexture); + + gl->fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture); + + gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); + gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); + gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); +} + /** * This is an event used to unref a GLContext on the main thread and * optionally delete a texture associated with that context. @@ -676,6 +696,9 @@ ImageLayerOGL::LoadAsTexture(GLuint aTextureUnit, gfxIntSize* aSize) ShadowImageLayerOGL::ShadowImageLayerOGL(LayerManagerOGL* aManager) : ShadowImageLayer(aManager, nsnull) , LayerOGL(aManager) + , mSharedHandle(0) + , mInverted(false) + , mTexture(0) { mImplData = static_cast(this); } @@ -687,15 +710,23 @@ bool ShadowImageLayerOGL::Init(const SharedImage& aFront) { if (aFront.type() == SharedImage::TSurfaceDescriptor) { - AutoOpenSurface autoSurf(OPEN_READ_ONLY, aFront.get_SurfaceDescriptor()); - mSize = autoSurf.Size(); - mTexImage = gl()->CreateTextureImage(nsIntSize(mSize.width, mSize.height), - autoSurf.ContentType(), - LOCAL_GL_CLAMP_TO_EDGE, - mForceSingleTile - ? TextureImage::ForceSingleTile - : TextureImage::NoFlags); - return true; + SurfaceDescriptor surface = aFront.get_SurfaceDescriptor(); + if (surface.type() == SurfaceDescriptor::TSharedTextureDescriptor) { + SharedTextureDescriptor texture = surface.get_SharedTextureDescriptor(); + mSize = texture.size(); + mSharedHandle = texture.handle(); + mShareType = texture.shareType(); + mInverted = texture.inverted(); + } else { + AutoOpenSurface autoSurf(OPEN_READ_ONLY, surface); + mSize = autoSurf.Size(); + mTexImage = gl()->CreateTextureImage(nsIntSize(mSize.width, mSize.height), + autoSurf.ContentType(), + LOCAL_GL_CLAMP_TO_EDGE, + mForceSingleTile + ? TextureImage::ForceSingleTile + : TextureImage::NoFlags); + } } else { YUVImage yuv = aFront.get_YUVImage(); @@ -739,15 +770,31 @@ ShadowImageLayerOGL::Swap(const SharedImage& aNewFront, mImageVersion = 0; } } else if (aNewFront.type() == SharedImage::TSurfaceDescriptor) { - AutoOpenSurface surf(OPEN_READ_ONLY, aNewFront.get_SurfaceDescriptor()); - gfxIntSize size = surf.Size(); - if (mSize != size || !mTexImage || - mTexImage->GetContentType() != surf.ContentType()) { - Init(aNewFront); + SurfaceDescriptor surface = aNewFront.get_SurfaceDescriptor(); + + if (surface.type() == SurfaceDescriptor::TSharedTextureDescriptor) { + SharedTextureDescriptor texture = surface.get_SharedTextureDescriptor(); + + SharedTextureHandle newHandle = texture.handle(); + mSize = texture.size(); + mInverted = texture.inverted(); + + if (mSharedHandle && newHandle != mSharedHandle) + gl()->ReleaseSharedHandle(mShareType, mSharedHandle); + + mSharedHandle = newHandle; + mShareType = texture.shareType(); + } else { + AutoOpenSurface surf(OPEN_READ_ONLY, surface); + gfxIntSize size = surf.Size(); + if (mSize != size || !mTexImage || + mTexImage->GetContentType() != surf.ContentType()) { + Init(aNewFront); + } + // XXX this is always just ridiculously slow + nsIntRegion updateRegion(nsIntRect(0, 0, size.width, size.height)); + mTexImage->DirectUpdate(surf.Get(), updateRegion); } - // XXX this is always just ridiculously slow - nsIntRegion updateRegion(nsIntRect(0, 0, size.width, size.height)); - mTexImage->DirectUpdate(surf.Get(), updateRegion); } else { const YUVImage& yuv = aNewFront.get_YUVImage(); UploadSharedYUVToTexture(yuv); @@ -880,7 +927,39 @@ ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer, mTexImage->GetTileRect().Size()); } while (mTexImage->NextTile()); } + } else if (mSharedHandle) { + GLContext::SharedHandleDetails handleDetails; + if (!gl()->GetSharedHandleDetails(mShareType, mSharedHandle, handleDetails)) { + NS_ERROR("Failed to get shared handle details"); + return; + } + ShaderProgramOGL* program = mOGLManager->GetProgram(handleDetails.mProgramType, GetMaskLayer()); + + program->Activate(); + program->SetLayerTransform(GetEffectiveTransform()); + program->SetLayerOpacity(GetEffectiveOpacity()); + program->SetRenderOffset(aOffset); + program->SetTextureUnit(0); + program->SetTextureTransform(handleDetails.mTextureTransform); + program->LoadMask(GetMaskLayer()); + + MakeTextureIfNeeded(gl(), mTexture); + gl()->fActiveTexture(LOCAL_GL_TEXTURE0); + gl()->fBindTexture(handleDetails.mTarget, mTexture); + + if (!gl()->AttachSharedHandle(mShareType, mSharedHandle)) { + NS_ERROR("Failed to bind shared texture handle"); + return; + } + + gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, + LOCAL_GL_ONE, LOCAL_GL_ONE); + gl()->ApplyFilterToBoundTexture(mFilter); + program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mSize)); + mOGLManager->BindAndDrawQuad(program, mInverted); + gl()->fBindTexture(handleDetails.mTarget, 0); + gl()->DetachSharedHandle(mShareType, mSharedHandle); } else { gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mYUVTexture[0].GetTextureID()); @@ -932,6 +1011,11 @@ ShadowImageLayerOGL::LoadAsTexture(GLuint aTextureUnit, gfxIntSize* aSize) void ShadowImageLayerOGL::CleanupResources() { + if (mSharedHandle) { + gl()->ReleaseSharedHandle(mShareType, mSharedHandle); + mSharedHandle = NULL; + } + mYUVTexture[0].Release(); mYUVTexture[1].Release(); mYUVTexture[2].Release(); diff --git a/gfx/layers/opengl/ImageLayerOGL.h b/gfx/layers/opengl/ImageLayerOGL.h index fa7d1b285980..abf309742229 100644 --- a/gfx/layers/opengl/ImageLayerOGL.h +++ b/gfx/layers/opengl/ImageLayerOGL.h @@ -180,6 +180,13 @@ private: nsRefPtr mTexImage; + + // For SharedTextureHandle + gl::SharedTextureHandle mSharedHandle; + gl::TextureImage::TextureShareType mShareType; + bool mInverted; + GLuint mTexture; + GLTexture mYUVTexture[3]; gfxIntSize mSize; gfxIntSize mCbCrSize; diff --git a/gfx/layers/opengl/LayerManagerOGL.cpp b/gfx/layers/opengl/LayerManagerOGL.cpp index 5111c69385bb..d86aeb4ba94e 100644 --- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -17,6 +17,7 @@ #include "TiledThebesLayerOGL.h" #include "mozilla/TimeStamp.h" #include "mozilla/Preferences.h" +#include "TexturePoolOGL.h" #include "gfxContext.h" #include "gfxUtils.h" @@ -751,6 +752,10 @@ LayerManagerOGL::Render() MakeCurrent(); } +#if MOZ_WIDGET_ANDROID + TexturePoolOGL::Fill(gl()); +#endif + SetupBackBuffer(width, height); SetupPipeline(width, height, ApplyWorldTransform); diff --git a/gfx/layers/opengl/LayerManagerOGLProgram.cpp b/gfx/layers/opengl/LayerManagerOGLProgram.cpp index 8701f30b1cc4..b05706b5a208 100644 --- a/gfx/layers/opengl/LayerManagerOGLProgram.cpp +++ b/gfx/layers/opengl/LayerManagerOGLProgram.cpp @@ -53,6 +53,23 @@ ProgramProfileOGL::GetProfileFor(gl::ShaderProgramType aType, AddCommonTextureArgs(result); result.mTextureCount = 1; break; + case gl::RGBALayerExternalProgramType: + if (aMask == Mask3d) { + result.mVertexShaderString = sLayerMask3DVS; + result.mFragmentShaderString = sRGBATextureLayerExternalMask3DFS; + } else if (aMask == Mask2d) { + result.mVertexShaderString = sLayerMaskVS; + result.mFragmentShaderString = sRGBATextureLayerExternalMaskFS; + } else { + result.mVertexShaderString = sLayerVS; + result.mFragmentShaderString = sRGBATextureLayerExternalFS; + } + AddCommonArgs(result); + AddCommonTextureArgs(result); + result.mUniforms.AppendElement(Argument("uTextureTransform")); + result.mHasTextureTransform = true; + result.mTextureCount = 1; + break; case gl::BGRALayerProgramType: if (aMask == Mask2d) { result.mVertexShaderString = sLayerMaskVS; diff --git a/gfx/layers/opengl/LayerManagerOGLProgram.h b/gfx/layers/opengl/LayerManagerOGLProgram.h index 20823cd4c20e..bc79c96d9e79 100644 --- a/gfx/layers/opengl/LayerManagerOGLProgram.h +++ b/gfx/layers/opengl/LayerManagerOGLProgram.h @@ -111,10 +111,12 @@ struct ProgramProfileOGL nsTArray mAttributes; PRUint32 mTextureCount; bool mHasMatrixProj; + bool mHasTextureTransform; private: ProgramProfileOGL() : mTextureCount(0), - mHasMatrixProj(false) {} + mHasMatrixProj(false), + mHasTextureTransform(false) {} }; @@ -142,7 +144,6 @@ public: mIsProjectionMatrixStale(false), mGL(aGL), mProgram(0), mProfile(aProfile), mProgramState(STATE_NEW) { } - ~ShaderProgramOGL() { if (mProgram <= 0) { return; @@ -246,6 +247,12 @@ public: mIsProjectionMatrixStale = false; } + // sets this program's texture transform, if it uses one + void SetTextureTransform(const gfx3DMatrix& aMatrix) { + if (mProfile.mHasTextureTransform) + SetMatrixUniform(mProfile.LookupUniformLocation("uTextureTransform"), aMatrix); + } + void SetRenderOffset(const nsIntPoint& aOffset) { float vals[4] = { float(aOffset.x), float(aOffset.y), 0.0f, 0.0f }; SetUniform(mProfile.LookupUniformLocation("uRenderTargetOffset"), 4, vals); diff --git a/gfx/layers/opengl/LayerManagerOGLShaders.h b/gfx/layers/opengl/LayerManagerOGLShaders.h index 8b046d664ed7..5a77fd79b920 100644 --- a/gfx/layers/opengl/LayerManagerOGLShaders.h +++ b/gfx/layers/opengl/LayerManagerOGLShaders.h @@ -232,6 +232,91 @@ gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;\n\ }\n\ "; +static const char sRGBATextureLayerExternalFS[] = "/* sRGBATextureLayerExternalFS */\n\ +/* Fragment Shader */\n\ +#ifdef GL_ES\n\ +precision lowp float;\n\ +#endif\n\ +\n\ +#ifndef NO_LAYER_OPACITY\n\ +uniform float uLayerOpacity;\n\ +#endif\n\ +#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\ +varying mediump vec2 vTexCoord;\n\ +#else\n\ +varying vec2 vTexCoord;\n\ +#endif\n\ +\n\ +#extension GL_OES_EGL_image_external : require\n\ +uniform samplerExternalOES uTexture;\n\ +uniform mat4 uTextureTransform;\n\ +void main()\n\ +{\n\ +float mask = 1.0;\n\ +\n\ +gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\ +}\n\ +"; + +static const char sRGBATextureLayerExternalMaskFS[] = "/* sRGBATextureLayerExternalMaskFS */\n\ +/* Fragment Shader */\n\ +#ifdef GL_ES\n\ +precision lowp float;\n\ +#endif\n\ +\n\ +#ifndef NO_LAYER_OPACITY\n\ +uniform float uLayerOpacity;\n\ +#endif\n\ +#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\ +varying mediump vec2 vTexCoord;\n\ +#else\n\ +varying vec2 vTexCoord;\n\ +#endif\n\ +\n\ +varying vec2 vMaskCoord;\n\ +uniform sampler2D uMaskTexture;\n\ +\n\ +#extension GL_OES_EGL_image_external : require\n\ +uniform samplerExternalOES uTexture;\n\ +uniform mat4 uTextureTransform;\n\ +void main()\n\ +{\n\ +float mask = texture2D(uMaskTexture, vMaskCoord).r;\n\ +\n\ +gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\ +}\n\ +"; + +static const char sRGBATextureLayerExternalMask3DFS[] = "/* sRGBATextureLayerExternalMask3DFS */\n\ +/* Fragment Shader */\n\ +#ifdef GL_ES\n\ +precision lowp float;\n\ +#endif\n\ +\n\ +#ifndef NO_LAYER_OPACITY\n\ +uniform float uLayerOpacity;\n\ +#endif\n\ +#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\ +varying mediump vec2 vTexCoord;\n\ +#else\n\ +varying vec2 vTexCoord;\n\ +#endif\n\ +\n\ +varying vec3 vMaskCoord;\n\ +uniform sampler2D uMaskTexture;\n\ +\n\ +#extension GL_OES_EGL_image_external : require\n\ +uniform samplerExternalOES uTexture;\n\ +uniform mat4 uTextureTransform;\n\ +void main()\n\ +{\n\ +vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;\n\ +float mask = texture2D(uMaskTexture, maskCoords).r;\n\ +\n\ +gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\ +}\n\ +"; + static const char sRGBARectTextureLayerFS[] = "/* sRGBARectTextureLayerFS */\n\ #extension GL_ARB_texture_rectangle : enable\n\ /* Fragment Shader */\n\ diff --git a/gfx/layers/opengl/LayerManagerOGLShaders.txt b/gfx/layers/opengl/LayerManagerOGLShaders.txt index 99871961f447..3299bab40f1f 100644 --- a/gfx/layers/opengl/LayerManagerOGLShaders.txt +++ b/gfx/layers/opengl/LayerManagerOGLShaders.txt @@ -211,6 +211,20 @@ $FRAGMENT_CALC_MASK$ } @end +// Single texture in RGBA format for use with GL_TEXTURE_EXTERNAL_OES +@shader sRGBATextureLayerExternalFS +$LAYER_FRAGMENT$ +#extension GL_OES_EGL_image_external : require +uniform samplerExternalOES uTexture; +uniform mat4 uTextureTransform; + +void main() +{ +$FRAGMENT_CALC_MASK$ + gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask; +} +@end + // Single texture in RGBA format, but with a Rect texture. // Container layer needs this to render a FBO group. diff --git a/gfx/layers/opengl/TexturePoolOGL.cpp b/gfx/layers/opengl/TexturePoolOGL.cpp new file mode 100644 index 000000000000..a42bd6f41ba8 --- /dev/null +++ b/gfx/layers/opengl/TexturePoolOGL.cpp @@ -0,0 +1,115 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TexturePoolOGL.h" +#include "GLContext.h" +#include "nsDeque.h" +#include "mozilla/Monitor.h" + +#define TEXTURE_POOL_SIZE 10 + +namespace mozilla { +namespace gl { + +static GLContext* sActiveContext = NULL; + +static Monitor* sMonitor = NULL; +static nsDeque* sTextures = NULL; + +GLuint TexturePoolOGL::AcquireTexture() +{ + NS_ASSERTION(sMonitor, "not initialized"); + + MonitorAutoLock lock(*sMonitor); + + if (!sActiveContext) { + // Wait for a context + sMonitor->Wait(); + + if (!sActiveContext) + return 0; + } + + GLuint texture = 0; + if (sActiveContext->IsOwningThreadCurrent()) { + sActiveContext->MakeCurrent(); + + sActiveContext->fGenTextures(1, &texture); + } else { + while (sTextures->GetSize() == 0) { + NS_WARNING("Waiting for texture"); + sMonitor->Wait(); + } + + GLuint* popped = (GLuint*) sTextures->Pop(); + if (!popped) { + NS_ERROR("Failed to pop texture pool item"); + return 0; + } + + texture = *popped; + delete popped; + + NS_ASSERTION(texture, "Failed to retrieve texture from pool"); + } + + return texture; +} + +static void Clear() +{ + if (!sActiveContext) + return; + + sActiveContext->MakeCurrent(); + + GLuint* item; + while (sTextures->GetSize()) { + item = (GLuint*)sTextures->Pop(); + sActiveContext->fDeleteTextures(1, item); + delete item; + } +} + +void TexturePoolOGL::Fill(GLContext* aContext) +{ + NS_ASSERTION(aContext, "NULL GLContext"); + NS_ASSERTION(sMonitor, "not initialized"); + + MonitorAutoLock lock(*sMonitor); + + if (sActiveContext != aContext) { + Clear(); + sActiveContext = aContext; + } + + if (sTextures->GetSize() == TEXTURE_POOL_SIZE) + return; + + sActiveContext->MakeCurrent(); + + GLuint* texture = NULL; + while (sTextures->GetSize() < TEXTURE_POOL_SIZE) { + texture = (GLuint*)malloc(sizeof(GLuint)); + sActiveContext->fGenTextures(1, texture); + sTextures->Push((void*) texture); + } + + sMonitor->NotifyAll(); +} + +void TexturePoolOGL::Init() +{ + sMonitor = new Monitor("TexturePoolOGL.sMonitor"); + sTextures = new nsDeque(); +} + +void TexturePoolOGL::Shutdown() +{ + delete sMonitor; + delete sTextures; +} + +} // gl +} // mozilla diff --git a/gfx/layers/opengl/TexturePoolOGL.h b/gfx/layers/opengl/TexturePoolOGL.h new file mode 100644 index 000000000000..32a34aad6b4e --- /dev/null +++ b/gfx/layers/opengl/TexturePoolOGL.h @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_TEXTUREPOOLOGL_H +#define GFX_TEXTUREPOOLOGL_H + +#include "GLContext.h" + +namespace mozilla { +namespace gl { + +// A texture pool for for the on-screen GLContext. The main purpose of this class +// is to provide the ability to easily allocate an on-screen texture from the +// content thread. The unfortunate nature of the SurfaceTexture API (see nsSurfaceTexture) +// necessitates this. +class TexturePoolOGL +{ +public: + // Get a new texture from the pool. Will block + // and wait for one to be created if necessary + static GLuint AcquireTexture(); + + // Called by the active LayerManagerOGL to fill + // the pool + static void Fill(GLContext* aContext); + + // Initializes the pool, but does not fill it. Called by gfxPlatform init. + static void Init(); + + // Clears all internal data structures in preparation for shutdown + static void Shutdown(); +}; + +} // gl +} // mozilla + +#endif // GFX_TEXTUREPOOLOGL_H diff --git a/gfx/thebes/Makefile.in b/gfx/thebes/Makefile.in index 8c5339dcfc8d..8ab5b6124eac 100644 --- a/gfx/thebes/Makefile.in +++ b/gfx/thebes/Makefile.in @@ -49,6 +49,7 @@ EXPORTS = \ gfxUserFontSet.h \ nsCoreAnimationSupport.h \ nsIOSurface.h \ + nsSurfaceTexture.h \ gfxSharedImageSurface.h \ gfxReusableSurfaceWrapper.h \ $(NULL) @@ -174,6 +175,7 @@ CPPSRCS = \ gfxHarfBuzzShaper.cpp \ gfxSharedImageSurface.cpp \ gfxReusableSurfaceWrapper.cpp \ + nsSurfaceTexture.cpp \ $(NULL) ifeq ($(MOZ_WIDGET_TOOLKIT),$(findstring $(MOZ_WIDGET_TOOLKIT),android gtk2 gonk qt)) diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 7e6eaf4283f3..1f3c27700024 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -59,6 +59,10 @@ #include "GLContext.h" #include "GLContextProvider.h" +#ifdef MOZ_WIDGET_ANDROID +#include "TexturePoolOGL.h" +#endif + #include "mozilla/FunctionTimer.h" #include "mozilla/Preferences.h" #include "mozilla/Assertions.h" @@ -335,6 +339,11 @@ gfxPlatform::Init() gPlatform->mWorkAroundDriverBugs = Preferences::GetBool("gfx.work-around-driver-bugs", true); +#ifdef MOZ_WIDGET_ANDROID + // Texture pool init + mozilla::gl::TexturePoolOGL::Init(); +#endif + // Force registration of the gfx component, thus arranging for // ::Shutdown to be called. nsCOMPtr forceReg @@ -371,6 +380,11 @@ gfxPlatform::Shutdown() gPlatform->mFontPrefsObserver = nsnull; } +#ifdef MOZ_WIDGET_ANDROID + // Shut down the texture pool + mozilla::gl::TexturePoolOGL::Shutdown(); +#endif + // Shut down the default GL context provider. mozilla::gl::GLContextProvider::Shutdown(); diff --git a/gfx/thebes/nsSurfaceTexture.cpp b/gfx/thebes/nsSurfaceTexture.cpp new file mode 100644 index 000000000000..a263f9752e34 --- /dev/null +++ b/gfx/thebes/nsSurfaceTexture.cpp @@ -0,0 +1,263 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:set ts=2 sts=2 sw=2 et cin: +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef MOZ_WIDGET_ANDROID + +#include +#include +#include +#include "nsSurfaceTexture.h" +#include "gfxImageSurface.h" +#include "AndroidBridge.h" + +using namespace mozilla; + +#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "nsSurfaceTexture" , ## args) + +// UGH +static std::map sInstances; +static int sNextID = 0; + +static class JNIFunctions { +public: + + JNIFunctions() : mInitialized(false) + { + } + + + bool EnsureInitialized() + { + if (mInitialized) + return true; + + JNIEnv* env = GetJNIForThread(); + if (!env) + return false; + + AutoLocalJNIFrame jniFrame(env); + + jSurfaceTextureClass = (jclass)env->NewGlobalRef(env->FindClass("android/graphics/SurfaceTexture")); + jSurfaceTexture_Ctor = env->GetMethodID(jSurfaceTextureClass, "", "(I)V"); + jSurfaceTexture_updateTexImage = env->GetMethodID(jSurfaceTextureClass, "updateTexImage", "()V"); + jSurfaceTexture_getTransformMatrix = env->GetMethodID(jSurfaceTextureClass, "getTransformMatrix", "([F)V"); + + mInitialized = true; + return true; + } + + jobject CreateSurfaceTexture(GLuint aTexture) + { + if (!EnsureInitialized()) + return NULL; + + JNIEnv* env = GetJNIForThread(); + if (!env) + return NULL; + + AutoLocalJNIFrame jniFrame(env); + + return env->NewGlobalRef(env->NewObject(jSurfaceTextureClass, jSurfaceTexture_Ctor, (int) aTexture)); + } + + void ReleaseSurfaceTexture(jobject aSurfaceTexture) + { + JNIEnv* env = GetJNIForThread(); + if (!env) + return; + + env->DeleteGlobalRef(aSurfaceTexture); + } + + void UpdateTexImage(jobject aSurfaceTexture) + { + JNIEnv* env = GetJNIForThread(); + if (!env) + return; + + AutoLocalJNIFrame jniFrame(env); + env->CallObjectMethod(aSurfaceTexture, jSurfaceTexture_updateTexImage); + } + + bool GetTransformMatrix(jobject aSurfaceTexture, gfx3DMatrix& aMatrix) + { + JNIEnv* env = GetJNIForThread(); + if (!env) + return false; + + AutoLocalJNIFrame jniFrame(env); + + jfloatArray jarray = env->NewFloatArray(16); + env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_getTransformMatrix, jarray); + + jfloat* array = env->GetFloatArrayElements(jarray, NULL); + + aMatrix._11 = array[0]; + aMatrix._12 = array[1]; + aMatrix._13 = array[2]; + aMatrix._14 = array[3]; + + aMatrix._21 = array[4]; + aMatrix._22 = array[5]; + aMatrix._23 = array[6]; + aMatrix._24 = array[7]; + + aMatrix._31 = array[8]; + aMatrix._32 = array[9]; + aMatrix._33 = array[10]; + aMatrix._34 = array[11]; + + aMatrix._41 = array[12]; + aMatrix._42 = array[13]; + aMatrix._43 = array[14]; + aMatrix._44 = array[15]; + + env->ReleaseFloatArrayElements(jarray, array, 0); + + return false; + } + +private: + bool mInitialized; + + jclass jSurfaceTextureClass; + jmethodID jSurfaceTexture_Ctor; + jmethodID jSurfaceTexture_updateTexImage; + jmethodID jSurfaceTexture_getTransformMatrix; + +} sJNIFunctions; + +nsSurfaceTexture* +nsSurfaceTexture::Create(GLuint aTexture) +{ + // Right now we only support creating this on the main thread because + // of the JNIEnv assumptions in JNIHelper and elsewhere + if (!NS_IsMainThread()) + return NULL; + + nsSurfaceTexture* st = new nsSurfaceTexture(); + if (!st->Init(aTexture)) { + LOG("Failed to initialize nsSurfaceTexture"); + delete st; + st = NULL; + } + + return st; +} + +nsSurfaceTexture* +nsSurfaceTexture::Find(int id) +{ + std::map::iterator it; + + it = sInstances.find(id); + if (it == sInstances.end()) + return NULL; + + return it->second; +} + +bool +nsSurfaceTexture::Check() +{ + return sJNIFunctions.EnsureInitialized(); +} + +bool +nsSurfaceTexture::Init(GLuint aTexture) +{ + if (!sJNIFunctions.EnsureInitialized()) + return false; + + JNIEnv* env = GetJNIForThread(); + if (!env) + return false; + + mSurfaceTexture = sJNIFunctions.CreateSurfaceTexture(aTexture); + if (!mSurfaceTexture) + return false; + + mNativeWindow = AndroidBridge::Bridge()->AcquireNativeWindowFromSurfaceTexture(env, mSurfaceTexture); + + mID = ++sNextID; + sInstances.insert(std::pair(mID, this)); + + return true; +} + +nsSurfaceTexture::nsSurfaceTexture() + : mSurfaceTexture(NULL), mNativeWindow(NULL) +{ +} + +nsSurfaceTexture::~nsSurfaceTexture() +{ + sInstances.erase(mID); + + mFrameAvailableCallback = NULL; + + if (mNativeWindow) { + AndroidBridge::Bridge()->ReleaseNativeWindowForSurfaceTexture(mSurfaceTexture); + mNativeWindow = NULL; + } + + JNIEnv* env = GetJNIForThread(); + if (!env) + return; + + if (mSurfaceTexture && env) { + AndroidBridge::Bridge()->UnregisterSurfaceTextureFrameListener(mSurfaceTexture); + + env->DeleteGlobalRef(mSurfaceTexture); + mSurfaceTexture = NULL; + } +} + +void* +nsSurfaceTexture::GetNativeWindow() +{ + return mNativeWindow; +} + +void +nsSurfaceTexture::UpdateTexImage() +{ + sJNIFunctions.UpdateTexImage(mSurfaceTexture); +} + +bool +nsSurfaceTexture::GetTransformMatrix(gfx3DMatrix& aMatrix) +{ + return sJNIFunctions.GetTransformMatrix(mSurfaceTexture, aMatrix); +} + +void +nsSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable) +{ + if (aRunnable) + AndroidBridge::Bridge()->RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID); + else + AndroidBridge::Bridge()->UnregisterSurfaceTextureFrameListener(mSurfaceTexture); + + mFrameAvailableCallback = aRunnable; +} + +void +nsSurfaceTexture::NotifyFrameAvailable() +{ + if (mFrameAvailableCallback) { + // Proxy to main thread if we aren't on it + if (!NS_IsMainThread()) { + // Proxy to main thread + nsCOMPtr event = NS_NewRunnableMethod(this, &nsSurfaceTexture::NotifyFrameAvailable); + NS_DispatchToCurrentThread(event); + } else { + mFrameAvailableCallback->Run(); + } + } +} + +#endif // MOZ_WIDGET_ANDROID \ No newline at end of file diff --git a/gfx/thebes/nsSurfaceTexture.h b/gfx/thebes/nsSurfaceTexture.h new file mode 100644 index 000000000000..3d7213589257 --- /dev/null +++ b/gfx/thebes/nsSurfaceTexture.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:set ts=2 sts=2 sw=2 et cin: +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsSurfaceTexture_h__ +#define nsSurfaceTexture_h__ +#ifdef MOZ_WIDGET_ANDROID + +#include +#include "nsIRunnable.h" +#include "gfxPlatform.h" +#include "gfx3DMatrix.h" +#include "GLDefs.h" + +class gfxASurface; + +/** + * This class is a wrapper around Android's SurfaceTexture class. + * Usage is pretty much exactly like the Java class, so see + * the Android documentation for details. + */ +class THEBES_API nsSurfaceTexture { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsSurfaceTexture) + +public: + static nsSurfaceTexture* Create(GLuint aTexture); + static nsSurfaceTexture* Find(int id); + + // Returns with reasonable certainty whether or not we'll + // be able to create and use a SurfaceTexture + static bool Check(); + + ~nsSurfaceTexture(); + + // This is an ANativeWindow. Use AndroidBridge::LockWindow and + // friends for manipulating it. + void* GetNativeWindow(); + + // This attaches the updated data to the TEXTURE_EXTERNAL target + void UpdateTexImage(); + + bool GetTransformMatrix(gfx3DMatrix& aMatrix); + int ID() { return mID; } + + void SetFrameAvailableCallback(nsIRunnable* aRunnable); + + // Only should be called by AndroidJNI when we get a + // callback from the underlying SurfaceTexture instance + void NotifyFrameAvailable(); +private: + nsSurfaceTexture(); + + bool Init(GLuint aTexture); + + jobject mSurfaceTexture; + void* mNativeWindow; + int mID; + nsRefPtr mFrameAvailableCallback; +}; + +#endif +#endif diff --git a/layout/base/nsDisplayItemTypes.h b/layout/base/nsDisplayItemTypes.h index 542cae67ebe2..c0447a0ea793 100644 --- a/layout/base/nsDisplayItemTypes.h +++ b/layout/base/nsDisplayItemTypes.h @@ -49,6 +49,7 @@ enum Type { TYPE_PAGE_SEQUENCE, TYPE_PLUGIN, TYPE_PLUGIN_READBACK, + TYPE_PLUGIN_VIDEO, TYPE_PRINT_PLUGIN, TYPE_REMOTE, TYPE_REMOTE_SHADOW, diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index cacf78eea045..6105386adf21 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -145,6 +145,11 @@ using mozilla::DefaultXDisplay; #include "gfxOS2Surface.h" #endif +#ifdef MOZ_WIDGET_ANDROID +#include "AndroidBridge.h" +#include "GLContext.h" +#endif + #ifdef CreateEvent // Thank you MS. #undef CreateEvent #endif @@ -932,6 +937,66 @@ nsDisplayPluginReadback::ComputeVisibility(nsDisplayListBuilder* aBuilder, return true; } +#ifdef MOZ_WIDGET_ANDROID + +class nsDisplayPluginVideo : public nsDisplayItem { +public: + nsDisplayPluginVideo(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsNPAPIPluginInstance::VideoInfo* aVideoInfo) + : nsDisplayItem(aBuilder, aFrame), mVideoInfo(aVideoInfo) + { + MOZ_COUNT_CTOR(nsDisplayPluginVideo); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayPluginVideo() { + MOZ_COUNT_DTOR(nsDisplayPluginVideo); + } +#endif + + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap); + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion); + + NS_DISPLAY_DECL_NAME("PluginVideo", TYPE_PLUGIN_VIDEO) + + virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerParameters& aContainerParameters) + { + return static_cast(mFrame)->BuildLayer(aBuilder, aManager, this); + } + + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerParameters& aParameters) + { + return LAYER_ACTIVE; + } + + nsNPAPIPluginInstance::VideoInfo* VideoInfo() { return mVideoInfo; } + +private: + nsNPAPIPluginInstance::VideoInfo* mVideoInfo; +}; + +nsRect +nsDisplayPluginVideo::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) +{ + *aSnap = false; + return GetDisplayItemBounds(aBuilder, this, mFrame); +} + +bool +nsDisplayPluginVideo::ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) +{ + return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, + aAllowVisibleRegionExpansion); +} + +#endif + nsRect nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { @@ -1086,6 +1151,9 @@ nsObjectFrame::IsOpaque() const #if defined(XP_MACOSX) // ??? return false; +#elif defined(MOZ_WIDGET_ANDROID) + // We don't know, so just assume transparent + return false; #else return !IsTransparentMode(); #endif @@ -1174,6 +1242,8 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, nsDisplayGeneric(aBuilder, this, PaintPrintPlugin, "PrintPlugin", nsDisplayItem::TYPE_PRINT_PLUGIN)); } else { + // We don't need this on Android, and it just confuses things +#if !MOZ_WIDGET_ANDROID if (aBuilder->IsPaintingToWindow() && GetLayerState(aBuilder, nsnull) == LAYER_ACTIVE && IsTransparentMode()) { @@ -1181,6 +1251,22 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, nsDisplayPluginReadback(aBuilder, this)); NS_ENSURE_SUCCESS(rv, rv); } +#endif + +#if MOZ_WIDGET_ANDROID + if (aBuilder->IsPaintingToWindow() && + GetLayerState(aBuilder, nsnull) == LAYER_ACTIVE) { + + nsTArray videos; + mInstanceOwner->GetVideos(videos); + + for (int i = 0; i < videos.Length(); i++) { + rv = replacedContent.AppendNewToTop(new (aBuilder) + nsDisplayPluginVideo(aBuilder, this, videos[i])); + NS_ENSURE_SUCCESS(rv, rv); + } + } +#endif rv = replacedContent.AppendNewToTop(new (aBuilder) nsDisplayPlugin(aBuilder, this)); @@ -1488,6 +1574,12 @@ nsObjectFrame::GetLayerState(nsDisplayListBuilder* aBuilder, } #endif +#ifdef MOZ_WIDGET_ANDROID + // We always want a layer on Honeycomb and later + if (AndroidBridge::Bridge()->GetAPIVersion() >= 11) + return LAYER_ACTIVE; +#endif + if (!mInstanceOwner->UseAsyncRendering()) { return LAYER_NONE; } @@ -1566,6 +1658,32 @@ nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder, imglayer->SetFilter(filter); layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0); +#ifdef MOZ_WIDGET_ANDROID + } else if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_VIDEO) { + nsDisplayPluginVideo* videoItem = reinterpret_cast(aItem); + nsNPAPIPluginInstance::VideoInfo* videoInfo = videoItem->VideoInfo(); + + nsRefPtr container = mInstanceOwner->GetImageContainerForVideo(videoInfo); + if (!container) + return nsnull; + + if (!layer) { + // Initialize ImageLayer + layer = aManager->CreateImageLayer(); + if (!layer) + return nsnull; + } + + ImageLayer* imglayer = static_cast(layer.get()); + imglayer->SetContainer(container); + + layer->SetContentFlags(IsOpaque() ? Layer::CONTENT_OPAQUE : 0); + + // Set the offset and size according to the video dimensions + r.MoveBy(videoInfo->mDimensions.TopLeft()); + size.width = videoInfo->mDimensions.width; + size.height = videoInfo->mDimensions.height; +#endif } else { NS_ASSERTION(aItem->GetType() == nsDisplayItem::TYPE_PLUGIN_READBACK, "Unknown item type"); diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 18edff6df51d..074ef20a1881 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -12,7 +12,6 @@ import org.mozilla.gecko.gfx.LayerController; import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.gfx.PluginLayer; import org.mozilla.gecko.gfx.PointUtils; -import org.mozilla.gecko.gfx.SurfaceTextureLayer; import org.mozilla.gecko.ui.PanZoomController; import java.io.*; @@ -235,14 +234,6 @@ abstract public class GeckoApp } } - // we don't support Honeycomb - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && - Build.VERSION.SDK_INT < 14 /*Build.VERSION_CODES.ICE_CREAM_SANDWICH*/ ) - { - Log.w(LOGTAG, "Blocking plugins because of Honeycomb"); - return new String[0]; - } - Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - start of getPluginDirectories"); ArrayList directories = new ArrayList(); @@ -1612,51 +1603,6 @@ abstract public class GeckoApp } }); } - - public Surface createSurface() { - Tabs tabs = Tabs.getInstance(); - Tab tab = tabs.getSelectedTab(); - if (tab == null) - return null; - - SurfaceTextureLayer layer = SurfaceTextureLayer.create(); - if (layer == null) - return null; - - Surface surface = layer.getSurface(); - tab.addPluginLayer(surface, layer); - return surface; - } - - public void destroySurface(Surface surface) { - Tabs tabs = Tabs.getInstance(); - Tab tab = tabs.getSelectedTab(); - if (tab == null) - return; - - Layer layer = tab.removePluginLayer(surface); - hidePluginLayer(layer); - } - - public void showSurface(Surface surface, int x, int y, - int w, int h, boolean inverted, boolean blend) { - Tabs tabs = Tabs.getInstance(); - Tab tab = tabs.getSelectedTab(); - if (tab == null) - return; - - LayerView layerView = mLayerController.getView(); - SurfaceTextureLayer layer = (SurfaceTextureLayer)tab.getPluginLayer(surface); - if (layer == null) - return; - - layer.update(new Rect(x, y, x + w, y + h), inverted, blend); - layerView.addLayer(layer); - - // FIXME: shouldn't be necessary, layer will request - // one when it gets first frame - layerView.requestRender(); - } private void hidePluginLayer(Layer layer) { LayerView layerView = mLayerController.getView(); @@ -1670,19 +1616,6 @@ abstract public class GeckoApp layerView.requestRender(); } - public void hideSurface(Surface surface) { - Tabs tabs = Tabs.getInstance(); - Tab tab = tabs.getSelectedTab(); - if (tab == null) - return; - - Layer layer = tab.getPluginLayer(surface); - if (layer == null) - return; - - hidePluginLayer(layer); - } - public void requestRender() { mLayerController.getView().requestRender(); } diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index cbea3fe1dd00..48e05b436473 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -145,6 +145,7 @@ public class GeckoAppShell public static native void loadNSSLibsNative(String apkName, boolean shouldExtract); public static native void onChangeNetworkLinkStatus(String status); public static native Message getNextMessageFromQueue(MessageQueue queue); + public static native void onSurfaceTextureFrameAvailable(Object surfaceTexture, int id); public static void registerGlobalExceptionHandler() { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @@ -1690,35 +1691,6 @@ public class GeckoAppShell GeckoApp.mAppContext.removePluginView(view, isFullScreen); } - public static Surface createSurface() { - Log.i(LOGTAG, "createSurface"); - return GeckoApp.mAppContext.createSurface(); - } - - public static void showSurface(Surface surface, - int x, int y, - int w, int h, - boolean inverted, - boolean blend) - { - Log.i(LOGTAG, "showSurface:" + surface + " @ x:" + x + " y:" + y + " w:" + w + " h:" + h + " inverted: " + inverted + " blend: " + blend); - try { - GeckoApp.mAppContext.showSurface(surface, x, y, w, h, inverted, blend); - } catch (Exception e) { - Log.i(LOGTAG, "Error in showSurface:", e); - } - } - - public static void hideSurface(Surface surface) { - Log.i(LOGTAG, "hideSurface:" + surface); - GeckoApp.mAppContext.hideSurface(surface); - } - - public static void destroySurface(Surface surface) { - Log.i(LOGTAG, "destroySurface:" + surface); - GeckoApp.mAppContext.destroySurface(surface); - } - public static Class loadPluginClass(String className, String libName) { Log.i(LOGTAG, "in loadPluginClass... attempting to access className, then libName....."); Log.i(LOGTAG, "className: " + className); @@ -2284,6 +2256,17 @@ public class GeckoAppShell return data; } + public static void registerSurfaceTextureFrameListener(Object surfaceTexture, final int id) { + ((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { + public void onFrameAvailable(SurfaceTexture surfaceTexture) { + GeckoAppShell.onSurfaceTextureFrameAvailable(surfaceTexture, id); + } + }); + } + + public static void unregisterSurfaceTextureFrameListener(Object surfaceTexture) { + ((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(null); + } } class ScreenshotHandler implements Runnable { diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index e65005e59b94..76bdb307f148 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -137,7 +137,6 @@ FENNEC_JAVA_FILES = \ gfx/ScreenshotLayer.java \ gfx/ScrollbarLayer.java \ gfx/SingleTileLayer.java \ - gfx/SurfaceTextureLayer.java \ gfx/TextLayer.java \ gfx/TextureGenerator.java \ gfx/TextureReaper.java \ diff --git a/mobile/android/base/gfx/SurfaceTextureLayer.java b/mobile/android/base/gfx/SurfaceTextureLayer.java deleted file mode 100644 index 90bf2fc60962..000000000000 --- a/mobile/android/base/gfx/SurfaceTextureLayer.java +++ /dev/null @@ -1,279 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.gecko.gfx; - -import org.mozilla.gecko.GeckoApp; - -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.SurfaceTexture; -import android.opengl.GLES20; -import android.util.Log; -import android.view.Surface; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; - -public class SurfaceTextureLayer extends Layer implements SurfaceTexture.OnFrameAvailableListener { - private static final String LOGTAG = "SurfaceTextureLayer"; - private static final int LOCAL_GL_TEXTURE_EXTERNAL_OES = 0x00008d65; // This is only defined in API level 15 for some reason (Android 4.0.3) - - private final SurfaceTexture mSurfaceTexture; - private final Surface mSurface; - private int mTextureId; - private boolean mHaveFrame; - private float[] mTextureTransform = new float[16]; - - private Rect mPageRect; - - private boolean mInverted; - private boolean mNewInverted; - private boolean mBlend; - private boolean mNewBlend; - - private static int mProgram; - private static int mPositionHandle; - private static int mTextureHandle; - private static int mSampleHandle; - private static int mProjectionMatrixHandle; - private static int mTextureMatrixHandle; - - private static final float[] PROJECTION_MATRIX = { - 2.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 2.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 2.0f, 0.0f, - -1.0f, -1.0f, 0.0f, 1.0f - }; - - private static final String VERTEX_SHADER = - "uniform mat4 projectionMatrix;\n" + - "uniform mat4 textureMatrix;\n" + - "attribute vec4 vPosition;\n" + - "attribute vec4 aTexCoord;\n" + - "varying vec2 vTexCoord;\n" + - "void main() {\n" + - " gl_Position = projectionMatrix * vPosition;\n" + - " vTexCoord = (textureMatrix * vec4(aTexCoord.x, aTexCoord.y, 0.0, 1.0)).xy;\n" + - "}\n"; - - private static String FRAGMENT_SHADER_OES = - "#extension GL_OES_EGL_image_external : require\n" + - "precision mediump float;\n" + - "varying vec2 vTexCoord; \n" + - "uniform samplerExternalOES sTexture; \n" + - "void main() {\n" + - " gl_FragColor = texture2D(sTexture, vTexCoord); \n" + - "}\n"; - - - private static final float TEXTURE_MAP[] = { - 0.0f, 1.0f, // top left - 0.0f, 0.0f, // bottom left - 1.0f, 1.0f, // top right - 1.0f, 0.0f, // bottom right - }; - - private static final float TEXTURE_MAP_INVERTED[] = { - 0.0f, 0.0f, // bottom left - 0.0f, 1.0f, // top left - 1.0f, 0.0f, // bottom right - 1.0f, 1.0f, // top right - }; - - private SurfaceTextureLayer(int textureId) { - mTextureId = textureId; - mHaveFrame = true; - mInverted = false; - - // We have our own special shaders necessary for rendering the SurfaceTexture - this.mUsesDefaultProgram = false; - - mSurfaceTexture = new SurfaceTexture(mTextureId); - mSurfaceTexture.setOnFrameAvailableListener(this); - - Surface tmp = null; - try { - tmp = Surface.class.getConstructor(SurfaceTexture.class).newInstance(mSurfaceTexture); } - catch (Exception ie) { - Log.e(LOGTAG, "error constructing the surface", ie); - } - - mSurface = tmp; - } - - public static SurfaceTextureLayer create() { - int textureId = TextureGenerator.get().take(); - if (textureId == 0) - return null; - - return new SurfaceTextureLayer(textureId); - } - - // For SurfaceTexture.OnFrameAvailableListener - public void onFrameAvailable(SurfaceTexture texture) { - mHaveFrame = true; - GeckoApp.mAppContext.requestRender(); - } - - public void update(Rect rect, boolean inverted, boolean blend) { - beginTransaction(); - - setPosition(rect); - - mNewInverted = inverted; - mNewBlend = blend; - - endTransaction(); - } - - @Override - protected void finalize() throws Throwable { - try { - if (mTextureId > 0) - TextureReaper.get().add(mTextureId); - } finally { - super.finalize(); - } - } - - @Override - protected void performUpdates(RenderContext context) { - super.performUpdates(context); - - mInverted = mNewInverted; - mBlend = mNewBlend; - } - - private static boolean ensureProgram() { - if (mProgram != 0) - return true; - - int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER); - int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_OES); - - mProgram = GLES20.glCreateProgram(); - GLES20.glAttachShader(mProgram, vertexShader); - GLES20.glAttachShader(mProgram, fragmentShader); - GLES20.glLinkProgram(mProgram); - - mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); - mTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoord"); - mSampleHandle = GLES20.glGetUniformLocation(mProgram, "sTexture"); - mProjectionMatrixHandle = GLES20.glGetUniformLocation(mProgram, "projectionMatrix"); - mTextureMatrixHandle = GLES20.glGetUniformLocation(mProgram, "textureMatrix"); - - return mProgram != 0; - } - - private static int loadShader(int type, String shaderCode) { - int shader = GLES20.glCreateShader(type); - GLES20.glShaderSource(shader, shaderCode); - GLES20.glCompileShader(shader); - return shader; - } - - private static void activateProgram() { - GLES20.glUseProgram(mProgram); - } - - public static void deactivateProgram() { - GLES20.glDisableVertexAttribArray(mTextureHandle); - GLES20.glDisableVertexAttribArray(mPositionHandle); - GLES20.glUseProgram(0); - } - - @Override - public void draw(RenderContext context) { - if (!ensureProgram() || !mHaveFrame) - return; - - RectF rect = getBounds(context); - RectF viewport = context.viewport; - rect.offset(-viewport.left, -viewport.top); - - float viewWidth = viewport.width(); - float viewHeight = viewport.height(); - - float top = viewHeight - rect.top; - float bot = viewHeight - rect.bottom; - - float[] textureCoords = mInverted ? TEXTURE_MAP_INVERTED : TEXTURE_MAP; - - float[] coords = { - // x, y, z, texture_x, texture_y - rect.left/viewWidth, bot/viewHeight, 0, - textureCoords[0], textureCoords[1], - - rect.left/viewWidth, (bot+rect.height())/viewHeight, 0, - textureCoords[2], textureCoords[3], - - (rect.left+rect.width())/viewWidth, bot/viewHeight, 0, - textureCoords[4], textureCoords[5], - - (rect.left+rect.width())/viewWidth, (bot+rect.height())/viewHeight, 0, - textureCoords[6], textureCoords[7] - }; - - FloatBuffer coordBuffer = context.coordBuffer; - coordBuffer.position(0); - coordBuffer.put(coords); - - activateProgram(); - - // Set the transformation matrix - GLES20.glUniformMatrix4fv(mProjectionMatrixHandle, 1, false, PROJECTION_MATRIX, 0); - - // Enable the arrays from which we get the vertex and texture coordinates - GLES20.glEnableVertexAttribArray(mPositionHandle); - GLES20.glEnableVertexAttribArray(mTextureHandle); - - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glUniform1i(mSampleHandle, 0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); - GLES20.glBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, mTextureId); - - mSurfaceTexture.updateTexImage(); - mSurfaceTexture.getTransformMatrix(mTextureTransform); - - GLES20.glUniformMatrix4fv(mTextureMatrixHandle, 1, false, mTextureTransform, 0); - - // Unbind any the current array buffer so we can use client side buffers - GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); - - // Vertex coordinates are x,y,z starting at position 0 into the buffer. - coordBuffer.position(0); - GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 20, - coordBuffer); - - // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer. - coordBuffer.position(3); - GLES20.glVertexAttribPointer(mTextureHandle, 2, GLES20.GL_FLOAT, false, 20, - coordBuffer); - - if (mBlend) { - GLES20.glEnable(GLES20.GL_BLEND); - GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA); - } - - GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); - - if (mBlend) - GLES20.glDisable(GLES20.GL_BLEND); - - deactivateProgram(); - } - - public SurfaceTexture getSurfaceTexture() { - return mSurfaceTexture; - } - - public Surface getSurface() { - return mSurface; - } -} - diff --git a/mozglue/android/APKOpen.cpp b/mozglue/android/APKOpen.cpp index 612bef625917..ec543794de48 100644 --- a/mozglue/android/APKOpen.cpp +++ b/mozglue/android/APKOpen.cpp @@ -323,6 +323,7 @@ SHELL_WRAPPER2(notifyFilePickerResult, jstring, jlong) SHELL_WRAPPER1_WITH_RETURN(getSurfaceBits, jobject, jobject) SHELL_WRAPPER1(onFullScreenPluginHidden, jobject) SHELL_WRAPPER1_WITH_RETURN(getNextMessageFromQueue, jobject, jobject) +SHELL_WRAPPER2(onSurfaceTextureFrameAvailable, jobject, jint); static void * xul_handle = NULL; static void * sqlite_handle = NULL; @@ -746,6 +747,7 @@ loadGeckoLibs(const char *apkName) GETFUNC(getSurfaceBits); GETFUNC(onFullScreenPluginHidden); GETFUNC(getNextMessageFromQueue); + GETFUNC(onSurfaceTextureFrameAvailable); #undef GETFUNC void (*XRE_StartupTimelineRecord)(int, MOZTime); diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 2cd22074f7bf..105a840b9fee 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -31,6 +31,7 @@ #include "mozilla/dom/ScreenOrientation.h" #include "nsIDOMWindowUtils.h" #include "nsIDOMClientRect.h" +#include "StrongPointer.h" #ifdef DEBUG #define ALOG_BRIDGE(args...) ALOG(args) @@ -49,6 +50,15 @@ AndroidBridge *AndroidBridge::sBridge = 0; static PRUintn sJavaEnvThreadIndex = 0; static void JavaThreadDetachFunc(void *arg); +// This is a dummy class that can be used in the template for android::sp +class AndroidRefable { + void incStrong(void* thing) { } + void decStrong(void* thing) { } +}; + +// This isn't in AndroidBridge.h because including StrongPointer.h there is gross +static android::sp (*android_SurfaceTexture_getNativeWindow)(JNIEnv* env, jobject surfaceTexture) = nsnull; + AndroidBridge * AndroidBridge::ConstructBridge(JNIEnv *jEnv, jclass jGeckoAppShellClass) @@ -178,11 +188,10 @@ AndroidBridge::Init(JNIEnv *jEnv, jSurfaceClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("android/view/Surface")); - PRInt32 apiVersion = 0; - if (!GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &apiVersion, jEnv)) + if (!GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &mAPIVersion, jEnv)) ALOG_BRIDGE("Failed to find API version"); - if (apiVersion <= 8 /* Froyo */) + if (mAPIVersion <= 8 /* Froyo */) jSurfacePointerField = jEnv->GetFieldID(jSurfaceClass, "mSurface", "I"); else /* not Froyo */ jSurfacePointerField = jEnv->GetFieldID(jSurfaceClass, "mNativeSurface", "I"); @@ -190,6 +199,8 @@ AndroidBridge::Init(JNIEnv *jEnv, jNotifyWakeLockChanged = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V"); jGetGfxInfoData = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getGfxInfoData", "()Ljava/lang/String;"); + jRegisterSurfaceTextureFrameListener = jEnv->GetStaticMethodID(jGeckoAppShellClass, "registerSurfaceTextureFrameListener", "(Ljava/lang/Object;I)V"); + jUnregisterSurfaceTextureFrameListener = jEnv->GetStaticMethodID(jGeckoAppShellClass, "unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V"); #ifdef MOZ_JAVA_COMPOSITOR jPumpMessageLoop = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "pumpMessageLoop", "()V"); @@ -197,11 +208,6 @@ AndroidBridge::Init(JNIEnv *jEnv, jAddPluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "addPluginView", "(Landroid/view/View;IIIIZ)V"); jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;Z)V"); - jCreateSurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "createSurface", "()Landroid/view/Surface;"); - jShowSurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "showSurface", "(Landroid/view/Surface;IIIIZZ)V"); - jHideSurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "hideSurface", "(Landroid/view/Surface;)V"); - jDestroySurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "destroySurface", "(Landroid/view/Surface;)V"); - jLayerView = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("org/mozilla/gecko/gfx/LayerView")); AndroidGLController::Init(jEnv); @@ -1396,11 +1402,20 @@ AndroidBridge::OpenGraphicsLibraries() ANativeWindow_lock = (int (*)(void*, void*, void*)) dlsym(handle, "ANativeWindow_lock"); ANativeWindow_unlockAndPost = (int (*)(void*))dlsym(handle, "ANativeWindow_unlockAndPost"); + // This is only available in Honeycomb and ICS. It was removed in Jelly Bean + ANativeWindow_fromSurfaceTexture = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurfaceTexture"); + mHasNativeWindowAccess = ANativeWindow_fromSurface && ANativeWindow_release && ANativeWindow_lock && ANativeWindow_unlockAndPost; ALOG_BRIDGE("Successfully opened libandroid.so, have native window access? %d", mHasNativeWindowAccess); } + // We need one symbol from here on Jelly Bean + handle = dlopen("libandroid_runtime.so", RTLD_LAZY | RTLD_LOCAL); + if (handle) { + android_SurfaceTexture_getNativeWindow = (android::sp (*)(JNIEnv*, jobject))dlsym(handle, "_ZN7android38android_SurfaceTexture_getNativeWindowEP7_JNIEnvP8_jobject"); + } + if (mHasNativeWindowAccess) return; @@ -1939,10 +1954,11 @@ AndroidBridge::AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface) if (mHasNativeWindowAccess) return ANativeWindow_fromSurface(aEnv, aSurface); - else if (mHasNativeWindowFallback) + + if (mHasNativeWindowFallback) return GetNativeSurface(aEnv, aSurface); - else - return nsnull; + + return nsnull; } void @@ -1958,6 +1974,31 @@ AndroidBridge::ReleaseNativeWindow(void *window) // have nothing to do here. We should probably ref it. } +void* +AndroidBridge::AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurfaceTexture) +{ + OpenGraphicsLibraries(); + + if (mHasNativeWindowAccess && ANativeWindow_fromSurfaceTexture) + return ANativeWindow_fromSurfaceTexture(aEnv, aSurfaceTexture); + + if (mHasNativeWindowAccess && android_SurfaceTexture_getNativeWindow) { + android::sp window = android_SurfaceTexture_getNativeWindow(aEnv, aSurfaceTexture); + return window.get(); + } + + return nsnull; +} + +void +AndroidBridge::ReleaseNativeWindowForSurfaceTexture(void *window) +{ + if (!window) + return; + + // FIXME: we don't ref the pointer we get, so nothing to do currently. We should ref it. +} + bool AndroidBridge::SetNativeWindowFormat(void *window, int width, int height, int format) { @@ -2190,75 +2231,6 @@ extern "C" { } } -jobject -AndroidBridge::CreateSurface() -{ -#ifndef MOZ_JAVA_COMPOSITOR - return NULL; -#else - JNIEnv* env = GetJNIEnv(); - if (!env) - return nsnull; - - AutoLocalJNIFrame jniFrame(env); - - jobject surface = env->CallStaticObjectMethod(mGeckoAppShellClass, jCreateSurface); - if (jniFrame.CheckForException()) - return nsnull; - - if (surface) - surface = env->NewGlobalRef(surface); - - return surface; -#endif -} - -void -AndroidBridge::DestroySurface(jobject surface) -{ -#ifdef MOZ_JAVA_COMPOSITOR - JNIEnv* env = GetJNIEnv(); - if (!env) - return; - - AutoLocalJNIFrame jniFrame(env); - - env->CallStaticVoidMethod(mGeckoAppShellClass, jDestroySurface, surface); - env->DeleteGlobalRef(surface); -#endif -} - -void -AndroidBridge::ShowSurface(jobject surface, const gfxRect& aRect, bool aInverted, bool aBlend) -{ -#ifdef MOZ_JAVA_COMPOSITOR - JNIEnv* env = GetJNIEnv(); - if (!env) - return; - - AutoLocalJNIFrame jniFrame(env, 0); - - env->CallStaticVoidMethod(mGeckoAppShellClass, jShowSurface, surface, - (int)aRect.x, (int)aRect.y, - (int)aRect.width, (int)aRect.height, - aInverted, aBlend); -#endif -} - -void -AndroidBridge::HideSurface(jobject surface) -{ -#ifdef MOZ_JAVA_COMPOSITOR - JNIEnv* env = GetJNIEnv(); - if (!env) - return; - - AutoLocalJNIFrame jniFrame(env, 0); - - env->CallStaticVoidMethod(mGeckoAppShellClass, jHideSurface, surface); -#endif -} - uint32_t AndroidBridge::GetScreenOrientation() { @@ -2358,6 +2330,38 @@ AndroidBridge::NotifyWakeLockChanged(const nsAString& topic, const nsAString& st env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyWakeLockChanged, jstrTopic, jstrState); } +void +AndroidBridge::ScheduleComposite() +{ +#if MOZ_JAVA_COMPOSITOR + nsWindow::ScheduleComposite(); +#endif +} + +void +AndroidBridge::RegisterSurfaceTextureFrameListener(jobject surfaceTexture, int id) +{ + JNIEnv* env = GetJNIEnv(); + if (!env) + return; + + AutoLocalJNIFrame jniFrame(env); + + env->CallStaticVoidMethod(mGeckoAppShellClass, jRegisterSurfaceTextureFrameListener, surfaceTexture, id); +} + +void +AndroidBridge::UnregisterSurfaceTextureFrameListener(jobject surfaceTexture) +{ + JNIEnv* env = GetJNIEnv(); + if (!env) + return; + + AutoLocalJNIFrame jniFrame(env); + + env->CallStaticVoidMethod(mGeckoAppShellClass, jUnregisterSurfaceTextureFrameListener, surfaceTexture); +} + void AndroidBridge::GetGfxInfoData(nsACString& aRet) { diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index 542862a3019d..c7caabadb015 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -297,6 +297,10 @@ public: void *AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface); void ReleaseNativeWindow(void *window); + + void *AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurface); + void ReleaseNativeWindowForSurfaceTexture(void *window); + bool SetNativeWindowFormat(void *window, int width, int height, int format); bool LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride); @@ -335,11 +339,6 @@ public: void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated, nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY); - jobject CreateSurface(); - void DestroySurface(jobject surface); - void ShowSurface(jobject surface, const gfxRect& aRect, bool aInverted, bool aBlend); - void HideSurface(jobject surface); - void AddPluginView(jobject view, const gfxRect& rect, bool isFullScreen); void RemovePluginView(jobject view, bool isFullScreen); @@ -357,6 +356,13 @@ public: void NotifyWakeLockChanged(const nsAString& topic, const nsAString& state); + int GetAPIVersion() { return mAPIVersion; } + bool IsHoneycomb() { return mAPIVersion >= 11 && mAPIVersion <= 13; } + + void ScheduleComposite(); + void RegisterSurfaceTextureFrameListener(jobject surfaceTexture, int id); + void UnregisterSurfaceTextureFrameListener(jobject surfaceTexture); + void GetGfxInfoData(nsACString& aRet); protected: @@ -390,6 +396,8 @@ protected: bool mHasNativeWindowAccess; bool mHasNativeWindowFallback; + int mAPIVersion; + nsCOMArray mRunnableQueue; // other things @@ -479,6 +487,8 @@ protected: jmethodID jUnlockScreenOrientation; jmethodID jPumpMessageLoop; jmethodID jNotifyWakeLockChanged; + jmethodID jRegisterSurfaceTextureFrameListener; + jmethodID jUnregisterSurfaceTextureFrameListener; // for GfxInfo (gfx feature detection and blacklisting) jmethodID jGetGfxInfoData; @@ -507,6 +517,7 @@ protected: int (* AndroidBitmap_unlockPixels)(JNIEnv *env, jobject bitmap); void* (*ANativeWindow_fromSurface)(JNIEnv *env, jobject surface); + void* (*ANativeWindow_fromSurfaceTexture)(JNIEnv *env, jobject surfaceTexture); void (*ANativeWindow_release)(void *window); int (*ANativeWindow_setBuffersGeometry)(void *window, int width, int height, int format); diff --git a/widget/android/AndroidJNI.cpp b/widget/android/AndroidJNI.cpp index 055f6caa04e4..768d048e56ea 100644 --- a/widget/android/AndroidJNI.cpp +++ b/widget/android/AndroidJNI.cpp @@ -38,6 +38,7 @@ #include "nsISmsRequestManager.h" #include "nsISmsDatabaseService.h" #include "nsPluginInstanceOwner.h" +#include "nsSurfaceTexture.h" using namespace mozilla; using namespace mozilla::dom::sms; @@ -1023,5 +1024,17 @@ Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue(JNIEnv* jenv, jclas return msg; } +NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable(JNIEnv* jenv, jclass, jobject surfaceTexture, jint id) +{ + nsSurfaceTexture* st = nsSurfaceTexture::Find(id); + if (!st) { + __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "Failed to find nsSurfaceTexture with id %d", id); + return; + } + + st->NotifyFrameAvailable(); +} + #endif } diff --git a/widget/android/AndroidMediaLayer.cpp b/widget/android/AndroidMediaLayer.cpp deleted file mode 100644 index 03d3d276553d..000000000000 --- a/widget/android/AndroidMediaLayer.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include -#include "AndroidMediaLayer.h" -#include "AndroidBridge.h" - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AndroidMediaLayer" , ## args) - - -namespace mozilla { - -AndroidMediaLayer::AndroidMediaLayer() - : mInverted(false), mVisible(true) { -} - -AndroidMediaLayer::~AndroidMediaLayer() { - if (mContentData.window && AndroidBridge::Bridge()) { - AndroidBridge::Bridge()->ReleaseNativeWindow(mContentData.window); - mContentData.window = NULL; - } - - if (mContentData.surface && AndroidBridge::Bridge()) { - AndroidBridge::Bridge()->DestroySurface(mContentData.surface); - mContentData.surface = NULL; - } - - std::map::iterator it; - - for (it = mVideoSurfaces.begin(); it != mVideoSurfaces.end(); it++) { - SurfaceData* data = it->second; - - if (AndroidBridge::Bridge()) { - AndroidBridge::Bridge()->ReleaseNativeWindow(data->window); - AndroidBridge::Bridge()->DestroySurface(data->surface); - } - - delete data; - } - - mVideoSurfaces.clear(); -} - -bool AndroidMediaLayer::EnsureContentSurface() { - if (!mContentData.surface && AndroidBridge::Bridge()) { - mContentData.surface = AndroidBridge::Bridge()->CreateSurface(); - if (mContentData.surface) { - mContentData.window = AndroidBridge::Bridge()->AcquireNativeWindow(AndroidBridge::GetJNIEnv(), mContentData.surface); - AndroidBridge::Bridge()->SetNativeWindowFormat(mContentData.window, 0, 0, AndroidBridge::WINDOW_FORMAT_RGBA_8888); - } - } - - return mContentData.surface && mContentData.window; -} - -void* AndroidMediaLayer::GetNativeWindowForContent() { - if (!EnsureContentSurface()) - return NULL; - - return mContentData.window; -} - -void* AndroidMediaLayer::RequestNativeWindowForVideo() { - if (!AndroidBridge::Bridge()) - return NULL; - - jobject surface = AndroidBridge::Bridge()->CreateSurface(); - if (surface) { - void* window = AndroidBridge::Bridge()->AcquireNativeWindow(AndroidBridge::GetJNIEnv(), surface); - if (window) { - AndroidBridge::Bridge()->SetNativeWindowFormat(window, 0, 0, AndroidBridge::WINDOW_FORMAT_RGBA_8888); - mVideoSurfaces[window] = new SurfaceData(surface, window); - return window; - } else { - LOG("Failed to create native window from surface"); - - // Cleanup - AndroidBridge::Bridge()->DestroySurface(surface); - } - } - - return NULL; -} - -void AndroidMediaLayer::ReleaseNativeWindowForVideo(void* aWindow) { - if (mVideoSurfaces.find(aWindow) == mVideoSurfaces.end() || !AndroidBridge::Bridge()) - return; - - SurfaceData* data = mVideoSurfaces[aWindow]; - - AndroidBridge::Bridge()->ReleaseNativeWindow(data->window); - AndroidBridge::Bridge()->DestroySurface(data->surface); - - mVideoSurfaces.erase(aWindow); - delete data; -} - -void AndroidMediaLayer::SetNativeWindowDimensions(void* aWindow, const gfxRect& aDimensions) { - if (mVideoSurfaces.find(aWindow) == mVideoSurfaces.end()) - return; - - SurfaceData* data = mVideoSurfaces[aWindow]; - data->dimensions = aDimensions; -} - -void AndroidMediaLayer::UpdatePosition(const gfxRect& aRect) { - if (!mVisible || !AndroidBridge::Bridge()) - return; - - std::map::iterator it; - - for (it = mVideoSurfaces.begin(); it != mVideoSurfaces.end(); it++) { - SurfaceData* data = it->second; - - gfxRect videoRect(aRect.x + data->dimensions.x, aRect.y + data->dimensions.y, - data->dimensions.width, data->dimensions.height); - - AndroidBridge::Bridge()->ShowSurface(data->surface, videoRect, mInverted, false); - } - - if (EnsureContentSurface()) { - AndroidBridge::Bridge()->ShowSurface(mContentData.surface, aRect, mInverted, true); - } -} - -void AndroidMediaLayer::SetVisible(bool aVisible) { - if (aVisible == mVisible || !AndroidBridge::Bridge()) - return; - - mVisible = aVisible; - if (mVisible) - return; - - // Hide all surfaces - std::map::iterator it; - - if (EnsureContentSurface()) - AndroidBridge::Bridge()->HideSurface(mContentData.surface); - - for (it = mVideoSurfaces.begin(); it != mVideoSurfaces.end(); it++) { - SurfaceData* data = it->second; - AndroidBridge::Bridge()->HideSurface(data->surface); - } -} - -} /* mozilla */ diff --git a/widget/android/AndroidMediaLayer.h b/widget/android/AndroidMediaLayer.h deleted file mode 100644 index c34e1b75e3c5..000000000000 --- a/widget/android/AndroidMediaLayer.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef AndroidMediaLayer_h_ -#define AndroidMediaLayer_h_ - -#include -#include -#include "gfxRect.h" -#include "nsISupports.h" - -namespace mozilla { - -class AndroidMediaLayer -{ -public: - AndroidMediaLayer(); - virtual ~AndroidMediaLayer(); - - NS_INLINE_DECL_REFCOUNTING(AndroidMediaLayer) - - void* GetNativeWindowForContent(); - - void* RequestNativeWindowForVideo(); - void ReleaseNativeWindowForVideo(void* aWindow); - - void SetNativeWindowDimensions(void* aWindow, const gfxRect& aDimensions); - - void UpdatePosition(const gfxRect& aRect); - - bool Inverted() { - return mInverted; - } - - void SetInverted(bool aInverted) { - mInverted = aInverted; - } - - bool IsVisible() { - return mVisible; - } - - void SetVisible(bool aVisible); - -private: - bool mInverted; - bool mVisible; - - class SurfaceData { - public: - SurfaceData() : - surface(NULL), window(NULL) { - } - - SurfaceData(jobject aSurface, void* aWindow) : - surface(aSurface), window(aWindow) { - } - - jobject surface; - void* window; - gfxRect dimensions; - }; - - bool EnsureContentSurface(); - - SurfaceData mContentData; - std::map mVideoSurfaces; -}; - -} /* mozilla */ -#endif /* AndroidMediaLayer_h_ */ diff --git a/widget/android/Makefile.in b/widget/android/Makefile.in index c793d63cc265..ede308b63a79 100644 --- a/widget/android/Makefile.in +++ b/widget/android/Makefile.in @@ -32,7 +32,6 @@ CPPSRCS = \ AndroidLayerViewWrapper.cpp \ AndroidGraphicBuffer.cpp \ AndroidJNI.cpp \ - AndroidMediaLayer.cpp \ nsWindow.cpp \ nsLookAndFeel.cpp \ nsScreenManagerAndroid.cpp \ @@ -74,6 +73,7 @@ LOCAL_INCLUDES += \ -I$(topsrcdir)/docshell/base \ -I$(topsrcdir)/content/events/src \ -I$(topsrcdir)/netwerk/cache \ + -I$(topsrcdir)/widget/android/android \ -I$(srcdir) \ $(NULL) diff --git a/widget/android/android/StrongPointer.h b/widget/android/android/StrongPointer.h new file mode 100644 index 000000000000..ca79fdfa4d9a --- /dev/null +++ b/widget/android/android/StrongPointer.h @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/************************************************************************* + * + * WARNING: EVERYTHING HERE IS NEUTERED + * + * The only reason we need this is to be able to call + * android_SurfaceTexture_getNativeWindow, which returns a + * android::sp. Therefore, we need the definition of + * android::sp (below) in order to get the pointer out. All of the actual + * ref management stuff is commented out by Mozilla. Do not try to use this + * for anything real. + */ + +#ifndef ANDROID_STRONG_POINTER_H +#define ANDROID_STRONG_POINTER_H + +#include +#include +#include + +// --------------------------------------------------------------------------- +namespace android { + +class TextOutput; +TextOutput& printStrongPointer(TextOutput& to, const void* val); + +template class wp; + +// --------------------------------------------------------------------------- + +#define COMPARE(_op_) \ +inline bool operator _op_ (const sp& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} \ +inline bool operator _op_ (const T* o) const { \ + return m_ptr _op_ o; \ +} \ +template \ +inline bool operator _op_ (const sp& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} \ +template \ +inline bool operator _op_ (const U* o) const { \ + return m_ptr _op_ o; \ +} \ +inline bool operator _op_ (const wp& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} \ +template \ +inline bool operator _op_ (const wp& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} + +// --------------------------------------------------------------------------- + +template +class sp +{ +public: + inline sp() : m_ptr(0) { } + + sp(T* other); + sp(const sp& other); + template sp(U* other); + template sp(const sp& other); + + ~sp(); + + // Assignment + + sp& operator = (T* other); + sp& operator = (const sp& other); + + template sp& operator = (const sp& other); + template sp& operator = (U* other); + + //! Special optimization for use by ProcessState (and nobody else). + void force_set(T* other); + + // Reset + + void clear(); + + // Accessors + + inline T& operator* () const { return *m_ptr; } + inline T* operator-> () const { return m_ptr; } + inline T* get() const { return m_ptr; } + + // Operators + + COMPARE(==) + COMPARE(!=) + COMPARE(>) + COMPARE(<) + COMPARE(<=) + COMPARE(>=) + +private: + template friend class sp; + template friend class wp; + void set_pointer(T* ptr); + T* m_ptr; +}; + +#undef COMPARE + +template +TextOutput& operator<<(TextOutput& to, const sp& val); + +// --------------------------------------------------------------------------- +// No user serviceable parts below here. + +template +sp::sp(T* other) +: m_ptr(other) + { + //if (other) other->incStrong(this); + } + +template +sp::sp(const sp& other) +: m_ptr(other.m_ptr) + { + //if (m_ptr) m_ptr->incStrong(this); + } + +template template +sp::sp(U* other) : m_ptr(other) +{ + //if (other) ((T*)other)->incStrong(this); +} + +template template +sp::sp(const sp& other) +: m_ptr(other.m_ptr) + { + //if (m_ptr) m_ptr->incStrong(this); + } + +template +sp::~sp() +{ + //if (m_ptr) m_ptr->decStrong(this); +} + +template +sp& sp::operator = (const sp& other) { + T* otherPtr(other.m_ptr); + /* + if (otherPtr) otherPtr->incStrong(this); + if (m_ptr) m_ptr->decStrong(this); + */ + m_ptr = otherPtr; + return *this; +} + +template +sp& sp::operator = (T* other) +{ + /* + if (other) other->incStrong(this); + if (m_ptr) m_ptr->decStrong(this); + */ + m_ptr = other; + return *this; +} + +template template +sp& sp::operator = (const sp& other) +{ + T* otherPtr(other.m_ptr); + /* + if (otherPtr) otherPtr->incStrong(this); + if (m_ptr) m_ptr->decStrong(this); + */ + m_ptr = otherPtr; + return *this; +} + +template template +sp& sp::operator = (U* other) +{ + /* + if (other) ((T*)other)->incStrong(this); + if (m_ptr) m_ptr->decStrong(this); + */ + m_ptr = other; + return *this; +} + +template +void sp::force_set(T* other) +{ + //other->forceIncStrong(this); + m_ptr = other; +} + +template +void sp::clear() +{ + if (m_ptr) { + m_ptr->decStrong(this); + m_ptr = 0; + } +} + +template +void sp::set_pointer(T* ptr) { + m_ptr = ptr; +} + +template +inline TextOutput& operator<<(TextOutput& to, const sp& val) +{ + return printStrongPointer(to, val.get()); +} + +}; // namespace android + +// --------------------------------------------------------------------------- + +#endif // ANDROID_STRONG_POINTER_H