1 /***************************************************************************
3 ** Copyright (C) 2011 - 2012 Research In Motion
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qqnxglcontext.h"
43 #include "qqnxrootwindow.h"
44 #include "qqnxscreen.h"
45 #include "qqnxwindow.h"
47 #include "private/qeglconvenience_p.h"
49 #include <QtCore/QDebug>
50 #include <QtGui/QOpenGLContext>
51 #include <QtGui/QScreen>
53 #ifdef QQNXGLCONTEXT_DEBUG
54 #define qGLContextDebug qDebug
56 #define qGLContextDebug QT_NO_QDEBUG_MACRO
61 EGLDisplay QQnxGLContext::ms_eglDisplay = EGL_NO_DISPLAY;
63 static EGLenum checkEGLError(const char *msg)
65 static const char *errmsg[] =
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",
83 EGLenum error = eglGetError();
84 fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]);
88 QQnxGLContext::QQnxGLContext(QOpenGLContext *glContext)
89 : QPlatformOpenGLContext(),
90 m_glContext(glContext),
91 m_eglSurface(EGL_NO_SURFACE),
92 m_newSurfaceRequested(true) // Create a surface the first time makeCurrent() is called
94 qGLContextDebug() << Q_FUNC_INFO;
95 QSurfaceFormat format = m_glContext->format();
97 // Set current rendering API
98 EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
99 if (eglResult != EGL_TRUE) {
100 qFatal("QQNX: failed to set EGL API, err=%d", eglGetError());
103 // Get colour channel sizes from window format
104 int alphaSize = format.alphaBufferSize();
105 int redSize = format.redBufferSize();
106 int greenSize = format.greenBufferSize();
107 int blueSize = format.blueBufferSize();
109 // Check if all channels are don't care
110 if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) {
111 // Set colour channels based on depth of window's screen
112 QQnxScreen *screen = static_cast<QQnxScreen*>(glContext->screen()->handle());
113 int depth = screen->depth();
115 // SCREEN_FORMAT_RGBA8888
121 // SCREEN_FORMAT_RGB565
128 // Choose best match based on supported pixel formats
129 if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) {
130 // SCREEN_FORMAT_RGB565
136 // SCREEN_FORMAT_RGBA8888
144 // Update colour channel sizes in window format
145 format.setAlphaBufferSize(alphaSize);
146 format.setRedBufferSize(redSize);
147 format.setGreenBufferSize(greenSize);
148 format.setBlueBufferSize(blueSize);
150 // Select EGL config based on requested window format
151 m_eglConfig = q_configFromGLFormat(ms_eglDisplay, format);
152 if (m_eglConfig == 0) {
153 qFatal("QQNXQBBWindow: failed to find EGL config");
156 m_eglContext = eglCreateContext(ms_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttrs());
157 if (m_eglContext == EGL_NO_CONTEXT) {
158 checkEGLError("eglCreateContext");
159 qFatal("QQNXQBBWindow: failed to create EGL context, err=%d", eglGetError());
162 // Query/cache window format of selected EGL config
163 m_windowFormat = q_glFormatFromConfig(ms_eglDisplay, m_eglConfig);
166 QQnxGLContext::~QQnxGLContext()
168 qGLContextDebug() << Q_FUNC_INFO;
170 // Cleanup EGL context if it exists
171 if (m_eglContext != EGL_NO_CONTEXT) {
172 eglDestroyContext(ms_eglDisplay, m_eglContext);
175 // Cleanup EGL surface if it exists
179 void QQnxGLContext::initialize()
181 qGLContextDebug() << Q_FUNC_INFO;
183 // Initialize connection to EGL
184 ms_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
185 if (ms_eglDisplay == EGL_NO_DISPLAY) {
186 checkEGLError("eglGetDisplay");
187 qFatal("QQNXQBBWindow: failed to obtain EGL display");
190 EGLBoolean eglResult = eglInitialize(ms_eglDisplay, 0, 0);
191 if (eglResult != EGL_TRUE) {
192 checkEGLError("eglInitialize");
193 qFatal("QQNXQBBWindow: failed to initialize EGL display, err=%d", eglGetError());
197 void QQnxGLContext::shutdown()
199 qGLContextDebug() << Q_FUNC_INFO;
201 // Close connection to EGL
202 eglTerminate(ms_eglDisplay);
205 void QQnxGLContext::requestSurfaceChange()
207 qGLContextDebug() << Q_FUNC_INFO;
208 m_newSurfaceRequested.testAndSetRelease(false, true);
211 bool QQnxGLContext::makeCurrent(QPlatformSurface *surface)
213 qGLContextDebug() << Q_FUNC_INFO;
215 Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
217 // Set current rendering API
218 EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
219 if (eglResult != EGL_TRUE) {
220 qFatal("QQNXQBBWindow: failed to set EGL API, err=%d", eglGetError());
223 if (m_newSurfaceRequested.testAndSetOrdered(true, false)) {
224 qGLContextDebug() << "New EGL surface requested";
227 createSurface(surface);
230 eglResult = eglMakeCurrent(ms_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
231 if (eglResult != EGL_TRUE) {
232 checkEGLError("eglMakeCurrent");
233 qFatal("QQNX: failed to set current EGL context, err=%d", eglGetError());
235 return (eglResult == EGL_TRUE);
238 void QQnxGLContext::doneCurrent()
240 qGLContextDebug() << Q_FUNC_INFO;
242 // set current rendering API
243 EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
244 if (eglResult != EGL_TRUE) {
245 qFatal("QQNX: failed to set EGL API, err=%d", eglGetError());
248 // clear curent EGL context and unbind EGL surface
249 eglResult = eglMakeCurrent(ms_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
250 if (eglResult != EGL_TRUE) {
251 qFatal("QQNX: failed to clear current EGL context, err=%d", eglGetError());
255 void QQnxGLContext::swapBuffers(QPlatformSurface *surface)
258 qGLContextDebug() << Q_FUNC_INFO;
260 // Set current rendering API
261 EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
262 if (eglResult != EGL_TRUE) {
263 qFatal("QQNX: failed to set EGL API, err=%d", eglGetError());
266 // Post EGL surface to window
267 eglResult = eglSwapBuffers(ms_eglDisplay, m_eglSurface);
268 if (eglResult != EGL_TRUE) {
269 qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError());
273 QFunctionPointer QQnxGLContext::getProcAddress(const QByteArray &procName)
275 qGLContextDebug() << Q_FUNC_INFO;
277 // Set current rendering API
278 EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
279 if (eglResult != EGL_TRUE) {
280 qFatal("QQNX: failed to set EGL API, err=%d", eglGetError());
283 // Lookup EGL extension function pointer
284 return static_cast<QFunctionPointer>(eglGetProcAddress(procName.constData()));
287 EGLint *QQnxGLContext::contextAttrs()
289 qGLContextDebug() << Q_FUNC_INFO;
291 // Choose EGL settings based on OpenGL version
292 #if defined(QT_OPENGL_ES_2)
293 static EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
300 bool QQnxGLContext::isCurrent() const
302 qGLContextDebug() << Q_FUNC_INFO;
303 return (eglGetCurrentContext() == m_eglContext);
306 void QQnxGLContext::createSurface(QPlatformSurface *surface)
308 qGLContextDebug() << Q_FUNC_INFO;
310 // Get a pointer to the corresponding platform window
311 QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface);
312 if (!platformWindow) {
313 qFatal("QQNX: unable to create EGLSurface without a QQnxWindow");
316 // Link the window and context
317 platformWindow->setPlatformOpenGLContext(this);
319 // Fetch the surface size from the window and update
320 // the window's buffers before we create the EGL surface
321 const QSize surfaceSize = platformWindow->requestedBufferSize();
322 platformWindow->setBufferSize(surfaceSize);
324 // Obtain the native handle for our window
325 screen_window_t handle = platformWindow->nativeHandle();
327 const EGLint eglSurfaceAttrs[] =
329 EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
333 // Create EGL surface
334 m_eglSurface = eglCreateWindowSurface(ms_eglDisplay, m_eglConfig, (EGLNativeWindowType) handle, eglSurfaceAttrs);
335 if (m_eglSurface == EGL_NO_SURFACE) {
336 checkEGLError("eglCreateWindowSurface");
337 qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError());
341 void QQnxGLContext::destroySurface()
343 qGLContextDebug() << Q_FUNC_INFO;
345 // Destroy EGL surface if it exists
346 if (m_eglSurface != EGL_NO_SURFACE) {
347 EGLBoolean eglResult = eglDestroySurface(ms_eglDisplay, m_eglSurface);
348 if (eglResult != EGL_TRUE) {
349 qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError());
353 m_eglSurface = EGL_NO_SURFACE;