/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtOpenGL module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qgl.h" #include "qgl_egl_p.h" #include "qglpixelbuffer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE static QGLScreen *glScreenForDevice(QPaintDevice *device) { QScreen *screen = qt_screen; if (screen->classId() == QScreen::MultiClass) { int screenNumber; if (device && device->devType() == QInternal::Widget) screenNumber = qApp->desktop()->screenNumber(static_cast(device)); else screenNumber = 0; screen = screen->subScreens()[screenNumber]; } while (screen->classId() == QScreen::ProxyClass) { screen = static_cast(screen)->screen(); } if (screen->classId() == QScreen::GLClass) return static_cast(screen); else return 0; } /***************************************************************************** QOpenGL debug facilities *****************************************************************************/ //#define DEBUG_OPENGL_REGION_UPDATE bool QGLFormat::hasOpenGL() { return true; } bool QGLFormat::hasOpenGLOverlays() { QGLScreen *glScreen = glScreenForDevice(0); if (glScreen) return (glScreen->options() & QGLScreen::Overlays); else return false; } void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device) { // Find the QGLScreen for this paint device. QGLScreen *glScreen = glScreenForDevice(device); if (!glScreen) { qWarning("QGLContext::chooseContext(): The screen is not a QGLScreen"); return; } int devType = device->devType(); if (devType == QInternal::Image) props.setPixelFormat(static_cast(device)->format()); else props.setPixelFormat(glScreen->pixelFormat()); } static bool qt_egl_create_surface (QEglContext *context, QPaintDevice *device, const QEglProperties *properties = 0) { // Get the screen surface functions, which are used to create native ids. QGLScreen *glScreen = glScreenForDevice(device); if (!glScreen) return false; QGLScreenSurfaceFunctions *funcs = glScreen->surfaceFunctions(); if (!funcs) return false; // Create the native drawable for the paint device. int devType = device->devType(); EGLNativePixmapType pixmapDrawable = 0; EGLNativeWindowType windowDrawable = 0; bool ok; if (devType == QInternal::Pixmap) { ok = funcs->createNativePixmap(static_cast(device), &pixmapDrawable); } else if (devType == QInternal::Image) { ok = funcs->createNativeImage(static_cast(device), &pixmapDrawable); } else { ok = funcs->createNativeWindow(static_cast(device), &windowDrawable); } if (!ok) { qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); return false; } // Create the EGL surface to draw into, based on the native drawable. const int *props; if (properties) props = properties->properties(); else props = 0; EGLSurface surf; if (devType == QInternal::Widget) { surf = eglCreateWindowSurface (context->display(), context->config(), windowDrawable, props); } else { surf = eglCreatePixmapSurface (context->display(), context->config(), pixmapDrawable, props); } if (surf == EGL_NO_SURFACE) { qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); return false; } context->setSurface(surf); return true; } bool QGLContext::chooseContext(const QGLContext* shareContext) { Q_D(QGLContext); // Validate the device. if (!device()) return false; int devType = device()->devType(); if (devType != QInternal::Pixmap && devType != QInternal::Image && devType != QInternal::Widget) { qWarning("QGLContext::chooseContext(): Cannot create QGLContext's for paint device type %d", devType); return false; } // Get the display and initialize it. d->eglContext = new QEglContext(); d->eglContext->setApi(QEgl::OpenGL); if (!d->eglContext->openDisplay(device())) { delete d->eglContext; d->eglContext = 0; return false; } // Construct the configuration we need for this surface. QEglProperties configProps; qt_egl_add_platform_config(configProps, device()); qt_egl_set_format(configProps, devType, d->glFormat); configProps.setRenderableType(QEgl::OpenGL); // Search for a matching configuration, reducing the complexity // each time until we get something that matches. if (!d->eglContext->chooseConfig(configProps)) { delete d->eglContext; d->eglContext = 0; return false; } // Inform the higher layers about the actual format properties. qt_egl_update_format(*(d->eglContext), d->glFormat); // Create a new context for the configuration. if (!d->eglContext->createContext (shareContext ? shareContext->d_func()->eglContext : 0)) { delete d->eglContext; d->eglContext = 0; return false; } #if defined(EGL_VERSION_1_1) if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget) eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval()); #endif // Create the EGL surface to draw into. We cannot use // QEglContext::createSurface() because it does not have // access to the QGLScreen. if (!qt_egl_create_surface(d->eglContext, device())) { delete d->eglContext; d->eglContext = 0; return false; } return true; } void QGLContext::reset() { Q_D(QGLContext); if (!d->valid) return; d->cleanup(); doneCurrent(); if (d->eglContext) { delete d->eglContext; d->eglContext = 0; } d->crWin = false; d->sharing = false; d->valid = false; d->transpColor = QColor(); d->initDone = false; qgl_share_reg()->removeShare(this); } void QGLContext::makeCurrent() { Q_D(QGLContext); if(!d->valid || !d->eglContext) { qWarning("QGLContext::makeCurrent(): Cannot make invalid context current"); return; } if (d->eglContext->makeCurrent()) QGLContextPrivate::setCurrentContext(this); } void QGLContext::doneCurrent() { Q_D(QGLContext); if (d->eglContext) d->eglContext->doneCurrent(); QGLContextPrivate::setCurrentContext(0); } void QGLContext::swapBuffers() const { Q_D(const QGLContext); if(!d->valid || !d->eglContext) return; d->eglContext->swapBuffers(); } QColor QGLContext::overlayTransparentColor() const { return QColor(0, 0, 0); // Invalid color } uint QGLContext::colorIndex(const QColor &c) const { //### color index doesn't work on egl Q_UNUSED(c); return 0; } void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase) { Q_UNUSED(fnt); Q_UNUSED(listBase); } void *QGLContext::getProcAddress(const QString &proc) const { return (void*)eglGetProcAddress(reinterpret_cast(proc.toLatin1().data())); } bool QGLWidget::event(QEvent *e) { return QWidget::event(e); } void QGLWidget::setMouseTracking(bool enable) { QWidget::setMouseTracking(enable); } void QGLWidget::resizeEvent(QResizeEvent *) { Q_D(QGLWidget); if (!isValid()) return; makeCurrent(); if (!d->glcx->initialized()) glInit(); resizeGL(width(), height()); //handle overlay } const QGLContext* QGLWidget::overlayContext() const { return 0; } void QGLWidget::makeOverlayCurrent() { //handle overlay } void QGLWidget::updateOverlayGL() { //handle overlay } void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext) { Q_D(QGLWidget); if(context == 0) { qWarning("QGLWidget::setContext: Cannot set null context"); return; } if(d->glcx) d->glcx->doneCurrent(); QGLContext* oldcx = d->glcx; d->glcx = context; if(!d->glcx->isValid()) d->glcx->create(shareContext ? shareContext : oldcx); if(deleteOldContext) delete oldcx; } void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget) { Q_Q(QGLWidget); QGLScreen *glScreen = glScreenForDevice(q); if (glScreen) { wsurf = static_cast(glScreen->createSurface(q)); q->setWindowSurface(wsurf); } initContext(context, shareWidget); if(q->isValid() && glcx->format().hasOverlay()) { //no overlay qWarning("QtOpenGL ES doesn't currently support overlays"); } } bool QGLWidgetPrivate::renderCxPm(QPixmap*) { return false; } void QGLWidgetPrivate::cleanupColormaps() { } const QGLColormap & QGLWidget::colormap() const { return d_func()->cmap; } void QGLWidget::setColormap(const QGLColormap &) { } void QGLExtensions::init() { static bool init_done = false; if (init_done) return; init_done = true; // We need a context current to initialize the extensions, // but getting a valid EGLNativeWindowType this early can be // problematic under QWS. So use a pbuffer instead. // // Unfortunately OpenGL/ES 2.0 systems don't normally // support pbuffers, so we have no choice but to try // our luck with a window on those systems. #if defined(QT_OPENGL_ES_2) QGLWidget tmpWidget; tmpWidget.makeCurrent(); init_extensions(); tmpWidget.doneCurrent(); #else QGLPixelBuffer pbuffer(16, 16); pbuffer.makeCurrent(); init_extensions(); pbuffer.doneCurrent(); #endif } QT_END_NAMESPACE