• 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_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