31f32cf0b800c900e5318ee505995e1b37c97606
[WebKit-https.git] / Source / WebCore / platform / graphics / glx / GLContextGLX.cpp
1 /*
2  * Copyright (C) 2011, 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 "GLContextGLX.h"
21
22 #if USE(GLX)
23 #include "GraphicsContext3D.h"
24 #include "OpenGLShims.h"
25 #include <GL/glx.h>
26 #include <wtf/OwnPtr.h>
27
28 namespace WebCore {
29
30 PassOwnPtr<GLContextGLX> GLContextGLX::createWindowContext(XID window, GLContext* sharingContext)
31 {
32     Display* display = sharedX11Display();
33     XWindowAttributes attributes;
34     if (!XGetWindowAttributes(display, window, &attributes))
35         return nullptr;
36
37     XVisualInfo visualInfo;
38     visualInfo.visualid = XVisualIDFromVisual(attributes.visual);
39
40     int numReturned = 0;
41     XVisualInfo* visualInfoList = XGetVisualInfo(display, VisualIDMask, &visualInfo, &numReturned);
42
43     GLXContext glxSharingContext = sharingContext ? static_cast<GLContextGLX*>(sharingContext)->m_context : 0;
44     GLXContext context = glXCreateContext(display, visualInfoList, glxSharingContext, True);
45     XFree(visualInfoList);
46
47     if (!context)
48         return nullptr;
49
50     // GLXPbuffer and XID are both the same types underneath, so we have to share
51     // a constructor here with the window path.
52     GLContextGLX* contextWrapper = new GLContextGLX(context);
53     contextWrapper->m_window = window;
54     return adoptPtr(contextWrapper);
55 }
56
57 PassOwnPtr<GLContextGLX> GLContextGLX::createPbufferContext(GLXContext sharingContext)
58 {
59     int fbConfigAttributes[] = {
60         GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
61         GLX_RENDER_TYPE, GLX_RGBA_BIT,
62         GLX_RED_SIZE, 1,
63         GLX_GREEN_SIZE, 1,
64         GLX_BLUE_SIZE, 1,
65         GLX_ALPHA_SIZE, 1,
66         GLX_DOUBLEBUFFER, GL_FALSE,
67         0
68     };
69
70     int returnedElements;
71     Display* display = sharedX11Display();
72     GLXFBConfig* configs = glXChooseFBConfig(display, 0, fbConfigAttributes, &returnedElements);
73     if (!returnedElements) {
74         XFree(configs);
75         return nullptr;
76     }
77
78     // We will be rendering to a texture, so our pbuffer does not need to be large.
79     static const int pbufferAttributes[] = { GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, 0 };
80     GLXPbuffer pbuffer = glXCreatePbuffer(display, configs[0], pbufferAttributes);
81     if (!pbuffer) {
82         XFree(configs);
83         return nullptr;
84     }
85
86     GLXContext context = glXCreateNewContext(display, configs[0], GLX_RGBA_TYPE, sharingContext, GL_TRUE);
87     XFree(configs);
88     if (!context) {
89         glXDestroyPbuffer(display, pbuffer);
90         return nullptr;
91     }
92
93     // GLXPbuffer and XID are both the same types underneath, so we have to share
94     // a constructor here with the window path.
95     GLContextGLX* contextWrapper = new GLContextGLX(context);
96     contextWrapper->m_pbuffer = pbuffer;
97     return adoptPtr(contextWrapper);
98 }
99
100 PassOwnPtr<GLContextGLX> GLContextGLX::createPixmapContext(GLXContext sharingContext)
101 {
102     static int visualAttributes[] = {
103         GLX_RGBA,
104         GLX_RED_SIZE, 1,
105         GLX_GREEN_SIZE, 1,
106         GLX_BLUE_SIZE, 1,
107         GLX_ALPHA_SIZE, 1,
108         0
109     };
110
111     Display* display = sharedX11Display();
112     XVisualInfo* visualInfo = glXChooseVisual(display, DefaultScreen(display), visualAttributes);
113     if (!visualInfo)
114         return nullptr;
115
116     GLXContext context = glXCreateContext(display, visualInfo, sharingContext, GL_TRUE);
117     if (!context) {
118         XFree(visualInfo);
119         return nullptr;
120     }
121
122     Pixmap pixmap = XCreatePixmap(display, DefaultRootWindow(display), 1, 1, visualInfo->depth);
123     if (!pixmap) {
124         XFree(visualInfo);
125         return nullptr;
126     }
127
128     GLXPixmap glxPixmap = glXCreateGLXPixmap(display, visualInfo, pixmap);
129     if (!glxPixmap) {
130         XFreePixmap(display, pixmap);
131         XFree(visualInfo);
132         return nullptr;
133     }
134
135     XFree(visualInfo);
136     return adoptPtr(new GLContextGLX(context, pixmap, glxPixmap));
137 }
138
139 PassOwnPtr<GLContextGLX> GLContextGLX::createContext(XID window, GLContext* sharingContext)
140 {
141     if (!sharedX11Display())
142         return nullptr;
143
144     static bool initialized = false;
145     static bool success = true;
146     if (!initialized) {
147         success = initializeOpenGLShims();
148         initialized = true;
149     }
150     if (!success)
151         return nullptr;
152
153     GLXContext glxSharingContext = sharingContext ? static_cast<GLContextGLX*>(sharingContext)->m_context : 0;
154     OwnPtr<GLContextGLX> context = window ? createWindowContext(window, sharingContext) : nullptr;
155     if (!context)
156         context = createPbufferContext(glxSharingContext);
157     if (!context)
158         context = createPixmapContext(glxSharingContext);
159     if (!context)
160         return nullptr;
161
162     return context.release();
163 }
164
165 GLContextGLX::GLContextGLX(GLXContext context)
166     : m_context(context)
167     , m_window(0)
168     , m_pbuffer(0)
169     , m_pixmap(0)
170     , m_glxPixmap(0)
171 {
172 }
173
174 GLContextGLX::GLContextGLX(GLXContext context, Pixmap pixmap, GLXPixmap glxPixmap)
175     : m_context(context)
176     , m_window(0)
177     , m_pbuffer(0)
178     , m_pixmap(pixmap)
179     , m_glxPixmap(glxPixmap)
180 {
181 }
182
183 GLContextGLX::~GLContextGLX()
184 {
185     if (m_context) {
186         // This may be necessary to prevent crashes with NVidia's closed source drivers. Originally
187         // from Mozilla's 3D canvas implementation at: http://bitbucket.org/ilmari/canvas3d/
188         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
189         glXMakeCurrent(sharedX11Display(), None, None);
190         glXDestroyContext(sharedX11Display(), m_context);
191     }
192
193     if (m_pbuffer) {
194         glXDestroyPbuffer(sharedX11Display(), m_pbuffer);
195         m_pbuffer = 0;
196     }
197     if (m_glxPixmap) {
198         glXDestroyGLXPixmap(sharedX11Display(), m_glxPixmap);
199         m_glxPixmap = 0;
200     }
201     if (m_pixmap) {
202         XFreePixmap(sharedX11Display(), m_pixmap);
203         m_pixmap = 0;
204     }
205 }
206
207 bool GLContextGLX::canRenderToDefaultFramebuffer()
208 {
209     return m_window;
210 }
211
212 IntSize GLContextGLX::defaultFrameBufferSize()
213 {
214     if (!canRenderToDefaultFramebuffer() || !m_window)
215         return IntSize();
216
217     int x, y;
218     Window rootWindow;
219     unsigned int width, height, borderWidth, depth;
220     if (!XGetGeometry(sharedX11Display(), m_window, &rootWindow, &x, &y, &width, &height, &borderWidth, &depth))
221         return IntSize();
222
223     return IntSize(width, height);
224 }
225
226 bool GLContextGLX::makeContextCurrent()
227 {
228     ASSERT(m_context && (m_window || m_pbuffer || m_glxPixmap));
229
230     GLContext::makeContextCurrent();
231     if (glXGetCurrentContext() == m_context)
232         return true;
233
234     if (m_window)
235         return glXMakeCurrent(sharedX11Display(), m_window, m_context);
236
237     if (m_pbuffer)
238         return glXMakeCurrent(sharedX11Display(), m_pbuffer, m_context);
239
240     return ::glXMakeCurrent(sharedX11Display(), m_glxPixmap, m_context);
241 }
242
243 void GLContextGLX::swapBuffers()
244 {
245     if (m_window)
246         glXSwapBuffers(sharedX11Display(), m_window);
247 }
248
249 void GLContextGLX::waitNative()
250 {
251     glXWaitX();
252 }
253
254 #if USE(3D_GRAPHICS)
255 PlatformGraphicsContext3D GLContextGLX::platformContext()
256 {
257     return m_context;
258 }
259 #endif
260
261 } // namespace WebCore
262
263 #endif // USE(GLX)