summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/libANGLE/renderer/gl/cgl
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/cgl')
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/gl/cgl/DisplayCGL.h77
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm275
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h65
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.mm143
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h100
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm332
6 files changed, 992 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/gl/cgl/DisplayCGL.h b/gfx/angle/src/libANGLE/renderer/gl/cgl/DisplayCGL.h
new file mode 100755
index 000000000..cc1b17bb7
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/gl/cgl/DisplayCGL.h
@@ -0,0 +1,77 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// DisplayCGL.h: CGL implementation of egl::Display
+
+#ifndef LIBANGLE_RENDERER_GL_CGL_DISPLAYCGL_H_
+#define LIBANGLE_RENDERER_GL_CGL_DISPLAYCGL_H_
+
+#include "libANGLE/renderer/gl/DisplayGL.h"
+
+struct _CGLContextObject;
+typedef _CGLContextObject *CGLContextObj;
+
+namespace rx
+{
+
+class DisplayCGL : public DisplayGL
+{
+ public:
+ DisplayCGL();
+ ~DisplayCGL() override;
+
+ egl::Error initialize(egl::Display *display) override;
+ void terminate() override;
+
+ SurfaceImpl *createWindowSurface(const egl::SurfaceState &state,
+ const egl::Config *configuration,
+ EGLNativeWindowType window,
+ const egl::AttributeMap &attribs) override;
+ SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state,
+ const egl::Config *configuration,
+ const egl::AttributeMap &attribs) override;
+ SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state,
+ const egl::Config *configuration,
+ EGLenum buftype,
+ EGLClientBuffer clientBuffer,
+ const egl::AttributeMap &attribs) override;
+ SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state,
+ const egl::Config *configuration,
+ NativePixmapType nativePixmap,
+ const egl::AttributeMap &attribs) override;
+
+ egl::ConfigSet generateConfigs() override;
+
+ bool testDeviceLost() override;
+ egl::Error restoreLostDevice() override;
+
+ bool isValidNativeWindow(EGLNativeWindowType window) const override;
+
+ egl::Error getDevice(DeviceImpl **device) override;
+
+ std::string getVendorString() const override;
+
+ egl::Error waitClient() const override;
+ egl::Error waitNative(EGLint engine,
+ egl::Surface *drawSurface,
+ egl::Surface *readSurface) const override;
+
+ egl::Error getDriverVersion(std::string *version) const override;
+
+ private:
+ const FunctionsGL *getFunctionsGL() const override;
+
+ void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
+ void generateCaps(egl::Caps *outCaps) const override;
+
+ egl::Display *mEGLDisplay;
+ FunctionsGL *mFunctions;
+ CGLContextObj mContext;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_GL_CGL_DISPLAYCGL_H_
diff --git a/gfx/angle/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm b/gfx/angle/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm
new file mode 100755
index 000000000..f87134c82
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/gl/cgl/DisplayCGL.mm
@@ -0,0 +1,275 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// DisplayCGL.mm: CGL implementation of egl::Display
+
+#include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
+
+#import <Cocoa/Cocoa.h>
+#include <dlfcn.h>
+#include <EGL/eglext.h>
+
+#include "common/debug.h"
+#include "libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h"
+#include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h"
+
+namespace
+{
+
+const char *kDefaultOpenGLDylibName =
+ "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib";
+const char *kFallbackOpenGLDylibName = "GL";
+
+}
+
+namespace rx
+{
+
+class FunctionsGLCGL : public FunctionsGL
+{
+ public:
+ FunctionsGLCGL(void *dylibHandle) : mDylibHandle(dylibHandle) {}
+
+ ~FunctionsGLCGL() override { dlclose(mDylibHandle); }
+
+ private:
+ void *loadProcAddress(const std::string &function) override
+ {
+ return dlsym(mDylibHandle, function.c_str());
+ }
+
+ void *mDylibHandle;
+};
+
+DisplayCGL::DisplayCGL() : DisplayGL(), mEGLDisplay(nullptr), mFunctions(nullptr), mContext(nullptr)
+{
+}
+
+DisplayCGL::~DisplayCGL()
+{
+}
+
+egl::Error DisplayCGL::initialize(egl::Display *display)
+{
+ mEGLDisplay = display;
+
+ CGLPixelFormatObj pixelFormat;
+ {
+ // TODO(cwallez) investigate which pixel format we want
+ CGLPixelFormatAttribute attribs[] = {
+ kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core),
+ static_cast<CGLPixelFormatAttribute>(0)};
+ GLint nVirtualScreens = 0;
+ CGLChoosePixelFormat(attribs, &pixelFormat, &nVirtualScreens);
+
+ if (pixelFormat == nullptr)
+ {
+ return egl::Error(EGL_NOT_INITIALIZED, "Could not create the context's pixel format.");
+ }
+ }
+
+ CGLCreateContext(pixelFormat, nullptr, &mContext);
+ if (mContext == nullptr)
+ {
+ return egl::Error(EGL_NOT_INITIALIZED, "Could not create the CGL context.");
+ }
+ CGLSetCurrentContext(mContext);
+
+ // There is no equivalent getProcAddress in CGL so we open the dylib directly
+ void *handle = dlopen(kDefaultOpenGLDylibName, RTLD_NOW);
+ if (!handle)
+ {
+ handle = dlopen(kFallbackOpenGLDylibName, RTLD_NOW);
+ }
+ if (!handle)
+ {
+ return egl::Error(EGL_NOT_INITIALIZED, "Could not open the OpenGL Framework.");
+ }
+
+ mFunctions = new FunctionsGLCGL(handle);
+ mFunctions->initialize();
+
+ return DisplayGL::initialize(display);
+}
+
+void DisplayCGL::terminate()
+{
+ DisplayGL::terminate();
+
+ if (mContext != nullptr)
+ {
+ CGLSetCurrentContext(nullptr);
+ CGLReleaseContext(mContext);
+ mContext = nullptr;
+ }
+
+ SafeDelete(mFunctions);
+}
+
+SurfaceImpl *DisplayCGL::createWindowSurface(const egl::SurfaceState &state,
+ const egl::Config *configuration,
+ EGLNativeWindowType window,
+ const egl::AttributeMap &attribs)
+{
+ return new WindowSurfaceCGL(state, this->getRenderer(), window, mFunctions, mContext);
+}
+
+SurfaceImpl *DisplayCGL::createPbufferSurface(const egl::SurfaceState &state,
+ const egl::Config *configuration,
+ const egl::AttributeMap &attribs)
+{
+ EGLint width = static_cast<EGLint>(attribs.get(EGL_WIDTH, 0));
+ EGLint height = static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0));
+ return new PbufferSurfaceCGL(state, this->getRenderer(), width, height, mFunctions);
+}
+
+SurfaceImpl *DisplayCGL::createPbufferFromClientBuffer(const egl::SurfaceState &state,
+ const egl::Config *configuration,
+ EGLenum buftype,
+ EGLClientBuffer clientBuffer,
+ const egl::AttributeMap &attribs)
+{
+ UNIMPLEMENTED();
+ return nullptr;
+}
+
+SurfaceImpl *DisplayCGL::createPixmapSurface(const egl::SurfaceState &state,
+ const egl::Config *configuration,
+ NativePixmapType nativePixmap,
+ const egl::AttributeMap &attribs)
+{
+ UNIMPLEMENTED();
+ return nullptr;
+}
+
+egl::Error DisplayCGL::getDevice(DeviceImpl **device)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_BAD_DISPLAY);
+}
+
+egl::ConfigSet DisplayCGL::generateConfigs()
+{
+ // TODO(cwallez): generate more config permutations
+ egl::ConfigSet configs;
+
+ const gl::Version &maxVersion = getMaxSupportedESVersion();
+ ASSERT(maxVersion >= gl::Version(2, 0));
+ bool supportsES3 = maxVersion >= gl::Version(3, 0);
+
+ egl::Config config;
+
+ // Native stuff
+ config.nativeVisualID = 0;
+ config.nativeVisualType = 0;
+ config.nativeRenderable = EGL_TRUE;
+
+ // Buffer sizes
+ config.redSize = 8;
+ config.greenSize = 8;
+ config.blueSize = 8;
+ config.alphaSize = 8;
+ config.depthSize = 24;
+ config.stencilSize = 8;
+
+ config.colorBufferType = EGL_RGB_BUFFER;
+ config.luminanceSize = 0;
+ config.alphaMaskSize = 0;
+
+ config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize;
+
+ config.transparentType = EGL_NONE;
+
+ // Pbuffer
+ config.maxPBufferWidth = 4096;
+ config.maxPBufferHeight = 4096;
+ config.maxPBufferPixels = 4096 * 4096;
+
+ // Caveat
+ config.configCaveat = EGL_NONE;
+
+ // Misc
+ config.sampleBuffers = 0;
+ config.samples = 0;
+ config.level = 0;
+ config.bindToTextureRGB = EGL_FALSE;
+ config.bindToTextureRGBA = EGL_FALSE;
+
+ config.surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
+
+ config.minSwapInterval = 1;
+ config.maxSwapInterval = 1;
+
+ config.renderTargetFormat = GL_RGBA8;
+ config.depthStencilFormat = GL_DEPTH24_STENCIL8;
+
+ config.conformant = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0);
+ config.renderableType = config.conformant;
+
+ config.matchNativePixmap = EGL_NONE;
+
+ configs.add(config);
+ return configs;
+}
+
+bool DisplayCGL::testDeviceLost()
+{
+ // TODO(cwallez) investigate implementing this
+ return false;
+}
+
+egl::Error DisplayCGL::restoreLostDevice()
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_BAD_DISPLAY);
+}
+
+bool DisplayCGL::isValidNativeWindow(EGLNativeWindowType window) const
+{
+ // TODO(cwallez) investigate implementing this
+ return true;
+}
+
+std::string DisplayCGL::getVendorString() const
+{
+ // TODO(cwallez) find a useful vendor string
+ return "";
+}
+
+const FunctionsGL *DisplayCGL::getFunctionsGL() const
+{
+ return mFunctions;
+}
+
+void DisplayCGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
+{
+}
+
+void DisplayCGL::generateCaps(egl::Caps *outCaps) const
+{
+ outCaps->textureNPOT = true;
+}
+
+egl::Error DisplayCGL::waitClient() const
+{
+ // TODO(cwallez) UNIMPLEMENTED()
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error DisplayCGL::waitNative(EGLint engine,
+ egl::Surface *drawSurface,
+ egl::Surface *readSurface) const
+{
+ // TODO(cwallez) UNIMPLEMENTED()
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error DisplayCGL::getDriverVersion(std::string *version) const
+{
+ *version = "";
+ return egl::Error(EGL_SUCCESS);
+}
+}
diff --git a/gfx/angle/src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h b/gfx/angle/src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h
new file mode 100755
index 000000000..7cbb74da4
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h
@@ -0,0 +1,65 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// PBufferSurfaceCGL.h: an implementation of egl::Surface for PBuffers for the CLG backend,
+// currently implemented using renderbuffers
+
+#ifndef LIBANGLE_RENDERER_GL_CGL_PBUFFERSURFACECGL_H_
+#define LIBANGLE_RENDERER_GL_CGL_PBUFFERSURFACECGL_H_
+
+#include "libANGLE/renderer/gl/SurfaceGL.h"
+
+namespace rx
+{
+
+class FunctionsGL;
+class StateManagerGL;
+struct WorkaroundsGL;
+
+class PbufferSurfaceCGL : public SurfaceGL
+{
+ public:
+ PbufferSurfaceCGL(const egl::SurfaceState &state,
+ RendererGL *renderer,
+ EGLint width,
+ EGLint height,
+ const FunctionsGL *functions);
+ ~PbufferSurfaceCGL() override;
+
+ egl::Error initialize() override;
+ egl::Error makeCurrent() override;
+
+ egl::Error swap() override;
+ egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override;
+ egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
+ egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override;
+ egl::Error releaseTexImage(EGLint buffer) override;
+ void setSwapInterval(EGLint interval) override;
+
+ EGLint getWidth() const override;
+ EGLint getHeight() const override;
+
+ EGLint isPostSubBufferSupported() const override;
+ EGLint getSwapBehavior() const override;
+
+ FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override;
+
+ private:
+ unsigned mWidth;
+ unsigned mHeight;
+
+ const FunctionsGL *mFunctions;
+ StateManagerGL *mStateManager;
+ RendererGL *mRenderer;
+
+ GLuint mFramebuffer;
+ GLuint mColorRenderbuffer;
+ GLuint mDSRenderbuffer;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_GL_CGL_PBUFFERSURFACECGL_H_
diff --git a/gfx/angle/src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.mm b/gfx/angle/src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.mm
new file mode 100755
index 000000000..c03d3836f
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.mm
@@ -0,0 +1,143 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// PBufferSurfaceCGL.cpp: an implementation of egl::Surface for PBuffers for the CLG backend,
+// currently implemented using renderbuffers
+
+#include "libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h"
+
+#include "common/debug.h"
+#include "libANGLE/renderer/gl/FunctionsGL.h"
+#include "libANGLE/renderer/gl/FramebufferGL.h"
+#include "libANGLE/renderer/gl/RendererGL.h"
+#include "libANGLE/renderer/gl/StateManagerGL.h"
+
+namespace rx
+{
+
+PbufferSurfaceCGL::PbufferSurfaceCGL(const egl::SurfaceState &state,
+ RendererGL *renderer,
+ EGLint width,
+ EGLint height,
+ const FunctionsGL *functions)
+ : SurfaceGL(state, renderer),
+ mWidth(width),
+ mHeight(height),
+ mFunctions(functions),
+ mStateManager(renderer->getStateManager()),
+ mRenderer(renderer),
+ mFramebuffer(0),
+ mColorRenderbuffer(0),
+ mDSRenderbuffer(0)
+{
+}
+
+PbufferSurfaceCGL::~PbufferSurfaceCGL()
+{
+ if (mFramebuffer != 0)
+ {
+ mFunctions->deleteFramebuffers(1, &mFramebuffer);
+ mFramebuffer = 0;
+ }
+
+ if (mColorRenderbuffer != 0)
+ {
+ mFunctions->deleteRenderbuffers(1, &mColorRenderbuffer);
+ mColorRenderbuffer = 0;
+ }
+ if (mDSRenderbuffer != 0)
+ {
+ mFunctions->deleteRenderbuffers(1, &mDSRenderbuffer);
+ mDSRenderbuffer = 0;
+ }
+}
+
+egl::Error PbufferSurfaceCGL::initialize()
+{
+ mFunctions->genRenderbuffers(1, &mColorRenderbuffer);
+ mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mColorRenderbuffer);
+ mFunctions->renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, mWidth, mHeight);
+
+ mFunctions->genRenderbuffers(1, &mDSRenderbuffer);
+ mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDSRenderbuffer);
+ mFunctions->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mWidth, mHeight);
+
+ mFunctions->genFramebuffers(1, &mFramebuffer);
+ mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+ mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ mColorRenderbuffer);
+ mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, mDSRenderbuffer);
+
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error PbufferSurfaceCGL::makeCurrent()
+{
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error PbufferSurfaceCGL::swap()
+{
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error PbufferSurfaceCGL::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
+{
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error PbufferSurfaceCGL::querySurfacePointerANGLE(EGLint attribute, void **value)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error PbufferSurfaceCGL::bindTexImage(gl::Texture *texture, EGLint buffer)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error PbufferSurfaceCGL::releaseTexImage(EGLint buffer)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+void PbufferSurfaceCGL::setSwapInterval(EGLint interval)
+{
+}
+
+EGLint PbufferSurfaceCGL::getWidth() const
+{
+ return mWidth;
+}
+
+EGLint PbufferSurfaceCGL::getHeight() const
+{
+ return mHeight;
+}
+
+EGLint PbufferSurfaceCGL::isPostSubBufferSupported() const
+{
+ UNIMPLEMENTED();
+ return EGL_FALSE;
+}
+
+EGLint PbufferSurfaceCGL::getSwapBehavior() const
+{
+ return EGL_BUFFER_PRESERVED;
+}
+
+FramebufferImpl *PbufferSurfaceCGL::createDefaultFramebuffer(const gl::FramebufferState &state)
+{
+ // TODO(cwallez) assert it happens only once?
+ return new FramebufferGL(mFramebuffer, state, mFunctions, mRenderer->getWorkarounds(),
+ mRenderer->getBlitter(), mStateManager);
+}
+
+}
diff --git a/gfx/angle/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h b/gfx/angle/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h
new file mode 100755
index 000000000..165ab0486
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h
@@ -0,0 +1,100 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// WindowSurfaceCGL.h: CGL implementation of egl::Surface for windows
+
+#ifndef LIBANGLE_RENDERER_GL_CGL_WINDOWSURFACECGL_H_
+#define LIBANGLE_RENDERER_GL_CGL_WINDOWSURFACECGL_H_
+
+#include "libANGLE/renderer/gl/SurfaceGL.h"
+
+struct _CGLContextObject;
+typedef _CGLContextObject *CGLContextObj;
+@class CALayer;
+struct __IOSurface;
+typedef __IOSurface *IOSurfaceRef;
+
+@class SwapLayer;
+
+namespace rx
+{
+
+class DisplayCGL;
+class FramebufferGL;
+class FunctionsGL;
+class StateManagerGL;
+struct WorkaroundsGL;
+
+struct SharedSwapState
+{
+ struct SwapTexture
+ {
+ GLuint texture;
+ unsigned int width;
+ unsigned int height;
+ uint64_t swapId;
+ };
+
+ SwapTexture textures[3];
+
+ // This code path is not going to be used by Chrome so we take the liberty
+ // to use pthreads directly instead of using mutexes and condition variables
+ // via the Platform API.
+ pthread_mutex_t mutex;
+ // The following members should be accessed only when holding the mutex
+ // (or doing construction / destruction)
+ SwapTexture *beingRendered;
+ SwapTexture *lastRendered;
+ SwapTexture *beingPresented;
+};
+
+class WindowSurfaceCGL : public SurfaceGL
+{
+ public:
+ WindowSurfaceCGL(const egl::SurfaceState &state,
+ RendererGL *renderer,
+ CALayer *layer,
+ const FunctionsGL *functions,
+ CGLContextObj context);
+ ~WindowSurfaceCGL() override;
+
+ egl::Error initialize() override;
+ egl::Error makeCurrent() override;
+
+ egl::Error swap() override;
+ egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override;
+ egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
+ egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override;
+ egl::Error releaseTexImage(EGLint buffer) override;
+ void setSwapInterval(EGLint interval) override;
+
+ EGLint getWidth() const override;
+ EGLint getHeight() const override;
+
+ EGLint isPostSubBufferSupported() const override;
+ EGLint getSwapBehavior() const override;
+
+ FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override;
+
+ private:
+ SwapLayer *mSwapLayer;
+ SharedSwapState mSwapState;
+ uint64_t mCurrentSwapId;
+
+ CALayer *mLayer;
+ CGLContextObj mContext;
+ const FunctionsGL *mFunctions;
+ StateManagerGL *mStateManager;
+ RendererGL *mRenderer;
+ const WorkaroundsGL &mWorkarounds;
+
+ GLuint mFramebuffer;
+ GLuint mDSRenderbuffer;
+};
+
+}
+
+#endif // LIBANGLE_RENDERER_GL_CGL_WINDOWSURFACECGL_H_
diff --git a/gfx/angle/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm b/gfx/angle/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm
new file mode 100755
index 000000000..c2ac4dca4
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm
@@ -0,0 +1,332 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// WindowSurfaceCGL.cpp: CGL implementation of egl::Surface for windows
+
+#include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h"
+
+#import <Cocoa/Cocoa.h>
+#include <OpenGL/OpenGL.h>
+#import <QuartzCore/QuartzCore.h>
+
+#include "common/debug.h"
+#include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
+#include "libANGLE/renderer/gl/FramebufferGL.h"
+#include "libANGLE/renderer/gl/RendererGL.h"
+#include "libANGLE/renderer/gl/StateManagerGL.h"
+
+@interface SwapLayer : CAOpenGLLayer
+{
+ CGLContextObj mDisplayContext;
+
+ bool initialized;
+ rx::SharedSwapState *mSwapState;
+ const rx::FunctionsGL *mFunctions;
+
+ GLuint mReadFramebuffer;
+}
+- (id)initWithSharedState:(rx::SharedSwapState *)swapState
+ withContext:(CGLContextObj)displayContext
+ withFunctions:(const rx::FunctionsGL *)functions;
+@end
+
+@implementation SwapLayer
+- (id)initWithSharedState:(rx::SharedSwapState *)swapState
+ withContext:(CGLContextObj)displayContext
+ withFunctions:(const rx::FunctionsGL *)functions
+ {
+ self = [super init];
+ if (self != nil)
+ {
+ self.asynchronous = YES;
+ mDisplayContext = displayContext;
+
+ initialized = false;
+ mSwapState = swapState;
+ mFunctions = functions;
+
+ [self setFrame:CGRectMake(0, 0, mSwapState->textures[0].width,
+ mSwapState->textures[0].height)];
+ }
+ return self;
+ }
+
+ - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
+ {
+ CGLPixelFormatAttribute attribs[] = {
+ kCGLPFADisplayMask, static_cast<CGLPixelFormatAttribute>(mask), kCGLPFAOpenGLProfile,
+ static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core),
+ static_cast<CGLPixelFormatAttribute>(0)};
+
+ CGLPixelFormatObj pixelFormat = nullptr;
+ GLint numFormats = 0;
+ CGLChoosePixelFormat(attribs, &pixelFormat, &numFormats);
+
+ return pixelFormat;
+ }
+
+ - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
+ {
+ CGLContextObj context = nullptr;
+ CGLCreateContext(pixelFormat, mDisplayContext, &context);
+ return context;
+ }
+
+ - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
+ pixelFormat:(CGLPixelFormatObj)pixelFormat
+ forLayerTime:(CFTimeInterval)timeInterval
+ displayTime:(const CVTimeStamp *)timeStamp
+ {
+ BOOL result = NO;
+
+ pthread_mutex_lock(&mSwapState->mutex);
+ {
+ if (mSwapState->lastRendered->swapId > mSwapState->beingPresented->swapId)
+ {
+ std::swap(mSwapState->lastRendered, mSwapState->beingPresented);
+ result = YES;
+ }
+ }
+ pthread_mutex_unlock(&mSwapState->mutex);
+
+ return result;
+ }
+
+ - (void)drawInCGLContext:(CGLContextObj)glContext
+ pixelFormat:(CGLPixelFormatObj)pixelFormat
+ forLayerTime:(CFTimeInterval)timeInterval
+ displayTime:(const CVTimeStamp *)timeStamp
+ {
+ CGLSetCurrentContext(glContext);
+ if (!initialized)
+ {
+ initialized = true;
+
+ mFunctions->genFramebuffers(1, &mReadFramebuffer);
+ }
+
+ const auto &texture = *mSwapState->beingPresented;
+ if ([self frame].size.width != texture.width || [self frame].size.height != texture.height)
+ {
+ [self setFrame:CGRectMake(0, 0, texture.width, texture.height)];
+
+ // Without this, the OSX compositor / window system doesn't see the resize.
+ [self setNeedsDisplay];
+ }
+
+ // TODO(cwallez) support 2.1 contexts too that don't have blitFramebuffer nor the
+ // GL_DRAW_FRAMEBUFFER_BINDING query
+ GLint drawFBO;
+ mFunctions->getIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFBO);
+
+ mFunctions->bindFramebuffer(GL_FRAMEBUFFER, mReadFramebuffer);
+ mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ texture.texture, 0);
+
+ mFunctions->bindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer);
+ mFunctions->bindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
+ mFunctions->blitFramebuffer(0, 0, texture.width, texture.height, 0, 0, texture.width,
+ texture.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ // Call the super method to flush the context
+ [super drawInCGLContext:glContext
+ pixelFormat:pixelFormat
+ forLayerTime:timeInterval
+ displayTime:timeStamp];
+ }
+ @end
+
+ namespace rx
+ {
+
+ WindowSurfaceCGL::WindowSurfaceCGL(const egl::SurfaceState &state,
+ RendererGL *renderer,
+ CALayer *layer,
+ const FunctionsGL *functions,
+ CGLContextObj context)
+ : SurfaceGL(state, renderer),
+ mSwapLayer(nil),
+ mCurrentSwapId(0),
+ mLayer(layer),
+ mContext(context),
+ mFunctions(functions),
+ mStateManager(renderer->getStateManager()),
+ mRenderer(renderer),
+ mWorkarounds(renderer->getWorkarounds()),
+ mFramebuffer(0),
+ mDSRenderbuffer(0)
+ {
+ pthread_mutex_init(&mSwapState.mutex, nullptr);
+}
+
+WindowSurfaceCGL::~WindowSurfaceCGL()
+{
+ pthread_mutex_destroy(&mSwapState.mutex);
+ if (mFramebuffer != 0)
+ {
+ mFunctions->deleteFramebuffers(1, &mFramebuffer);
+ mFramebuffer = 0;
+ }
+
+ if (mDSRenderbuffer != 0)
+ {
+ mFunctions->deleteRenderbuffers(1, &mDSRenderbuffer);
+ mDSRenderbuffer = 0;
+ }
+
+ if (mSwapLayer != nil)
+ {
+ [mSwapLayer removeFromSuperlayer];
+ [mSwapLayer release];
+ mSwapLayer = nil;
+ }
+
+ for (size_t i = 0; i < ArraySize(mSwapState.textures); ++i)
+ {
+ if (mSwapState.textures[i].texture != 0)
+ {
+ mFunctions->deleteTextures(1, &mSwapState.textures[i].texture);
+ mSwapState.textures[i].texture = 0;
+ }
+ }
+}
+
+egl::Error WindowSurfaceCGL::initialize()
+{
+ unsigned width = getWidth();
+ unsigned height = getHeight();
+
+ for (size_t i = 0; i < ArraySize(mSwapState.textures); ++i)
+ {
+ mFunctions->genTextures(1, &mSwapState.textures[i].texture);
+ mStateManager->bindTexture(GL_TEXTURE_2D, mSwapState.textures[i].texture);
+ mFunctions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, nullptr);
+ mSwapState.textures[i].width = width;
+ mSwapState.textures[i].height = height;
+ mSwapState.textures[i].swapId = 0;
+ }
+ mSwapState.beingRendered = &mSwapState.textures[0];
+ mSwapState.lastRendered = &mSwapState.textures[1];
+ mSwapState.beingPresented = &mSwapState.textures[2];
+
+ mSwapLayer = [[SwapLayer alloc] initWithSharedState:&mSwapState
+ withContext:mContext
+ withFunctions:mFunctions];
+ [mLayer addSublayer:mSwapLayer];
+
+ mFunctions->genRenderbuffers(1, &mDSRenderbuffer);
+ mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDSRenderbuffer);
+ mFunctions->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
+
+ mFunctions->genFramebuffers(1, &mFramebuffer);
+ mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+ mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ mSwapState.beingRendered->texture, 0);
+ mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ mDSRenderbuffer);
+
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceCGL::makeCurrent()
+{
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceCGL::swap()
+{
+ mFunctions->flush();
+ mSwapState.beingRendered->swapId = ++mCurrentSwapId;
+
+ pthread_mutex_lock(&mSwapState.mutex);
+ {
+ std::swap(mSwapState.beingRendered, mSwapState.lastRendered);
+ }
+ pthread_mutex_unlock(&mSwapState.mutex);
+
+ unsigned width = getWidth();
+ unsigned height = getHeight();
+ auto &texture = *mSwapState.beingRendered;
+
+ if (texture.width != width || texture.height != height)
+ {
+ mStateManager->bindTexture(GL_TEXTURE_2D, texture.texture);
+ mFunctions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, nullptr);
+
+ mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDSRenderbuffer);
+ mFunctions->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
+
+ texture.width = width;
+ texture.height = height;
+ }
+
+ mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+ mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ mSwapState.beingRendered->texture, 0);
+
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceCGL::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceCGL::querySurfacePointerANGLE(EGLint attribute, void **value)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceCGL::bindTexImage(gl::Texture *texture, EGLint buffer)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceCGL::releaseTexImage(EGLint buffer)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+void WindowSurfaceCGL::setSwapInterval(EGLint interval)
+{
+ // TODO(cwallez) investigate implementing swap intervals other than 0
+}
+
+EGLint WindowSurfaceCGL::getWidth() const
+{
+ return CGRectGetWidth([mLayer frame]);
+}
+
+EGLint WindowSurfaceCGL::getHeight() const
+{
+ return CGRectGetHeight([mLayer frame]);
+}
+
+EGLint WindowSurfaceCGL::isPostSubBufferSupported() const
+{
+ UNIMPLEMENTED();
+ return EGL_FALSE;
+}
+
+EGLint WindowSurfaceCGL::getSwapBehavior() const
+{
+ return EGL_BUFFER_DESTROYED;
+}
+
+FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::FramebufferState &state)
+{
+ // TODO(cwallez) assert it happens only once?
+ return new FramebufferGL(mFramebuffer, state, mFunctions, mWorkarounds, mRenderer->getBlitter(),
+ mStateManager);
+}
+
+}