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