0b030bd5fe0a4501495279697fced1838f3dae3d
[profile/ivi/qtbase.git] / src / plugins / platforms / qnx / qqnxglcontext.cpp
1 /***************************************************************************
2 **
3 ** Copyright (C) 2011 - 2012 Research In Motion
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqnxglcontext.h"
43 #include "qqnxrootwindow.h"
44 #include "qqnxscreen.h"
45 #include "qqnxwindow.h"
46
47 #include "private/qeglconvenience_p.h"
48
49 #include <QtCore/QDebug>
50 #include <QtGui/QOpenGLContext>
51 #include <QtGui/QScreen>
52
53 #ifdef QQNXGLCONTEXT_DEBUG
54 #define qGLContextDebug qDebug
55 #else
56 #define qGLContextDebug QT_NO_QDEBUG_MACRO
57 #endif
58
59 QT_BEGIN_NAMESPACE
60
61 EGLDisplay QQnxGLContext::ms_eglDisplay = EGL_NO_DISPLAY;
62
63 static EGLenum checkEGLError(const char *msg)
64 {
65     static const char *errmsg[] =
66     {
67         "EGL function succeeded",
68         "EGL is not initialized, or could not be initialized, for the specified display",
69         "EGL cannot access a requested resource",
70         "EGL failed to allocate resources for the requested operation",
71         "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list",
72         "EGLConfig argument does not name a valid EGLConfig",
73         "EGLContext argument does not name a valid EGLContext",
74         "EGL current surface of the calling thread is no longer valid",
75         "EGLDisplay argument does not name a valid EGLDisplay",
76         "EGL arguments are inconsistent",
77         "EGLNativePixmapType argument does not refer to a valid native pixmap",
78         "EGLNativeWindowType argument does not refer to a valid native window",
79         "EGL one or more argument values are invalid",
80         "EGLSurface argument does not name a valid surface configured for rendering",
81         "EGL power management event has occurred",
82     };
83     EGLenum error = eglGetError();
84     fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]);
85     return error;
86 }
87
88 QQnxGLContext::QQnxGLContext(QOpenGLContext *glContext)
89     : QPlatformOpenGLContext(),
90       m_glContext(glContext),
91       m_eglSurface(EGL_NO_SURFACE)
92 {
93     qGLContextDebug() << Q_FUNC_INFO;
94     QSurfaceFormat format = m_glContext->format();
95
96     // Set current rendering API
97     EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
98     if (eglResult != EGL_TRUE) {
99         qFatal("QQNX: failed to set EGL API, err=%d", eglGetError());
100     }
101
102     // Get colour channel sizes from window format
103     int alphaSize = format.alphaBufferSize();
104     int redSize = format.redBufferSize();
105     int greenSize = format.greenBufferSize();
106     int blueSize = format.blueBufferSize();
107
108     // Check if all channels are don't care
109     if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) {
110         // Set colour channels based on depth of window's screen
111         QQnxScreen *screen = static_cast<QQnxScreen*>(glContext->screen()->handle());
112         int depth = screen->depth();
113         if (depth == 32) {
114             // SCREEN_FORMAT_RGBA8888
115             alphaSize = 8;
116             redSize = 8;
117             greenSize = 8;
118             blueSize = 8;
119         } else {
120             // SCREEN_FORMAT_RGB565
121             alphaSize = 0;
122             redSize = 5;
123             greenSize = 6;
124             blueSize = 5;
125         }
126     } else {
127         // Choose best match based on supported pixel formats
128         if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) {
129             // SCREEN_FORMAT_RGB565
130             alphaSize = 0;
131             redSize = 5;
132             greenSize = 6;
133             blueSize = 5;
134         } else {
135             // SCREEN_FORMAT_RGBA8888
136             alphaSize = 8;
137             redSize = 8;
138             greenSize = 8;
139             blueSize = 8;
140         }
141     }
142
143     // Update colour channel sizes in window format
144     format.setAlphaBufferSize(alphaSize);
145     format.setRedBufferSize(redSize);
146     format.setGreenBufferSize(greenSize);
147     format.setBlueBufferSize(blueSize);
148
149     // Select EGL config based on requested window format
150     m_eglConfig = q_configFromGLFormat(ms_eglDisplay, format);
151     if (m_eglConfig == 0) {
152         qFatal("QQNXQBBWindow: failed to find EGL config");
153     }
154
155     m_eglContext = eglCreateContext(ms_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttrs());
156     if (m_eglContext == EGL_NO_CONTEXT) {
157         checkEGLError("eglCreateContext");
158         qFatal("QQNXQBBWindow: failed to create EGL context, err=%d", eglGetError());
159     }
160
161     // Query/cache window format of selected EGL config
162     m_windowFormat = q_glFormatFromConfig(ms_eglDisplay, m_eglConfig);
163 }
164
165 QQnxGLContext::~QQnxGLContext()
166 {
167     qGLContextDebug() << Q_FUNC_INFO;
168
169     // Cleanup EGL context if it exists
170     if (m_eglContext != EGL_NO_CONTEXT) {
171         eglDestroyContext(ms_eglDisplay, m_eglContext);
172     }
173
174     // Cleanup EGL surface if it exists
175     destroySurface();
176 }
177
178 void QQnxGLContext::initialize()
179 {
180     qGLContextDebug() << Q_FUNC_INFO;
181
182     // Initialize connection to EGL
183     ms_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
184     if (ms_eglDisplay == EGL_NO_DISPLAY) {
185         checkEGLError("eglGetDisplay");
186         qFatal("QQNXQBBWindow: failed to obtain EGL display");
187     }
188
189     EGLBoolean eglResult = eglInitialize(ms_eglDisplay, 0, 0);
190     if (eglResult != EGL_TRUE) {
191         checkEGLError("eglInitialize");
192         qFatal("QQNXQBBWindow: failed to initialize EGL display, err=%d", eglGetError());
193     }
194 }
195
196 void QQnxGLContext::shutdown()
197 {
198     qGLContextDebug() << Q_FUNC_INFO;
199
200     // Close connection to EGL
201     eglTerminate(ms_eglDisplay);
202 }
203
204 bool QQnxGLContext::makeCurrent(QPlatformSurface *surface)
205 {
206     qGLContextDebug() << Q_FUNC_INFO;
207
208     Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
209
210     // Set current rendering API
211     EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
212     if (eglResult != EGL_TRUE) {
213         qFatal("QQNXQBBWindow: failed to set EGL API, err=%d", eglGetError());
214     }
215
216     if (m_eglSurface == EGL_NO_SURFACE)
217         createSurface(surface);
218
219     eglResult = eglMakeCurrent(ms_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
220     if (eglResult != EGL_TRUE) {
221         checkEGLError("eglMakeCurrent");
222         qFatal("QQNX: failed to set current EGL context, err=%d", eglGetError());
223     }
224     return (eglResult == EGL_TRUE);
225 }
226
227 void QQnxGLContext::doneCurrent()
228 {
229     qGLContextDebug() << Q_FUNC_INFO;
230
231     // set current rendering API
232     EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
233     if (eglResult != EGL_TRUE) {
234         qFatal("QQNX: failed to set EGL API, err=%d", eglGetError());
235     }
236
237     // clear curent EGL context and unbind EGL surface
238     eglResult = eglMakeCurrent(ms_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
239     if (eglResult != EGL_TRUE) {
240         qFatal("QQNX: failed to clear current EGL context, err=%d", eglGetError());
241     }
242 }
243
244 void QQnxGLContext::swapBuffers(QPlatformSurface *surface)
245 {
246     Q_UNUSED(surface);
247     qGLContextDebug() << Q_FUNC_INFO;
248
249     // Set current rendering API
250     EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
251     if (eglResult != EGL_TRUE) {
252         qFatal("QQNX: failed to set EGL API, err=%d", eglGetError());
253     }
254
255     // Post EGL surface to window
256     eglResult = eglSwapBuffers(ms_eglDisplay, m_eglSurface);
257     if (eglResult != EGL_TRUE) {
258         qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError());
259     }
260 }
261
262 QFunctionPointer QQnxGLContext::getProcAddress(const QByteArray &procName)
263 {
264     qGLContextDebug() << Q_FUNC_INFO;
265
266     // Set current rendering API
267     EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
268     if (eglResult != EGL_TRUE) {
269         qFatal("QQNX: failed to set EGL API, err=%d", eglGetError());
270     }
271
272     // Lookup EGL extension function pointer
273     return static_cast<QFunctionPointer>(eglGetProcAddress(procName.constData()));
274 }
275
276 EGLint *QQnxGLContext::contextAttrs()
277 {
278     qGLContextDebug() << Q_FUNC_INFO;
279
280     // Choose EGL settings based on OpenGL version
281 #if defined(QT_OPENGL_ES_2)
282     static EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
283     return attrs;
284 #else
285     return 0;
286 #endif
287 }
288
289 bool QQnxGLContext::isCurrent() const
290 {
291     qGLContextDebug() << Q_FUNC_INFO;
292     return (eglGetCurrentContext() == m_eglContext);
293 }
294
295 void QQnxGLContext::createSurface(QPlatformSurface *surface)
296 {
297     qGLContextDebug() << Q_FUNC_INFO;
298
299     // Get a pointer to the corresponding platform window
300     QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface);
301     if (!platformWindow) {
302         qFatal("QQNX: unable to create EGLSurface without a QQnxWindow");
303     }
304
305     // If the platform window does not yet have any buffers, we create
306     // a temporary set of buffers with a size of 1x1 pixels. This will
307     // suffice until such time as the platform window has obtained
308     // buffers of the proper size
309     if (!platformWindow->hasBuffers()) {
310         platformWindow->setPlatformOpenGLContext(this);
311         platformWindow->setBufferSize(platformWindow->geometry().size());
312     }
313
314     // Obtain the native handle for our window
315     screen_window_t handle = platformWindow->nativeHandle();
316
317     const EGLint eglSurfaceAttrs[] =
318     {
319         EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
320         EGL_NONE
321     };
322
323     // Create EGL surface
324     m_eglSurface = eglCreateWindowSurface(ms_eglDisplay, m_eglConfig, (EGLNativeWindowType) handle, eglSurfaceAttrs);
325     if (m_eglSurface == EGL_NO_SURFACE) {
326         checkEGLError("eglCreateWindowSurface");
327         qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError());
328     }
329 }
330
331 void QQnxGLContext::destroySurface()
332 {
333     qGLContextDebug() << Q_FUNC_INFO;
334
335     // Destroy EGL surface if it exists
336     if (m_eglSurface != EGL_NO_SURFACE) {
337         EGLBoolean eglResult = eglDestroySurface(ms_eglDisplay, m_eglSurface);
338         if (eglResult != EGL_TRUE) {
339             qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError());
340         }
341     }
342
343     m_eglSurface = EGL_NO_SURFACE;
344 }
345
346 QT_END_NAMESPACE