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