• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2// Copyright 2015 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// WindowSurfaceCGL.cpp: CGL implementation of egl::Surface for windows
8
9#include "common/platform.h"
10
11#if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
12
13#    include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h"
14
15#    import <Cocoa/Cocoa.h>
16#    include <OpenGL/OpenGL.h>
17#    import <QuartzCore/QuartzCore.h>
18
19#    include "common/debug.h"
20#    include "libANGLE/Context.h"
21#    include "libANGLE/renderer/gl/FramebufferGL.h"
22#    include "libANGLE/renderer/gl/RendererGL.h"
23#    include "libANGLE/renderer/gl/StateManagerGL.h"
24#    include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
25
26@interface WebSwapLayer : CAOpenGLLayer {
27    CGLContextObj mDisplayContext;
28
29    bool initialized;
30    rx::SharedSwapState *mSwapState;
31    const rx::FunctionsGL *mFunctions;
32
33    GLuint mReadFramebuffer;
34}
35- (id)initWithSharedState:(rx::SharedSwapState *)swapState
36              withContext:(CGLContextObj)displayContext
37            withFunctions:(const rx::FunctionsGL *)functions;
38@end
39
40@implementation WebSwapLayer
41- (id)initWithSharedState:(rx::SharedSwapState *)swapState
42              withContext:(CGLContextObj)displayContext
43            withFunctions:(const rx::FunctionsGL *)functions
44{
45    self = [super init];
46    if (self != nil)
47    {
48        self.asynchronous = YES;
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- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
62{
63    CGLPixelFormatAttribute attribs[] = {
64        kCGLPFADisplayMask, static_cast<CGLPixelFormatAttribute>(mask), kCGLPFAOpenGLProfile,
65        static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core),
66        static_cast<CGLPixelFormatAttribute>(0)};
67
68    CGLPixelFormatObj pixelFormat = nullptr;
69    GLint numFormats              = 0;
70    CGLChoosePixelFormat(attribs, &pixelFormat, &numFormats);
71
72    return pixelFormat;
73}
74
75- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
76{
77    CGLContextObj context = nullptr;
78    CGLCreateContext(pixelFormat, mDisplayContext, &context);
79    return context;
80}
81
82- (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
83                pixelFormat:(CGLPixelFormatObj)pixelFormat
84               forLayerTime:(CFTimeInterval)timeInterval
85                displayTime:(const CVTimeStamp *)timeStamp
86{
87    BOOL result = NO;
88
89    pthread_mutex_lock(&mSwapState->mutex);
90    {
91        if (mSwapState->lastRendered->swapId > mSwapState->beingPresented->swapId)
92        {
93            std::swap(mSwapState->lastRendered, mSwapState->beingPresented);
94            result = YES;
95        }
96    }
97    pthread_mutex_unlock(&mSwapState->mutex);
98
99    return result;
100}
101
102- (void)drawInCGLContext:(CGLContextObj)glContext
103             pixelFormat:(CGLPixelFormatObj)pixelFormat
104            forLayerTime:(CFTimeInterval)timeInterval
105             displayTime:(const CVTimeStamp *)timeStamp
106{
107    CGLSetCurrentContext(glContext);
108    if (!initialized)
109    {
110        initialized = true;
111
112        mFunctions->genFramebuffers(1, &mReadFramebuffer);
113    }
114
115    const auto &texture = *mSwapState->beingPresented;
116    if ([self frame].size.width != texture.width || [self frame].size.height != texture.height)
117    {
118        [self setFrame:CGRectMake(0, 0, texture.width, texture.height)];
119
120        // Without this, the OSX compositor / window system doesn't see the resize.
121        [self setNeedsDisplay];
122    }
123
124    // TODO(cwallez) support 2.1 contexts too that don't have blitFramebuffer nor the
125    // GL_DRAW_FRAMEBUFFER_BINDING query
126    GLint drawFBO;
127    mFunctions->getIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFBO);
128
129    mFunctions->bindFramebuffer(GL_FRAMEBUFFER, mReadFramebuffer);
130    mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
131                                     texture.texture, 0);
132
133    mFunctions->bindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer);
134    mFunctions->bindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
135    mFunctions->blitFramebuffer(0, 0, texture.width, texture.height, 0, 0, texture.width,
136                                texture.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
137
138    // Call the super method to flush the context
139    [super drawInCGLContext:glContext
140                pixelFormat:pixelFormat
141               forLayerTime:timeInterval
142                displayTime:timeStamp];
143}
144@end
145
146namespace rx
147{
148
149WindowSurfaceCGL::WindowSurfaceCGL(const egl::SurfaceState &state,
150                                   RendererGL *renderer,
151                                   EGLNativeWindowType layer,
152                                   CGLContextObj context)
153    : SurfaceGL(state),
154      mSwapLayer(nil),
155      mCurrentSwapId(0),
156      mLayer((__bridge CALayer *)layer),
157      mContext(context),
158      mFunctions(renderer->getFunctions()),
159      mStateManager(renderer->getStateManager()),
160      mDSRenderbuffer(0)
161{
162    pthread_mutex_init(&mSwapState.mutex, nullptr);
163}
164
165WindowSurfaceCGL::~WindowSurfaceCGL()
166{
167    pthread_mutex_destroy(&mSwapState.mutex);
168
169    if (mDSRenderbuffer != 0)
170    {
171        mFunctions->deleteRenderbuffers(1, &mDSRenderbuffer);
172        mDSRenderbuffer = 0;
173    }
174
175    if (mSwapLayer != nil)
176    {
177        [mSwapLayer removeFromSuperlayer];
178        [mSwapLayer release];
179        mSwapLayer = nil;
180    }
181
182    for (size_t i = 0; i < ArraySize(mSwapState.textures); ++i)
183    {
184        if (mSwapState.textures[i].texture != 0)
185        {
186            mFunctions->deleteTextures(1, &mSwapState.textures[i].texture);
187            mSwapState.textures[i].texture = 0;
188        }
189    }
190}
191
192egl::Error WindowSurfaceCGL::initialize(const egl::Display *display)
193{
194    unsigned width  = getWidth();
195    unsigned height = getHeight();
196
197    for (size_t i = 0; i < ArraySize(mSwapState.textures); ++i)
198    {
199        mFunctions->genTextures(1, &mSwapState.textures[i].texture);
200        mStateManager->bindTexture(gl::TextureType::_2D, mSwapState.textures[i].texture);
201        mFunctions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
202                               GL_UNSIGNED_BYTE, nullptr);
203        mSwapState.textures[i].width  = width;
204        mSwapState.textures[i].height = height;
205        mSwapState.textures[i].swapId = 0;
206    }
207    mSwapState.beingRendered  = &mSwapState.textures[0];
208    mSwapState.lastRendered   = &mSwapState.textures[1];
209    mSwapState.beingPresented = &mSwapState.textures[2];
210
211    mSwapLayer = [[WebSwapLayer alloc] initWithSharedState:&mSwapState
212                                               withContext:mContext
213                                             withFunctions:mFunctions];
214    [mLayer addSublayer:mSwapLayer];
215    [mSwapLayer setContentsScale:[mLayer contentsScale]];
216
217    mFunctions->genRenderbuffers(1, &mDSRenderbuffer);
218    mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDSRenderbuffer);
219    mFunctions->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
220
221    return egl::Error(EGL_SUCCESS);
222}
223
224egl::Error WindowSurfaceCGL::makeCurrent(const gl::Context *context)
225{
226    return egl::Error(EGL_SUCCESS);
227}
228
229egl::Error WindowSurfaceCGL::swap(const gl::Context *context)
230{
231    const FunctionsGL *functions = GetFunctionsGL(context);
232    StateManagerGL *stateManager = GetStateManagerGL(context);
233
234    functions->flush();
235    mSwapState.beingRendered->swapId = ++mCurrentSwapId;
236
237    pthread_mutex_lock(&mSwapState.mutex);
238    {
239        std::swap(mSwapState.beingRendered, mSwapState.lastRendered);
240    }
241    pthread_mutex_unlock(&mSwapState.mutex);
242
243    unsigned width  = getWidth();
244    unsigned height = getHeight();
245    auto &texture   = *mSwapState.beingRendered;
246
247    if (texture.width != width || texture.height != height)
248    {
249        stateManager->bindTexture(gl::TextureType::_2D, texture.texture);
250        functions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
251                              GL_UNSIGNED_BYTE, nullptr);
252
253        stateManager->bindRenderbuffer(GL_RENDERBUFFER, mDSRenderbuffer);
254        functions->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
255
256        texture.width  = width;
257        texture.height = height;
258    }
259
260    FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(context->getFramebuffer({0}));
261    stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebufferGL->getFramebufferID());
262    functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
263                                    mSwapState.beingRendered->texture, 0);
264
265    return egl::Error(EGL_SUCCESS);
266}
267
268egl::Error WindowSurfaceCGL::postSubBuffer(const gl::Context *context,
269                                           EGLint x,
270                                           EGLint y,
271                                           EGLint width,
272                                           EGLint height)
273{
274    UNIMPLEMENTED();
275    return egl::Error(EGL_SUCCESS);
276}
277
278egl::Error WindowSurfaceCGL::querySurfacePointerANGLE(EGLint attribute, void **value)
279{
280    UNIMPLEMENTED();
281    return egl::Error(EGL_SUCCESS);
282}
283
284egl::Error WindowSurfaceCGL::bindTexImage(const gl::Context *context,
285                                          gl::Texture *texture,
286                                          EGLint buffer)
287{
288    UNIMPLEMENTED();
289    return egl::Error(EGL_SUCCESS);
290}
291
292egl::Error WindowSurfaceCGL::releaseTexImage(const gl::Context *context, EGLint buffer)
293{
294    UNIMPLEMENTED();
295    return egl::Error(EGL_SUCCESS);
296}
297
298void WindowSurfaceCGL::setSwapInterval(EGLint interval)
299{
300    // TODO(cwallez) investigate implementing swap intervals other than 0
301}
302
303EGLint WindowSurfaceCGL::getWidth() const
304{
305    return static_cast<EGLint>(CGRectGetWidth([mLayer frame]) * [mLayer contentsScale]);
306}
307
308EGLint WindowSurfaceCGL::getHeight() const
309{
310    return static_cast<EGLint>(CGRectGetHeight([mLayer frame]) * [mLayer contentsScale]);
311}
312
313EGLint WindowSurfaceCGL::isPostSubBufferSupported() const
314{
315    UNIMPLEMENTED();
316    return EGL_FALSE;
317}
318
319EGLint WindowSurfaceCGL::getSwapBehavior() const
320{
321    return EGL_BUFFER_DESTROYED;
322}
323
324FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::Context *context,
325                                                            const gl::FramebufferState &state)
326{
327    const FunctionsGL *functions = GetFunctionsGL(context);
328    StateManagerGL *stateManager = GetStateManagerGL(context);
329
330    GLuint framebuffer = 0;
331    functions->genFramebuffers(1, &framebuffer);
332    stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
333    functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
334                                    mSwapState.beingRendered->texture, 0);
335    functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
336                                       mDSRenderbuffer);
337
338    return new FramebufferGL(state, framebuffer, true, false);
339}
340
341}  // namespace rx
342
343#endif  // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
344