b9389b483f93cc24ed452acbeffc0da2c6d80bb0
[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 <wtf/OwnPtr.h>
26
27 #if USE(OPENGL_ES_2)
28 #include <GLES2/gl2.h>
29 #include <GLES2/gl2ext.h>
30 #else
31 #include "OpenGLShims.h"
32 #endif
33
34 namespace WebCore {
35
36 static EGLDisplay gSharedEGLDisplay = EGL_NO_DISPLAY;
37
38 #if USE(OPENGL_ES_2)
39 static const EGLenum gGLAPI = EGL_OPENGL_ES_API;
40 #else
41 static const EGLenum gGLAPI = EGL_OPENGL_API;
42 #endif
43
44 static EGLDisplay sharedEGLDisplay()
45 {
46     static bool initialized = false;
47     if (!initialized) {
48         initialized = true;
49 #if PLATFORM(X11)
50         gSharedEGLDisplay = eglGetDisplay(GLContext::sharedX11Display());
51 #else
52         gSharedEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
53 #endif
54         if (gSharedEGLDisplay != EGL_NO_DISPLAY && (!eglInitialize(gSharedEGLDisplay, 0, 0) || !eglBindAPI(gGLAPI)))
55             gSharedEGLDisplay = EGL_NO_DISPLAY;
56     }
57     return gSharedEGLDisplay;
58 }
59
60 static const EGLint gContextAttributes[] = {
61 #if USE(OPENGL_ES_2)
62     EGL_CONTEXT_CLIENT_VERSION, 2,
63 #endif
64     EGL_NONE
65 };
66
67 static bool getEGLConfig(EGLConfig* config, GLContextEGL::EGLSurfaceType surfaceType)
68 {
69     EGLint attributeList[] = {
70 #if USE(OPENGL_ES_2)
71         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
72 #else
73         EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
74 #endif
75         EGL_RED_SIZE, 8,
76         EGL_GREEN_SIZE, 8,
77         EGL_BLUE_SIZE, 8,
78         EGL_STENCIL_SIZE, 8,
79         EGL_ALPHA_SIZE, 8,
80         EGL_SURFACE_TYPE, EGL_NONE,
81         EGL_NONE
82     };
83
84     switch (surfaceType) {
85     case GLContextEGL::PbufferSurface:
86         attributeList[13] = EGL_PBUFFER_BIT;
87         break;
88     case GLContextEGL::PixmapSurface:
89         attributeList[13] = EGL_PIXMAP_BIT;
90         break;
91     case GLContextEGL::WindowSurface:
92         attributeList[13] = EGL_WINDOW_BIT;
93         break;
94     }
95
96     EGLint numberConfigsReturned;
97     return eglChooseConfig(sharedEGLDisplay(), attributeList, config, 1, &numberConfigsReturned) && numberConfigsReturned;
98 }
99
100 PassOwnPtr<GLContextEGL> GLContextEGL::createWindowContext(EGLNativeWindowType window, GLContext* sharingContext)
101 {
102     EGLContext eglSharingContext = sharingContext ? static_cast<GLContextEGL*>(sharingContext)->m_context : 0;
103
104     EGLDisplay display = sharedEGLDisplay();
105     if (display == EGL_NO_DISPLAY)
106         return nullptr;
107
108     EGLConfig config;
109     if (!getEGLConfig(&config, WindowSurface))
110         return nullptr;
111
112     EGLContext context = eglCreateContext(display, config, eglSharingContext, gContextAttributes);
113     if (context == EGL_NO_CONTEXT)
114         return nullptr;
115
116     EGLSurface surface = eglCreateWindowSurface(display, config, window, 0);
117     if (surface == EGL_NO_SURFACE)
118         return nullptr;
119
120     return adoptPtr(new GLContextEGL(context, surface, WindowSurface));
121 }
122
123 PassOwnPtr<GLContextEGL> GLContextEGL::createPbufferContext(EGLContext sharingContext)
124 {
125     EGLDisplay display = sharedEGLDisplay();
126     if (display == EGL_NO_DISPLAY)
127         return nullptr;
128
129     EGLConfig config;
130     if (!getEGLConfig(&config, PbufferSurface))
131         return nullptr;
132
133     EGLContext context = eglCreateContext(display, config, sharingContext, gContextAttributes);
134     if (context == EGL_NO_CONTEXT)
135         return nullptr;
136
137     static const int pbufferAttributes[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
138     EGLSurface surface = eglCreatePbufferSurface(display, config, pbufferAttributes);
139     if (surface == EGL_NO_SURFACE) {
140         eglDestroyContext(display, context);
141         return nullptr;
142     }
143
144     return adoptPtr(new GLContextEGL(context, surface, PbufferSurface));
145 }
146
147 PassOwnPtr<GLContextEGL> GLContextEGL::createPixmapContext(EGLContext sharingContext)
148 {
149 #if PLATFORM(X11)
150     EGLDisplay display = sharedEGLDisplay();
151     if (display == EGL_NO_DISPLAY)
152         return nullptr;
153
154     EGLConfig config;
155     if (!getEGLConfig(&config, PixmapSurface))
156         return nullptr;
157
158     EGLContext context = eglCreateContext(display, config, sharingContext, gContextAttributes);
159     if (context == EGL_NO_CONTEXT)
160         return nullptr;
161
162     EGLint depth;
163     if (!eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth))
164         return nullptr;
165
166     Pixmap pixmap = XCreatePixmap(sharedX11Display(), DefaultRootWindow(sharedX11Display()), 1, 1, depth);
167     if (!pixmap)
168         return nullptr;
169
170     EGLSurface surface = eglCreatePixmapSurface(display, config, pixmap, 0);
171 #else
172     EGLSurface surface = EGL_NO_SURFACE;
173 #endif
174     if (surface == EGL_NO_SURFACE)
175         return nullptr;
176
177     return adoptPtr(new GLContextEGL(context, surface, PixmapSurface));
178 }
179
180 PassOwnPtr<GLContextEGL> GLContextEGL::createContext(EGLNativeWindowType window, GLContext* sharingContext)
181 {
182     if (!sharedEGLDisplay())
183         return nullptr;
184
185     static bool initialized = false;
186     static bool success = true;
187     if (!initialized) {
188 #if !USE(OPENGL_ES_2)
189         success = initializeOpenGLShims();
190 #endif
191         initialized = true;
192     }
193     if (!success)
194         return nullptr;
195
196     EGLContext eglSharingContext = sharingContext ? static_cast<GLContextEGL*>(sharingContext)->m_context : 0;
197     OwnPtr<GLContextEGL> context = window ? createWindowContext(window, sharingContext) : nullptr;
198     if (!context)
199         context = createPixmapContext(eglSharingContext);
200
201     if (!context)
202         context = createPbufferContext(eglSharingContext);
203     
204     return context.release();
205 }
206
207 GLContextEGL::GLContextEGL(EGLContext context, EGLSurface surface, EGLSurfaceType type)
208     : m_context(context)
209     , m_surface(surface)
210     , m_type(type)
211 {
212 }
213
214 GLContextEGL::~GLContextEGL()
215 {
216     EGLDisplay display = sharedEGLDisplay();
217     if (m_context) {
218         glBindFramebuffer(GL_FRAMEBUFFER, 0);
219         eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
220         eglDestroyContext(display, m_context);
221     }
222
223     if (m_surface)
224         eglDestroySurface(display, m_surface);
225 }
226
227 bool GLContextEGL::canRenderToDefaultFramebuffer()
228 {
229     return m_type == WindowSurface;
230 }
231
232 IntSize GLContextEGL::defaultFrameBufferSize()
233 {
234     if (!canRenderToDefaultFramebuffer())
235         return IntSize();
236
237     EGLint width, height;
238     if (!eglQuerySurface(sharedEGLDisplay(), m_surface, EGL_WIDTH, &width)
239         || !eglQuerySurface(sharedEGLDisplay(), m_surface, EGL_HEIGHT, &height))
240         return IntSize();
241
242     return IntSize(width, height);
243 }
244
245 bool GLContextEGL::makeContextCurrent()
246 {
247     ASSERT(m_context && m_surface);
248
249     GLContext::makeContextCurrent();
250     if (eglGetCurrentContext() == m_context)
251         return true;
252
253     return eglMakeCurrent(sharedEGLDisplay(), m_surface, m_surface, m_context);
254 }
255
256 void GLContextEGL::swapBuffers()
257 {
258     ASSERT(m_surface);
259     eglSwapBuffers(sharedEGLDisplay(), m_surface);
260 }
261
262 void GLContextEGL::waitNative()
263 {
264     eglWaitNative(EGL_CORE_NATIVE_ENGINE);
265 }
266
267 #if ENABLE(WEBGL)
268 PlatformGraphicsContext3D GLContextEGL::platformContext()
269 {
270     return m_context;
271 }
272 #endif
273
274 } // namespace WebCore
275
276 #endif // USE(EGL)