| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the test suite of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** 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 The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qopenglcontextwindow.h" |
| #include <QtGui/QOpenGLFunctions> |
| #include <QtGui/QOffscreenSurface> |
| #include <QtGui/QGuiApplication> |
| #include <QtGui/QMatrix4x4> |
| #include <qpa/qplatformnativeinterface.h> |
| |
| #include <QtEglSupport/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; |
| } |