Bug 1100126 - Don't allow detaching a SurfaceTexture on PowerVR devices due to fencing issues. r=jgilbert, a=sledru
authorJames Willcox <snorp@snorp.net>
Mon, 02 Feb 2015 15:25:22 -0600
changeset 249688 4d763d0c00378d512dfd2023c5320829dc95f162
parent 249687 511fb27a5333c5e2a6e1052c197ab4091c92926e
child 249689 2acd2127a0c0a195e2ddc6ed09f1f262188b1e52
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert, sledru
bugs1100126
milestone37.0a2
Bug 1100126 - Don't allow detaching a SurfaceTexture on PowerVR devices due to fencing issues. r=jgilbert, a=sledru
gfx/gl/AndroidSurfaceTexture.cpp
gfx/gl/AndroidSurfaceTexture.h
gfx/gl/GLBlitHelper.cpp
--- a/gfx/gl/AndroidSurfaceTexture.cpp
+++ b/gfx/gl/AndroidSurfaceTexture.cpp
@@ -26,22 +26,16 @@ using namespace mozilla::widget::sdk;
 namespace mozilla {
 namespace gl {
 
 // UGH
 static std::map<int, AndroidSurfaceTexture*> sInstances;
 static int sNextID = 0;
 
 static bool
-IsDetachSupported()
-{
-  return AndroidBridge::Bridge()->GetAPIVersion() >= 16; /* Jelly Bean */
-}
-
-static bool
 IsSTSupported()
 {
   return AndroidBridge::Bridge()->GetAPIVersion() >= 14; /* ICS */
 }
 
 TemporaryRef<AndroidSurfaceTexture>
 AndroidSurfaceTexture::Create()
 {
@@ -82,60 +76,75 @@ AndroidSurfaceTexture::Attach(GLContext*
 {
   MonitorAutoLock lock(mMonitor);
 
   if (mAttachedContext == aContext) {
     NS_WARNING("Tried to attach same GLContext to AndroidSurfaceTexture");
     return NS_OK;
   }
 
-  if (!IsDetachSupported()) {
+  if (!CanDetach()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   while (mAttachedContext) {
     // Wait until it's detached (or we time out)
     if (NS_FAILED(lock.Wait(aTimeout))) {
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
   MOZ_ASSERT(aContext->IsOwningThreadCurrent(), "Trying to attach GLContext from different thread");
 
   mAttachedContext = aContext;
   mAttachedContext->MakeCurrent();
   aContext->fGenTextures(1, &mTexture);
 
+  UpdateCanDetach();
+
   return mSurfaceTexture->AttachToGLContext(mTexture);
 }
 
 nsresult
 AndroidSurfaceTexture::Detach()
 {
   MonitorAutoLock lock(mMonitor);
 
-  if (!IsDetachSupported() ||
-      !mAttachedContext || !mAttachedContext->IsOwningThreadCurrent()) {
+  if (!CanDetach() ||
+      !mAttachedContext ||
+      !mAttachedContext->IsOwningThreadCurrent())
+  {
     return NS_ERROR_FAILURE;
   }
 
   mAttachedContext->MakeCurrent();
 
   mSurfaceTexture->DetachFromGLContext();
 
   mTexture = 0;
   mAttachedContext = nullptr;
   lock.NotifyAll();
   return NS_OK;
 }
 
+void
+AndroidSurfaceTexture::UpdateCanDetach()
+{
+  // The API for attach/detach only exists on 16+, and PowerVR has some sort of
+  // fencing issue.
+  mCanDetach = AndroidBridge::Bridge()->GetAPIVersion() >= 16 &&
+    (!mAttachedContext || mAttachedContext->Vendor() != GLVendor::Imagination);
+}
+
 bool
 AndroidSurfaceTexture::Init(GLContext* aContext, GLuint aTexture)
 {
-  if (!aTexture && !IsDetachSupported()) {
+  UpdateCanDetach();
+
+  if (!aTexture && !CanDetach()) {
     // We have no texture and cannot initialize detached, bail out
     return false;
   }
 
   if (NS_WARN_IF(NS_FAILED(
       SurfaceTexture::New(aTexture, ReturnTo(&mSurfaceTexture))))) {
     return false;
   }
@@ -162,16 +171,17 @@ AndroidSurfaceTexture::Init(GLContext* a
 }
 
 AndroidSurfaceTexture::AndroidSurfaceTexture()
   : mTexture(0)
   , mSurfaceTexture()
   , mSurface()
   , mMonitor("AndroidSurfaceTexture::mContextMonitor")
   , mAttachedContext(nullptr)
+  , mCanDetach(false)
 {
 }
 
 AndroidSurfaceTexture::~AndroidSurfaceTexture()
 {
   sInstances.erase(mID);
 
   mFrameAvailableCallback = nullptr;
--- a/gfx/gl/AndroidSurfaceTexture.h
+++ b/gfx/gl/AndroidSurfaceTexture.h
@@ -56,19 +56,22 @@ public:
   // If we are on Jelly Bean, the SurfaceTexture can be detached and reattached
   // to allow consumption from different GLContexts. It is recommended to only
   // attach while you are consuming in order to allow this.
   //
   // Only one GLContext may be attached at any given time. If another is already
   // attached, we try to wait for it to become detached.
   nsresult Attach(GLContext* aContext, PRIntervalTime aTiemout = PR_INTERVAL_NO_TIMEOUT);
 
-  // This is a noop on ICS, and will always fail
   nsresult Detach();
 
+  // Ability to detach is based on API version (16+), and we also block PowerVR since it has some type
+  // of fencing problem. Bug 1100126.
+  bool CanDetach() { return mCanDetach; }
+
   GLContext* GetAttachedContext() { return mAttachedContext; }
 
   AndroidNativeWindow* NativeWindow() {
     return mNativeWindow;
   }
 
   // This attaches the updated data to the TEXTURE_EXTERNAL target
   void UpdateTexImage();
@@ -89,23 +92,25 @@ public:
   GLuint Texture() { return mTexture; }
   const widget::sdk::Surface::Ref& JavaSurface() { return mSurface; }
 
 private:
   AndroidSurfaceTexture();
   ~AndroidSurfaceTexture();
 
   bool Init(GLContext* aContext, GLuint aTexture);
+  void UpdateCanDetach();
 
   GLuint mTexture;
   widget::sdk::SurfaceTexture::GlobalRef mSurfaceTexture;
   widget::sdk::Surface::GlobalRef mSurface;
 
   Monitor mMonitor;
   GLContext* mAttachedContext;
+  bool mCanDetach;
 
   RefPtr<AndroidNativeWindow> mNativeWindow;
   int mID;
   nsRefPtr<nsIRunnable> mFrameAvailableCallback;
 };
 
 }
 }
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -718,24 +718,26 @@ GLBlitHelper::BlitGrallocImage(layers::G
     sEGLLibrary.fDestroyImage(sEGLLibrary.Display(), image);
     mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, oldBinding);
     return true;
 }
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
 
+#define ATTACH_WAIT_MS 50
+
 bool
 GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage, bool yflip)
 {
     AndroidSurfaceTexture* surfaceTexture = stImage->GetData()->mSurfTex;
 
     ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
 
-    if (NS_FAILED(surfaceTexture->Attach(mGL)))
+    if (NS_FAILED(surfaceTexture->Attach(mGL, PR_MillisecondsToInterval(ATTACH_WAIT_MS))))
         return false;
 
     // UpdateTexImage() changes the EXTERNAL binding, so save it here
     // so we can restore it after.
     int oldBinding = 0;
     mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &oldBinding);
 
     surfaceTexture->UpdateTexImage();