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 idunknown
push userunknown
push dateunknown
reviewersroc, benwa, blocking2.0betaN
bugs591687
milestone2.0b12pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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;