• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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