Commit 12ce8f68 by Kenneth Russell Committed by Commit Bot

Upstream WebKit's iOS port of ANGLE.

Added the EAGL backend authored by Dean Jackson from Apple, and the refactoring changes needed to support it side-by-side with the macOS backend. Ran "git cl format" against these diffs. Defined the EGL_ANGLE_device_eagl extension and allocated an enum out of ANGLE's reserved range. The iOS backend is not yet included in any of the GN files. Bug: angleproject:4263 Change-Id: I631c32930433c03bb16a242955ffedf55174bb29 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1987278Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJames Darpinian <jdarpinian@chromium.org> Commit-Queue: Kenneth Russell <kbr@chromium.org>
parent 7a37d3ac
Name
ANGLE_device_eagl
Name Strings
EGL_ANGLE_device_eagl
Contributors
Dean Jackson (dino 'at' apple.com)
Ken Russell (kbr 'at' google.com)
Contact
Ken Russell (kbr 'at' google.com)
Status
Draft
Version
Version 1, January 3, 2020
Number
EGL Extension #XXX
Extension Type
EGL device extension
Dependencies
This extension is written against the language of EGL 1.5 as
modified by EGL_EXT_device_query.
EGL_EXT_device_query is required.
Overview
ANGLE on iOS internally uses an OpenGL ES context allocated via EAGL.
This extension defines a mapping from an EGL device to the underlying
EAGLContext, after it's been queried from an EGL display.
IP Status
No known claims.
New Types
None.
New Procedures and Functions
None.
New Tokens
Accepted as a queried <attribute> in eglQueryDeviceAttribEXT:
EGL_EAGL_CONTEXT_ANGLE 0x348C
Add a new section 2.1.3 (EAGL Devices) after 2.1.2 (Devices)
On iOS the underlying EAGLContext can be queried from the EGL device. The
intented purpose is to allow applications to create new EAGLContexts which
share resources with this one.
Changes to section 3.2 (Devices)
Replace the paragraph immediately following the prototype for
eglQueryDeviceAttribEXT:
<attribute> must be EGL_EAGL_CONTEXT_ANGLE. On success, EGL_TRUE is
returned, and a valid EAGLContext corresponding to the EGL device is
returned in <value>. This object is compatible with OpenGL ES and EAGL API
functions. If the EGL device is not currently associated with an
EAGLContext, EGL_BAD_ATTRIBUTE is returned, and <value> is left unchanged.
Issues
None
Revision History
Version 1, January 3, 2020 (Ken Russell)
- Initial Draft
......@@ -274,6 +274,11 @@ EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithFrameTokenANGLE(EGLDisplay dpy,
#endif
#endif /* EGL_ANGLE_swap_with_frame_token */
#ifndef EGL_ANGLE_device_eagl
#define EGL_ANGLE_device_eagl 1
#define EGL_EAGL_CONTEXT_ANGLE 0x348C
#endif
// clang-format on
#endif // INCLUDE_EGL_EGLEXT_ANGLE_
......@@ -185,6 +185,7 @@ IGNORED_INCLUDES = {
b'libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h',
b'libANGLE/renderer/gl/glx/DisplayGLX.h',
b'libANGLE/renderer/gl/cgl/DisplayCGL.h',
b'libANGLE/renderer/gl/eagl/DisplayEAGL.h',
b'libANGLE/renderer/gl/egl/ozone/DisplayOzone.h',
b'libANGLE/renderer/gl/egl/android/DisplayAndroid.h',
b'libANGLE/renderer/gl/wgl/DisplayWGL.h',
......
......@@ -118,8 +118,15 @@
# include <TargetConditionals.h>
# if TARGET_OS_OSX
# define ANGLE_PLATFORM_MACOS 1
# elif TARGET_OS_IOS
# elif TARGET_OS_IPHONE
# define ANGLE_PLATFORM_IOS 1
# define GLES_SILENCE_DEPRECATION
# if TARGET_OS_SIMULATOR
# define ANGLE_PLATFORM_IOS_SIMULATOR 1
# endif
# if TARGET_OS_MACCATALYST
# define ANGLE_PLATFORM_MACCATALYST
# endif
# endif
#endif
......
//
// Copyright 2020 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.
//
// SystemInfo_ios.cpp: implementation of the iOS-specific parts of SystemInfo.h
#include "common/platform.h"
#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
# include "gpu_info_util/SystemInfo_internal.h"
namespace angle
{
bool GetSystemInfo(SystemInfo *info)
{
{
// TODO(anglebug.com/4275): Get the actual system version.
info->machineModelVersion = "0.0";
}
return true;
}
} // namespace angle
#endif // defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
......@@ -4,11 +4,11 @@
// found in the LICENSE file.
//
// SystemInfo_mac.mm: implementation of the Mac-specific parts of SystemInfo.h
// SystemInfo_macos.mm: implementation of the macOS-specific parts of SystemInfo.h
#include "common/platform.h"
#ifdef ANGLE_PLATFORM_MACOS
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
# include "gpu_info_util/SystemInfo_internal.h"
......@@ -244,4 +244,4 @@ bool GetSystemInfo(SystemInfo *info)
} // namespace angle
#endif // ANGLE_PLATFORM_MACOS
#endif // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
......@@ -1007,6 +1007,9 @@ struct DeviceExtensions
// EGL_ANGLE_device_cgl
bool deviceCGL = false;
// EGL_ANGLE_device_eagl
bool deviceEAGL = false;
};
struct ClientExtensions
......
......@@ -52,8 +52,10 @@
# include "libANGLE/renderer/gl/wgl/DisplayWGL.h"
# elif defined(ANGLE_USE_X11)
# include "libANGLE/renderer/gl/glx/DisplayGLX.h"
# elif defined(ANGLE_PLATFORM_APPLE)
# elif defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
# include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
# elif defined(ANGLE_PLATFORM_IOS)
# include "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
# elif defined(ANGLE_USE_OZONE)
# include "libANGLE/renderer/gl/egl/ozone/DisplayOzone.h"
# elif defined(ANGLE_PLATFORM_ANDROID)
......@@ -241,8 +243,10 @@ rx::DisplayImpl *CreateDisplayFromAttribs(EGLAttrib displayType, const DisplaySt
impl = new rx::DisplayWGL(state);
# elif defined(ANGLE_USE_X11)
impl = new rx::DisplayGLX(state);
# elif defined(ANGLE_PLATFORM_APPLE)
# elif defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
impl = new rx::DisplayCGL(state);
# elif defined(ANGLE_PLATFORM_IOS)
impl = new rx::DisplayEAGL(state);
# elif defined(ANGLE_USE_OZONE)
// This might work but has never been tried, so disallow for now.
impl = nullptr;
......
......@@ -1008,7 +1008,11 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
AddRGBAFormat(&map, GL_RGBA, false, 8, 8, 8, 8, 0, GL_RGBA, GL_BYTE, GL_SIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported, NeverSupported);
AddRGBAFormat(&map, GL_SRGB, false, 8, 8, 8, 0, 0, GL_SRGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireExt<&Extensions::sRGB>, AlwaysSupported, NeverSupported, NeverSupported);
AddRGBAFormat(&map, GL_SRGB_ALPHA_EXT, false, 8, 8, 8, 8, 0, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireExt<&Extensions::sRGB>, AlwaysSupported, RequireExt<&Extensions::sRGB>, NeverSupported);
#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
AddRGBAFormat(&map, GL_BGRA_EXT, false, 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireES<2, 0>, AlwaysSupported, RequireES<2, 0>, NeverSupported);
#else
AddRGBAFormat(&map, GL_BGRA_EXT, false, 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported, RequireExt<&Extensions::textureFormatBGRA8888>, NeverSupported);
#endif
// Unsized integer formats
// |Internal format |sized | R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Filterable | Texture attachment | Renderbuffer |
......
......@@ -8,7 +8,7 @@
#include "common/platform.h"
#ifdef ANGLE_PLATFORM_MACOS
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
# include "libANGLE/renderer/gl/cgl/DeviceCGL.h"
......@@ -58,4 +58,4 @@ void DeviceCGL::generateExtensions(egl::DeviceExtensions *outExtensions) const
} // namespace rx
#endif // ANGLE_PLATFORM_MACOS
#endif // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
......@@ -8,7 +8,7 @@
#include "common/platform.h"
#ifdef ANGLE_PLATFORM_MACOS
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
# include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
......@@ -82,10 +82,7 @@ egl::Error DisplayCGL::initialize(egl::Display *display)
std::vector<CGLPixelFormatAttribute> attribs;
attribs.push_back(kCGLPFAOpenGLProfile);
attribs.push_back(static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core));
if (mSupportsGPUSwitching)
{
attribs.push_back(kCGLPFAAllowOfflineRenderers);
}
attribs.push_back(kCGLPFAAllowOfflineRenderers);
attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
GLint nVirtualScreens = 0;
CGLChoosePixelFormat(attribs.data(), &mPixelFormat, &nVirtualScreens);
......@@ -295,7 +292,7 @@ egl::Error DisplayCGL::restoreLostDevice(const egl::Display *display)
bool DisplayCGL::isValidNativeWindow(EGLNativeWindowType window) const
{
NSObject *layer = reinterpret_cast<NSObject *>(window);
NSObject *layer = (__bridge NSObject *)window;
return [layer isKindOfClass:[CALayer class]];
}
......@@ -448,4 +445,4 @@ void DisplayCGL::populateFeatureList(angle::FeatureList *features)
}
}
#endif // ANGLE_PLATFORM_MACOS
#endif // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
......@@ -9,7 +9,7 @@
#include "common/platform.h"
#ifdef ANGLE_PLATFORM_MACOS
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
# include "libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.h"
......@@ -335,4 +335,4 @@ bool IOSurfaceSurfaceCGL::hasEmulatedAlphaChannel() const
} // namespace rx
#endif // ANGLE_PLATFORM_MACOS
#endif // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
......@@ -9,9 +9,7 @@
#include "libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h"
#include "common/platform.h"
#ifdef ANGLE_PLATFORM_MACOS
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
# include "common/debug.h"
# include "libANGLE/renderer/gl/FramebufferGL.h"
......@@ -143,4 +141,4 @@ FramebufferImpl *PbufferSurfaceCGL::createDefaultFramebuffer(const gl::Context *
} // namespace rx
#endif // ANGLE_PLATFORM_MACOS
#endif // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
......@@ -8,9 +8,7 @@
#include "libANGLE/renderer/gl/cgl/RendererCGL.h"
#include "common/platform.h"
#ifdef ANGLE_PLATFORM_MACOS
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
# include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
......@@ -32,4 +30,4 @@ WorkerContext *RendererCGL::createWorkerContext(std::string *infoLog)
} // namespace rx
#endif // ANGLE_PLATFORM_MACOS
#endif // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
......@@ -8,7 +8,7 @@
#include "common/platform.h"
#ifdef ANGLE_PLATFORM_MACOS
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
# include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h"
......@@ -153,7 +153,7 @@ WindowSurfaceCGL::WindowSurfaceCGL(const egl::SurfaceState &state,
: SurfaceGL(state),
mSwapLayer(nil),
mCurrentSwapId(0),
mLayer(reinterpret_cast<CALayer *>(layer)),
mLayer((__bridge CALayer *)layer),
mContext(context),
mFunctions(renderer->getFunctions()),
mStateManager(renderer->getStateManager()),
......@@ -339,4 +339,4 @@ FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::Context *c
} // namespace rx
#endif // ANGLE_PLATFORM_MACOS
#endif // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
//
// Copyright 2020 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.
//
// ContextEAGL:
// iOS-specific subclass of ContextGL.
//
#include "libANGLE/renderer/gl/eagl/ContextEAGL.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
namespace rx
{
ContextEAGL::ContextEAGL(const gl::State &state,
gl::ErrorSet *errorSet,
const std::shared_ptr<RendererGL> &renderer)
: ContextGL(state, errorSet, renderer)
{}
} // namespace rx
//
// Copyright 2020 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.
//
// ContextEAGL:
// iOS-specific subclass of ContextGL.
//
#ifndef LIBANGLE_RENDERER_GL_EAGL_CONTEXTEAGL_H_
#define LIBANGLE_RENDERER_GL_EAGL_CONTEXTEAGL_H_
#include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/RendererGL.h"
namespace rx
{
class ContextEAGL : public ContextGL
{
public:
ContextEAGL(const gl::State &state,
gl::ErrorSet *errorSet,
const std::shared_ptr<RendererGL> &renderer);
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_EAGL_CONTEXTEAGL_H_
//
// Copyright 2020 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.
//
// DeviceEAGL.cpp: EAGL implementation of egl::Device
#import "common/platform.h"
#if defined(ANGLE_PLATFORM_IOS)
# include "libANGLE/renderer/gl/eagl/DeviceEAGL.h"
# include "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
# include <EGL/eglext.h>
namespace rx
{
DeviceEAGL::DeviceEAGL() {}
DeviceEAGL::~DeviceEAGL() {}
egl::Error DeviceEAGL::initialize()
{
return egl::NoError();
}
egl::Error DeviceEAGL::getAttribute(const egl::Display *display, EGLint attribute, void **outValue)
{
DisplayEAGL *displayImpl = GetImplAs<DisplayEAGL>(display);
switch (attribute)
{
case EGL_EAGL_CONTEXT_ANGLE:
*outValue = displayImpl->getEAGLContext();
break;
default:
return egl::EglBadAttribute();
}
return egl::NoError();
}
EGLint DeviceEAGL::getType()
{
return 0;
}
void DeviceEAGL::generateExtensions(egl::DeviceExtensions *outExtensions) const
{
outExtensions->deviceEAGL = true;
}
} // namespace rx
#endif // defined(ANGLE_PLATFORM_IOS)
//
// Copyright 2020 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.
//
// DeviceEAGL.h: EAGL implementation of egl::Device
#ifndef LIBANGLE_RENDERER_GL_EAGL_DEVICEEAGL_H_
#define LIBANGLE_RENDERER_GL_EAGL_DEVICEEAGL_H_
#include "libANGLE/Device.h"
#include "libANGLE/renderer/DeviceImpl.h"
namespace rx
{
class DeviceEAGL : public DeviceImpl
{
public:
DeviceEAGL();
~DeviceEAGL() override;
egl::Error initialize() override;
egl::Error getAttribute(const egl::Display *display,
EGLint attribute,
void **outValue) override;
EGLint getType() override;
void generateExtensions(egl::DeviceExtensions *outExtensions) const override;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_EAGL_DEVICEEAGL_H_
//
// Copyright 2020 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.
//
// DisplayEAGL.h: EAGL implementation of egl::Display
#ifndef LIBANGLE_RENDERER_GL_EAGL_DISPLAYEAGL_H_
#define LIBANGLE_RENDERER_GL_EAGL_DISPLAYEAGL_H_
#include "libANGLE/renderer/gl/DisplayGL.h"
#ifdef __OBJC__
@class EAGLContext;
typedef EAGLContext *EAGLContextObj;
#else
typedef void *EAGLContextObj;
#endif
namespace rx
{
class WorkerContext;
class DisplayEAGL : public DisplayGL
{
public:
DisplayEAGL(const egl::DisplayState &state);
~DisplayEAGL() override;
egl::Error initialize(egl::Display *display) override;
void terminate() override;
SurfaceImpl *createWindowSurface(const egl::SurfaceState &state,
EGLNativeWindowType window,
const egl::AttributeMap &attribs) override;
SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state,
const egl::AttributeMap &attribs) override;
SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) override;
SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state,
NativePixmapType nativePixmap,
const egl::AttributeMap &attribs) override;
ContextImpl *createContext(const gl::State &state,
gl::ErrorSet *errorSet,
const egl::Config *configuration,
const gl::Context *shareContext,
const egl::AttributeMap &attribs) override;
egl::ConfigSet generateConfigs() override;
bool testDeviceLost() override;
egl::Error restoreLostDevice(const egl::Display *display) override;
bool isValidNativeWindow(EGLNativeWindowType window) const override;
egl::Error validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const override;
DeviceImpl *createDevice() override;
std::string getVendorString() const override;
egl::Error waitClient(const gl::Context *context) override;
egl::Error waitNative(const gl::Context *context, EGLint engine) override;
gl::Version getMaxSupportedESVersion() const override;
EAGLContextObj getEAGLContext() const;
WorkerContext *createWorkerContext(std::string *infoLog);
void initializeFrontendFeatures(angle::FrontendFeatures *features) const override;
void populateFeatureList(angle::FeatureList *features) override;
private:
egl::Error makeCurrentSurfaceless(gl::Context *context) override;
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
void generateCaps(egl::Caps *outCaps) const override;
std::shared_ptr<RendererGL> mRenderer;
egl::Display *mEGLDisplay;
EAGLContextObj mContext;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_EAGL_DISPLAYEAGL_H_
//
// Copyright 2020 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.
//
// DisplayEAGL.cpp: EAGL implementation of egl::Display
#import "common/platform.h"
#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
# import "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
# import "common/debug.h"
# import "gpu_info_util/SystemInfo.h"
# import "libANGLE/Display.h"
# import "libANGLE/renderer/gl/eagl/ContextEAGL.h"
# import "libANGLE/renderer/gl/eagl/DeviceEAGL.h"
# import "libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.h"
# import "libANGLE/renderer/gl/eagl/PbufferSurfaceEAGL.h"
# import "libANGLE/renderer/gl/eagl/RendererEAGL.h"
# import "libANGLE/renderer/gl/eagl/WindowSurfaceEAGL.h"
# import <Foundation/Foundation.h>
# import <OpenGLES/EAGL.h>
# import <QuartzCore/QuartzCore.h>
# import <dlfcn.h>
# define GLES_SILENCE_DEPRECATION
# if !defined(ANGLE_PLATFORM_IOS_SIMULATOR)
namespace
{
const char *kOpenGLESDylibName = "/System/Library/Frameworks/OpenGLES.framework/OpenGLES";
}
# endif
namespace rx
{
class FunctionsGLEAGL : public FunctionsGL
{
public:
FunctionsGLEAGL(void *dylibHandle) : mDylibHandle(dylibHandle) {}
~FunctionsGLEAGL() override { dlclose(mDylibHandle); }
private:
void *loadProcAddress(const std::string &function) const override
{
return dlsym(mDylibHandle, function.c_str());
}
void *mDylibHandle;
};
DisplayEAGL::DisplayEAGL(const egl::DisplayState &state)
: DisplayGL(state), mEGLDisplay(nullptr), mContext(nullptr)
{}
DisplayEAGL::~DisplayEAGL() {}
egl::Error DisplayEAGL::initialize(egl::Display *display)
{
mEGLDisplay = display;
# if defined(ANGLE_PLATFORM_IOS_SIMULATOR)
return egl::EglNotInitialized()
<< "ANGLE with EAGL not supported on iOS Simulator due to lack of IOSurface support.";
# else
angle::SystemInfo info;
if (!angle::GetSystemInfo(&info))
{
return egl::EglNotInitialized() << "Unable to query ANGLE's SystemInfo.";
}
mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if (mContext == nullptr)
{
return egl::EglNotInitialized() << "Could not create the EAGL context.";
}
[EAGLContext setCurrentContext:mContext];
// There is no equivalent getProcAddress in EAGL so we open the dylib directly
void *handle = dlopen(kOpenGLESDylibName, RTLD_NOW);
if (!handle)
{
return egl::EglNotInitialized() << "Could not open the OpenGLES Framework.";
}
std::unique_ptr<FunctionsGL> functionsGL(new FunctionsGLEAGL(handle));
functionsGL->initialize(display->getAttributeMap());
mRenderer.reset(new RendererEAGL(std::move(functionsGL), display->getAttributeMap(), this));
const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
if (maxVersion < gl::Version(2, 0))
{
return egl::EglNotInitialized() << "OpenGL ES 2.0 is not supportable.";
}
return DisplayGL::initialize(display);
# endif
}
void DisplayEAGL::terminate()
{
DisplayGL::terminate();
mRenderer.reset();
if (mContext != nullptr)
{
[EAGLContext setCurrentContext:nil];
mContext = nullptr;
}
}
SurfaceImpl *DisplayEAGL::createWindowSurface(const egl::SurfaceState &state,
EGLNativeWindowType window,
const egl::AttributeMap &attribs)
{
return new WindowSurfaceEAGL(state, mRenderer.get(), window, mContext);
}
SurfaceImpl *DisplayEAGL::createPbufferSurface(const egl::SurfaceState &state,
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 PbufferSurfaceEAGL(state, mRenderer.get(), width, height);
}
SurfaceImpl *DisplayEAGL::createPbufferFromClientBuffer(const egl::SurfaceState &state,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs)
{
ASSERT(buftype == EGL_IOSURFACE_ANGLE);
return new IOSurfaceSurfaceEAGL(state, mContext, clientBuffer, attribs);
}
SurfaceImpl *DisplayEAGL::createPixmapSurface(const egl::SurfaceState &state,
NativePixmapType nativePixmap,
const egl::AttributeMap &attribs)
{
UNIMPLEMENTED();
return nullptr;
}
ContextImpl *DisplayEAGL::createContext(const gl::State &state,
gl::ErrorSet *errorSet,
const egl::Config *configuration,
const gl::Context *shareContext,
const egl::AttributeMap &attribs)
{
return new ContextEAGL(state, errorSet, mRenderer);
}
DeviceImpl *DisplayEAGL::createDevice()
{
return new DeviceEAGL();
}
egl::ConfigSet DisplayEAGL::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;
config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
configs.add(config);
return configs;
}
bool DisplayEAGL::testDeviceLost()
{
// TODO(cwallez) investigate implementing this
return false;
}
egl::Error DisplayEAGL::restoreLostDevice(const egl::Display *display)
{
UNIMPLEMENTED();
return egl::EglBadDisplay();
}
bool DisplayEAGL::isValidNativeWindow(EGLNativeWindowType window) const
{
NSObject *layer = (__bridge NSObject *)window;
return [layer isKindOfClass:[CALayer class]];
}
egl::Error DisplayEAGL::validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const
{
ASSERT(buftype == EGL_IOSURFACE_ANGLE);
if (!IOSurfaceSurfaceEAGL::validateAttributes(clientBuffer, attribs))
{
return egl::EglBadAttribute();
}
return egl::NoError();
}
std::string DisplayEAGL::getVendorString() const
{
// TODO(cwallez) find a useful vendor string
return "";
}
EAGLContextObj DisplayEAGL::getEAGLContext() const
{
return mContext;
}
void DisplayEAGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
outExtensions->iosurfaceClientBuffer = true;
outExtensions->surfacelessContext = true;
outExtensions->deviceQuery = true;
// Contexts are virtualized so textures can be shared globally
outExtensions->displayTextureShareGroup = true;
outExtensions->powerPreference = false;
DisplayGL::generateExtensions(outExtensions);
}
void DisplayEAGL::generateCaps(egl::Caps *outCaps) const
{
outCaps->textureNPOT = true;
}
egl::Error DisplayEAGL::waitClient(const gl::Context *context)
{
// TODO(cwallez) UNIMPLEMENTED()
return egl::NoError();
}
egl::Error DisplayEAGL::waitNative(const gl::Context *context, EGLint engine)
{
// TODO(cwallez) UNIMPLEMENTED()
return egl::NoError();
}
gl::Version DisplayEAGL::getMaxSupportedESVersion() const
{
return mRenderer->getMaxSupportedESVersion();
}
egl::Error DisplayEAGL::makeCurrentSurfaceless(gl::Context *context)
{
// We have nothing to do as mContext is always current, and that EAGL is surfaceless by
// default.
return egl::NoError();
}
class WorkerContextEAGL final : public WorkerContext
{
public:
WorkerContextEAGL(EAGLContextObj context);
~WorkerContextEAGL() override;
bool makeCurrent() override;
void unmakeCurrent() override;
private:
EAGLContextObj mContext;
};
WorkerContextEAGL::WorkerContextEAGL(EAGLContextObj context) : mContext(context) {}
WorkerContextEAGL::~WorkerContextEAGL()
{
[EAGLContext setCurrentContext:nil];
mContext = nullptr;
}
bool WorkerContextEAGL::makeCurrent()
{
if (![EAGLContext setCurrentContext:static_cast<EAGLContext *>(mContext)])
{
ERR() << "Unable to make gl context current.";
return false;
}
return true;
}
void WorkerContextEAGL::unmakeCurrent()
{
[EAGLContext setCurrentContext:nil];
}
WorkerContext *DisplayEAGL::createWorkerContext(std::string *infoLog)
{
EAGLContextObj context = nullptr;
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if (!context)
{
*infoLog += "Could not create the EAGL context.";
return nullptr;
}
return new WorkerContextEAGL(context);
}
void DisplayEAGL::initializeFrontendFeatures(angle::FrontendFeatures *features) const
{
mRenderer->initializeFrontendFeatures(features);
}
void DisplayEAGL::populateFeatureList(angle::FeatureList *features)
{
mRenderer->getFeatures().populateFeatureList(features);
}
}
#endif // defined(ANGLE_PLATFORM_IOS)
//
// Copyright 2020 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.
//
#ifndef LIBANGLE_RENDERER_GL_EAGL_IOSURFACESURFACEEAGL_H_
#define LIBANGLE_RENDERER_GL_EAGL_IOSURFACESURFACEEAGL_H_
#include "libANGLE/renderer/gl/SurfaceGL.h"
#include "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
struct __IOSurface;
typedef __IOSurface *IOSurfaceRef;
namespace egl
{
class AttributeMap;
} // namespace egl
namespace rx
{
class DisplayEAGL;
class FunctionsGL;
class StateManagerGL;
class IOSurfaceSurfaceEAGL : public SurfaceGL
{
public:
IOSurfaceSurfaceEAGL(const egl::SurfaceState &state,
EAGLContextObj cglContext,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs);
~IOSurfaceSurfaceEAGL() override;
egl::Error initialize(const egl::Display *display) override;
egl::Error makeCurrent(const gl::Context *context) override;
egl::Error unMakeCurrent(const gl::Context *context) override;
egl::Error swap(const gl::Context *context) override;
egl::Error postSubBuffer(const gl::Context *context,
EGLint x,
EGLint y,
EGLint width,
EGLint height) override;
egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
egl::Error bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer) override;
egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
void setSwapInterval(EGLint interval) override;
EGLint getWidth() const override;
EGLint getHeight() const override;
EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override;
static bool validateAttributes(EGLClientBuffer buffer, const egl::AttributeMap &attribs);
FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state) override;
bool hasEmulatedAlphaChannel() const override;
private:
angle::Result initializeAlphaChannel(const gl::Context *context, GLuint texture);
EAGLContextObj mEAGLContext;
IOSurfaceRef mIOSurface;
int mWidth;
int mHeight;
int mPlane;
int mFormatIndex;
bool mAlphaInitialized;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_EAGL_IOSURFACESURFACEEAGL_H_
//
// Copyright 2020 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.
//
// IOSurfaceSurfaceEAGL.mm: an implementation of PBuffers created from IOSurfaces using
// EGL_ANGLE_iosurface_client_buffer
#import "common/platform.h"
#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
# import "libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.h"
# import "common/debug.h"
# import "libANGLE/AttributeMap.h"
# import "libANGLE/renderer/gl/BlitGL.h"
# import "libANGLE/renderer/gl/FramebufferGL.h"
# import "libANGLE/renderer/gl/FunctionsGL.h"
# import "libANGLE/renderer/gl/RendererGL.h"
# import "libANGLE/renderer/gl/StateManagerGL.h"
# import "libANGLE/renderer/gl/TextureGL.h"
# import "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
# import <OpenGLES/EAGL.h>
# import <OpenGLES/EAGLDrawable.h>
# import <OpenGLES/EAGLIOSurface.h>
namespace rx
{
namespace
{
struct IOSurfaceFormatInfo
{
GLenum internalFormat;
GLenum type;
size_t componentBytes;
GLenum nativeInternalFormat;
GLenum nativeFormat;
GLenum nativeType;
};
// clang-format off
static const IOSurfaceFormatInfo kIOSurfaceFormats[] = {
{GL_RED, GL_UNSIGNED_BYTE, 1, GL_RED, GL_RED, GL_UNSIGNED_BYTE },
{GL_R16UI, GL_UNSIGNED_SHORT, 2, GL_RED, GL_RED, GL_UNSIGNED_SHORT},
{GL_RG, GL_UNSIGNED_BYTE, 2, GL_RG, GL_RG, GL_UNSIGNED_BYTE },
{GL_RGB, GL_UNSIGNED_BYTE, 4, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE },
{GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE },
{GL_RGBA, GL_HALF_FLOAT, 8, GL_RGBA, GL_RGBA, GL_HALF_FLOAT },
};
// clang-format on
int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
{
for (int i = 0; i < static_cast<int>(ArraySize(kIOSurfaceFormats)); ++i)
{
const auto &formatInfo = kIOSurfaceFormats[i];
if (formatInfo.internalFormat == internalFormat && formatInfo.type == type)
{
return i;
}
}
return -1;
}
} // anonymous namespace
IOSurfaceSurfaceEAGL::IOSurfaceSurfaceEAGL(const egl::SurfaceState &state,
EAGLContextObj cglContext,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
: SurfaceGL(state),
mEAGLContext(cglContext),
mIOSurface(nullptr),
mWidth(0),
mHeight(0),
mPlane(0),
mFormatIndex(-1),
mAlphaInitialized(false)
{
// Keep reference to the IOSurface so it doesn't get deleted while the pbuffer exists.
mIOSurface = reinterpret_cast<IOSurfaceRef>(buffer);
CFRetain(mIOSurface);
// Extract attribs useful for the call to EAGLTexImageIOSurface2D
mWidth = static_cast<int>(attribs.get(EGL_WIDTH));
mHeight = static_cast<int>(attribs.get(EGL_HEIGHT));
mPlane = static_cast<int>(attribs.get(EGL_IOSURFACE_PLANE_ANGLE));
EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
EGLAttrib type = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
mFormatIndex =
FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
ASSERT(mFormatIndex >= 0);
mAlphaInitialized = !hasEmulatedAlphaChannel();
}
IOSurfaceSurfaceEAGL::~IOSurfaceSurfaceEAGL()
{
if (mIOSurface != nullptr)
{
CFRelease(mIOSurface);
mIOSurface = nullptr;
}
}
egl::Error IOSurfaceSurfaceEAGL::initialize(const egl::Display *display)
{
return egl::NoError();
}
egl::Error IOSurfaceSurfaceEAGL::makeCurrent(const gl::Context *context)
{
return egl::NoError();
}
egl::Error IOSurfaceSurfaceEAGL::unMakeCurrent(const gl::Context *context)
{
GetFunctionsGL(context)->flush();
return egl::NoError();
}
egl::Error IOSurfaceSurfaceEAGL::swap(const gl::Context *context)
{
return egl::NoError();
}
egl::Error IOSurfaceSurfaceEAGL::postSubBuffer(const gl::Context *context,
EGLint x,
EGLint y,
EGLint width,
EGLint height)
{
UNREACHABLE();
return egl::NoError();
}
egl::Error IOSurfaceSurfaceEAGL::querySurfacePointerANGLE(EGLint attribute, void **value)
{
UNREACHABLE();
return egl::NoError();
}
egl::Error IOSurfaceSurfaceEAGL::bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint)
{
# if !defined(ANGLE_PLATFORM_IOS_SIMULATOR)
StateManagerGL *stateManager = GetStateManagerGL(context);
const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
GLuint textureID = textureGL->getTextureID();
stateManager->bindTexture(gl::TextureType::_2D, textureID);
const auto &format = kIOSurfaceFormats[mFormatIndex];
if (![mEAGLContext texImageIOSurface:mIOSurface
target:GL_TEXTURE_2D
internalFormat:format.nativeInternalFormat
width:mWidth
height:mHeight
format:format.nativeFormat
type:format.nativeType
plane:mPlane])
{
return egl::EglContextLost() << "EAGLContext texImageIOSurface2D failed.";
}
if (IsError(initializeAlphaChannel(context, textureID)))
{
return egl::EglContextLost() << "Failed to initialize IOSurface alpha channel.";
}
return egl::NoError();
# else
return egl::EglContextLost() << "EAGLContext IOSurface not supported in the simulator.";
# endif
}
egl::Error IOSurfaceSurfaceEAGL::releaseTexImage(const gl::Context *context, EGLint buffer)
{
const FunctionsGL *functions = GetFunctionsGL(context);
functions->flush();
return egl::NoError();
}
void IOSurfaceSurfaceEAGL::setSwapInterval(EGLint interval)
{
UNREACHABLE();
}
EGLint IOSurfaceSurfaceEAGL::getWidth() const
{
return mWidth;
}
EGLint IOSurfaceSurfaceEAGL::getHeight() const
{
return mHeight;
}
EGLint IOSurfaceSurfaceEAGL::isPostSubBufferSupported() const
{
UNREACHABLE();
return EGL_FALSE;
}
EGLint IOSurfaceSurfaceEAGL::getSwapBehavior() const
{
// N/A because you can't MakeCurrent an IOSurface, return any valid value.
return EGL_BUFFER_PRESERVED;
}
// static
bool IOSurfaceSurfaceEAGL::validateAttributes(EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
{
# if !defined(ANGLE_PLATFORM_IOS_SIMULATOR)
IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(buffer);
// The plane must exist for this IOSurface. IOSurfaceGetPlaneCount can return 0 for non-planar
// ioSurfaces but we will treat non-planar like it is a single plane.
size_t surfacePlaneCount = std::max(size_t(1), IOSurfaceGetPlaneCount(ioSurface));
EGLAttrib plane = attribs.get(EGL_IOSURFACE_PLANE_ANGLE);
if (plane < 0 || static_cast<size_t>(plane) >= surfacePlaneCount)
{
return false;
}
// The width height specified must be at least (1, 1) and at most the plane size
EGLAttrib width = attribs.get(EGL_WIDTH);
EGLAttrib height = attribs.get(EGL_HEIGHT);
if (width <= 0 || static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, plane) ||
height <= 0 || static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, plane))
{
return false;
}
// Find this IOSurface format
EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
EGLAttrib type = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
int formatIndex =
FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
if (formatIndex < 0)
{
return false;
}
// Check that the format matches this IOSurface plane
if (IOSurfaceGetBytesPerElementOfPlane(ioSurface, plane) !=
kIOSurfaceFormats[formatIndex].componentBytes)
{
return false;
}
return true;
# else
return false;
# endif
}
// Wraps a FramebufferGL to hook the destroy function to delete the texture associated with the
// framebuffer.
class IOSurfaceFramebuffer : public FramebufferGL
{
public:
IOSurfaceFramebuffer(const gl::FramebufferState &data,
GLuint id,
GLuint textureId,
bool isDefault,
bool emulatedAlpha)
: FramebufferGL(data, id, isDefault, emulatedAlpha), mTextureId(textureId)
{}
void destroy(const gl::Context *context) override
{
GetFunctionsGL(context)->deleteTextures(1, &mTextureId);
FramebufferGL::destroy(context);
}
private:
GLuint mTextureId;
};
FramebufferImpl *IOSurfaceSurfaceEAGL::createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state)
{
const FunctionsGL *functions = GetFunctionsGL(context);
StateManagerGL *stateManager = GetStateManagerGL(context);
GLuint texture = 0;
functions->genTextures(1, &texture);
stateManager->bindTexture(gl::TextureType::_2D, texture);
# if !defined(ANGLE_PLATFORM_IOS_SIMULATOR)
const auto &format = kIOSurfaceFormats[mFormatIndex];
if (![mEAGLContext texImageIOSurface:mIOSurface
target:GL_TEXTURE_2D
internalFormat:format.nativeInternalFormat
width:mWidth
height:mHeight
format:format.nativeFormat
type:format.nativeType
plane:mPlane])
{
ERR() << "[EAGLContext texImageIOSurface] failed";
return nullptr;
}
# else
ERR() << "IOSurfaces not supported on iOS Simulator";
# endif
if (IsError(initializeAlphaChannel(context, texture)))
{
ERR() << "Failed to initialize IOSurface alpha channel.";
return nullptr;
}
GLuint framebuffer = 0;
functions->genFramebuffers(1, &framebuffer);
stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
stateManager->bindTexture(gl::TextureType::_2D, texture);
functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
0);
return new IOSurfaceFramebuffer(state, framebuffer, texture, true, hasEmulatedAlphaChannel());
}
angle::Result IOSurfaceSurfaceEAGL::initializeAlphaChannel(const gl::Context *context,
GLuint texture)
{
if (mAlphaInitialized)
{
return angle::Result::Continue;
}
BlitGL *blitter = GetBlitGL(context);
ANGLE_TRY(blitter->clearRenderableTextureAlphaToOne(context, texture,
gl::TextureTarget::Rectangle, 0));
mAlphaInitialized = true;
return angle::Result::Continue;
}
bool IOSurfaceSurfaceEAGL::hasEmulatedAlphaChannel() const
{
const auto &format = kIOSurfaceFormats[mFormatIndex];
return format.internalFormat == GL_RGB;
}
} // namespace rx
#endif // defined(ANGLE_PLATFORM_IOS)
//
// Copyright 2020 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.
//
// PBufferSurfaceEAGL.cpp: an implementation of egl::Surface for PBuffers for the EAGL backend,
// currently implemented using renderbuffers
#import "common/platform.h"
#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
# include "libANGLE/renderer/gl/eagl/PbufferSurfaceEAGL.h"
# include "common/debug.h"
# include "libANGLE/renderer/gl/FramebufferGL.h"
# include "libANGLE/renderer/gl/FunctionsGL.h"
# include "libANGLE/renderer/gl/RendererGL.h"
# include "libANGLE/renderer/gl/StateManagerGL.h"
namespace rx
{
PbufferSurfaceEAGL::PbufferSurfaceEAGL(const egl::SurfaceState &state,
RendererGL *renderer,
EGLint width,
EGLint height)
: SurfaceGL(state),
mWidth(width),
mHeight(height),
mFunctions(renderer->getFunctions()),
mStateManager(renderer->getStateManager()),
mColorRenderbuffer(0),
mDSRenderbuffer(0)
{}
PbufferSurfaceEAGL::~PbufferSurfaceEAGL()
{
if (mColorRenderbuffer != 0)
{
mFunctions->deleteRenderbuffers(1, &mColorRenderbuffer);
mColorRenderbuffer = 0;
}
if (mDSRenderbuffer != 0)
{
mFunctions->deleteRenderbuffers(1, &mDSRenderbuffer);
mDSRenderbuffer = 0;
}
}
egl::Error PbufferSurfaceEAGL::initialize(const egl::Display *display)
{
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);
return egl::NoError();
}
egl::Error PbufferSurfaceEAGL::makeCurrent(const gl::Context *context)
{
return egl::NoError();
}
egl::Error PbufferSurfaceEAGL::swap(const gl::Context *context)
{
return egl::NoError();
}
egl::Error PbufferSurfaceEAGL::postSubBuffer(const gl::Context *context,
EGLint x,
EGLint y,
EGLint width,
EGLint height)
{
return egl::NoError();
}
egl::Error PbufferSurfaceEAGL::querySurfacePointerANGLE(EGLint attribute, void **value)
{
UNIMPLEMENTED();
return egl::NoError();
}
egl::Error PbufferSurfaceEAGL::bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer)
{
ERR() << "PbufferSurfaceEAGL::bindTexImage";
UNIMPLEMENTED();
return egl::NoError();
}
egl::Error PbufferSurfaceEAGL::releaseTexImage(const gl::Context *context, EGLint buffer)
{
UNIMPLEMENTED();
return egl::NoError();
}
void PbufferSurfaceEAGL::setSwapInterval(EGLint interval) {}
EGLint PbufferSurfaceEAGL::getWidth() const
{
return mWidth;
}
EGLint PbufferSurfaceEAGL::getHeight() const
{
return mHeight;
}
EGLint PbufferSurfaceEAGL::isPostSubBufferSupported() const
{
UNIMPLEMENTED();
return EGL_FALSE;
}
EGLint PbufferSurfaceEAGL::getSwapBehavior() const
{
return EGL_BUFFER_PRESERVED;
}
FramebufferImpl *PbufferSurfaceEAGL::createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state)
{
const FunctionsGL *functions = GetFunctionsGL(context);
StateManagerGL *stateManager = GetStateManagerGL(context);
GLuint framebuffer = 0;
functions->genFramebuffers(1, &framebuffer);
stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
mColorRenderbuffer);
functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
mDSRenderbuffer);
return new FramebufferGL(state, framebuffer, true, false);
}
} // namespace rx
#endif // defined(ANGLE_PLATFORM_IOS)
//
// Copyright 2020 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.
//
// PBufferSurfaceEAGL.h: an implementation of egl::Surface for PBuffers for the EAGL backend,
// currently implemented using renderbuffers
#ifndef LIBANGLE_RENDERER_GL_EAGL_PBUFFERSURFACEEAGL_H_
#define LIBANGLE_RENDERER_GL_EAGL_PBUFFERSURFACEEAGL_H_
#include "libANGLE/renderer/gl/SurfaceGL.h"
namespace rx
{
class FunctionsGL;
class RendererGL;
class StateManagerGL;
class PbufferSurfaceEAGL : public SurfaceGL
{
public:
PbufferSurfaceEAGL(const egl::SurfaceState &state,
RendererGL *renderer,
EGLint width,
EGLint height);
~PbufferSurfaceEAGL() override;
egl::Error initialize(const egl::Display *display) override;
egl::Error makeCurrent(const gl::Context *context) override;
egl::Error swap(const gl::Context *context) override;
egl::Error postSubBuffer(const gl::Context *context,
EGLint x,
EGLint y,
EGLint width,
EGLint height) override;
egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
egl::Error bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer) override;
egl::Error releaseTexImage(const gl::Context *context, 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::Context *context,
const gl::FramebufferState &state) override;
private:
unsigned mWidth;
unsigned mHeight;
// TODO(geofflang): Don't store these, they are potentially specific to a single GL context.
// http://anglebug.com/2464
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
GLuint mColorRenderbuffer;
GLuint mDSRenderbuffer;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_EAGL_PBUFFERSURFACEEAGL_H_
//
// Copyright 2020 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.
//
// RendererEAGL.cpp: Implements the class methods for RendererEAGL.
#import "common/platform.h"
#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
# include "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
# include "libANGLE/renderer/gl/eagl/RendererEAGL.h"
namespace rx
{
RendererEAGL::RendererEAGL(std::unique_ptr<FunctionsGL> functions,
const egl::AttributeMap &attribMap,
DisplayEAGL *display)
: RendererGL(std::move(functions), attribMap, display), mDisplay(display)
{}
RendererEAGL::~RendererEAGL() {}
WorkerContext *RendererEAGL::createWorkerContext(std::string *infoLog)
{
return mDisplay->createWorkerContext(infoLog);
}
} // namespace rx
#endif // defined(ANGLE_PLATFORM_IOS)
//
// Copyright 2020 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.
//
// RendererEAGL.h: implements createWorkerContext for RendererGL.
#ifndef LIBANGLE_RENDERER_GL_EAGL_RENDEREREAGL_H_
#define LIBANGLE_RENDERER_GL_EAGL_RENDEREREAGL_H_
#include "libANGLE/renderer/gl/RendererGL.h"
namespace rx
{
class DisplayEAGL;
class RendererEAGL : public RendererGL
{
public:
RendererEAGL(std::unique_ptr<FunctionsGL> functions,
const egl::AttributeMap &attribMap,
DisplayEAGL *display);
~RendererEAGL() override;
private:
WorkerContext *createWorkerContext(std::string *infoLog) override;
DisplayEAGL *mDisplay;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_GLX_RENDERERGLX_H_
//
// Copyright 2020 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.
//
// WindowSurfaceEAGL.h: EAGL implementation of egl::Surface
#ifndef LIBANGLE_RENDERER_GL_EAGL_WINDOWSURFACEEAGL_H_
#define LIBANGLE_RENDERER_GL_EAGL_WINDOWSURFACEEAGL_H_
#include "libANGLE/renderer/gl/SurfaceGL.h"
#ifdef __OBJC__
@class EAGLContext;
typedef EAGLContext *EAGLContextObj;
#else
typedef void *EAGLContextObj;
#endif
@class CALayer;
struct __IOSurface;
typedef __IOSurface *IOSurfaceRef;
// WebKit's build process requires that every Objective-C class name has the prefix "Web".
@class WebSwapLayer;
namespace rx
{
class DisplayEAGL;
class FramebufferGL;
class FunctionsGL;
class RendererGL;
class StateManagerGL;
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 WindowSurfaceEAGL : public SurfaceGL
{
public:
WindowSurfaceEAGL(const egl::SurfaceState &state,
RendererGL *renderer,
EGLNativeWindowType layer,
EAGLContextObj context);
~WindowSurfaceEAGL() override;
egl::Error initialize(const egl::Display *display) override;
egl::Error makeCurrent(const gl::Context *context) override;
egl::Error swap(const gl::Context *context) override;
egl::Error postSubBuffer(const gl::Context *context,
EGLint x,
EGLint y,
EGLint width,
EGLint height) override;
egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
egl::Error bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer) override;
egl::Error releaseTexImage(const gl::Context *context, 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::Context *context,
const gl::FramebufferState &state) override;
private:
WebSwapLayer *mSwapLayer;
SharedSwapState mSwapState;
uint64_t mCurrentSwapId;
CALayer *mLayer;
EAGLContextObj mContext;
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
GLuint mDSRenderbuffer;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_EAGL_WINDOWSURFACEEAGL_H_
//
// Copyright 2020 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.
//
// WindowSurfaceEAGL.cpp: EAGL implementation of egl::Surface
#import "common/platform.h"
#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
# import "libANGLE/renderer/gl/eagl/WindowSurfaceEAGL.h"
# import "common/debug.h"
# import "libANGLE/Context.h"
# import "libANGLE/renderer/gl/FramebufferGL.h"
# import "libANGLE/renderer/gl/RendererGL.h"
# import "libANGLE/renderer/gl/StateManagerGL.h"
# import "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
# import <OpenGLES/EAGL.h>
# import <QuartzCore/QuartzCore.h>
// TODO(anglebug.com/4275): It's not clear why this needs to be an EAGLLayer.
@interface WebSwapLayer : CAEAGLLayer {
EAGLContextObj mDisplayContext;
bool initialized;
rx::SharedSwapState *mSwapState;
const rx::FunctionsGL *mFunctions;
GLuint mReadFramebuffer;
}
- (id)initWithSharedState:(rx::SharedSwapState *)swapState
withContext:(EAGLContextObj)displayContext
withFunctions:(const rx::FunctionsGL *)functions;
@end
@implementation WebSwapLayer
- (id)initWithSharedState:(rx::SharedSwapState *)swapState
withContext:(EAGLContextObj)displayContext
withFunctions:(const rx::FunctionsGL *)functions
{
self = [super init];
if (self != nil)
{
mDisplayContext = displayContext;
initialized = false;
mSwapState = swapState;
mFunctions = functions;
[self setFrame:CGRectMake(0, 0, mSwapState->textures[0].width,
mSwapState->textures[0].height)];
}
return self;
}
- (void)display
{
pthread_mutex_lock(&mSwapState->mutex);
{
if (mSwapState->lastRendered->swapId > mSwapState->beingPresented->swapId)
{
std::swap(mSwapState->lastRendered, mSwapState->beingPresented);
}
}
pthread_mutex_unlock(&mSwapState->mutex);
[EAGLContext setCurrentContext:mDisplayContext];
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)];
// TODO(anglebug.com/4275): If this continues to remain an EAGLLayer, then this is
// where we'd probably want to create the renderbuffer storage.
[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);
mFunctions->bindRenderbuffer(GL_RENDERBUFFER, texture.texture);
[mDisplayContext presentRenderbuffer:GL_RENDERBUFFER];
[EAGLContext setCurrentContext:nil];
}
@end
namespace rx
{
WindowSurfaceEAGL::WindowSurfaceEAGL(const egl::SurfaceState &state,
RendererGL *renderer,
EGLNativeWindowType layer,
EAGLContextObj context)
: SurfaceGL(state),
mSwapLayer(nil),
mCurrentSwapId(0),
mLayer((__bridge CALayer *)layer),
mContext(context),
mFunctions(renderer->getFunctions()),
mStateManager(renderer->getStateManager()),
mDSRenderbuffer(0)
{
pthread_mutex_init(&mSwapState.mutex, nullptr);
}
WindowSurfaceEAGL::~WindowSurfaceEAGL()
{
pthread_mutex_destroy(&mSwapState.mutex);
if (mDSRenderbuffer != 0)
{
mFunctions->deleteRenderbuffers(1, &mDSRenderbuffer);
mDSRenderbuffer = 0;
}
if (mSwapLayer != nil)
{
[mSwapLayer removeFromSuperlayer];
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 WindowSurfaceEAGL::initialize(const egl::Display *display)
{
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::TextureType::_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 = [[WebSwapLayer 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);
return egl::Error(EGL_SUCCESS);
}
egl::Error WindowSurfaceEAGL::makeCurrent(const gl::Context *context)
{
return egl::Error(EGL_SUCCESS);
}
egl::Error WindowSurfaceEAGL::swap(const gl::Context *context)
{
const FunctionsGL *functions = GetFunctionsGL(context);
StateManagerGL *stateManager = GetStateManagerGL(context);
functions->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)
{
stateManager->bindTexture(gl::TextureType::_2D, texture.texture);
functions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
stateManager->bindRenderbuffer(GL_RENDERBUFFER, mDSRenderbuffer);
functions->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
texture.width = width;
texture.height = height;
}
FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(context->getFramebuffer({0}));
stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebufferGL->getFramebufferID());
functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
mSwapState.beingRendered->texture, 0);
return egl::Error(EGL_SUCCESS);
}
egl::Error WindowSurfaceEAGL::postSubBuffer(const gl::Context *context,
EGLint x,
EGLint y,
EGLint width,
EGLint height)
{
UNIMPLEMENTED();
return egl::Error(EGL_SUCCESS);
}
egl::Error WindowSurfaceEAGL::querySurfacePointerANGLE(EGLint attribute, void **value)
{
UNIMPLEMENTED();
return egl::Error(EGL_SUCCESS);
}
egl::Error WindowSurfaceEAGL::bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer)
{
UNIMPLEMENTED();
return egl::Error(EGL_SUCCESS);
}
egl::Error WindowSurfaceEAGL::releaseTexImage(const gl::Context *context, EGLint buffer)
{
UNIMPLEMENTED();
return egl::Error(EGL_SUCCESS);
}
void WindowSurfaceEAGL::setSwapInterval(EGLint interval)
{
// TODO(cwallez) investigate implementing swap intervals other than 0
}
EGLint WindowSurfaceEAGL::getWidth() const
{
return (EGLint)CGRectGetWidth([mLayer frame]);
}
EGLint WindowSurfaceEAGL::getHeight() const
{
return (EGLint)CGRectGetHeight([mLayer frame]);
}
EGLint WindowSurfaceEAGL::isPostSubBufferSupported() const
{
UNIMPLEMENTED();
return EGL_FALSE;
}
EGLint WindowSurfaceEAGL::getSwapBehavior() const
{
return EGL_BUFFER_DESTROYED;
}
FramebufferImpl *WindowSurfaceEAGL::createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state)
{
const FunctionsGL *functions = GetFunctionsGL(context);
StateManagerGL *stateManager = GetStateManagerGL(context);
GLuint framebuffer = 0;
functions->genFramebuffers(1, &framebuffer);
stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
mSwapState.beingRendered->texture, 0);
functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
mDSRenderbuffer);
return new FramebufferGL(state, framebuffer, true, false);
}
} // namespace rx
#endif // defined(ANGLE_PLATFORM_IOS)
......@@ -1284,7 +1284,7 @@ void GenerateCaps(const FunctionsGL *functions,
extensions->textureSRGBDecode = functions->hasGLExtension("GL_EXT_texture_sRGB_decode") ||
functions->hasGLESExtension("GL_EXT_texture_sRGB_decode");
#if defined(ANGLE_PLATFORM_APPLE)
#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
VendorID vendor = GetVendorID(functions);
if ((IsAMD(vendor) || IsIntel(vendor)) && *maxSupportedESVersion >= gl::Version(3, 0))
{
......
......@@ -129,7 +129,7 @@ libangle_gpu_info_util_libpci_sources =
libangle_gpu_info_util_x11_sources = [ "src/gpu_info_util/SystemInfo_x11.cpp" ]
libangle_gpu_info_util_mac_sources = [ "src/gpu_info_util/SystemInfo_mac.mm" ]
libangle_gpu_info_util_mac_sources = [ "src/gpu_info_util/SystemInfo_macos.mm" ]
libangle_includes = [
"include/angle_gl.h",
......
......@@ -301,6 +301,15 @@ EGLBoolean EGLAPIENTRY EGL_QueryDeviceAttribEXT(EGLDeviceEXT device,
}
error = dev->getAttribute(attribute, value);
break;
case EGL_EAGL_CONTEXT_ANGLE:
if (!dev->getExtensions().deviceEAGL)
{
thread->setError(EglBadAttribute(), GetDebug(), "eglQueryDeviceAttribEXT",
GetDeviceIfValid(dev));
return EGL_FALSE;
}
error = dev->getAttribute(attribute, value);
break;
case EGL_CGL_CONTEXT_ANGLE:
case EGL_CGL_PIXEL_FORMAT_ANGLE:
if (!dev->getExtensions().deviceCGL)
......
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