174 lines
6.3 KiB
C++
174 lines
6.3 KiB
C++
|
/****************************************************************************
|
||
|
**
|
||
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||
|
** Contact: http://www.qt-project.org/legal
|
||
|
**
|
||
|
** This file is part of the test suite of the Qt Toolkit.
|
||
|
**
|
||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||
|
** Commercial License Usage
|
||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||
|
** accordance with the commercial license agreement provided with the
|
||
|
** Software or, alternatively, in accordance with the terms contained in
|
||
|
** a written agreement between you and Digia. For licensing terms and
|
||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||
|
** use the contact form at http://qt.digia.com/contact-us.
|
||
|
**
|
||
|
** 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, Digia gives you certain additional
|
||
|
** rights. These rights are described in the Digia 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.
|
||
|
**
|
||
|
**
|
||
|
** $QT_END_LICENSE$
|
||
|
**
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "qopenglcontextwindow.h"
|
||
|
#include <QtGui/QOpenGLFunctions>
|
||
|
#include <QtGui/QOffscreenSurface>
|
||
|
#include <QtGui/QGuiApplication>
|
||
|
#include <QtGui/QMatrix4x4>
|
||
|
#include <qpa/qplatformnativeinterface.h>
|
||
|
|
||
|
#include <QtPlatformSupport/private/qeglconvenience_p.h>
|
||
|
#include <QtPlatformHeaders/QEGLNativeContext>
|
||
|
|
||
|
QOpenGLContextWindow::QOpenGLContextWindow()
|
||
|
: m_blitter(0)
|
||
|
{
|
||
|
setSurfaceType(OpenGLSurface);
|
||
|
|
||
|
m_context = new QOpenGLContext(this);
|
||
|
m_context->setFormat(requestedFormat());
|
||
|
m_context->create();
|
||
|
|
||
|
m_image = QImage(QStringLiteral("qticon64.png")).convertToFormat(QImage::Format_RGBA8888);
|
||
|
Q_ASSERT(!m_image.isNull());
|
||
|
|
||
|
create(); // to make sure format() returns something real
|
||
|
createForeignContext();
|
||
|
}
|
||
|
|
||
|
QOpenGLContextWindow::~QOpenGLContextWindow()
|
||
|
{
|
||
|
if (m_blitter) {
|
||
|
m_blitter->destroy(); // the dtor does not call this for some reason
|
||
|
delete m_blitter;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QOpenGLContextWindow::render()
|
||
|
{
|
||
|
if (!m_context->makeCurrent(this))
|
||
|
qFatal("makeCurrent() failed");
|
||
|
|
||
|
QOpenGLFunctions *f = m_context->functions();
|
||
|
f->glViewport(0, 0, dWidth(), dHeight());
|
||
|
f->glClearColor(0, 0, 0, 1);
|
||
|
f->glClear(GL_COLOR_BUFFER_BIT);
|
||
|
|
||
|
if (!m_blitter) {
|
||
|
m_blitter = new QOpenGLTextureBlitter;
|
||
|
m_blitter->create();
|
||
|
}
|
||
|
|
||
|
// Draw the image. If nothing gets shown, then something went wrong with the context
|
||
|
// adoption or sharing was not successfully enabled.
|
||
|
m_blitter->bind();
|
||
|
QRectF r(0, 0, dWidth(), dHeight());
|
||
|
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(QRectF(100, 100, 100, 100), r.toRect());
|
||
|
m_blitter->blit(m_textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
|
||
|
m_blitter->release();
|
||
|
|
||
|
m_context->swapBuffers(this);
|
||
|
}
|
||
|
|
||
|
void QOpenGLContextWindow::exposeEvent(QExposeEvent *)
|
||
|
{
|
||
|
if (isExposed())
|
||
|
render();
|
||
|
}
|
||
|
|
||
|
void QOpenGLContextWindow::createForeignContext()
|
||
|
{
|
||
|
// Here a context will be created manually. This context will share with m_context's
|
||
|
// underlying native context. This way the texture, that belongs to the context
|
||
|
// created here, will be accessible from m_context too.
|
||
|
|
||
|
EGLContext shareCtx = m_context->nativeHandle().value<QEGLNativeContext>().context();
|
||
|
Q_ASSERT(shareCtx != EGL_NO_CONTEXT);
|
||
|
|
||
|
EGLDisplay dpy = (EGLDisplay) qGuiApp->platformNativeInterface()->nativeResourceForWindow(
|
||
|
QByteArrayLiteral("egldisplay"), this);
|
||
|
Q_ASSERT(dpy != EGL_NO_DISPLAY);
|
||
|
|
||
|
QSurfaceFormat fmt = format();
|
||
|
EGLConfig config = q_configFromGLFormat(dpy, fmt);
|
||
|
|
||
|
QVector<EGLint> contextAttrs;
|
||
|
contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION);
|
||
|
contextAttrs.append(fmt.majorVersion());
|
||
|
contextAttrs.append(EGL_NONE);
|
||
|
switch (fmt.renderableType()) {
|
||
|
#ifdef EGL_VERSION_1_4
|
||
|
case QSurfaceFormat::OpenGL:
|
||
|
eglBindAPI(EGL_OPENGL_API);
|
||
|
break;
|
||
|
#endif // EGL_VERSION_1_4
|
||
|
default:
|
||
|
eglBindAPI(EGL_OPENGL_ES_API);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
EGLContext ctx = eglCreateContext(dpy, config, shareCtx, contextAttrs.constData());
|
||
|
Q_ASSERT(ctx != EGL_NO_CONTEXT);
|
||
|
|
||
|
// Wrap ctx into a QOpenGLContext.
|
||
|
QOpenGLContext *ctxWrap = new QOpenGLContext;
|
||
|
ctxWrap->setNativeHandle(QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(ctx, dpy)));
|
||
|
ctxWrap->setShareContext(m_context); // only needed for correct bookkeeping
|
||
|
if (!ctxWrap->create())
|
||
|
qFatal("Failed to created wrapping context");
|
||
|
Q_ASSERT(ctxWrap->nativeHandle().value<QEGLNativeContext>().context() == ctx);
|
||
|
|
||
|
QOffscreenSurface surface;
|
||
|
surface.setFormat(fmt);
|
||
|
surface.create();
|
||
|
|
||
|
if (!ctxWrap->makeCurrent(&surface))
|
||
|
qFatal("Failed to make pbuffer surface current");
|
||
|
|
||
|
// Create the texture.
|
||
|
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
|
||
|
GLuint textureId = 0;
|
||
|
f->glGenTextures(1, &textureId);
|
||
|
f->glBindTexture(GL_TEXTURE_2D, textureId);
|
||
|
f->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||
|
f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_image.width(), m_image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||
|
m_image.constBits());
|
||
|
Q_ASSERT(f->glGetError() == GL_NO_ERROR);
|
||
|
|
||
|
ctxWrap->doneCurrent();
|
||
|
delete ctxWrap; // ctx is not destroyed
|
||
|
eglDestroyContext(dpy, ctx); // resources like the texture stay alive until any context on the share list is alive
|
||
|
Q_ASSERT(eglGetError() == EGL_SUCCESS);
|
||
|
|
||
|
m_textureId = textureId;
|
||
|
}
|