blob: 64d032799a1ea0eca72d9ab162f011cbaecbc62a [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2011 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$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qdebug.h>
#include "qglpixelbuffer.h"
#include "qglpixelbuffer_p.h"
#include "qgl_egl_p.h"
#include <qimage.h>
#include <private/qgl_p.h>
QT_BEGIN_NAMESPACE
#ifdef EGL_BIND_TO_TEXTURE_RGBA
#define QGL_RENDER_TEXTURE 1
#else
#define QGL_RENDER_TEXTURE 0
#endif
bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidget *shareWidget)
{
// Create the EGL context.
ctx = new QEglContext();
ctx->setApi(QEgl::OpenGL);
// Find the shared context.
QEglContext *shareContext = 0;
if (shareWidget && shareWidget->d_func()->glcx)
shareContext = shareWidget->d_func()->glcx->d_func()->eglContext;
// Choose an appropriate configuration. We use the best format
// we can find, even if it is greater than the requested format.
// We try for a pbuffer that is capable of texture rendering if possible.
textureFormat = EGL_NONE;
if (shareContext) {
// Use the same configuration as the widget we are sharing with.
ctx->setConfig(shareContext->config());
#if QGL_RENDER_TEXTURE
if (ctx->configAttrib(EGL_BIND_TO_TEXTURE_RGBA) == EGL_TRUE)
textureFormat = EGL_TEXTURE_RGBA;
else if (ctx->configAttrib(EGL_BIND_TO_TEXTURE_RGB) == EGL_TRUE)
textureFormat = EGL_TEXTURE_RGB;
#endif
} else {
QEglProperties configProps;
qt_eglproperties_set_glformat(configProps, f);
configProps.setDeviceType(QInternal::Pbuffer);
configProps.setRenderableType(ctx->api());
bool ok = false;
#if QGL_RENDER_TEXTURE
textureFormat = EGL_TEXTURE_RGBA;
configProps.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat);
if (!ok) {
// Try again with RGB texture rendering.
textureFormat = EGL_TEXTURE_RGB;
configProps.removeValue(EGL_BIND_TO_TEXTURE_RGBA);
configProps.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat);
if (!ok) {
// One last try for a pbuffer with no texture rendering.
configProps.removeValue(EGL_BIND_TO_TEXTURE_RGB);
textureFormat = EGL_NONE;
}
}
#endif
if (!ok) {
if (!ctx->chooseConfig(configProps, QEgl::BestPixelFormat)) {
delete ctx;
ctx = 0;
return false;
}
}
}
// Retrieve the actual format properties.
qt_glformat_from_eglconfig(format, ctx->config());
// Create the attributes needed for the pbuffer.
QEglProperties attribs;
attribs.setValue(EGL_WIDTH, size.width());
attribs.setValue(EGL_HEIGHT, size.height());
#if QGL_RENDER_TEXTURE
if (textureFormat != EGL_NONE) {
attribs.setValue(EGL_TEXTURE_FORMAT, textureFormat);
attribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
}
#endif
// Create the pbuffer surface.
pbuf = eglCreatePbufferSurface(ctx->display(), ctx->config(), attribs.properties());
#if QGL_RENDER_TEXTURE
if (pbuf == EGL_NO_SURFACE && textureFormat != EGL_NONE) {
// Try again with texture rendering disabled.
textureFormat = EGL_NONE;
attribs.removeValue(EGL_TEXTURE_FORMAT);
attribs.removeValue(EGL_TEXTURE_TARGET);
pbuf = eglCreatePbufferSurface(ctx->display(), ctx->config(), attribs.properties());
}
#endif
if (pbuf == EGL_NO_SURFACE) {
qWarning() << "QGLPixelBufferPrivate::init(): Unable to create EGL pbuffer surface:" << QEgl::errorString();
return false;
}
// Create a new context for the configuration.
if (!ctx->createContext(shareContext)) {
delete ctx;
ctx = 0;
return false;
}
return true;
}
bool QGLPixelBufferPrivate::cleanup()
{
// No need to destroy "pbuf" here - it is done in QGLContext::reset().
return true;
}
bool QGLPixelBuffer::bindToDynamicTexture(GLuint texture_id)
{
#if QGL_RENDER_TEXTURE
Q_D(QGLPixelBuffer);
if (d->invalid || d->textureFormat == EGL_NONE || !d->ctx)
return false;
glBindTexture(GL_TEXTURE_2D, texture_id);
return eglBindTexImage(d->ctx->display(), d->pbuf, EGL_BACK_BUFFER);
#else
Q_UNUSED(texture_id);
return false;
#endif
}
void QGLPixelBuffer::releaseFromDynamicTexture()
{
#if QGL_RENDER_TEXTURE
Q_D(QGLPixelBuffer);
if (d->invalid || d->textureFormat == EGL_NONE || !d->ctx)
return;
eglReleaseTexImage(d->ctx->display(), d->pbuf, EGL_BACK_BUFFER);
#endif
}
GLuint QGLPixelBuffer::generateDynamicTexture() const
{
#if QGL_RENDER_TEXTURE
Q_D(const QGLPixelBuffer);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
if (d->textureFormat == EGL_TEXTURE_RGB)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, d->req_size.width(), d->req_size.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, d->req_size.width(), d->req_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
return texture;
#else
return 0;
#endif
}
bool QGLPixelBuffer::hasOpenGLPbuffers()
{
// See if we have at least 1 configuration that matches the default format.
EGLDisplay dpy = QEgl::display();
if (dpy == EGL_NO_DISPLAY)
return false;
QEglProperties configProps;
qt_eglproperties_set_glformat(configProps, QGLFormat::defaultFormat());
configProps.setDeviceType(QInternal::Pbuffer);
configProps.setRenderableType(QEgl::OpenGL);
do {
EGLConfig cfg = 0;
EGLint matching = 0;
if (eglChooseConfig(dpy, configProps.properties(),
&cfg, 1, &matching) && matching > 0)
return true;
} while (configProps.reduceConfiguration());
return false;
}
QT_END_NAMESPACE