Build ANGLE as a dynamic library
[WebKit-https.git] / Source / ThirdParty / ANGLE / src / libANGLE / renderer / gl / cgl / WindowSurfaceCGL.mm
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
146 namespace rx
147 {
148
149 WindowSurfaceCGL::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
165 WindowSurfaceCGL::~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 = nil;
179     }
180
181     for (size_t i = 0; i < ArraySize(mSwapState.textures); ++i)
182     {
183         if (mSwapState.textures[i].texture != 0)
184         {
185             mFunctions->deleteTextures(1, &mSwapState.textures[i].texture);
186             mSwapState.textures[i].texture = 0;
187         }
188     }
189 }
190
191 egl::Error WindowSurfaceCGL::initialize(const egl::Display *display)
192 {
193     unsigned width  = getWidth();
194     unsigned height = getHeight();
195
196     for (size_t i = 0; i < ArraySize(mSwapState.textures); ++i)
197     {
198         mFunctions->genTextures(1, &mSwapState.textures[i].texture);
199         mStateManager->bindTexture(gl::TextureType::_2D, mSwapState.textures[i].texture);
200         mFunctions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
201                                GL_UNSIGNED_BYTE, nullptr);
202         mSwapState.textures[i].width  = width;
203         mSwapState.textures[i].height = height;
204         mSwapState.textures[i].swapId = 0;
205     }
206     mSwapState.beingRendered  = &mSwapState.textures[0];
207     mSwapState.lastRendered   = &mSwapState.textures[1];
208     mSwapState.beingPresented = &mSwapState.textures[2];
209
210     mSwapLayer = [[WebSwapLayer alloc] initWithSharedState:&mSwapState
211                                                withContext:mContext
212                                              withFunctions:mFunctions];
213     [mLayer addSublayer:mSwapLayer];
214
215     mFunctions->genRenderbuffers(1, &mDSRenderbuffer);
216     mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mDSRenderbuffer);
217     mFunctions->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
218
219     return egl::Error(EGL_SUCCESS);
220 }
221
222 egl::Error WindowSurfaceCGL::makeCurrent(const gl::Context *context)
223 {
224     return egl::Error(EGL_SUCCESS);
225 }
226
227 egl::Error WindowSurfaceCGL::swap(const gl::Context *context)
228 {
229     const FunctionsGL *functions = GetFunctionsGL(context);
230     StateManagerGL *stateManager = GetStateManagerGL(context);
231
232     functions->flush();
233     mSwapState.beingRendered->swapId = ++mCurrentSwapId;
234
235     pthread_mutex_lock(&mSwapState.mutex);
236     {
237         std::swap(mSwapState.beingRendered, mSwapState.lastRendered);
238     }
239     pthread_mutex_unlock(&mSwapState.mutex);
240
241     unsigned width  = getWidth();
242     unsigned height = getHeight();
243     auto &texture   = *mSwapState.beingRendered;
244
245     if (texture.width != width || texture.height != height)
246     {
247         stateManager->bindTexture(gl::TextureType::_2D, texture.texture);
248         functions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
249                               GL_UNSIGNED_BYTE, nullptr);
250
251         stateManager->bindRenderbuffer(GL_RENDERBUFFER, mDSRenderbuffer);
252         functions->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
253
254         texture.width  = width;
255         texture.height = height;
256     }
257
258     FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(context->getFramebuffer({0}));
259     stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebufferGL->getFramebufferID());
260     functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
261                                     mSwapState.beingRendered->texture, 0);
262
263     return egl::Error(EGL_SUCCESS);
264 }
265
266 egl::Error WindowSurfaceCGL::postSubBuffer(const gl::Context *context,
267                                            EGLint x,
268                                            EGLint y,
269                                            EGLint width,
270                                            EGLint height)
271 {
272     UNIMPLEMENTED();
273     return egl::Error(EGL_SUCCESS);
274 }
275
276 egl::Error WindowSurfaceCGL::querySurfacePointerANGLE(EGLint attribute, void **value)
277 {
278     UNIMPLEMENTED();
279     return egl::Error(EGL_SUCCESS);
280 }
281
282 egl::Error WindowSurfaceCGL::bindTexImage(const gl::Context *context,
283                                           gl::Texture *texture,
284                                           EGLint buffer)
285 {
286     UNIMPLEMENTED();
287     return egl::Error(EGL_SUCCESS);
288 }
289
290 egl::Error WindowSurfaceCGL::releaseTexImage(const gl::Context *context, EGLint buffer)
291 {
292     UNIMPLEMENTED();
293     return egl::Error(EGL_SUCCESS);
294 }
295
296 void WindowSurfaceCGL::setSwapInterval(EGLint interval)
297 {
298     // TODO(cwallez) investigate implementing swap intervals other than 0
299 }
300
301 EGLint WindowSurfaceCGL::getWidth() const
302 {
303     return (EGLint)CGRectGetWidth([mLayer frame]);
304 }
305
306 EGLint WindowSurfaceCGL::getHeight() const
307 {
308     return (EGLint)CGRectGetHeight([mLayer frame]);
309 }
310
311 EGLint WindowSurfaceCGL::isPostSubBufferSupported() const
312 {
313     UNIMPLEMENTED();
314     return EGL_FALSE;
315 }
316
317 EGLint WindowSurfaceCGL::getSwapBehavior() const
318 {
319     return EGL_BUFFER_DESTROYED;
320 }
321
322 FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::Context *context,
323                                                             const gl::FramebufferState &state)
324 {
325     const FunctionsGL *functions = GetFunctionsGL(context);
326     StateManagerGL *stateManager = GetStateManagerGL(context);
327
328     GLuint framebuffer = 0;
329     functions->genFramebuffers(1, &framebuffer);
330     stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
331     functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
332                                     mSwapState.beingRendered->texture, 0);
333     functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
334                                        mDSRenderbuffer);
335
336     return new FramebufferGL(state, framebuffer, true, false);
337 }
338
339 }  // namespace rx
340
341 #endif  // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)