[WPE] libepoxy headers can use EGL_CAST, which might not be defined by eglplatform.h
[WebKit-https.git] / Source / WebCore / platform / graphics / egl / GLContextEGL.cpp
1 /*
2  * Copyright (C) 2012 Igalia, S.L.
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20 #include "GLContextEGL.h"
21
22 #if USE(EGL)
23
24 #include "GraphicsContext3D.h"
25 #include "PlatformDisplay.h"
26
27 #if USE(LIBEPOXY)
28 #include "EpoxyEGL.h"
29 #else
30 #include <EGL/egl.h>
31 #endif
32
33 #if USE(CAIRO)
34 #include <cairo.h>
35 #endif
36
37 #if USE(LIBEPOXY)
38 #include <epoxy/gl.h>
39 #elif USE(OPENGL_ES_2)
40 #define GL_GLEXT_PROTOTYPES 1
41 #include <GLES2/gl2.h>
42 #include <GLES2/gl2ext.h>
43 #else
44 #include "OpenGLShims.h"
45 #endif
46
47 #if ENABLE(ACCELERATED_2D_CANVAS)
48 // cairo-gl.h includes some definitions from GLX that conflict with
49 // the ones provided by us. Since GLContextEGL doesn't use any GLX
50 // functions we can safely disable them.
51 #undef CAIRO_HAS_GLX_FUNCTIONS
52 #include <cairo-gl.h>
53 #endif
54
55 namespace WebCore {
56
57 static const EGLint gContextAttributes[] = {
58 #if USE(OPENGL_ES_2)
59     EGL_CONTEXT_CLIENT_VERSION, 2,
60 #endif
61     EGL_NONE
62 };
63
64 #if USE(OPENGL_ES_2)
65 static const EGLenum gEGLAPIVersion = EGL_OPENGL_ES_API;
66 #else
67 static const EGLenum gEGLAPIVersion = EGL_OPENGL_API;
68 #endif
69
70 bool GLContextEGL::getEGLConfig(EGLDisplay display, EGLConfig* config, EGLSurfaceType surfaceType)
71 {
72     EGLint attributeList[] = {
73 #if USE(OPENGL_ES_2)
74         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
75 #else
76         EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
77 #endif
78         EGL_RED_SIZE, 8,
79         EGL_GREEN_SIZE, 8,
80         EGL_BLUE_SIZE, 8,
81         EGL_STENCIL_SIZE, 8,
82         EGL_ALPHA_SIZE, 8,
83         EGL_SURFACE_TYPE, EGL_NONE,
84         EGL_NONE
85     };
86
87     switch (surfaceType) {
88     case GLContextEGL::PbufferSurface:
89         attributeList[13] = EGL_PBUFFER_BIT;
90         break;
91     case GLContextEGL::PixmapSurface:
92         attributeList[13] = EGL_PIXMAP_BIT;
93         break;
94     case GLContextEGL::WindowSurface:
95     case GLContextEGL::Surfaceless:
96         attributeList[13] = EGL_WINDOW_BIT;
97         break;
98     }
99
100     EGLint numberConfigsReturned;
101     return eglChooseConfig(display, attributeList, config, 1, &numberConfigsReturned) && numberConfigsReturned;
102 }
103
104 std::unique_ptr<GLContextEGL> GLContextEGL::createWindowContext(GLNativeWindowType window, PlatformDisplay& platformDisplay, EGLContext sharingContext)
105 {
106     EGLDisplay display = platformDisplay.eglDisplay();
107     EGLConfig config;
108     if (!getEGLConfig(display, &config, WindowSurface))
109         return nullptr;
110
111     EGLContext context = eglCreateContext(display, config, sharingContext, gContextAttributes);
112     if (context == EGL_NO_CONTEXT)
113         return nullptr;
114
115     EGLSurface surface = EGL_NO_SURFACE;
116 #if PLATFORM(GTK)
117 #if PLATFORM(X11)
118     if (platformDisplay.type() == PlatformDisplay::Type::X11)
119         surface = createWindowSurfaceX11(display, config, window);
120 #endif
121 #if PLATFORM(WAYLAND)
122     if (platformDisplay.type() == PlatformDisplay::Type::Wayland)
123         surface = createWindowSurfaceWayland(display, config, window);
124 #endif
125 #elif PLATFORM(WPE)
126     if (platformDisplay.type() == PlatformDisplay::Type::WPE)
127         surface = createWindowSurfaceWPE(display, config, window);
128 #else
129     surface = eglCreateWindowSurface(display, config, static_cast<EGLNativeWindowType>(window), nullptr);
130 #endif
131     if (surface == EGL_NO_SURFACE) {
132         eglDestroyContext(display, context);
133         return nullptr;
134     }
135
136     return std::unique_ptr<GLContextEGL>(new GLContextEGL(platformDisplay, context, surface, WindowSurface));
137 }
138
139 std::unique_ptr<GLContextEGL> GLContextEGL::createPbufferContext(PlatformDisplay& platformDisplay, EGLContext sharingContext)
140 {
141     EGLDisplay display = platformDisplay.eglDisplay();
142     EGLConfig config;
143     if (!getEGLConfig(display, &config, PbufferSurface))
144         return nullptr;
145
146     EGLContext context = eglCreateContext(display, config, sharingContext, gContextAttributes);
147     if (context == EGL_NO_CONTEXT)
148         return nullptr;
149
150     static const int pbufferAttributes[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
151     EGLSurface surface = eglCreatePbufferSurface(display, config, pbufferAttributes);
152     if (surface == EGL_NO_SURFACE) {
153         eglDestroyContext(display, context);
154         return nullptr;
155     }
156
157     return std::unique_ptr<GLContextEGL>(new GLContextEGL(platformDisplay, context, surface, PbufferSurface));
158 }
159
160 std::unique_ptr<GLContextEGL> GLContextEGL::createSurfacelessContext(PlatformDisplay& platformDisplay, EGLContext sharingContext)
161 {
162     EGLDisplay display = platformDisplay.eglDisplay();
163     if (display == EGL_NO_DISPLAY)
164         return nullptr;
165
166     const char* extensions = eglQueryString(display, EGL_EXTENSIONS);
167     if (!GLContext::isExtensionSupported(extensions, "EGL_KHR_surfaceless_context") && !GLContext::isExtensionSupported(extensions, "EGL_KHR_surfaceless_opengl"))
168         return nullptr;
169
170     EGLConfig config;
171     if (!getEGLConfig(display, &config, Surfaceless))
172         return nullptr;
173
174     EGLContext context = eglCreateContext(display, config, sharingContext, gContextAttributes);
175     if (context == EGL_NO_CONTEXT)
176         return nullptr;
177
178     return std::unique_ptr<GLContextEGL>(new GLContextEGL(platformDisplay, context, EGL_NO_SURFACE, Surfaceless));
179 }
180
181 std::unique_ptr<GLContextEGL> GLContextEGL::createContext(GLNativeWindowType window, PlatformDisplay& platformDisplay)
182 {
183     if (platformDisplay.eglDisplay() == EGL_NO_DISPLAY)
184         return nullptr;
185
186     if (eglBindAPI(gEGLAPIVersion) == EGL_FALSE)
187         return nullptr;
188
189     EGLContext eglSharingContext = platformDisplay.sharingGLContext() ? static_cast<GLContextEGL*>(platformDisplay.sharingGLContext())->m_context : EGL_NO_CONTEXT;
190     auto context = window ? createWindowContext(window, platformDisplay, eglSharingContext) : nullptr;
191     if (!context)
192         context = createSurfacelessContext(platformDisplay, eglSharingContext);
193     if (!context) {
194 #if PLATFORM(X11)
195         if (platformDisplay.type() == PlatformDisplay::Type::X11)
196             context = createPixmapContext(platformDisplay, eglSharingContext);
197 #endif
198 #if PLATFORM(WAYLAND)
199         if (platformDisplay.type() == PlatformDisplay::Type::Wayland)
200             context = createWaylandContext(platformDisplay, eglSharingContext);
201 #endif
202 #if PLATFORM(WPE)
203         if (platformDisplay.type() == PlatformDisplay::Type::WPE)
204             context = createWPEContext(platformDisplay, eglSharingContext);
205 #endif
206     }
207     if (!context)
208         context = createPbufferContext(platformDisplay, eglSharingContext);
209
210     return context;
211 }
212
213 std::unique_ptr<GLContextEGL> GLContextEGL::createSharingContext(PlatformDisplay& platformDisplay)
214 {
215     if (platformDisplay.eglDisplay() == EGL_NO_DISPLAY)
216         return nullptr;
217
218     if (eglBindAPI(gEGLAPIVersion) == EGL_FALSE)
219         return nullptr;
220
221     auto context = createSurfacelessContext(platformDisplay);
222     if (!context) {
223 #if PLATFORM(X11)
224         if (platformDisplay.type() == PlatformDisplay::Type::X11)
225             context = createPixmapContext(platformDisplay);
226 #endif
227 #if PLATFORM(WAYLAND)
228         if (platformDisplay.type() == PlatformDisplay::Type::Wayland)
229             context = createWaylandContext(platformDisplay);
230 #endif
231 #if PLATFORM(WPE)
232         if (platformDisplay.type() == PlatformDisplay::Type::WPE)
233             context = createWPEContext(platformDisplay);
234 #endif
235     }
236     if (!context)
237         context = createPbufferContext(platformDisplay);
238
239     return context;
240 }
241
242 GLContextEGL::GLContextEGL(PlatformDisplay& display, EGLContext context, EGLSurface surface, EGLSurfaceType type)
243     : GLContext(display)
244     , m_context(context)
245     , m_surface(surface)
246     , m_type(type)
247 {
248     ASSERT(type != PixmapSurface);
249     ASSERT(type == Surfaceless || surface != EGL_NO_SURFACE);
250 }
251
252 GLContextEGL::~GLContextEGL()
253 {
254 #if USE(CAIRO)
255     if (m_cairoDevice)
256         cairo_device_destroy(m_cairoDevice);
257 #endif
258
259     EGLDisplay display = m_display.eglDisplay();
260     if (m_context) {
261         glBindFramebuffer(GL_FRAMEBUFFER, 0);
262         eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
263         eglDestroyContext(display, m_context);
264     }
265
266     if (m_surface)
267         eglDestroySurface(display, m_surface);
268
269 #if PLATFORM(WAYLAND)
270     destroyWaylandWindow();
271 #endif
272 #if PLATFORM(WPE)
273     destroyWPETarget();
274 #endif
275 }
276
277 bool GLContextEGL::canRenderToDefaultFramebuffer()
278 {
279     return m_type == WindowSurface;
280 }
281
282 IntSize GLContextEGL::defaultFrameBufferSize()
283 {
284     if (!canRenderToDefaultFramebuffer())
285         return IntSize();
286
287     EGLDisplay display = m_display.eglDisplay();
288     EGLint width, height;
289     if (!eglQuerySurface(display, m_surface, EGL_WIDTH, &width)
290         || !eglQuerySurface(display, m_surface, EGL_HEIGHT, &height))
291         return IntSize();
292
293     return IntSize(width, height);
294 }
295
296 bool GLContextEGL::makeContextCurrent()
297 {
298     ASSERT(m_context);
299
300     GLContext::makeContextCurrent();
301     if (eglGetCurrentContext() == m_context)
302         return true;
303
304     return eglMakeCurrent(m_display.eglDisplay(), m_surface, m_surface, m_context);
305 }
306
307 void GLContextEGL::swapBuffers()
308 {
309     ASSERT(m_surface);
310     eglSwapBuffers(m_display.eglDisplay(), m_surface);
311 }
312
313 void GLContextEGL::waitNative()
314 {
315     eglWaitNative(EGL_CORE_NATIVE_ENGINE);
316 }
317
318 void GLContextEGL::swapInterval(int interval)
319 {
320     ASSERT(m_surface);
321     eglSwapInterval(m_display.eglDisplay(), interval);
322 }
323
324 #if USE(CAIRO)
325 cairo_device_t* GLContextEGL::cairoDevice()
326 {
327     if (m_cairoDevice)
328         return m_cairoDevice;
329
330 #if ENABLE(ACCELERATED_2D_CANVAS)
331     m_cairoDevice = cairo_egl_device_create(m_display.eglDisplay(), m_context);
332 #endif
333
334     return m_cairoDevice;
335 }
336 #endif
337
338 #if ENABLE(GRAPHICS_CONTEXT_3D)
339 PlatformGraphicsContext3D GLContextEGL::platformContext()
340 {
341     return m_context;
342 }
343 #endif
344
345 } // namespace WebCore
346
347 #endif // USE(EGL)