Commit 86f8dd7c by Corentin Wallez

Implement a minimal EGL -> CGL backend

This succesfully renders HelloTriangle and some samples but fails on a lot of tests. In particular it doesn't handle resizing the window and doesn't have depth or stencil buffers. BUG=angleproject:891 Change-Id: I16356471b470f764acb38e8dd3589e9c0129829d Reviewed-on: https://chromium-review.googlesource.com/290770Tested-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarKenneth Russell <kbr@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 5cf466d3
...@@ -117,11 +117,15 @@ typedef Window EGLNativeWindowType; ...@@ -117,11 +117,15 @@ typedef Window EGLNativeWindowType;
#elif defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) ) #elif defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) )
// TODO(jmadill): native implementation for OSX #if defined(__OBJC__)
@class CALayer;
#else
class CALayer;
#endif
typedef void *EGLNativeDisplayType; typedef void *EGLNativeDisplayType;
typedef void *EGLNativePixmapType; typedef void *EGLNativePixmapType;
typedef void *EGLNativeWindowType; typedef CALayer *EGLNativeWindowType;
#else #else
#error "Platform not recognized" #error "Platform not recognized"
......
...@@ -184,8 +184,7 @@ class TIntermLoop : public TIntermNode ...@@ -184,8 +184,7 @@ class TIntermLoop : public TIntermNode
TIntermLoop *getAsLoopNode() override { return this; } TIntermLoop *getAsLoopNode() override { return this; }
void traverse(TIntermTraverser *it) override; void traverse(TIntermTraverser *it) override;
bool replaceChildNode( bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TIntermNode *original, TIntermNode *replacement) override;
TLoopType getType() const { return mType; } TLoopType getType() const { return mType; }
TIntermNode *getInit() { return mInit; } TIntermNode *getInit() { return mInit; }
...@@ -217,8 +216,7 @@ class TIntermBranch : public TIntermNode ...@@ -217,8 +216,7 @@ class TIntermBranch : public TIntermNode
mExpression(e) { } mExpression(e) { }
void traverse(TIntermTraverser *it) override; void traverse(TIntermTraverser *it) override;
bool replaceChildNode( bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TIntermNode *original, TIntermNode *replacement) override;
TOperator getFlowOp() { return mFlowOp; } TOperator getFlowOp() { return mFlowOp; }
TIntermTyped* getExpression() { return mExpression; } TIntermTyped* getExpression() { return mExpression; }
...@@ -395,8 +393,7 @@ class TIntermBinary : public TIntermOperator ...@@ -395,8 +393,7 @@ class TIntermBinary : public TIntermOperator
TIntermBinary *getAsBinaryNode() override { return this; }; TIntermBinary *getAsBinaryNode() override { return this; };
void traverse(TIntermTraverser *it) override; void traverse(TIntermTraverser *it) override;
bool replaceChildNode( bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TIntermNode *original, TIntermNode *replacement) override;
bool hasSideEffects() const override bool hasSideEffects() const override
{ {
...@@ -443,13 +440,9 @@ class TIntermUnary : public TIntermOperator ...@@ -443,13 +440,9 @@ class TIntermUnary : public TIntermOperator
void traverse(TIntermTraverser *it) override; void traverse(TIntermTraverser *it) override;
TIntermUnary *getAsUnaryNode() override { return this; } TIntermUnary *getAsUnaryNode() override { return this; }
bool replaceChildNode( bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TIntermNode *original, TIntermNode *replacement) override;
bool hasSideEffects() const override bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
{
return isAssignment() || mOperand->hasSideEffects();
}
void setOperand(TIntermTyped *operand) { mOperand = operand; } void setOperand(TIntermTyped *operand) { mOperand = operand; }
TIntermTyped *getOperand() { return mOperand; } TIntermTyped *getOperand() { return mOperand; }
...@@ -499,8 +492,7 @@ class TIntermAggregate : public TIntermOperator ...@@ -499,8 +492,7 @@ class TIntermAggregate : public TIntermOperator
TIntermAggregate *getAsAggregate() override { return this; } TIntermAggregate *getAsAggregate() override { return this; }
void traverse(TIntermTraverser *it) override; void traverse(TIntermTraverser *it) override;
bool replaceChildNode( bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TIntermNode *original, TIntermNode *replacement) override;
bool replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements); bool replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements);
bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions); bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions);
// Conservatively assume function calls and other aggregate operators have side-effects // Conservatively assume function calls and other aggregate operators have side-effects
...@@ -568,8 +560,7 @@ class TIntermSelection : public TIntermTyped ...@@ -568,8 +560,7 @@ class TIntermSelection : public TIntermTyped
TIntermTyped *deepCopy() const override { return new TIntermSelection(*this); } TIntermTyped *deepCopy() const override { return new TIntermSelection(*this); }
void traverse(TIntermTraverser *it) override; void traverse(TIntermTraverser *it) override;
bool replaceChildNode( bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TIntermNode *original, TIntermNode *replacement) override;
// Conservatively assume selections have side-effects // Conservatively assume selections have side-effects
bool hasSideEffects() const override { return true; } bool hasSideEffects() const override { return true; }
......
...@@ -35,6 +35,18 @@ FramebufferGL::FramebufferGL(const gl::Framebuffer::Data &data, const FunctionsG ...@@ -35,6 +35,18 @@ FramebufferGL::FramebufferGL(const gl::Framebuffer::Data &data, const FunctionsG
} }
} }
FramebufferGL::FramebufferGL(GLuint id,
const gl::Framebuffer::Data &data,
const FunctionsGL *functions,
StateManagerGL *stateManager)
: FramebufferImpl(data),
mFunctions(functions),
mStateManager(stateManager),
mFramebufferID(id),
mIsDefault(true)
{
}
FramebufferGL::~FramebufferGL() FramebufferGL::~FramebufferGL()
{ {
mStateManager->deleteFramebuffer(mFramebufferID); mStateManager->deleteFramebuffer(mFramebufferID);
......
...@@ -21,6 +21,13 @@ class FramebufferGL : public FramebufferImpl ...@@ -21,6 +21,13 @@ class FramebufferGL : public FramebufferImpl
{ {
public: public:
FramebufferGL(const gl::Framebuffer::Data &data, const FunctionsGL *functions, StateManagerGL *stateManager, bool isDefault); FramebufferGL(const gl::Framebuffer::Data &data, const FunctionsGL *functions, StateManagerGL *stateManager, bool isDefault);
// Constructor called when we need to create a FramebufferGL from an
// existing framebuffer name, for example for the default framebuffer
// on the Mac EGL CGL backend.
FramebufferGL(GLuint id,
const gl::Framebuffer::Data &data,
const FunctionsGL *functions,
StateManagerGL *stateManager);
~FramebufferGL() override; ~FramebufferGL() override;
void onUpdateColorAttachment(size_t index) override; void onUpdateColorAttachment(size_t index) override;
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
#include "libANGLE/renderer/gl/DisplayGL.h" #include "libANGLE/renderer/gl/DisplayGL.h"
struct _CGLContextObject;
typedef _CGLContextObject *CGLContextObj;
namespace rx namespace rx
{ {
...@@ -54,6 +57,8 @@ class DisplayCGL : public DisplayGL ...@@ -54,6 +57,8 @@ class DisplayCGL : public DisplayGL
void generateCaps(egl::Caps *outCaps) const override; void generateCaps(egl::Caps *outCaps) const override;
egl::Display *mEGLDisplay; egl::Display *mEGLDisplay;
FunctionsGL *mFunctions;
CGLContextObj mContext;
}; };
} }
......
...@@ -8,15 +8,42 @@ ...@@ -8,15 +8,42 @@
#include "libANGLE/renderer/gl/CGL/DisplayCGL.h" #include "libANGLE/renderer/gl/CGL/DisplayCGL.h"
#import <Cocoa/Cocoa.h>
#include <dlfcn.h>
#include <EGL/eglext.h>
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/renderer/gl/CGL/WindowSurfaceCGL.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 namespace rx
{ {
DisplayCGL::DisplayCGL() class FunctionsGLCGL : public FunctionsGL
: DisplayGL(), {
mEGLDisplay(nullptr) public:
FunctionsGLCGL(void *dylibHandle) : mDylibHandle(dylibHandle) {}
virtual ~FunctionsGLCGL() { 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)
{ {
} }
...@@ -26,23 +53,66 @@ DisplayCGL::~DisplayCGL() ...@@ -26,23 +53,66 @@ DisplayCGL::~DisplayCGL()
egl::Error DisplayCGL::initialize(egl::Display *display) egl::Error DisplayCGL::initialize(egl::Display *display)
{ {
UNIMPLEMENTED();
mEGLDisplay = 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); return DisplayGL::initialize(display);
} }
void DisplayCGL::terminate() void DisplayCGL::terminate()
{ {
UNIMPLEMENTED();
DisplayGL::terminate(); DisplayGL::terminate();
if (mContext != nullptr)
{
CGLSetCurrentContext(nullptr);
CGLReleaseContext(mContext);
mContext = nullptr;
}
SafeDelete(mFunctions);
} }
SurfaceImpl *DisplayCGL::createWindowSurface(const egl::Config *configuration, SurfaceImpl *DisplayCGL::createWindowSurface(const egl::Config *configuration,
EGLNativeWindowType window, EGLNativeWindowType window,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
{ {
UNIMPLEMENTED(); return new WindowSurfaceCGL(this->getRenderer(), window, mFunctions);
return new WindowSurfaceCGL(this->getRenderer());
} }
SurfaceImpl *DisplayCGL::createPbufferSurface(const egl::Config *configuration, SurfaceImpl *DisplayCGL::createPbufferSurface(const egl::Config *configuration,
...@@ -76,20 +146,73 @@ egl::Error DisplayCGL::getDevice(DeviceImpl **device) ...@@ -76,20 +146,73 @@ egl::Error DisplayCGL::getDevice(DeviceImpl **device)
egl::ConfigSet DisplayCGL::generateConfigs() const egl::ConfigSet DisplayCGL::generateConfigs() const
{ {
UNIMPLEMENTED(); // TODO(cwallez): generate more config permutations
egl::ConfigSet configs; egl::ConfigSet configs;
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;
config.minSwapInterval = 1;
config.maxSwapInterval = 1;
config.renderTargetFormat = GL_RGBA8;
config.depthStencilFormat = GL_DEPTH24_STENCIL8;
config.conformant = EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR;
config.renderableType = EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR;
config.matchNativePixmap = EGL_NONE;
configs.add(config);
return configs; return configs;
} }
bool DisplayCGL::isDeviceLost() const bool DisplayCGL::isDeviceLost() const
{ {
UNIMPLEMENTED(); // TODO(cwallez) investigate implementing this
return false; return false;
} }
bool DisplayCGL::testDeviceLost() bool DisplayCGL::testDeviceLost()
{ {
UNIMPLEMENTED(); // TODO(cwallez) investigate implementing this
return false; return false;
} }
...@@ -101,20 +224,19 @@ egl::Error DisplayCGL::restoreLostDevice() ...@@ -101,20 +224,19 @@ egl::Error DisplayCGL::restoreLostDevice()
bool DisplayCGL::isValidNativeWindow(EGLNativeWindowType window) const bool DisplayCGL::isValidNativeWindow(EGLNativeWindowType window) const
{ {
UNIMPLEMENTED(); // TODO(cwallez) investigate implementing this
return true; return true;
} }
std::string DisplayCGL::getVendorString() const std::string DisplayCGL::getVendorString() const
{ {
UNIMPLEMENTED(); // TODO(cwallez) find a useful vendor string
return ""; return "";
} }
const FunctionsGL *DisplayCGL::getFunctionsGL() const const FunctionsGL *DisplayCGL::getFunctionsGL() const
{ {
UNIMPLEMENTED(); return mFunctions;
return nullptr;
} }
void DisplayCGL::generateExtensions(egl::DisplayExtensions *outExtensions) const void DisplayCGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
...@@ -124,6 +246,7 @@ void DisplayCGL::generateExtensions(egl::DisplayExtensions *outExtensions) const ...@@ -124,6 +246,7 @@ void DisplayCGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
void DisplayCGL::generateCaps(egl::Caps *outCaps) const void DisplayCGL::generateCaps(egl::Caps *outCaps) const
{ {
UNIMPLEMENTED(); outCaps->textureNPOT = true;
} }
} }
...@@ -11,13 +11,24 @@ ...@@ -11,13 +11,24 @@
#include "libANGLE/renderer/gl/SurfaceGL.h" #include "libANGLE/renderer/gl/SurfaceGL.h"
@class CALayer;
struct __IOSurface;
typedef __IOSurface *IOSurfaceRef;
namespace rx namespace rx
{ {
class DisplayCGL;
class FramebufferGL;
class FunctionsGL;
class StateManagerGL;
class DisplayLink;
class WindowSurfaceCGL : public SurfaceGL class WindowSurfaceCGL : public SurfaceGL
{ {
public: public:
WindowSurfaceCGL(RendererGL *renderer); WindowSurfaceCGL(RendererGL *renderer, CALayer *layer, const FunctionsGL *functions);
~WindowSurfaceCGL() override; ~WindowSurfaceCGL() override;
egl::Error initialize() override; egl::Error initialize() override;
...@@ -35,6 +46,31 @@ class WindowSurfaceCGL : public SurfaceGL ...@@ -35,6 +46,31 @@ class WindowSurfaceCGL : public SurfaceGL
EGLint isPostSubBufferSupported() const override; EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override; EGLint getSwapBehavior() const override;
FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) override;
private:
struct Surface
{
IOSurfaceRef ioSurface;
GLuint texture;
uint64_t lastPresentNanos;
};
void freeSurfaceData(Surface *surface);
egl::Error initializeSurfaceData(Surface *surface, int width, int height);
CALayer *mLayer;
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
DisplayLink *mDisplayLink;
// CGL doesn't have a default framebuffer, we instead render to an IOSurface
// that will be set as the content of the CALayer which is our native window.
// We use two IOSurfaces to do double buffering.
Surface mSurfaces[2];
int mCurrentSurface;
GLuint mFramebuffer;
}; };
} }
......
...@@ -740,6 +740,24 @@ ...@@ -740,6 +740,24 @@
[ [
'<@(libangle_gl_cgl_sources)', '<@(libangle_gl_cgl_sources)',
], ],
'link_settings':
{
# TODO(cwallez) Chromium uses an SDKROOT prefix, use it when we want to
# support compiling ANGLE in Chromium on Mac
'libraries':
[
'OpenGL.framework',
'IOSurface.framework',
'Cocoa.framework',
'QuartzCore.framework',
],
},
'all_dependent_settings':
{
'xcode_settings': {
'LD_RUNPATH_SEARCH_PATHS': ['@executable_path/.'],
},
}
}], }],
], ],
}], }],
...@@ -795,15 +813,10 @@ ...@@ -795,15 +813,10 @@
} }
}, },
}], }],
['OS == "mac"', ['angle_build_winphone==1',
{ {
'all_dependent_settings': 'msvs_enable_winphone' : '1',
{ }],
'xcode_settings': {
'LD_RUNPATH_SEARCH_PATHS': ['@executable_path/.'],
},
}
}]
], ],
}, },
], ],
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <CoreServices/CoreServices.h> #include <CoreServices/CoreServices.h>
#include <mach/mach.h> #include <mach/mach.h>
#include <mach/mach_time.h> #include <mach/mach_time.h>
#include <iostream>
OSXTimer::OSXTimer() OSXTimer::OSXTimer()
: mRunning(false) : mRunning(false)
...@@ -35,16 +34,16 @@ double OSXTimer::getElapsedTime() const ...@@ -35,16 +34,16 @@ double OSXTimer::getElapsedTime() const
// If this is the first time we've run, get the timebase. // If this is the first time we've run, get the timebase.
// We can use denom == 0 to indicate that sTimebaseInfo is // We can use denom == 0 to indicate that sTimebaseInfo is
// uninitialised because it makes no sense to have a zero // uninitialised because it makes no sense to have a zero
// denominator is a fraction. // denominator in a fraction.
static mach_timebase_info_data_t timebaseInfo; static mach_timebase_info_data_t timebaseInfo;
static double secondCoeff;
if ( timebaseInfo.denom == 0 ) if ( timebaseInfo.denom == 0 )
{ {
mach_timebase_info(&timebaseInfo); mach_timebase_info(&timebaseInfo);
secondCoeff = timebaseInfo.numer * (1.0 / 1000000000) / timebaseInfo.denom;
} }
double secondCoeff = timebaseInfo.numer * (1.0 / 1000000000) / timebaseInfo.denom;
if (mRunning) if (mRunning)
{ {
return secondCoeff * (mach_absolute_time() - mStartTime); return secondCoeff * (mach_absolute_time() - mStartTime);
......
...@@ -85,7 +85,7 @@ static bool InitializeAppKit() ...@@ -85,7 +85,7 @@ static bool InitializeAppKit()
return true; return true;
} }
// NS's abd CG's coordinate system starts at the bottom left, while OSWindow's coordinate // NS's and CG's coordinate systems start at the bottom left, while OSWindow's coordinate
// system starts at the top left. This function converts the Y coordinate accordingly. // system starts at the top left. This function converts the Y coordinate accordingly.
static float YCoordToFromCG(float y) static float YCoordToFromCG(float y)
{ {
...@@ -546,11 +546,13 @@ bool OSXWindow::initialize(const std::string &name, size_t width, size_t height) ...@@ -546,11 +546,13 @@ bool OSXWindow::initialize(const std::string &name, size_t width, size_t height)
{ {
return false; return false;
} }
[mView setWantsLayer:YES];
[mWindow setContentView: mView]; [mWindow setContentView: mView];
[mWindow setTitle: [NSString stringWithUTF8String: name.c_str()]]; [mWindow setTitle: [NSString stringWithUTF8String: name.c_str()]];
[mWindow setAcceptsMouseMovedEvents: YES]; [mWindow setAcceptsMouseMovedEvents: YES];
[mWindow center]; [mWindow center];
[NSApp activateIgnoringOtherApps: YES]; [NSApp activateIgnoringOtherApps: YES];
mX = 0; mX = 0;
...@@ -576,15 +578,12 @@ void OSXWindow::destroy() ...@@ -576,15 +578,12 @@ void OSXWindow::destroy()
EGLNativeWindowType OSXWindow::getNativeWindow() const EGLNativeWindowType OSXWindow::getNativeWindow() const
{ {
//TODO(cwallez): implement it once we have defined what EGLNativeWindowType is return [mView layer];
UNIMPLEMENTED();
return static_cast<EGLNativeWindowType>(0);
} }
EGLNativeDisplayType OSXWindow::getNativeDisplay() const EGLNativeDisplayType OSXWindow::getNativeDisplay() const
{ {
//TODO(cwallez): implement it once we have defined what EGLNativeWindowType is // TODO(cwallez): implement it once we have defined what EGLNativeDisplayType is
UNIMPLEMENTED();
return static_cast<EGLNativeDisplayType>(0); return static_cast<EGLNativeDisplayType>(0);
} }
......
...@@ -135,9 +135,12 @@ ...@@ -135,9 +135,12 @@
], ],
'link_settings': 'link_settings':
{ {
# TODO(cwallez) Chromium uses an SDKROOT prefix, use it when we want to
# support compiling ANGLE in Chromium on Mac
'libraries': 'libraries':
[ [
'-framework AppKit', 'AppKit.framework',
'QuartzCore.framework',
], ],
}, },
}], }],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment