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;
#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 *EGLNativePixmapType;
typedef void *EGLNativeWindowType;
typedef CALayer *EGLNativeWindowType;
#else
#error "Platform not recognized"
......
......@@ -184,8 +184,7 @@ class TIntermLoop : public TIntermNode
TIntermLoop *getAsLoopNode() override { return this; }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(
TIntermNode *original, TIntermNode *replacement) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TLoopType getType() const { return mType; }
TIntermNode *getInit() { return mInit; }
......@@ -217,8 +216,7 @@ class TIntermBranch : public TIntermNode
mExpression(e) { }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(
TIntermNode *original, TIntermNode *replacement) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
TOperator getFlowOp() { return mFlowOp; }
TIntermTyped* getExpression() { return mExpression; }
......@@ -395,8 +393,7 @@ class TIntermBinary : public TIntermOperator
TIntermBinary *getAsBinaryNode() override { return this; };
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(
TIntermNode *original, TIntermNode *replacement) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
bool hasSideEffects() const override
{
......@@ -443,13 +440,9 @@ class TIntermUnary : public TIntermOperator
void traverse(TIntermTraverser *it) override;
TIntermUnary *getAsUnaryNode() override { return this; }
bool replaceChildNode(
TIntermNode *original, TIntermNode *replacement) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
bool hasSideEffects() const override
{
return isAssignment() || mOperand->hasSideEffects();
}
bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
void setOperand(TIntermTyped *operand) { mOperand = operand; }
TIntermTyped *getOperand() { return mOperand; }
......@@ -499,8 +492,7 @@ class TIntermAggregate : public TIntermOperator
TIntermAggregate *getAsAggregate() override { return this; }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(
TIntermNode *original, TIntermNode *replacement) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
bool replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements);
bool insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions);
// Conservatively assume function calls and other aggregate operators have side-effects
......@@ -568,8 +560,7 @@ class TIntermSelection : public TIntermTyped
TIntermTyped *deepCopy() const override { return new TIntermSelection(*this); }
void traverse(TIntermTraverser *it) override;
bool replaceChildNode(
TIntermNode *original, TIntermNode *replacement) override;
bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
// Conservatively assume selections have side-effects
bool hasSideEffects() const override { return true; }
......
......@@ -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()
{
mStateManager->deleteFramebuffer(mFramebufferID);
......
......@@ -21,6 +21,13 @@ class FramebufferGL : public FramebufferImpl
{
public:
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;
void onUpdateColorAttachment(size_t index) override;
......
......@@ -11,6 +11,9 @@
#include "libANGLE/renderer/gl/DisplayGL.h"
struct _CGLContextObject;
typedef _CGLContextObject *CGLContextObj;
namespace rx
{
......@@ -54,6 +57,8 @@ class DisplayCGL : public DisplayGL
void generateCaps(egl::Caps *outCaps) const override;
egl::Display *mEGLDisplay;
FunctionsGL *mFunctions;
CGLContextObj mContext;
};
}
......
......@@ -8,15 +8,42 @@
#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/WindowSurfaceCGL.h"
namespace
{
const char *kDefaultOpenGLDylibName =
"/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib";
const char *kFallbackOpenGLDylibName = "GL";
}
namespace rx
{
DisplayCGL::DisplayCGL()
: DisplayGL(),
mEGLDisplay(nullptr)
class FunctionsGLCGL : public FunctionsGL
{
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()
egl::Error DisplayCGL::initialize(egl::Display *display)
{
UNIMPLEMENTED();
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()
{
UNIMPLEMENTED();
DisplayGL::terminate();
if (mContext != nullptr)
{
CGLSetCurrentContext(nullptr);
CGLReleaseContext(mContext);
mContext = nullptr;
}
SafeDelete(mFunctions);
}
SurfaceImpl *DisplayCGL::createWindowSurface(const egl::Config *configuration,
EGLNativeWindowType window,
const egl::AttributeMap &attribs)
{
UNIMPLEMENTED();
return new WindowSurfaceCGL(this->getRenderer());
return new WindowSurfaceCGL(this->getRenderer(), window, mFunctions);
}
SurfaceImpl *DisplayCGL::createPbufferSurface(const egl::Config *configuration,
......@@ -76,20 +146,73 @@ egl::Error DisplayCGL::getDevice(DeviceImpl **device)
egl::ConfigSet DisplayCGL::generateConfigs() const
{
UNIMPLEMENTED();
// TODO(cwallez): generate more config permutations
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;
}
bool DisplayCGL::isDeviceLost() const
{
UNIMPLEMENTED();
// TODO(cwallez) investigate implementing this
return false;
}
bool DisplayCGL::testDeviceLost()
{
UNIMPLEMENTED();
// TODO(cwallez) investigate implementing this
return false;
}
......@@ -101,20 +224,19 @@ egl::Error DisplayCGL::restoreLostDevice()
bool DisplayCGL::isValidNativeWindow(EGLNativeWindowType window) const
{
UNIMPLEMENTED();
// TODO(cwallez) investigate implementing this
return true;
}
std::string DisplayCGL::getVendorString() const
{
UNIMPLEMENTED();
// TODO(cwallez) find a useful vendor string
return "";
}
const FunctionsGL *DisplayCGL::getFunctionsGL() const
{
UNIMPLEMENTED();
return nullptr;
return mFunctions;
}
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
{
UNIMPLEMENTED();
outCaps->textureNPOT = true;
}
}
......@@ -11,13 +11,24 @@
#include "libANGLE/renderer/gl/SurfaceGL.h"
@class CALayer;
struct __IOSurface;
typedef __IOSurface *IOSurfaceRef;
namespace rx
{
class DisplayCGL;
class FramebufferGL;
class FunctionsGL;
class StateManagerGL;
class DisplayLink;
class WindowSurfaceCGL : public SurfaceGL
{
public:
WindowSurfaceCGL(RendererGL *renderer);
WindowSurfaceCGL(RendererGL *renderer, CALayer *layer, const FunctionsGL *functions);
~WindowSurfaceCGL() override;
egl::Error initialize() override;
......@@ -35,6 +46,31 @@ class WindowSurfaceCGL : public SurfaceGL
EGLint isPostSubBufferSupported() 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 @@
[
'<@(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 @@
}
},
}],
['OS == "mac"',
['angle_build_winphone==1',
{
'all_dependent_settings':
{
'xcode_settings': {
'LD_RUNPATH_SEARCH_PATHS': ['@executable_path/.'],
},
}
}]
'msvs_enable_winphone' : '1',
}],
],
},
],
......
......@@ -11,7 +11,6 @@
#include <CoreServices/CoreServices.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <iostream>
OSXTimer::OSXTimer()
: mRunning(false)
......@@ -35,16 +34,16 @@ double OSXTimer::getElapsedTime() const
// If this is the first time we've run, get the timebase.
// We can use denom == 0 to indicate that sTimebaseInfo is
// 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 double secondCoeff;
if ( timebaseInfo.denom == 0 )
{
mach_timebase_info(&timebaseInfo);
secondCoeff = timebaseInfo.numer * (1.0 / 1000000000) / timebaseInfo.denom;
}
double secondCoeff = timebaseInfo.numer * (1.0 / 1000000000) / timebaseInfo.denom;
if (mRunning)
{
return secondCoeff * (mach_absolute_time() - mStartTime);
......
......@@ -85,7 +85,7 @@ static bool InitializeAppKit()
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.
static float YCoordToFromCG(float y)
{
......@@ -546,11 +546,13 @@ bool OSXWindow::initialize(const std::string &name, size_t width, size_t height)
{
return false;
}
[mView setWantsLayer:YES];
[mWindow setContentView: mView];
[mWindow setTitle: [NSString stringWithUTF8String: name.c_str()]];
[mWindow setAcceptsMouseMovedEvents: YES];
[mWindow center];
[NSApp activateIgnoringOtherApps: YES];
mX = 0;
......@@ -576,15 +578,12 @@ void OSXWindow::destroy()
EGLNativeWindowType OSXWindow::getNativeWindow() const
{
//TODO(cwallez): implement it once we have defined what EGLNativeWindowType is
UNIMPLEMENTED();
return static_cast<EGLNativeWindowType>(0);
return [mView layer];
}
EGLNativeDisplayType OSXWindow::getNativeDisplay() const
{
//TODO(cwallez): implement it once we have defined what EGLNativeWindowType is
UNIMPLEMENTED();
// TODO(cwallez): implement it once we have defined what EGLNativeDisplayType is
return static_cast<EGLNativeDisplayType>(0);
}
......
......@@ -135,9 +135,12 @@
],
'link_settings':
{
# TODO(cwallez) Chromium uses an SDKROOT prefix, use it when we want to
# support compiling ANGLE in Chromium on Mac
'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