Bug 591687: Add new image type for IOSurfaces on Mac OS X. r=roc r=benwa a=blocking2.0betaN+
authorMatt Woodrow <mwoodrow@mozilla.com>
Sat, 12 Feb 2011 11:02:08 -0500
changeset 62472 3fb968523cbd2607862d4eb1a0c4edbc519d16a4
parent 62471 280500da6255330fa72f968947c506286015c6ef
child 62473 b0c3b563b2fa0afef993fa4c1fa3c5ae16aee1f8
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersroc, benwa, blocking2
bugs591687
milestone2.0b12pre
Bug 591687: Add new image type for IOSurfaces on Mac OS X. r=roc r=benwa a=blocking2.0betaN+
gfx/layers/ImageLayers.h
gfx/layers/Makefile.in
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.h
gfx/layers/opengl/MacIOSurfaceImageOGL.h
gfx/layers/opengl/MacIOSurfaceImageOGL.mm
gfx/thebes/nsCoreAnimationSupport.h
gfx/thebes/nsCoreAnimationSupport.mm
--- a/gfx/layers/ImageLayers.h
+++ b/gfx/layers/ImageLayers.h
@@ -37,16 +37,17 @@
 
 #ifndef GFX_IMAGELAYER_H
 #define GFX_IMAGELAYER_H
 
 #include "Layers.h"
 
 #include "gfxPattern.h"
 #include "nsThreadUtils.h"
+#include "nsCoreAnimationSupport.h"
 
 namespace mozilla {
 namespace layers {
 
 enum StereoMode {
   STEREO_MODE_MONO,
   STEREO_MODE_LEFT_RIGHT,
   STEREO_MODE_RIGHT_LEFT,
@@ -90,17 +91,25 @@ public:
      * It makes it easy to render a cairo surface when another Image format
      * could be used. It can also avoid copying the surface data in some
      * cases.
      * 
      * Images in CAIRO_SURFACE format should only be created and
      * manipulated on the main thread, since the underlying cairo surface
      * is main-thread-only.
      */
-    CAIRO_SURFACE
+    CAIRO_SURFACE,
+
+    /**
+     * The MAC_IO_SURFACE format creates a MacIOSurfaceImage. This
+     * is only supported on Mac with OpenGL layers.
+     *
+     * It wraps an IOSurface object and binds it directly to a GL texture.
+     */
+    MAC_IO_SURFACE
   };
 
   Format GetFormat() { return mFormat; }
   void* GetImplData() { return mImplData; }
 
 protected:
   Image(void* aImplData, Format aFormat) :
     mImplData(aImplData),
@@ -333,12 +342,31 @@ public:
    * The surface must not be modified after this call!!!
    */
   virtual void SetData(const Data& aData) = 0;
 
 protected:
   CairoImage(void* aImplData) : Image(aImplData, CAIRO_SURFACE) {}
 };
 
+#ifdef XP_MACOSX
+class THEBES_API MacIOSurfaceImage : public Image {
+public:
+  struct Data {
+    nsIOSurface* mIOSurface;
+  };
+
+ /**
+  * This can only be called on the main thread. It may add a reference
+  * to the surface (which will eventually be released on the main thread).
+  * The surface must not be modified after this call!!!
+  */
+  virtual void SetData(const Data& aData) = 0;
+
+protected:
+  MacIOSurfaceImage(void* aImplData) : Image(aImplData, MAC_IO_SURFACE) {}
+};
+#endif
+
 }
 }
 
 #endif /* GFX_IMAGELAYER_H */
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -78,16 +78,22 @@ CPPSRCS = \
         CanvasLayerOGL.cpp \
         ColorLayerOGL.cpp \
         ContainerLayerOGL.cpp \
         ImageLayerOGL.cpp \
         LayerManagerOGL.cpp \
         ThebesLayerOGL.cpp \
         $(NULL)
 
+ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
+CMMSRCS = \
+        MacIOSurfaceImageOGL.mm \
+        $(NULL)
+endif
+
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 ifdef MOZ_ENABLE_D3D9_LAYER
 EXPORTS += \
         LayerManagerD3D9.h \
         DeviceManagerD3D9.h \
         $(NULL)
 
 CPPSRCS += \
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -39,16 +39,17 @@
 #ifdef MOZ_IPC
 # include "gfxSharedImageSurface.h"
 #endif
 
 #include "ImageLayerOGL.h"
 #include "gfxImageSurface.h"
 #include "yuv_convert.h"
 #include "GLContextProvider.h"
+#include "MacIOSurfaceImageOGL.h"
 
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 using mozilla::MutexAutoLock;
 
@@ -213,16 +214,22 @@ ImageContainerOGL::CreateImage(const Ima
   }
   nsRefPtr<Image> img;
   if (aFormats[0] == Image::PLANAR_YCBCR) {
     img = new PlanarYCbCrImageOGL(static_cast<LayerManagerOGL*>(mManager),
                                   mRecycleBin);
   } else if (aFormats[0] == Image::CAIRO_SURFACE) {
     img = new CairoImageOGL(static_cast<LayerManagerOGL*>(mManager));
   }
+#ifdef XP_MACOSX
+  else if (aFormats[0] == Image::MAC_IO_SURFACE) {
+    img = new MacIOSurfaceImageOGL(static_cast<LayerManagerOGL*>(mManager));
+  }
+#endif
+
   return img.forget();
 }
 
 void
 ImageContainerOGL::SetCurrentImage(Image *aImage)
 {
   nsRefPtr<Image> oldImage;
 
@@ -314,25 +321,32 @@ ImageContainerOGL::GetCurrentSize()
 
   if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
     PlanarYCbCrImageOGL *yuvImage =
       static_cast<PlanarYCbCrImageOGL*>(mActiveImage.get());
     if (!yuvImage->HasData()) {
       return gfxIntSize(0,0);
     }
     return yuvImage->mSize;
-
   }
 
   if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
     CairoImageOGL *cairoImage =
       static_cast<CairoImageOGL*>(mActiveImage.get());
     return cairoImage->mSize;
   }
 
+#ifdef XP_MACOSX
+  if (mActiveImage->GetFormat() == Image::MAC_IO_SURFACE) {
+    MacIOSurfaceImageOGL *ioImage =
+      static_cast<MacIOSurfaceImageOGL*>(mActiveImage.get());
+      return ioImage->mSize;
+  }
+#endif
+
   return gfxIntSize(0,0);
 }
 
 PRBool
 ImageContainerOGL::SetLayerManager(LayerManager *aManager)
 {
   if (!aManager) {
     // the layer manager just entirely went away
@@ -442,16 +456,47 @@ ImageLayerOGL::RenderLayer(int,
                                         cairoImage->mSize.width,
                                         cairoImage->mSize.height));
     program->SetLayerTransform(GetEffectiveTransform());
     program->SetLayerOpacity(GetEffectiveOpacity());
     program->SetRenderOffset(aOffset);
     program->SetTextureUnit(0);
 
     mOGLManager->BindAndDrawQuad(program);
+#ifdef XP_MACOSX
+  } else if (image->GetFormat() == Image::MAC_IO_SURFACE) {
+     MacIOSurfaceImageOGL *ioImage =
+       static_cast<MacIOSurfaceImageOGL*>(image.get());
+
+     gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, ioImage->mTexture.GetTextureID());
+
+     ColorTextureLayerProgram *program = 
+       mOGLManager->GetRGBARectLayerProgram();
+     
+     program->Activate();
+     if (program->GetTexCoordMultiplierUniformLocation() != -1) {
+       // 2DRect case, get the multiplier right for a sampler2DRect
+       float f[] = { float(ioImage->mSize.width), float(ioImage->mSize.height) };
+       program->SetUniform(program->GetTexCoordMultiplierUniformLocation(),
+                           2, f);
+     } else {
+       NS_ASSERTION(0, "no rects?");
+     }
+     
+     program->SetLayerQuadRect(nsIntRect(0, 0, 
+                                         ioImage->mSize.width, 
+                                         ioImage->mSize.height));
+     program->SetLayerTransform(GetEffectiveTransform());
+     program->SetLayerOpacity(GetEffectiveOpacity());
+     program->SetRenderOffset(aOffset);
+     program->SetTextureUnit(0);
+    
+     mOGLManager->BindAndDrawQuad(program);
+     gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
+#endif
   }
 
   DEBUG_GL_ERROR_CHECK(gl());
 }
 
 static void
 InitTexture(GLContext* aGL, GLuint aTexture, GLenum aFormat, const gfxIntSize& aSize)
 {
@@ -698,17 +743,16 @@ CairoImageOGL::SetData(const CairoImage:
     return;
 
   mLayerProgram =
     gl->UploadSurfaceToTexture(aData.mSurface,
                                nsIntRect(0,0, mSize.width, mSize.height),
                                tex);
 }
 
-
 #ifdef MOZ_IPC
 
 ShadowImageLayerOGL::ShadowImageLayerOGL(LayerManagerOGL* aManager)
   : ShadowImageLayer(aManager, nsnull)
   , LayerOGL(aManager)
 {
   mImplData = static_cast<LayerOGL*>(this);
 }  
--- a/gfx/layers/opengl/ImageLayerOGL.h
+++ b/gfx/layers/opengl/ImageLayerOGL.h
@@ -235,17 +235,16 @@ public:
   void SetData(const Data &aData);
 
   GLTexture mTexture;
   gfxIntSize mSize;
   nsRefPtr<GLContext> mASurfaceAsGLContext;
   gl::ShaderProgramType mLayerProgram;
 };
 
