• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2// Copyright 2020 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// DisplayEAGL.cpp: EAGL implementation of egl::Display
8
9#import "common/platform.h"
10
11#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)
12
13#    import "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
14
15#    import "common/debug.h"
16#    import "gpu_info_util/SystemInfo.h"
17#    import "libANGLE/Display.h"
18#    import "libANGLE/renderer/gl/eagl/ContextEAGL.h"
19#    import "libANGLE/renderer/gl/eagl/DeviceEAGL.h"
20#    import "libANGLE/renderer/gl/eagl/IOSurfaceSurfaceEAGL.h"
21#    import "libANGLE/renderer/gl/eagl/PbufferSurfaceEAGL.h"
22#    import "libANGLE/renderer/gl/eagl/RendererEAGL.h"
23#    import "libANGLE/renderer/gl/eagl/WindowSurfaceEAGL.h"
24
25#    import <Foundation/Foundation.h>
26#    import <OpenGLES/EAGL.h>
27#    import <QuartzCore/QuartzCore.h>
28#    import <dlfcn.h>
29
30#    define GLES_SILENCE_DEPRECATION
31
32namespace
33{
34
35const char *kOpenGLESDylibName = "/System/Library/Frameworks/OpenGLES.framework/OpenGLES";
36
37}
38
39namespace rx
40{
41
42class FunctionsGLEAGL : public FunctionsGL
43{
44  public:
45    FunctionsGLEAGL(void *dylibHandle) : mDylibHandle(dylibHandle) {}
46
47    ~FunctionsGLEAGL() override { dlclose(mDylibHandle); }
48
49  private:
50    void *loadProcAddress(const std::string &function) const override
51    {
52        return dlsym(mDylibHandle, function.c_str());
53    }
54
55    void *mDylibHandle;
56};
57
58DisplayEAGL::DisplayEAGL(const egl::DisplayState &state)
59    : DisplayGL(state), mEGLDisplay(nullptr), mContext(nullptr)
60{}
61
62DisplayEAGL::~DisplayEAGL() {}
63
64egl::Error DisplayEAGL::initialize(egl::Display *display)
65{
66    mEGLDisplay = display;
67
68    angle::SystemInfo info;
69    if (!angle::GetSystemInfo(&info))
70    {
71        return egl::EglNotInitialized() << "Unable to query ANGLE's SystemInfo.";
72    }
73
74    mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
75    if (mContext == nullptr)
76    {
77        return egl::EglNotInitialized() << "Could not create the EAGL context.";
78    }
79    [EAGLContext setCurrentContext:mContext];
80
81    // There is no equivalent getProcAddress in EAGL so we open the dylib directly
82    void *handle = dlopen(kOpenGLESDylibName, RTLD_NOW);
83    if (!handle)
84    {
85        return egl::EglNotInitialized() << "Could not open the OpenGLES Framework.";
86    }
87
88    std::unique_ptr<FunctionsGL> functionsGL(new FunctionsGLEAGL(handle));
89    functionsGL->initialize(display->getAttributeMap());
90
91    mRenderer.reset(new RendererEAGL(std::move(functionsGL), display->getAttributeMap(), this));
92
93    const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
94    if (maxVersion < gl::Version(2, 0))
95    {
96        return egl::EglNotInitialized() << "OpenGL ES 2.0 is not supportable.";
97    }
98
99    return DisplayGL::initialize(display);
100}
101
102void DisplayEAGL::terminate()
103{
104    DisplayGL::terminate();
105
106    mRenderer.reset();
107    if (mContext != nullptr)
108    {
109        [EAGLContext setCurrentContext:nil];
110        mContext = nullptr;
111    }
112}
113
114SurfaceImpl *DisplayEAGL::createWindowSurface(const egl::SurfaceState &state,
115                                              EGLNativeWindowType window,
116                                              const egl::AttributeMap &attribs)
117{
118    return new WindowSurfaceEAGL(state, mRenderer.get(), window, mContext);
119}
120
121SurfaceImpl *DisplayEAGL::createPbufferSurface(const egl::SurfaceState &state,
122                                               const egl::AttributeMap &attribs)
123{
124    EGLint width  = static_cast<EGLint>(attribs.get(EGL_WIDTH, 0));
125    EGLint height = static_cast<EGLint>(attribs.get(EGL_HEIGHT, 0));
126    return new PbufferSurfaceEAGL(state, mRenderer.get(), width, height);
127}
128
129SurfaceImpl *DisplayEAGL::createPbufferFromClientBuffer(const egl::SurfaceState &state,
130                                                        EGLenum buftype,
131                                                        EGLClientBuffer clientBuffer,
132                                                        const egl::AttributeMap &attribs)
133{
134    ASSERT(buftype == EGL_IOSURFACE_ANGLE);
135    return new IOSurfaceSurfaceEAGL(state, mContext, clientBuffer, attribs);
136}
137
138SurfaceImpl *DisplayEAGL::createPixmapSurface(const egl::SurfaceState &state,
139                                              NativePixmapType nativePixmap,
140                                              const egl::AttributeMap &attribs)
141{
142    UNIMPLEMENTED();
143    return nullptr;
144}
145
146ContextImpl *DisplayEAGL::createContext(const gl::State &state,
147                                        gl::ErrorSet *errorSet,
148                                        const egl::Config *configuration,
149                                        const gl::Context *shareContext,
150                                        const egl::AttributeMap &attribs)
151{
152    return new ContextEAGL(state, errorSet, mRenderer);
153}
154
155DeviceImpl *DisplayEAGL::createDevice()
156{
157    return new DeviceEAGL();
158}
159
160egl::ConfigSet DisplayEAGL::generateConfigs()
161{
162    // TODO(cwallez): generate more config permutations
163    egl::ConfigSet configs;
164
165    const gl::Version &maxVersion = getMaxSupportedESVersion();
166    ASSERT(maxVersion >= gl::Version(2, 0));
167    bool supportsES3 = maxVersion >= gl::Version(3, 0);
168
169    egl::Config config;
170
171    // Native stuff
172    config.nativeVisualID   = 0;
173    config.nativeVisualType = 0;
174    config.nativeRenderable = EGL_TRUE;
175
176    // Buffer sizes
177    config.redSize     = 8;
178    config.greenSize   = 8;
179    config.blueSize    = 8;
180    config.alphaSize   = 8;
181    config.depthSize   = 24;
182    config.stencilSize = 8;
183
184    config.colorBufferType = EGL_RGB_BUFFER;
185    config.luminanceSize   = 0;
186    config.alphaMaskSize   = 0;
187
188    config.bufferSize = config.redSize + config.greenSize + config.blueSize + config.alphaSize;
189
190    config.transparentType = EGL_NONE;
191
192    // Pbuffer
193    config.maxPBufferWidth  = 4096;
194    config.maxPBufferHeight = 4096;
195    config.maxPBufferPixels = 4096 * 4096;
196
197    // Caveat
198    config.configCaveat = EGL_NONE;
199
200    // Misc
201    config.sampleBuffers     = 0;
202    config.samples           = 0;
203    config.level             = 0;
204    config.bindToTextureRGB  = EGL_FALSE;
205    config.bindToTextureRGBA = EGL_FALSE;
206
207#    if !ANGLE_PLATFORM_MACCATALYST
208    config.bindToTextureTarget = EGL_TEXTURE_2D;
209#    else
210    config.bindToTextureTarget = EGL_TEXTURE_RECTANGLE_ANGLE;
211#    endif
212
213    config.surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
214
215    config.minSwapInterval = 1;
216    config.maxSwapInterval = 1;
217
218    config.renderTargetFormat = GL_RGBA8;
219    config.depthStencilFormat = GL_DEPTH24_STENCIL8;
220
221    config.conformant     = EGL_OPENGL_ES2_BIT | (supportsES3 ? EGL_OPENGL_ES3_BIT_KHR : 0);
222    config.renderableType = config.conformant;
223
224    config.matchNativePixmap = EGL_NONE;
225
226    config.colorComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
227
228    configs.add(config);
229    return configs;
230}
231
232bool DisplayEAGL::testDeviceLost()
233{
234    // TODO(cwallez) investigate implementing this
235    return false;
236}
237
238egl::Error DisplayEAGL::restoreLostDevice(const egl::Display *display)
239{
240    UNIMPLEMENTED();
241    return egl::EglBadDisplay();
242}
243
244bool DisplayEAGL::isValidNativeWindow(EGLNativeWindowType window) const
245{
246    NSObject *layer = (__bridge NSObject *)window;
247    return [layer isKindOfClass:[CALayer class]];
248}
249
250egl::Error DisplayEAGL::validateClientBuffer(const egl::Config *configuration,
251                                             EGLenum buftype,
252                                             EGLClientBuffer clientBuffer,
253                                             const egl::AttributeMap &attribs) const
254{
255    ASSERT(buftype == EGL_IOSURFACE_ANGLE);
256
257    if (!IOSurfaceSurfaceEAGL::validateAttributes(clientBuffer, attribs))
258    {
259        return egl::EglBadAttribute();
260    }
261
262    return egl::NoError();
263}
264
265std::string DisplayEAGL::getVendorString() const
266{
267    // TODO(cwallez) find a useful vendor string
268    return "";
269}
270
271EAGLContextObj DisplayEAGL::getEAGLContext() const
272{
273    return mContext;
274}
275
276void DisplayEAGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
277{
278    outExtensions->iosurfaceClientBuffer = true;
279    outExtensions->surfacelessContext    = true;
280    outExtensions->deviceQuery           = true;
281
282    // Contexts are virtualized so textures can be shared globally
283    outExtensions->displayTextureShareGroup = true;
284
285    outExtensions->powerPreference = false;
286
287    DisplayGL::generateExtensions(outExtensions);
288}
289
290void DisplayEAGL::generateCaps(egl::Caps *outCaps) const
291{
292    outCaps->textureNPOT = true;
293}
294
295egl::Error DisplayEAGL::waitClient(const gl::Context *context)
296{
297    // TODO(cwallez) UNIMPLEMENTED()
298    return egl::NoError();
299}
300
301egl::Error DisplayEAGL::waitNative(const gl::Context *context, EGLint engine)
302{
303    // TODO(cwallez) UNIMPLEMENTED()
304    return egl::NoError();
305}
306
307gl::Version DisplayEAGL::getMaxSupportedESVersion() const
308{
309    return mRenderer->getMaxSupportedESVersion();
310}
311
312egl::Error DisplayEAGL::makeCurrentSurfaceless(gl::Context *context)
313{
314    // We have nothing to do as mContext is always current, and that EAGL is surfaceless by
315    // default.
316    return egl::NoError();
317}
318
319class WorkerContextEAGL final : public WorkerContext
320{
321  public:
322    WorkerContextEAGL(EAGLContextObj context);
323    ~WorkerContextEAGL() override;
324
325    bool makeCurrent() override;
326    void unmakeCurrent() override;
327
328  private:
329    EAGLContextObj mContext;
330};
331
332WorkerContextEAGL::WorkerContextEAGL(EAGLContextObj context) : mContext(context) {}
333
334WorkerContextEAGL::~WorkerContextEAGL()
335{
336    [EAGLContext setCurrentContext:nil];
337    mContext = nullptr;
338}
339
340bool WorkerContextEAGL::makeCurrent()
341{
342    if (![EAGLContext setCurrentContext:static_cast<EAGLContext *>(mContext)])
343    {
344        ERR() << "Unable to make gl context current.";
345        return false;
346    }
347    return true;
348}
349
350void WorkerContextEAGL::unmakeCurrent()
351{
352    [EAGLContext setCurrentContext:nil];
353}
354
355WorkerContext *DisplayEAGL::createWorkerContext(std::string *infoLog)
356{
357    EAGLContextObj context = nullptr;
358    context                = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
359    if (!context)
360    {
361        *infoLog += "Could not create the EAGL context.";
362        return nullptr;
363    }
364
365    return new WorkerContextEAGL(context);
366}
367
368void DisplayEAGL::initializeFrontendFeatures(angle::FrontendFeatures *features) const
369{
370    mRenderer->initializeFrontendFeatures(features);
371}
372
373void DisplayEAGL::populateFeatureList(angle::FeatureList *features)
374{
375    mRenderer->getFeatures().populateFeatureList(features);
376}
377}
378
379#endif  // defined(ANGLE_PLATFORM_IOS)
380