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