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