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