summaryrefslogtreecommitdiff
path: root/gfx/gl
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/gl')
-rw-r--r--gfx/gl/ForceDiscreteGPUHelperCGL.h36
-rw-r--r--gfx/gl/GLBlitHelper.cpp111
-rw-r--r--gfx/gl/GLBlitHelper.h3
-rw-r--r--gfx/gl/GLContext.cpp78
-rw-r--r--gfx/gl/GLContextCGL.h67
-rw-r--r--gfx/gl/GLContextEAGL.h80
-rw-r--r--gfx/gl/GLContextProvider.h7
-rw-r--r--gfx/gl/GLContextProviderCGL.mm397
-rw-r--r--gfx/gl/GLContextProviderEAGL.mm275
-rwxr-xr-xgfx/gl/GLScreenBuffer.cpp8
-rw-r--r--gfx/gl/SharedSurfaceIO.cpp248
-rw-r--r--gfx/gl/SharedSurfaceIO.h100
-rw-r--r--gfx/gl/moz.build32
13 files changed, 1440 insertions, 2 deletions
diff --git a/gfx/gl/ForceDiscreteGPUHelperCGL.h b/gfx/gl/ForceDiscreteGPUHelperCGL.h
new file mode 100644
index 0000000000..3b4cb07efa
--- /dev/null
+++ b/gfx/gl/ForceDiscreteGPUHelperCGL.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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 ForceDiscreteGPUHelperCGL_h_
+#define ForceDiscreteGPUHelperCGL_h_
+
+#include <OpenGL/OpenGL.h>
+
+/** This RAII helper guarantees that we're on the discrete GPU during its lifetime.
+ *
+ * As long as any ForceDiscreteGPUHelperCGL object is alive, we're on the discrete GPU.
+ */
+class ForceDiscreteGPUHelperCGL
+{
+ CGLPixelFormatObj mPixelFormatObj;
+
+public:
+ ForceDiscreteGPUHelperCGL()
+ {
+ // the code in this function is taken from Chromium, src/ui/gfx/gl/gl_context_cgl.cc, r122013
+ // BSD-style license, (c) The Chromium Authors
+ CGLPixelFormatAttribute attribs[1];
+ attribs[0] = static_cast<CGLPixelFormatAttribute>(0);
+ GLint num_pixel_formats = 0;
+ CGLChoosePixelFormat(attribs, &mPixelFormatObj, &num_pixel_formats);
+ }
+
+ ~ForceDiscreteGPUHelperCGL()
+ {
+ CGLReleasePixelFormat(mPixelFormatObj);
+ }
+};
+
+#endif // ForceDiscreteGPUHelperCGL_h_
diff --git a/gfx/gl/GLBlitHelper.cpp b/gfx/gl/GLBlitHelper.cpp
index 12e30c8804..da7f5b462d 100644
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -14,6 +14,11 @@
#include "mozilla/gfx/Matrix.h"
#include "mozilla/UniquePtr.h"
+#ifdef XP_MACOSX
+#include "MacIOSurfaceImage.h"
+#include "GLContextCGL.h"
+#endif
+
using mozilla::layers::PlanarYCbCrImage;
using mozilla::layers::PlanarYCbCrData;
@@ -181,6 +186,34 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
} \n\
";
+#ifdef XP_MACOSX
+ const char kTexNV12PlanarBlit_FragShaderSource[] = "\
+ #version 100 \n\
+ #extension GL_ARB_texture_rectangle : require \n\
+ #ifdef GL_ES \n\
+ precision mediump float \n\
+ #endif \n\
+ varying vec2 vTexCoord; \n\
+ uniform sampler2DRect uYTexture; \n\
+ uniform sampler2DRect uCbCrTexture; \n\
+ uniform vec2 uYTexScale; \n\
+ uniform vec2 uCbCrTexScale; \n\
+ void main() \n\
+ { \n\
+ float y = texture2DRect(uYTexture, vTexCoord * uYTexScale).r; \n\
+ float cb = texture2DRect(uCbCrTexture, vTexCoord * uCbCrTexScale).r; \n\
+ float cr = texture2DRect(uCbCrTexture, vTexCoord * uCbCrTexScale).a; \n\
+ y = (y - 0.06275) * 1.16438; \n\
+ cb = cb - 0.50196; \n\
+ cr = cr - 0.50196; \n\
+ gl_FragColor.r = y + cr * 1.59603; \n\
+ gl_FragColor.g = y - 0.81297 * cr - 0.39176 * cb; \n\
+ gl_FragColor.b = y + cb * 2.01723; \n\
+ gl_FragColor.a = 1.0; \n\
+ } \n\
+ ";
+#endif
+
bool success = false;
GLuint* programPtr;
@@ -203,6 +236,13 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
fragShaderPtr = &mTexYUVPlanarBlit_FragShader;
fragShaderSource = kTexYUVPlanarBlit_FragShaderSource;
break;
+#ifdef XP_MACOSX
+ case ConvertMacIOSurfaceImage:
+ programPtr = &mTexNV12PlanarBlit_Program;
+ fragShaderPtr = &mTexNV12PlanarBlit_FragShader;
+ fragShaderSource = kTexNV12PlanarBlit_FragShaderSource;
+ break;
+#endif
default:
return false;
}
@@ -353,6 +393,24 @@ GLBlitHelper::InitTexQuadProgram(BlitType target)
mGL->fUniform1i(texCr, Channel_Cr);
break;
}
+ case ConvertMacIOSurfaceImage: {
+#ifdef XP_MACOSX
+ GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
+ GLint texCbCr = mGL->fGetUniformLocation(program, "uCbCrTexture");
+ mYTexScaleLoc = mGL->fGetUniformLocation(program, "uYTexScale");
+ mCbCrTexScaleLoc= mGL->fGetUniformLocation(program, "uCbCrTexScale");
+
+ DebugOnly<bool> hasUniformLocations = texY != -1 &&
+ texCbCr != -1 &&
+ mYTexScaleLoc != -1 &&
+ mCbCrTexScaleLoc != -1;
+ MOZ_ASSERT(hasUniformLocations, "uniforms not found");
+
+ mGL->fUniform1i(texY, Channel_Y);
+ mGL->fUniform1i(texCbCr, Channel_Cb);
+#endif
+ break;
+ }
default:
return false;
}
@@ -620,6 +678,47 @@ GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage)
return true;
}
+#ifdef XP_MACOSX
+bool
+GLBlitHelper::BlitMacIOSurfaceImage(layers::MacIOSurfaceImage* ioImage)
+{
+ ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
+ MacIOSurface* surf = ioImage->GetSurface();
+
+ GLint oldTex[2];
+ for (int i = 0; i < 2; i++) {
+ mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+ mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex[i]);
+ }
+
+ GLuint textures[2];
+ mGL->fGenTextures(2, textures);
+
+ mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[0]);
+ mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+ mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+ surf->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(mGL)->GetCGLContext(), 0);
+ mGL->fUniform2f(mYTexScaleLoc, surf->GetWidth(0), surf->GetHeight(0));
+
+ mGL->fActiveTexture(LOCAL_GL_TEXTURE1);
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[1]);
+ mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+ mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+ surf->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(mGL)->GetCGLContext(), 1);
+ mGL->fUniform2f(mCbCrTexScaleLoc, surf->GetWidth(1), surf->GetHeight(1));
+
+ mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+ for (int i = 0; i < 2; i++) {
+ mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
+ mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
+ }
+
+ mGL->fDeleteTextures(2, textures);
+ return true;
+}
+#endif
+
bool
GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
const gfx::IntSize& destSize,
@@ -637,6 +736,13 @@ GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
srcOrigin = OriginPos::BottomLeft;
break;
+#ifdef XP_MACOSX
+ case ImageFormat::MAC_IOSURFACE:
+ type = ConvertMacIOSurfaceImage;
+ srcOrigin = OriginPos::TopLeft;
+ break;
+#endif
+
default:
return false;
}
@@ -662,6 +768,11 @@ GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
return ret;
}
+#ifdef XP_MACOSX
+ case ConvertMacIOSurfaceImage:
+ return BlitMacIOSurfaceImage(srcImage->AsMacIOSurfaceImage());
+#endif
+
default:
return false;
}
diff --git a/gfx/gl/GLBlitHelper.h b/gfx/gl/GLBlitHelper.h
index 9dd8cd8870..c2858f5913 100644
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -107,6 +107,9 @@ class GLBlitHelper final
void BindAndUploadEGLImage(EGLImage image, GLuint target);
bool BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage);
+#ifdef XP_MACOSX
+ bool BlitMacIOSurfaceImage(layers::MacIOSurfaceImage* ioImage);
+#endif
explicit GLBlitHelper(GLContext* gl);
diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp
index 0106f4fd09..72a7bea58b 100644
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -36,6 +36,10 @@
#include "mozilla/DebugOnly.h"
+#ifdef XP_MACOSX
+#include <CoreServices/CoreServices.h>
+#endif
+
#if defined(MOZ_WIDGET_COCOA)
#include "nsCocoaFeatures.h"
#endif
@@ -873,6 +877,18 @@ GLContext::InitWithPrefixImpl(const char* prefix, bool trygl)
// multisampling hardcodes blending with the default blendfunc, which breaks WebGL.
MarkUnsupported(GLFeature::framebuffer_multisample);
}
+
+#ifdef XP_MACOSX
+ // The Mac Nvidia driver, for versions up to and including 10.8,
+ // don't seem to properly support this. See 814839
+ // this has been fixed in Mac OS X 10.9. See 907946
+ // and it also works in 10.8.3 and higher. See 1094338.
+ if (Vendor() == gl::GLVendor::NVIDIA &&
+ !nsCocoaFeatures::IsAtLeastVersion(10,8,3))
+ {
+ MarkUnsupported(GLFeature::depth_texture);
+ }
+#endif
}
if (IsExtensionSupported(GLContext::ARB_pixel_buffer_object)) {
@@ -993,6 +1009,25 @@ GLContext::InitWithPrefixImpl(const char* prefix, bool trygl)
raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
raw_fGetIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
+#ifdef XP_MACOSX
+ if (mWorkAroundDriverBugs) {
+ if (mVendor == GLVendor::Intel) {
+ // see bug 737182 for 2D textures, bug 684882 for cube map textures.
+ mMaxTextureSize = std::min(mMaxTextureSize, 4096);
+ mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 512);
+ // for good measure, we align renderbuffers on what we do for 2D textures
+ mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096);
+ mNeedsTextureSizeChecks = true;
+ } else if (mVendor == GLVendor::NVIDIA) {
+ // See bug 879656. 8192 fails, 8191 works.
+ mMaxTextureSize = std::min(mMaxTextureSize, 8191);
+ mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 8191);
+
+ // Part of the bug 879656, but it also doesn't hurt the 877949
+ mNeedsTextureSizeChecks = true;
+ }
+ }
+#endif
#ifdef MOZ_X11
if (mWorkAroundDriverBugs) {
if (mVendor == GLVendor::Nouveau) {
@@ -1765,6 +1800,20 @@ GLContext::InitExtensions()
MarkExtensionUnsupported(ANGLE_texture_compression_dxt3);
MarkExtensionUnsupported(ANGLE_texture_compression_dxt5);
}
+
+#ifdef XP_MACOSX
+ // Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD
+ // 3000 appears to be buggy WRT updating sub-images of S3TC
+ // textures with glCompressedTexSubImage2D. Works on Intel HD 4000
+ // and Intel HD 5000/Iris that I tested.
+ // Bug 1124996: Appears to be the same on OSX Yosemite (10.10)
+ if (nsCocoaFeatures::macOSVersionMajor() == 10 &&
+ nsCocoaFeatures::macOSVersionMinor() >= 9 &&
+ Renderer() == GLRenderer::IntelHD3000)
+ {
+ MarkExtensionUnsupported(EXT_texture_compression_s3tc);
+ }
+#endif
}
if (shouldDumpExts) {
@@ -2779,6 +2828,35 @@ GLContext::fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum f
}
AfterGLReadCall();
+
+ // Check if GL is giving back 1.0 alpha for
+ // RGBA reads to RGBA images from no-alpha buffers.
+#ifdef XP_MACOSX
+ if (WorkAroundDriverBugs() &&
+ Vendor() == gl::GLVendor::NVIDIA &&
+ format == LOCAL_GL_RGBA &&
+ type == LOCAL_GL_UNSIGNED_BYTE &&
+ !IsCoreProfile() &&
+ width && height)
+ {
+ GLint alphaBits = 0;
+ fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits);
+ if (!alphaBits) {
+ const uint32_t alphaMask = 0xff000000;
+
+ uint32_t* itr = (uint32_t*)pixels;
+ uint32_t testPixel = *itr;
+ if ((testPixel & alphaMask) != alphaMask) {
+ // We need to set the alpha channel to 1.0 manually.
+ uint32_t* itrEnd = itr + width*height; // Stride is guaranteed to be width*4.
+
+ for (; itr != itrEnd; itr++) {
+ *itr |= alphaMask;
+ }
+ }
+ }
+ }
+#endif
}
void
diff --git a/gfx/gl/GLContextCGL.h b/gfx/gl/GLContextCGL.h
new file mode 100644
index 0000000000..29d5d982d7
--- /dev/null
+++ b/gfx/gl/GLContextCGL.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 GLCONTEXTCGL_H_
+#define GLCONTEXTCGL_H_
+
+#include "GLContext.h"
+
+#include "OpenGL/OpenGL.h"
+
+#ifdef __OBJC__
+#include <AppKit/NSOpenGL.h>
+#else
+typedef void NSOpenGLContext;
+#endif
+
+namespace mozilla {
+namespace gl {
+
+class GLContextCGL : public GLContext
+{
+ friend class GLContextProviderCGL;
+
+ NSOpenGLContext* const mContext;
+
+public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL, override)
+ GLContextCGL(CreateContextFlags flags, const SurfaceCaps& caps,
+ NSOpenGLContext* context, bool isOffscreen, ContextProfile profile);
+
+ ~GLContextCGL();
+
+ virtual GLContextType GetContextType() const override { return GLContextType::CGL; }
+
+ static GLContextCGL* Cast(GLContext* gl) {
+ MOZ_ASSERT(gl->GetContextType() == GLContextType::CGL);
+ return static_cast<GLContextCGL*>(gl);
+ }
+
+ bool Init() override;
+
+ NSOpenGLContext* GetNSOpenGLContext() const { return mContext; }
+ CGLContextObj GetCGLContext() const;
+
+ virtual bool MakeCurrentImpl(bool aForce) override;
+
+ virtual bool IsCurrent() override;
+
+ virtual GLenum GetPreferredARGB32Format() const override;
+
+ virtual bool SetupLookupFunction() override;
+
+ virtual bool IsDoubleBuffered() const override;
+
+ virtual bool SupportsRobustness() const override { return false; }
+
+ virtual bool SwapBuffers() override;
+
+ virtual void GetWSIInfo(nsCString* const out) const override;
+};
+
+} // namespace gl
+} // namespace mozilla
+
+#endif // GLCONTEXTCGL_H_
diff --git a/gfx/gl/GLContextEAGL.h b/gfx/gl/GLContextEAGL.h
new file mode 100644
index 0000000000..f677d23d57
--- /dev/null
+++ b/gfx/gl/GLContextEAGL.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 GLCONTEXTEAGL_H_
+#define GLCONTEXTEAGL_H_
+
+#include "GLContext.h"
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <OpenGLES/EAGL.h>
+
+namespace mozilla {
+namespace gl {
+
+class GLContextEAGL : public GLContext
+{
+ friend class GLContextProviderEAGL;
+
+ EAGLContext* const mContext;
+
+public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEAGL, override)
+ GLContextEAGL(CreateContextFlags flags, const SurfaceCaps& caps, EAGLContext* context,
+ GLContext* sharedContext, bool isOffscreen, ContextProfile profile);
+
+ ~GLContextEAGL();
+
+ virtual GLContextType GetContextType() const override {
+ return GLContextType::EAGL;
+ }
+
+ static GLContextEAGL* Cast(GLContext* gl) {
+ MOZ_ASSERT(gl->GetContextType() == GLContextType::EAGL);
+ return static_cast<GLContextEAGL*>(gl);
+ }
+
+ bool Init() override;
+
+ bool AttachToWindow(nsIWidget* aWidget);
+
+ EAGLContext* GetEAGLContext() const { return mContext; }
+
+ virtual bool MakeCurrentImpl(bool aForce) override;
+
+ virtual bool IsCurrent() override;
+
+ virtual bool SetupLookupFunction() override;
+
+ virtual bool IsDoubleBuffered() const override;
+
+ virtual bool SupportsRobustness() const override { return false; }
+
+ virtual bool SwapBuffers() override;
+
+ virtual void GetWSIInfo(nsCString* const out) const override;
+
+ virtual GLuint GetDefaultFramebuffer() override {
+ return mBackbufferFB;
+ }
+
+ virtual bool RenewSurface(nsIWidget* aWidget) override {
+ // FIXME: should use the passed widget instead of the existing one.
+ return RecreateRB();
+ }
+
+private:
+ GLuint mBackbufferRB;
+ GLuint mBackbufferFB;
+
+ void* mLayer;
+
+ bool RecreateRB();
+};
+
+} // namespace gl
+} // namespace mozilla
+
+#endif // GLCONTEXTEAGL_H_
diff --git a/gfx/gl/GLContextProvider.h b/gfx/gl/GLContextProvider.h
index d9b3f04196..6e096c1f7e 100644
--- a/gfx/gl/GLContextProvider.h
+++ b/gfx/gl/GLContextProvider.h
@@ -34,6 +34,13 @@ namespace gl {
#define DEFAULT_IMPL WGL
#endif
+#ifdef XP_MACOSX
+ #define GL_CONTEXT_PROVIDER_NAME GLContextProviderCGL
+ #include "GLContextProviderImpl.h"
+ #undef GL_CONTEXT_PROVIDER_NAME
+ #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL
+#endif
+
#if defined(MOZ_X11)
#define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX
#include "GLContextProviderImpl.h"
diff --git a/gfx/gl/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm
new file mode 100644
index 0000000000..7cc89eac9f
--- /dev/null
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -0,0 +1,397 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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 "GLContextProvider.h"
+#include "GLContextCGL.h"
+#include "nsDebug.h"
+#include "nsIWidget.h"
+#include <OpenGL/gl.h>
+#include "gfxFailure.h"
+#include "gfxPrefs.h"
+#include "prenv.h"
+#include "GeckoProfiler.h"
+#include "mozilla/gfx/MacIOSurface.h"
+#include "mozilla/widget/CompositorWidget.h"
+
+#include <OpenGL/OpenGL.h>
+
+// When running inside a VM, creating an accelerated OpenGL context usually
+// fails. Uncomment this line to emulate that behavior.
+// #define EMULATE_VM
+
+namespace mozilla {
+namespace gl {
+
+using namespace mozilla::gfx;
+using namespace mozilla::widget;
+
+class CGLLibrary
+{
+public:
+ CGLLibrary()
+ : mInitialized(false)
+ , mUseDoubleBufferedWindows(true)
+ , mOGLLibrary(nullptr)
+ {}
+
+ bool EnsureInitialized()
+ {
+ if (mInitialized) {
+ return true;
+ }
+ if (!mOGLLibrary) {
+ mOGLLibrary = PR_LoadLibrary("/System/Library/Frameworks/OpenGL.framework/OpenGL");
+ if (!mOGLLibrary) {
+ NS_WARNING("Couldn't load OpenGL Framework.");
+ return false;
+ }
+ }
+
+ const char* db = PR_GetEnv("MOZ_CGL_DB");
+ if (db) {
+ mUseDoubleBufferedWindows = *db != '0';
+ }
+
+ mInitialized = true;
+ return true;
+ }
+
+ bool UseDoubleBufferedWindows() const {
+ MOZ_ASSERT(mInitialized);
+ return mUseDoubleBufferedWindows;
+ }
+
+private:
+ bool mInitialized;
+ bool mUseDoubleBufferedWindows;
+ PRLibrary* mOGLLibrary;
+};
+
+CGLLibrary sCGLLibrary;
+
+GLContextCGL::GLContextCGL(CreateContextFlags flags, const SurfaceCaps& caps,
+ NSOpenGLContext* context, bool isOffscreen,
+ ContextProfile profile)
+ : GLContext(flags, caps, nullptr, isOffscreen)
+ , mContext(context)
+{
+ SetProfileVersion(profile, 210);
+}
+
+GLContextCGL::~GLContextCGL()
+{
+ MarkDestroyed();
+ [mContext release];
+}
+
+bool
+GLContextCGL::Init()
+{
+ return InitWithPrefix("gl", true);
+}
+
+CGLContextObj
+GLContextCGL::GetCGLContext() const
+{
+ return static_cast<CGLContextObj>([mContext CGLContextObj]);
+}
+
+bool
+GLContextCGL::MakeCurrentImpl(bool aForce)
+{
+ if (IsDestroyed()) {
+ [NSOpenGLContext clearCurrentContext];
+ return false;
+ }
+
+ if (!aForce && [NSOpenGLContext currentContext] == mContext) {
+ return true;
+ }
+
+ if (mContext) {
+ [mContext makeCurrentContext];
+ MOZ_ASSERT(IsCurrent());
+ // Use non-blocking swap in "ASAP mode".
+ // ASAP mode means that rendering is iterated as fast as possible.
+ // ASAP mode is entered when layout.frame_rate=0 (requires restart).
+ // If swapInt is 1, then glSwapBuffers will block and wait for a vblank signal.
+ // When we're iterating as fast as possible, however, we want a non-blocking
+ // glSwapBuffers, which will happen when swapInt==0.
+ GLint swapInt = gfxPrefs::LayoutFrameRate() == 0 ? 0 : 1;
+ [mContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
+ }
+ return true;
+}
+
+bool
+GLContextCGL::IsCurrent() {
+ return [NSOpenGLContext currentContext] == mContext;
+}
+
+GLenum
+GLContextCGL::GetPreferredARGB32Format() const
+{
+ return LOCAL_GL_BGRA;
+}
+
+bool
+GLContextCGL::SetupLookupFunction()
+{
+ return false;
+}
+
+bool
+GLContextCGL::IsDoubleBuffered() const
+{
+ return sCGLLibrary.UseDoubleBufferedWindows();
+}
+
+bool
+GLContextCGL::SwapBuffers()
+{
+ PROFILER_LABEL("GLContextCGL", "SwapBuffers",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ [mContext flushBuffer];
+ return true;
+}
+
+void
+GLContextCGL::GetWSIInfo(nsCString* const out) const
+{
+ out->AppendLiteral("CGL");
+}
+
+already_AddRefed<GLContext>
+GLContextProviderCGL::CreateWrappingExisting(void*, void*)
+{
+ return nullptr;
+}
+
+static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered[] = {
+ NSOpenGLPFAAllowOfflineRenderers,
+ 0
+};
+
+static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered_accel[] = {
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFAAllowOfflineRenderers,
+ 0
+};
+
+static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered[] = {
+ NSOpenGLPFAAllowOfflineRenderers,
+ NSOpenGLPFADoubleBuffer,
+ 0
+};
+
+static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered_accel[] = {
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFAAllowOfflineRenderers,
+ NSOpenGLPFADoubleBuffer,
+ 0
+};
+
+static const NSOpenGLPixelFormatAttribute kAttribs_offscreen[] = {
+ 0
+};
+
+static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_allow_offline[] = {
+ NSOpenGLPFAAllowOfflineRenderers,
+ 0
+};
+
+static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_accel[] = {
+ NSOpenGLPFAAccelerated,
+ 0
+};
+
+static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_coreProfile[] = {
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
+ 0
+};
+
+static NSOpenGLContext*
+CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs)
+{
+ NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc]
+ initWithAttributes:attribs];
+ if (!format) {
+ NS_WARNING("Failed to create NSOpenGLPixelFormat.");
+ return nullptr;
+ }
+
+ NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format
+ shareContext:nullptr];
+
+ [format release];
+
+ return context;
+}
+
+already_AddRefed<GLContext>
+GLContextProviderCGL::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
+{
+ return CreateForWindow(aCompositorWidget->RealWidget(), aForceAccelerated);
+}
+
+already_AddRefed<GLContext>
+GLContextProviderCGL::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
+{
+ if (!sCGLLibrary.EnsureInitialized()) {
+ return nullptr;
+ }
+
+#ifdef EMULATE_VM
+ if (aForceAccelerated) {
+ return nullptr;
+ }
+#endif
+
+ const NSOpenGLPixelFormatAttribute* attribs;
+ if (sCGLLibrary.UseDoubleBufferedWindows()) {
+ attribs = aForceAccelerated ? kAttribs_doubleBuffered_accel : kAttribs_doubleBuffered;
+ } else {
+ attribs = aForceAccelerated ? kAttribs_singleBuffered_accel : kAttribs_singleBuffered;
+ }
+ NSOpenGLContext* context = CreateWithFormat(attribs);
+ if (!context) {
+ return nullptr;
+ }
+
+ // make the context transparent
+ GLint opaque = 0;
+ [context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
+
+ SurfaceCaps caps = SurfaceCaps::ForRGBA();
+ ContextProfile profile = ContextProfile::OpenGLCompatibility;
+ RefPtr<GLContextCGL> glContext = new GLContextCGL(CreateContextFlags::NONE, caps,
+ context, false, profile);
+
+ if (!glContext->Init()) {
+ glContext = nullptr;
+ [context release];
+ return nullptr;
+ }
+
+ return glContext.forget();
+}
+
+static already_AddRefed<GLContextCGL>
+CreateOffscreenFBOContext(CreateContextFlags flags)
+{
+ if (!sCGLLibrary.EnsureInitialized()) {
+ return nullptr;
+ }
+
+ ContextProfile profile;
+ NSOpenGLContext* context = nullptr;
+
+ if (!(flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE)) {
+ profile = ContextProfile::OpenGLCore;
+ context = CreateWithFormat(kAttribs_offscreen_coreProfile);
+ }
+ if (!context) {
+ profile = ContextProfile::OpenGLCompatibility;
+
+ if (flags & CreateContextFlags::ALLOW_OFFLINE_RENDERER) {
+ if (gfxPrefs::RequireHardwareGL())
+ context = CreateWithFormat(kAttribs_singleBuffered);
+ else
+ context = CreateWithFormat(kAttribs_offscreen_allow_offline);
+
+ } else {
+ if (gfxPrefs::RequireHardwareGL())
+ context = CreateWithFormat(kAttribs_offscreen_accel);
+ else
+ context = CreateWithFormat(kAttribs_offscreen);
+ }
+ }
+ if (!context) {
+ NS_WARNING("Failed to create NSOpenGLContext.");
+ return nullptr;
+ }
+
+ SurfaceCaps dummyCaps = SurfaceCaps::Any();
+ RefPtr<GLContextCGL> glContext = new GLContextCGL(flags, dummyCaps, context, true,
+ profile);
+
+ if (gfxPrefs::GLMultithreaded()) {
+ CGLEnable(glContext->GetCGLContext(), kCGLCEMPEngine);
+ }
+ return glContext.forget();
+}
+
+already_AddRefed<GLContext>
+GLContextProviderCGL::CreateHeadless(CreateContextFlags flags,
+ nsACString* const out_failureId)
+{
+ RefPtr<GLContextCGL> gl;
+ gl = CreateOffscreenFBOContext(flags);
+ if (!gl) {
+ *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_CGL_FBO");
+ return nullptr;
+ }
+
+ if (!gl->Init()) {
+ *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_CGL_INIT");
+ NS_WARNING("Failed during Init.");
+ return nullptr;
+ }
+
+ return gl.forget();
+}
+
+already_AddRefed<GLContext>
+GLContextProviderCGL::CreateOffscreen(const IntSize& size,
+ const SurfaceCaps& minCaps,
+ CreateContextFlags flags,
+ nsACString* const out_failureId)
+{
+ RefPtr<GLContext> gl = CreateHeadless(flags, out_failureId);
+ if (!gl) {
+ return nullptr;
+ }
+
+ if (!gl->InitOffscreen(size, minCaps)) {
+ *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_CGL_INIT");
+ return nullptr;
+ }
+
+ return gl.forget();
+}
+
+static RefPtr<GLContext> gGlobalContext;
+
+GLContext*
+GLContextProviderCGL::GetGlobalContext()
+{
+ static bool triedToCreateContext = false;
+ if (!triedToCreateContext) {
+ triedToCreateContext = true;
+
+ MOZ_RELEASE_ASSERT(!gGlobalContext);
+ nsCString discardFailureId;
+ RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE,
+ &discardFailureId);
+ gGlobalContext = temp;
+
+ if (!gGlobalContext) {
+ NS_WARNING("Couldn't init gGlobalContext.");
+ }
+ }
+
+ return gGlobalContext;
+}
+
+void
+GLContextProviderCGL::Shutdown()
+{
+ gGlobalContext = nullptr;
+}
+
+} /* namespace gl */
+} /* namespace mozilla */
diff --git a/gfx/gl/GLContextProviderEAGL.mm b/gfx/gl/GLContextProviderEAGL.mm
new file mode 100644
index 0000000000..11c7cce776
--- /dev/null
+++ b/gfx/gl/GLContextProviderEAGL.mm
@@ -0,0 +1,275 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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 "GLContextProvider.h"
+#include "GLContextEAGL.h"
+#include "nsDebug.h"
+#include "nsIWidget.h"
+#include "gfxPrefs.h"
+#include "gfxFailure.h"
+#include "prenv.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/widget/CompositorWidget.h"
+#include "GeckoProfiler.h"
+
+#import <UIKit/UIKit.h>
+
+namespace mozilla {
+namespace gl {
+
+using namespace mozilla::widget;
+
+GLContextEAGL::GLContextEAGL(CreateContextFlags flags, const SurfaceCaps& caps,
+ EAGLContext* context, GLContext* sharedContext,
+ bool isOffscreen, ContextProfile profile)
+ : GLContext(flags, caps, sharedContext, isOffscreen)
+ , mContext(context)
+ , mBackbufferRB(0)
+ , mBackbufferFB(0)
+ , mLayer(nil)
+{
+ SetProfileVersion(ContextProfile::OpenGLES,
+ [context API] == kEAGLRenderingAPIOpenGLES3 ? 300 : 200);
+}
+
+GLContextEAGL::~GLContextEAGL()
+{
+ if (MakeCurrent()) {
+ if (mBackbufferFB) {
+ fDeleteFramebuffers(1, &mBackbufferFB);
+ }
+ if (mBackbufferRB) {
+ fDeleteRenderbuffers(1, &mBackbufferRB);
+ }
+ }
+
+ mLayer = nil;
+ MarkDestroyed();
+ [mContext release];
+}
+
+bool
+GLContextEAGL::Init()
+{
+ return InitWithPrefix("gl", true);
+}
+
+bool
+GLContextEAGL::AttachToWindow(nsIWidget* aWidget)
+{
+ // This should only be called once
+ MOZ_ASSERT(!mBackbufferFB && !mBackbufferRB);
+
+ UIView* view =
+ reinterpret_cast<UIView*>(aWidget->GetNativeData(NS_NATIVE_WIDGET));
+
+ if (!view) {
+ MOZ_CRASH("no view!");
+ }
+
+ mLayer = [view layer];
+
+ fGenFramebuffers(1, &mBackbufferFB);
+ return RecreateRB();
+}
+
+bool
+GLContextEAGL::RecreateRB()
+{
+ MakeCurrent();
+
+ CAEAGLLayer* layer = (CAEAGLLayer*)mLayer;
+
+ if (mBackbufferRB) {
+ // It doesn't seem to be enough to just call renderbufferStorage: below,
+ // we apparently have to recreate the RB.
+ fDeleteRenderbuffers(1, &mBackbufferRB);
+ mBackbufferRB = 0;
+ }
+
+ fGenRenderbuffers(1, &mBackbufferRB);
+ fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mBackbufferRB);
+
+ [mContext renderbufferStorage:LOCAL_GL_RENDERBUFFER
+ fromDrawable:layer];
+
+ fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackbufferFB);
+ fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
+ LOCAL_GL_RENDERBUFFER, mBackbufferRB);
+
+ return LOCAL_GL_FRAMEBUFFER_COMPLETE == fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+}
+
+bool
+GLContextEAGL::MakeCurrentImpl(bool aForce)
+{
+ if (!aForce && [EAGLContext currentContext] == mContext) {
+ return true;
+ }
+
+ if (IsDestroyed()) {
+ [EAGLContext setCurrentContext:nil];
+ return false;
+ }
+
+ return [EAGLContext setCurrentContext:mContext];
+}
+
+bool
+GLContextEAGL::IsCurrent() {
+ return [EAGLContext currentContext] == mContext;
+}
+
+bool
+GLContextEAGL::SetupLookupFunction()
+{
+ return false;
+}
+
+bool
+GLContextEAGL::IsDoubleBuffered() const
+{
+ return true;
+}
+
+bool
+GLContextEAGL::SwapBuffers()
+{
+ PROFILER_LABEL("GLContextEAGL", "SwapBuffers",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ [mContext presentRenderbuffer:LOCAL_GL_RENDERBUFFER];
+ return true;
+}
+
+void
+GLContextEAGL::GetWSIInfo(nsCString* const out) const
+{
+ out->AppendLiteral("EAGL");
+}
+
+already_AddRefed<GLContext>
+GLContextProviderEAGL::CreateWrappingExisting(void*, void*)
+{
+ return nullptr;
+}
+
+static GLContextEAGL*
+GetGlobalContextEAGL()
+{
+ return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext());
+}
+
+static already_AddRefed<GLContext>
+CreateEAGLContext(CreateContextFlags flags, bool aOffscreen, GLContextEAGL* sharedContext)
+{
+ EAGLRenderingAPI apis[] = { kEAGLRenderingAPIOpenGLES3, kEAGLRenderingAPIOpenGLES2 };
+
+ // Try to create a GLES3 context if we can, otherwise fall back to GLES2
+ EAGLContext* context = nullptr;
+ for (EAGLRenderingAPI api : apis) {
+ if (sharedContext) {
+ context = [[EAGLContext alloc] initWithAPI:api
+ sharegroup:sharedContext->GetEAGLContext().sharegroup];
+ } else {
+ context = [[EAGLContext alloc] initWithAPI:api];
+ }
+
+ if (context) {
+ break;
+ }
+ }
+
+ if (!context) {
+ return nullptr;
+ }
+
+ SurfaceCaps caps = SurfaceCaps::ForRGBA();
+ ContextProfile profile = ContextProfile::OpenGLES;
+ RefPtr<GLContextEAGL> glContext = new GLContextEAGL(flags, caps, context,
+ sharedContext,
+ aOffscreen,
+ profile);
+
+ if (!glContext->Init()) {
+ glContext = nullptr;
+ return nullptr;
+ }
+
+ return glContext.forget();
+}
+
+already_AddRefed<GLContext>
+GLContextProviderEAGL::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
+{
+ return CreateForWindow(aCompositorWidget->RealWidget(), aForceAccelerated);
+}
+
+already_AddRefed<GLContext>
+GLContextProviderEAGL::CreateForWindow(nsIWidget* aWidget, bool aForceAccelerated)
+{
+ RefPtr<GLContext> glContext = CreateEAGLContext(CreateContextFlags::NONE, false,
+ GetGlobalContextEAGL());
+ if (!glContext) {
+ return nullptr;
+ }
+
+ if (!GLContextEAGL::Cast(glContext)->AttachToWindow(aWidget)) {
+ return nullptr;
+ }
+
+ return glContext.forget();
+}
+
+already_AddRefed<GLContext>
+GLContextProviderEAGL::CreateHeadless(CreateContextFlags flags,
+ nsACString* const out_failureId)
+{
+ return CreateEAGLContext(flags, true, GetGlobalContextEAGL());
+}
+
+already_AddRefed<GLContext>
+GLContextProviderEAGL::CreateOffscreen(const mozilla::gfx::IntSize& size,
+ const SurfaceCaps& caps,
+ CreateContextFlags flags,
+ nsACString* const out_failureId)
+{
+ RefPtr<GLContext> glContext = CreateHeadless(flags, out_failureId);
+ if (!glContext->InitOffscreen(size, caps)) {
+ return nullptr;
+ }
+
+ return glContext.forget();
+}
+
+static RefPtr<GLContext> gGlobalContext;
+
+GLContext*
+GLContextProviderEAGL::GetGlobalContext()
+{
+ static bool triedToCreateContext = false;
+ if (!triedToCreateContext) {
+ triedToCreateContext = true;
+
+ MOZ_RELEASE_ASSERT(!gGlobalContext, "GFX: Global GL context already initialized.");
+ RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE);
+ gGlobalContext = temp;
+
+ if (!gGlobalContext) {
+ MOZ_CRASH("Failed to create global context");
+ }
+ }
+
+ return gGlobalContext;
+}
+
+void
+GLContextProviderEAGL::Shutdown()
+{
+ gGlobalContext = nullptr;
+}
+
+} /* namespace gl */
+} /* namespace mozilla */
diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp
index 0ac0322be4..5d95eb9285 100755
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -24,6 +24,10 @@
#include "mozilla/gfx/DeviceManagerDx.h"
#endif
+#ifdef XP_MACOSX
+#include "SharedSurfaceIO.h"
+#endif
+
#ifdef GL_PROVIDER_GLX
#include "GLXLibrary.h"
#include "SharedSurfaceGLX.h"
@@ -80,7 +84,9 @@ GLScreenBuffer::CreateFactory(GLContext* gl,
if (!gfxPrefs::WebGLForceLayersReadback()) {
switch (backend) {
case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
-#if defined(GL_PROVIDER_GLX)
+#if defined(XP_MACOSX)
+ factory = SurfaceFactory_IOSurface::Create(gl, caps, ipcChannel, flags);
+#elif defined(GL_PROVIDER_GLX)
if (sGLXLibrary.UseTextureFromPixmap())
factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
#elif defined(MOZ_WIDGET_UIKIT)
diff --git a/gfx/gl/SharedSurfaceIO.cpp b/gfx/gl/SharedSurfaceIO.cpp
new file mode 100644
index 0000000000..50262d6cce
--- /dev/null
+++ b/gfx/gl/SharedSurfaceIO.cpp
@@ -0,0 +1,248 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* 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 "SharedSurfaceIO.h"
+
+#include "GLContextCGL.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/gfx/MacIOSurface.h"
+#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
+#include "ScopedGLHelpers.h"
+
+namespace mozilla {
+namespace gl {
+
+/*static*/ UniquePtr<SharedSurface_IOSurface>
+SharedSurface_IOSurface::Create(const RefPtr<MacIOSurface>& ioSurf,
+ GLContext* gl,
+ bool hasAlpha)
+{
+ MOZ_ASSERT(ioSurf);
+ MOZ_ASSERT(gl);
+
+ auto size = gfx::IntSize::Truncate(ioSurf->GetWidth(), ioSurf->GetHeight());
+
+ typedef SharedSurface_IOSurface ptrT;
+ UniquePtr<ptrT> ret( new ptrT(ioSurf, gl, size, hasAlpha) );
+ return Move(ret);
+}
+
+void
+SharedSurface_IOSurface::ProducerReleaseImpl()
+{
+ mGL->MakeCurrent();
+ mGL->fFlush();
+}
+
+bool
+SharedSurface_IOSurface::CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border)
+{
+ /* Bug 896693 - OpenGL framebuffers that are backed by IOSurface on OSX expose a bug
+ * in glCopyTexImage2D --- internalformats GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA
+ * return the wrong results. To work around, copy framebuffer to a temporary texture
+ * using GL_RGBA (which works), attach as read framebuffer and glCopyTexImage2D
+ * instead.
+ */
+
+ // https://www.opengl.org/sdk/docs/man3/xhtml/glCopyTexImage2D.xml says that width or
+ // height set to 0 results in a NULL texture. Lets not do any work and punt to
+ // original glCopyTexImage2D, since the FBO below will fail when trying to attach a
+ // texture of 0 width or height.
+ if (width == 0 || height == 0)
+ return false;
+
+ switch (internalformat) {
+ case LOCAL_GL_ALPHA:
+ case LOCAL_GL_LUMINANCE:
+ case LOCAL_GL_LUMINANCE_ALPHA:
+ break;
+
+ default:
+ return false;
+ }
+
+ MOZ_ASSERT(mGL->IsCurrent());
+
+ ScopedTexture destTex(mGL);
+ {
+ ScopedBindTexture bindTex(mGL, destTex.Texture());
+ mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER,
+ LOCAL_GL_NEAREST);
+ mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER,
+ LOCAL_GL_NEAREST);
+ mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S,
+ LOCAL_GL_CLAMP_TO_EDGE);
+ mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T,
+ LOCAL_GL_CLAMP_TO_EDGE);
+ mGL->raw_fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, x, y, width,
+ height, 0);
+ }
+
+ ScopedFramebufferForTexture tmpFB(mGL, destTex.Texture(), LOCAL_GL_TEXTURE_2D);
+ ScopedBindFramebuffer bindFB(mGL, tmpFB.FB());
+ mGL->raw_fCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+
+ return true;
+}
+
+bool
+SharedSurface_IOSurface::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid* pixels)
+{
+ // Calling glReadPixels when an IOSurface is bound to the current framebuffer
+ // can cause corruption in following glReadPixel calls (even if they aren't
+ // reading from an IOSurface).
+ // We workaround this by copying to a temporary texture, and doing the readback
+ // from that.
+ MOZ_ASSERT(mGL->IsCurrent());
+
+ ScopedTexture destTex(mGL);
+ {
+ ScopedFramebufferForTexture srcFB(mGL, ProdTexture(), ProdTextureTarget());
+
+ ScopedBindFramebuffer bindFB(mGL, srcFB.FB());
+ ScopedBindTexture bindTex(mGL, destTex.Texture());
+ mGL->raw_fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0,
+ mHasAlpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB,
+ x, y,
+ width, height, 0);
+ }
+
+ ScopedFramebufferForTexture destFB(mGL, destTex.Texture());
+
+ ScopedBindFramebuffer bindFB(mGL, destFB.FB());
+ mGL->raw_fReadPixels(0, 0, width, height, format, type, pixels);
+ return true;
+}
+
+static void
+BackTextureWithIOSurf(GLContext* gl, GLuint tex, MacIOSurface* ioSurf)
+{
+ MOZ_ASSERT(gl->IsCurrent());
+
+ ScopedBindTexture texture(gl, tex, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
+
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ LOCAL_GL_TEXTURE_MIN_FILTER,
+ LOCAL_GL_LINEAR);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ LOCAL_GL_TEXTURE_MAG_FILTER,
+ LOCAL_GL_LINEAR);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ LOCAL_GL_TEXTURE_WRAP_S,
+ LOCAL_GL_CLAMP_TO_EDGE);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ LOCAL_GL_TEXTURE_WRAP_T,
+ LOCAL_GL_CLAMP_TO_EDGE);
+
+ CGLContextObj cgl = GLContextCGL::Cast(gl)->GetCGLContext();
+ MOZ_ASSERT(cgl);
+
+ ioSurf->CGLTexImageIOSurface2D(cgl);
+}
+
+SharedSurface_IOSurface::SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
+ GLContext* gl,
+ const gfx::IntSize& size,
+ bool hasAlpha)
+ : SharedSurface(SharedSurfaceType::IOSurface,
+ AttachmentType::GLTexture,
+ gl,
+ size,
+ hasAlpha,
+ true)
+ , mIOSurf(ioSurf)
+{
+ gl->MakeCurrent();
+ mProdTex = 0;
+ gl->fGenTextures(1, &mProdTex);
+ BackTextureWithIOSurf(gl, mProdTex, mIOSurf);
+}
+
+SharedSurface_IOSurface::~SharedSurface_IOSurface()
+{
+ if (!mGL || !mGL->MakeCurrent())
+ return;
+
+ mGL->fDeleteTextures(1, &mProdTex);
+}
+
+bool
+SharedSurface_IOSurface::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
+{
+ bool isOpaque = !mHasAlpha;
+ *out_descriptor = layers::SurfaceDescriptorMacIOSurface(mIOSurf->GetIOSurfaceID(),
+ mIOSurf->GetContentsScaleFactor(),
+ isOpaque);
+ return true;
+}
+
+bool
+SharedSurface_IOSurface::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
+{
+ MOZ_ASSERT(out_surface);
+ mIOSurf->Lock();
+ size_t bytesPerRow = mIOSurf->GetBytesPerRow();
+ size_t ioWidth = mIOSurf->GetDevicePixelWidth();
+ size_t ioHeight = mIOSurf->GetDevicePixelHeight();
+
+ const unsigned char* ioData = (unsigned char*)mIOSurf->GetBaseAddress();
+ gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE);
+ if (!map.IsMapped()) {
+ mIOSurf->Unlock();
+ return false;
+ }
+
+ for (size_t i = 0; i < ioHeight; i++) {
+ memcpy(map.GetData() + i * map.GetStride(),
+ ioData + i * bytesPerRow, ioWidth * 4);
+ }
+
+ mIOSurf->Unlock();
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////
+// SurfaceFactory_IOSurface
+
+/*static*/ UniquePtr<SurfaceFactory_IOSurface>
+SurfaceFactory_IOSurface::Create(GLContext* gl, const SurfaceCaps& caps,
+ const RefPtr<layers::LayersIPCChannel>& allocator,
+ const layers::TextureFlags& flags)
+{
+ auto maxDims = gfx::IntSize::Truncate(MacIOSurface::GetMaxWidth(),
+ MacIOSurface::GetMaxHeight());
+
+ typedef SurfaceFactory_IOSurface ptrT;
+ UniquePtr<ptrT> ret( new ptrT(gl, caps, allocator, flags, maxDims) );
+ return Move(ret);
+}
+
+UniquePtr<SharedSurface>
+SurfaceFactory_IOSurface::CreateShared(const gfx::IntSize& size)
+{
+ if (size.width > mMaxDims.width ||
+ size.height > mMaxDims.height)
+ {
+ return nullptr;
+ }
+
+ bool hasAlpha = mReadCaps.alpha;
+ RefPtr<MacIOSurface> ioSurf;
+ ioSurf = MacIOSurface::CreateIOSurface(size.width, size.height, 1.0,
+ hasAlpha);
+
+ if (!ioSurf) {
+ NS_WARNING("Failed to create MacIOSurface.");
+ return nullptr;
+ }
+
+ return SharedSurface_IOSurface::Create(ioSurf, mGL, hasAlpha);
+}
+
+} // namespace gl
+} // namespace mozilla
diff --git a/gfx/gl/SharedSurfaceIO.h b/gfx/gl/SharedSurfaceIO.h
new file mode 100644
index 0000000000..16e0cbbb7f
--- /dev/null
+++ b/gfx/gl/SharedSurfaceIO.h
@@ -0,0 +1,100 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* 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 SHARED_SURFACEIO_H_
+#define SHARED_SURFACEIO_H_
+
+#include "mozilla/RefPtr.h"
+#include "SharedSurface.h"
+
+class MacIOSurface;
+
+namespace mozilla {
+namespace gl {
+
+class SharedSurface_IOSurface : public SharedSurface
+{
+private:
+ const RefPtr<MacIOSurface> mIOSurf;
+ GLuint mProdTex;
+
+public:
+ static UniquePtr<SharedSurface_IOSurface> Create(const RefPtr<MacIOSurface>& ioSurf,
+ GLContext* gl,
+ bool hasAlpha);
+
+private:
+ SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
+ GLContext* gl, const gfx::IntSize& size,
+ bool hasAlpha);
+
+public:
+ ~SharedSurface_IOSurface();
+
+ virtual void LockProdImpl() override { }
+ virtual void UnlockProdImpl() override { }
+
+ virtual void ProducerAcquireImpl() override {}
+ virtual void ProducerReleaseImpl() override;
+
+ virtual bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border) override;
+ virtual bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid* pixels) override;
+
+ virtual GLuint ProdTexture() override {
+ return mProdTex;
+ }
+
+ virtual GLenum ProdTextureTarget() const override {
+ return LOCAL_GL_TEXTURE_RECTANGLE_ARB;
+ }
+
+ static SharedSurface_IOSurface* Cast(SharedSurface* surf) {
+ MOZ_ASSERT(surf->mType == SharedSurfaceType::IOSurface);
+ return static_cast<SharedSurface_IOSurface*>(surf);
+ }
+
+ MacIOSurface* GetIOSurface() const {
+ return mIOSurf;
+ }
+
+ virtual bool NeedsIndirectReads() const override {
+ return true;
+ }
+
+ virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
+
+ virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
+};
+
+class SurfaceFactory_IOSurface : public SurfaceFactory
+{
+public:
+ // Infallible.
+ static UniquePtr<SurfaceFactory_IOSurface> Create(GLContext* gl,
+ const SurfaceCaps& caps,
+ const RefPtr<layers::LayersIPCChannel>& allocator,
+ const layers::TextureFlags& flags);
+protected:
+ const gfx::IntSize mMaxDims;
+
+ SurfaceFactory_IOSurface(GLContext* gl, const SurfaceCaps& caps,
+ const RefPtr<layers::LayersIPCChannel>& allocator,
+ const layers::TextureFlags& flags,
+ const gfx::IntSize& maxDims)
+ : SurfaceFactory(SharedSurfaceType::IOSurface, gl, caps, allocator, flags)
+ , mMaxDims(maxDims)
+ { }
+
+ virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override;
+};
+
+} // namespace gl
+
+} /* namespace mozilla */
+
+#endif /* SHARED_SURFACEIO_H_ */
diff --git a/gfx/gl/moz.build b/gfx/gl/moz.build
index 7bf5a4ab04..c490400cbf 100644
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -7,6 +7,10 @@ gl_provider = 'Null'
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
gl_provider = 'WGL'
+elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+ gl_provider = 'CGL'
+elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit':
+ gl_provider = 'EAGL'
elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
if CONFIG['MOZ_EGL_XRENDER_COMPOSITE']:
gl_provider = 'EGL'
@@ -19,6 +23,7 @@ if CONFIG['MOZ_GL_PROVIDER']:
EXPORTS += [
'DecomposeIntoNoRepeatTriangles.h',
'EGLUtils.h',
+ 'ForceDiscreteGPUHelperCGL.h',
'GfxTexturesReporter.h',
'GLBlitHelper.h',
'GLConsts.h',
@@ -73,7 +78,32 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']:
# Suppress warnings from Skia header files.
SOURCES['SkiaGLGlue.cpp'].flags += ['-Wno-implicit-fallthrough']
-if gl_provider == 'GLX':
+if gl_provider == 'CGL':
+ # These files include Mac headers that are unfriendly to unified builds
+ SOURCES += [
+ "GLContextProviderCGL.mm",
+ ]
+ EXPORTS += [
+ 'GLContextCGL.h',
+ 'SharedSurfaceIO.h',
+ ]
+ # SharedSurfaceIO.cpp includes MacIOSurface.h which include Mac headers
+ # which define Size and Point types in root namespace with often conflict with
+ # our own types. While I haven't actually hit this issue in the present case,
+ # it's been an issue in gfx/layers so let's not risk it.
+ SOURCES += [
+ 'SharedSurfaceIO.cpp',
+ ]
+elif gl_provider == 'EAGL':
+ # These files include ObjC headers that are unfriendly to unified builds
+ SOURCES += [
+ 'GLContextProviderEAGL.mm',
+ ]
+ EXPORTS += [
+ 'GLContextEAGL.h',
+ ]
+
+elif gl_provider == 'GLX':
# GLContextProviderGLX.cpp needs to be kept out of UNIFIED_SOURCES
# as it includes X11 headers which cause conflicts.
SOURCES += [