-
 #ifdef MOZ_IPC
 class ShadowImageLayerOGL : public ShadowImageLayer,
                             public LayerOGL
 {
   typedef gl::TextureImage TextureImage;
 
 public:
   ShadowImageLayerOGL(LayerManagerOGL* aManager);
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/MacIOSurfaceImageOGL.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@mozilla.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef GFX_MACIOSURFACEIMAGEOGL_H
+#define GFX_MACIOSURFACEIMAGEOGL_H
+#ifdef XP_MACOSX
+
+#include "nsCoreAnimationSupport.h"
+
+namespace mozilla {
+namespace layers {
+
+class THEBES_API MacIOSurfaceImageOGL : public MacIOSurfaceImage
+{
+  typedef mozilla::gl::GLContext GLContext;
+
+public:
+  MacIOSurfaceImageOGL(LayerManagerOGL *aManager);
+
+  void SetData(const Data &aData);
+
+  GLTexture mTexture;
+  gfxIntSize mSize;
+  nsAutoPtr<nsIOSurface> mIOSurface;
+};
+
+} /* layers */
+} /* mozilla */
+#endif /* XP_MACOSX */
+#endif /* GFX_MACIOSURFACEIMAGEOGL_H */
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/MacIOSurfaceImageOGL.mm
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Matt Woodrow <mwoodrow@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ImageLayerOGL.h"
+#include "MacIOSurfaceImageOGL.h"
+#include <AppKit/NSOpenGL.h>
+#include "OpenGL/OpenGL.h"
+
+using namespace mozilla::gl;
+
+namespace mozilla {
+namespace layers {
+
+MacIOSurfaceImageOGL::MacIOSurfaceImageOGL(LayerManagerOGL *aManager)
+  : MacIOSurfaceImage(nsnull), mSize(0, 0)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread to create a cairo image");
+
+  if (aManager) {
+    // Allocate texture now to grab a reference to the GLContext
+    GLContext *gl = aManager->glForResources();
+    mTexture.Allocate(gl);
+    gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture.GetTextureID());
+    gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 
+                       LOCAL_GL_TEXTURE_MIN_FILTER, 
+                       LOCAL_GL_NEAREST);
+    gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 
+                       LOCAL_GL_TEXTURE_MAG_FILTER, 
+                       LOCAL_GL_NEAREST);
+    gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
+  }
+}
+
+void
+MacIOSurfaceImageOGL::SetData(const MacIOSurfaceImage::Data &aData)
+{
+  mIOSurface = nsIOSurface::LookupSurface(aData.mIOSurface->GetIOSurfaceID());
+  mSize = gfxIntSize(mIOSurface->GetWidth(), mIOSurface->GetHeight());
+  
+  GLContext *gl = mTexture.GetGLContext();
+  gl->MakeCurrent();
+    
+  gl->fActiveTexture(LOCAL_GL_TEXTURE0);
+  gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture.GetTextureID());
+
+  void *nativeCtx = gl->GetNativeData(GLContext::NativeGLContext);
+  NSOpenGLContext* nsCtx = (NSOpenGLContext*)nativeCtx;
+
+  mIOSurface->CGLTexImageIOSurface2D((CGLContextObj)[nsCtx CGLContextObj],
+                                     LOCAL_GL_RGBA, LOCAL_GL_BGRA,
+                                     LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, 0);
+
+  gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
+}
+
+} /* layers */
+} /* mozilla */
\ No newline at end of file
--- a/gfx/thebes/nsCoreAnimationSupport.h
+++ b/gfx/thebes/nsCoreAnimationSupport.h
@@ -39,16 +39,17 @@
 
 #ifndef nsCoreAnimationSupport_h__
 #define nsCoreAnimationSupport_h__
 #ifdef XP_MACOSX
 
 #import "ApplicationServices/ApplicationServices.h"
 #include "nscore.h"
 #include "gfxTypes.h"
