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// WindowSurfaceEAGL.cpp: EAGL implementation of egl::Surface 8 9#import "common/platform.h" 10 11#if defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST) 12 13# import "libANGLE/renderer/gl/eagl/WindowSurfaceEAGL.h" 14 15# import "common/debug.h" 16# import "libANGLE/Context.h" 17# import "libANGLE/renderer/gl/FramebufferGL.h" 18# import "libANGLE/renderer/gl/RendererGL.h" 19# import "libANGLE/renderer/gl/StateManagerGL.h" 20# import "libANGLE/renderer/gl/eagl/DisplayEAGL.h" 21 22# import <OpenGLES/EAGL.h> 23# import <QuartzCore/QuartzCore.h> 24 25// TODO(anglebug.com/4275): It's not clear why this needs to be an EAGLLayer. 26 27@interface WebSwapLayer : CAEAGLLayer { 28 EAGLContextObj mDisplayContext; 29 30 bool initialized; 31 rx::SharedSwapState *mSwapState; 32 const rx::FunctionsGL *mFunctions; 33 34 GLuint mReadFramebuffer; 35} 36- (id)initWithSharedState:(rx::SharedSwapState *)swapState 37 withContext:(EAGLContextObj)displayContext 38 withFunctions:(const rx::FunctionsGL *)functions; 39@end 40 41@implementation WebSwapLayer 42- (id)initWithSharedState:(rx::SharedSwapState *)swapState 43 withContext:(EAGLContextObj)displayContext 44 withFunctions:(const rx::FunctionsGL *)functions 45{ 46 self = [super init]; 47 if (self != nil) 48 { 49 mDisplayContext = displayContext; 50 51 initialized = false; 52 mSwapState = swapState; 53 mFunctions = functions; 54 55 [self setFrame:CGRectMake(0, 0, mSwapState->textures[0].width, 56 mSwapState->textures[0].height)]; 57 } 58 return self; 59} 60 61- (void)display 62{ 63 pthread_mutex_lock(&mSwapState->mutex); 64 { 65 if (mSwapState->lastRendered->swapId > mSwapState->beingPresented->swapId) 66 { 67 std::swap(mSwapState->lastRendered, mSwapState->beingPresented); 68 } 69 } 70 pthread_mutex_unlock(&mSwapState->mutex); 71 72 [EAGLContext setCurrentContext:mDisplayContext]; 73 74 if (!initialized) 75 { 76 initialized = true; 77 78 mFunctions->genFramebuffers(1, &mReadFramebuffer); 79 } 80 81 const auto &texture = *mSwapState->beingPresented; 82 83 if ([self frame].size.width != texture.width || [self frame].size.height != texture.height) 84 { 85 [self setFrame:CGRectMake(0, 0, texture.width, texture.height)]; 86 87 // TODO(anglebug.com/4275): If this continues to remain an EAGLLayer, then this is 88 // where we'd probably want to create the renderbuffer storage. 89 [self setNeedsDisplay]; 90 } 91 92 // TODO(cwallez) support 2.1 contexts too that don't have blitFramebuffer nor the 93 // GL_DRAW_FRAMEBUFFER_BINDING query 94 GLint drawFBO; 95 mFunctions->getIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFBO); 96 97 mFunctions->bindFramebuffer(GL_FRAMEBUFFER, mReadFramebuffer); 98 mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 99 texture.texture, 0); 100 101 mFunctions->bindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer); 102 mFunctions->bindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO); 103 mFunctions->blitFramebuffer(0, 0, texture.width, texture.height, 0, 0, texture.width, 104 texture.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); 105 106 mFunctions->bindRenderbuffer(GL_RENDERBUFFER, texture.texture); 107 [mDisplayContext presentRenderbuffer:GL_RENDERBUFFER]; 108 [EAGLContext setCurrentContext:nil]; 109} 110@end 111 112namespace rx 113{ 114 115WindowSurfaceEAGL::WindowSurfaceEAGL(const egl::SurfaceState &state, 116 RendererGL *renderer, 117 EGLNativeWindowType layer, 118 EAGLContextObj context) 119 : SurfaceGL(state), 120 mSwapLayer(nil), 121 mCurrentSwapId(0), 122 mLayer((__bridge CALayer *)layer), 123 mContext(context), 124 mFunctions(renderer->getFunctions()), 125 mStateManager(renderer->getStateManager()), 126 mDSRenderbuffer(0) 127{ 128 pthread_mutex_init(&mSwapState.mutex, nullptr); 129} 130 131WindowSurfaceEAGL::~WindowSurfaceEAGL() 132{ 133 pthread_mutex_destroy(&mSwapState.mutex); 134 135 if (mDSRenderbuffer != 0) 136 { 137 mFunctions->deleteRenderbuffers(1, &mDSRenderbuffer); 138 mDSRenderbuffer = 0; 139 } 140 141 if (mSwapLayer != nil) 142 { 143 [mSwapLayer removeFromSuperlayer]; 144 mSwapLayer = nil; 145 } 146 147 for (size_t i = 0; i < ArraySize(mSwapState.textures); ++i) 148 { 149 if (mSwapState.textures[i].texture != 0) 150 { 151 mFunctions->deleteTextures(1, &mSwapState.textures[i].texture); 152 mSwapState.textures[i].texture = 0; 153 } 154 } 155} 156 157egl::Error WindowSurfaceEAGL::initialize(const egl::Display *display) 158{ 159 unsigned width = getWidth(); 160 unsigned height = getHeight(); 161 162 for (size_t i = 0; i < ArraySize(mSwapState.textures); ++i) 163 { 164 mFunctions->genTextures(1, &mSwapState.textures[i].texture); 165 mStateManager->bindTexture(gl::TextureType::_2D, mSwapState.textures[i].texture); 166 mFunctions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, 167 GL_UNSIGNED_BYTE, nullptr); 168 mSwapState.textures[i].width = width; 169 mSwapState.textures[i].height = height; 170 mSwapState.textures[i].swapId = 0; 171 } 172 mSwapState.beingRendered = &mSwapState.textures[0]; 173 mSwapState.lastRendered = &mSwapState.textures[1]; 174 mSwapState.beingPresented = &mSwapState.textures[2]; 175 176 mSwapLayer = [[WebSwapLayer alloc] initWithSharedState:&mSwapState 177 withContext:mContext 178 withFunctions:mFunctions]; 179 [mLayer addSublayer:mSwapLayer]; 180 [mSwapLayer setContentsScale:[mLayer contentsScale]]; 181 182 mFunctions->genRenderbuffers(1, &mDSRenderbuffer); 183 mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDSRenderbuffer); 184 mFunctions->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); 185 186 return egl::Error(EGL_SUCCESS); 187} 188 189egl::Error WindowSurfaceEAGL::makeCurrent(const gl::Context *context) 190{ 191 return egl::Error(EGL_SUCCESS); 192} 193 194egl::Error WindowSurfaceEAGL::swap(const gl::Context *context) 195{ 196 const FunctionsGL *functions = GetFunctionsGL(context); 197 StateManagerGL *stateManager = GetStateManagerGL(context); 198 199 functions->flush(); 200 mSwapState.beingRendered->swapId = ++mCurrentSwapId; 201 202 pthread_mutex_lock(&mSwapState.mutex); 203 { 204 std::swap(mSwapState.beingRendered, mSwapState.lastRendered); 205 } 206 pthread_mutex_unlock(&mSwapState.mutex); 207 208 unsigned width = getWidth(); 209 unsigned height = getHeight(); 210 auto &texture = *mSwapState.beingRendered; 211 212 if (texture.width != width || texture.height != height) 213 { 214 stateManager->bindTexture(gl::TextureType::_2D, texture.texture); 215 functions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, 216 GL_UNSIGNED_BYTE, nullptr); 217 218 stateManager->bindRenderbuffer(GL_RENDERBUFFER, mDSRenderbuffer); 219 functions->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); 220 221 texture.width = width; 222 texture.height = height; 223 } 224 225 FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(context->getFramebuffer({0})); 226 stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebufferGL->getFramebufferID()); 227 functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 228 mSwapState.beingRendered->texture, 0); 229 230 return egl::Error(EGL_SUCCESS); 231} 232 233egl::Error WindowSurfaceEAGL::postSubBuffer(const gl::Context *context, 234 EGLint x, 235 EGLint y, 236 EGLint width, 237 EGLint height) 238{ 239 UNIMPLEMENTED(); 240 return egl::Error(EGL_SUCCESS); 241} 242 243egl::Error WindowSurfaceEAGL::querySurfacePointerANGLE(EGLint attribute, void **value) 244{ 245 UNIMPLEMENTED(); 246 return egl::Error(EGL_SUCCESS); 247} 248 249egl::Error WindowSurfaceEAGL::bindTexImage(const gl::Context *context, 250 gl::Texture *texture, 251 EGLint buffer) 252{ 253 UNIMPLEMENTED(); 254 return egl::Error(EGL_SUCCESS); 255} 256 257egl::Error WindowSurfaceEAGL::releaseTexImage(const gl::Context *context, EGLint buffer) 258{ 259 UNIMPLEMENTED(); 260 return egl::Error(EGL_SUCCESS); 261} 262 263void WindowSurfaceEAGL::setSwapInterval(EGLint interval) 264{ 265 // TODO(cwallez) investigate implementing swap intervals other than 0 266} 267 268EGLint WindowSurfaceEAGL::getWidth() const 269{ 270 return static_cast<EGLint>(CGRectGetWidth([mLayer frame]) * [mLayer contentsScale]); 271} 272 273EGLint WindowSurfaceEAGL::getHeight() const 274{ 275 return static_cast<EGLint>(CGRectGetHeight([mLayer frame]) * [mLayer contentsScale]); 276} 277 278EGLint WindowSurfaceEAGL::isPostSubBufferSupported() const 279{ 280 UNIMPLEMENTED(); 281 return EGL_FALSE; 282} 283 284EGLint WindowSurfaceEAGL::getSwapBehavior() const 285{ 286 return EGL_BUFFER_DESTROYED; 287} 288 289FramebufferImpl *WindowSurfaceEAGL::createDefaultFramebuffer(const gl::Context *context, 290 const gl::FramebufferState &state) 291{ 292 const FunctionsGL *functions = GetFunctionsGL(context); 293 StateManagerGL *stateManager = GetStateManagerGL(context); 294 295 GLuint framebuffer = 0; 296 functions->genFramebuffers(1, &framebuffer); 297 stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); 298 functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 299 mSwapState.beingRendered->texture, 0); 300 functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 301 mDSRenderbuffer); 302 303 return new FramebufferGL(state, framebuffer, true, false); 304} 305 306} // namespace rx 307 308#endif // defined(ANGLE_PLATFORM_IOS) 309