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