+#import <QuartzCore/QuartzCore.h>
 
 // Get the system color space.
 CGColorSpaceRef THEBES_API CreateSystemColorSpace();
 
 // Manages a CARenderer
 struct _CGLPBufferObject;
 struct _CGLContextObject;
 class nsIOSurface;
@@ -98,16 +99,19 @@ public:
   ~nsIOSurface() { CFRelease(mIOSurfacePtr); }
   IOSurfaceID GetIOSurfaceID();
   void *GetBaseAddress();
   size_t GetWidth();
   size_t GetHeight();
   size_t GetBytesPerRow();
   void Lock();
   void Unlock();
+  CGLError CGLTexImageIOSurface2D(CGLContextObj ctxt,
+                                  GLenum internalFormat, GLenum format, 
+                                  GLenum type, GLuint plane);
 private:
   friend class nsCARenderer;
   CFTypeRef mIOSurfacePtr;
 };
 
 #endif // XP_MACOSX
 #endif // nsCoreAnimationSupport_h__
 
--- a/gfx/thebes/nsCoreAnimationSupport.mm
+++ b/gfx/thebes/nsCoreAnimationSupport.mm
@@ -318,17 +318,17 @@ nsIOSurface* nsIOSurface::LookupSurface(
     return nsnull;
   // IOSurfaceLookup does not retain the object for us,
   // we want IOSurfacePtr to remain for the lifetime of
   // nsIOSurface.
   CFRetain(surfaceRef);
 
   nsIOSurface* ioSurface = new nsIOSurface(surfaceRef);
   if (!ioSurface) {
-    ::CFRelease(ioSurface);
+    ::CFRelease(surfaceRef);
     return nsnull;
   }
   return ioSurface;
 }
 
 IOSurfaceID nsIOSurface::GetIOSurfaceID() { 
   return nsIOSurfaceLib::IOSurfaceGetID(mIOSurfacePtr);
 }
@@ -353,16 +353,29 @@ size_t nsIOSurface::GetBytesPerRow() {
 void nsIOSurface::Lock() {
   nsIOSurfaceLib::IOSurfaceLock(mIOSurfacePtr, READ_ONLY, NULL);
 }
 
 void nsIOSurface::Unlock() {
   nsIOSurfaceLib::IOSurfaceUnlock(mIOSurfacePtr, READ_ONLY, NULL);
 }
 
+CGLError 
+nsIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctxt,
+                                    GLenum internalFormat, GLenum format, 
+                                    GLenum type, GLuint plane)
+{
+  return nsIOSurfaceLib::CGLTexImageIOSurface2D(ctxt,
+                                                GL_TEXTURE_RECTANGLE_ARB, 
+                                                internalFormat,
+                                                GetWidth(), GetHeight(),
+                                                format, type,
+                                                mIOSurfacePtr, plane);
+}
+
 nsCARenderer::~nsCARenderer() {
   Destroy();
 }
 
 CGColorSpaceRef CreateSystemColorSpace() {
     CMProfileRef system_profile = nsnull;
     CGColorSpaceRef cspace = nsnull;