Enabling QQuickWidget and QOpenGLWidget

Enable child widgets (without a native window) that render to an FBO
and are composed with the raster backingstore by the platform plugin.
A preliminary version of QOpenGLWidget is included as private API.

Change-Id: I8f984a4d7db285069ce3d6564707942c823d890d
Reviewed-by: Jørgen Lind <jorgen.lind@digia.com>
This commit is contained in:
Paul Olav Tvete 2013-12-18 14:48:22 +01:00 committed by The Qt Project
parent 5ae5bebb93
commit eacd58d4e7
26 changed files with 1164 additions and 26 deletions

View File

@ -516,6 +516,7 @@ public:
AA_SynthesizeTouchForUnhandledMouseEvents = 11,
AA_SynthesizeMouseForUnhandledTouchEvents = 12,
AA_UseHighDpiPixmaps = 13,
AA_ForceRasterWidgets = 14,
// Add new attributes before this line
AA_AttributeCount

View File

@ -165,6 +165,9 @@
sizes in layout geometry calculations should typically divide by
QPixmap::devicePixelRatio() to get device-independent layout geometry.
\value AA_ForceRasterWidgets Make top-level widgets use pure raster surfaces,
and do not support non-native GL-based child widgets.
The following values are obsolete:
\value AA_ImmediateWidgetCreation This attribute is no longer fully

View File

@ -761,8 +761,7 @@ bool QOpenGLContext::makeCurrent(QSurface *surface)
if (!surface->surfaceHandle())
return false;
if (surface->surfaceType() != QSurface::OpenGLSurface) {
if (!surface->supportsOpenGL()) {
qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface" << surface;
return false;
}
@ -837,7 +836,7 @@ void QOpenGLContext::swapBuffers(QSurface *surface)
return;
}
if (surface->surfaceType() != QSurface::OpenGLSurface) {
if (!surface->supportsOpenGL()) {
qWarning() << "QOpenGLContext::swapBuffers() called with non-opengl surface";
return;
}

View File

@ -95,7 +95,8 @@ public:
NonFullScreenWindows,
NativeWidgets,
WindowManagement,
SyncState
SyncState,
RasterGLSurface
};
virtual ~QPlatformIntegration() { }

View File

@ -74,6 +74,9 @@ QT_BEGIN_NAMESPACE
a software rasterizer like Qt's raster paint engine.
\value OpenGLSurface The surface is an OpenGL compatible surface and can be used
in conjunction with QOpenGLContext.
\value RasterGLSurface The surface can be rendered to using a software rasterizer,
and also supports OpenGL. This surface type is intended for internal Qt use, and
requires the use of private API.
*/
@ -83,6 +86,19 @@ QT_BEGIN_NAMESPACE
Returns the format of the surface.
*/
/*!
Returns true if the surface is OpenGL compatible and can be used in
conjunction with QOpenGLContext; otherwise returns false.
\since 5.3
*/
bool QSurface::supportsOpenGL() const
{
SurfaceType type = surfaceType();
return type == OpenGLSurface || type == RasterGLSurface;
}
/*!
\fn QPlatformSurface *QSurface::surfaceHandle() const

View File

@ -64,7 +64,8 @@ public:
enum SurfaceType {
RasterSurface,
OpenGLSurface
OpenGLSurface,
RasterGLSurface
};
virtual ~QSurface();
@ -75,6 +76,7 @@ public:
virtual QPlatformSurface *surfaceHandle() const = 0;
virtual SurfaceType surfaceType() const = 0;
bool supportsOpenGL() const;
virtual QSize size() const = 0;

View File

@ -44,6 +44,16 @@
#include <qpixmap.h>
#include <private/qwindow_p.h>
#include <qopengl.h>
#include <qopenglcontext.h>
#include <QtGui/QMatrix4x4>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFunctions>
#ifndef QT_NO_OPENGL
#include <QtGui/private/qopengltextureblitter_p.h>
#endif
QT_BEGIN_NAMESPACE
class QPlatformBackingStorePrivate
@ -51,13 +61,103 @@ class QPlatformBackingStorePrivate
public:
QPlatformBackingStorePrivate(QWindow *w)
: window(w)
#ifndef QT_NO_OPENGL
, blitter(0)
#endif
{
}
~QPlatformBackingStorePrivate()
{
#ifndef QT_NO_OPENGL
if (blitter)
blitter->destroy();
delete blitter;
#endif
}
QWindow *window;
QSize size;
#ifndef QT_NO_OPENGL
mutable GLuint textureId;
mutable QSize textureSize;
QOpenGLTextureBlitter *blitter;
#endif
};
#ifndef QT_NO_OPENGL
struct QBackingstoreTextureInfo
{
GLuint textureId;
QRect rect;
};
Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_MOVABLE_TYPE);
class QPlatformTextureListPrivate : public QObjectPrivate
{
public:
QPlatformTextureListPrivate()
: locked(false)
{
}
QList<QBackingstoreTextureInfo> textures;
bool locked;
};
QPlatformTextureList::QPlatformTextureList(QObject *parent)
: QObject(*new QPlatformTextureListPrivate, parent)
{
}
QPlatformTextureList::~QPlatformTextureList()
{
}
int QPlatformTextureList::count() const
{
Q_D(const QPlatformTextureList);
return d->textures.count();
}
GLuint QPlatformTextureList::textureId(int index) const
{
Q_D(const QPlatformTextureList);
return d->textures.at(index).textureId;
}
QRect QPlatformTextureList::geometry(int index) const
{
Q_D(const QPlatformTextureList);
return d->textures.at(index).rect;
}
void QPlatformTextureList::lock(bool on)
{
Q_D(QPlatformTextureList);
if (on != d->locked) {
d->locked = on;
emit locked(on);
}
}
bool QPlatformTextureList::isLocked() const
{
Q_D(const QPlatformTextureList);
return d->locked;
}
void QPlatformTextureList::appendTexture(GLuint textureId, const QRect &geometry)
{
Q_D(QPlatformTextureList);
QBackingstoreTextureInfo bi;
bi.textureId = textureId;
bi.rect = geometry;
d->textures.append(bi);
}
#endif // QT_NO_OPENGL
/*!
\class QPlatformBackingStore
\since 5.0
@ -79,6 +179,147 @@ public:
Note that the \a offset parameter is currently unused.
*/
#ifndef QT_NO_OPENGL
/*!
Flushes the given \a region from the specified \a window onto the
screen, and composes it with the specified \a textures.
The default implementation retrieves the contents using toTexture()
and composes using OpenGL. May be reimplemented in subclasses if there
is a more efficient native way to do it.
Note that the \a offset parameter is currently unused.
*/
void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &region,
const QPoint &offset,
QPlatformTextureList *textures, QOpenGLContext *context)
{
Q_UNUSED(offset);
context->makeCurrent(window);
glViewport(0, 0, window->width(), window->height());
if (!d_ptr->blitter) {
d_ptr->blitter = new QOpenGLTextureBlitter;
d_ptr->blitter->create();
}
d_ptr->blitter->bind();
QRect windowRect(QPoint(), window->size());
for (int i = 0; i < textures->count(); ++i) {
GLuint textureId = textures->textureId(i);
glBindTexture(GL_TEXTURE_2D, textureId);
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), windowRect,
QOpenGLTextureBlitter::OriginTopLeft);
d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft);
}
GLuint textureId = toTexture(region);
if (!textureId)
return;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(windowRect, windowRect,
QOpenGLTextureBlitter::OriginTopLeft);
d_ptr->blitter->setSwizzleRB(true);
d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
d_ptr->blitter->setSwizzleRB(false);
glDisable(GL_BLEND);
d_ptr->blitter->release();
context->swapBuffers(window);
}
/*!
Implemented in subclasses to return the content of the backingstore as a QImage.
If QPlatformIntegration::RasterGLSurface is supported, either this function or
toTexture() must be implemented.
\sa toTexture()
*/
QImage QPlatformBackingStore::toImage() const
{
return QImage();
}
/*!
May be reimplemented in subclasses to return the content of the
backingstore as an OpenGL texture. \a dirtyRegion is the part of the
backingstore which may have changed since the last call to this function. The
caller of this function must ensure that there is a current context.
The ownership of the texture is not transferred. The caller must not store
the return value between calls, but instead call this function before each use.
The default implementation returns a cached texture if \a dirtyRegion is
empty and the window has not been resized, otherwise it retrieves the
content using toImage() and performs a texture upload.
*/
GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion) const
{
QImage image = toImage();
QSize imageSize = image.size();
if (imageSize.isEmpty())
return 0;
bool resized = d_ptr->textureSize != imageSize;
if (dirtyRegion.isEmpty() && !resized)
return d_ptr->textureId;
if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_RGBA8888)
image = image.convertToFormat(QImage::Format_RGBA8888);
if (resized) {
if (d_ptr->textureId)
glDeleteTextures(1, &d_ptr->textureId);
glGenTextures(1, &d_ptr->textureId);
glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
#ifndef QT_OPENGL_ES_2
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
#endif
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageSize.width(), imageSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
const_cast<uchar*>(image.constBits()));
d_ptr->textureSize = imageSize;
} else {
glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
QRect imageRect = image.rect();
QRect rect = dirtyRegion.boundingRect() & imageRect;
// if the rect is wide enough it's cheaper to just
// extend it instead of doing an image copy
if (rect.width() >= imageRect.width() / 2) {
rect.setX(0);
rect.setWidth(imageRect.width());
}
// if the sub-rect is full-width we can pass the image data directly to
// OpenGL instead of copying, since there's no gap between scanlines
if (rect.width() == imageRect.width()) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
image.constScanLine(rect.y()));
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
image.copy(rect).constBits());
}
}
return d_ptr->textureId;
}
#endif // QT_NO_OPENGL
/*!
\fn QPaintDevice* QPlatformBackingStore::paintDevice()

View File

@ -52,9 +52,11 @@
//
#include <QtCore/qrect.h>
#include <QtCore/qobject.h>
#include <QtGui/qwindow.h>
#include <QtGui/qregion.h>
#include <QtGui/qopengl.h>
QT_BEGIN_NAMESPACE
@ -65,6 +67,31 @@ class QPoint;
class QImage;
class QPlatformBackingStorePrivate;
class QPlatformWindow;
class QPlatformTextureList;
class QPlatformTextureListPrivate;
class QOpenGLContext;
#ifndef QT_NO_OPENGL
class Q_GUI_EXPORT QPlatformTextureList : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QPlatformTextureList)
public:
explicit QPlatformTextureList(QObject *parent = 0);
~QPlatformTextureList();
int count() const;
GLuint textureId(int index) const;
QRect geometry(int index) const;
void lock(bool on);
bool isLocked() const;
void appendTexture(GLuint textureId, const QRect &geometry);
Q_SIGNALS:
void locked(bool);
};
#endif
class Q_GUI_EXPORT QPlatformBackingStore
{
@ -79,6 +106,11 @@ public:
// 'window' can be a child window, in which case 'region' is in child window coordinates and
// offset is the (child) window's offset in relation to the window surface.
virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset) = 0;
#ifndef QT_NO_OPENGL
virtual void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset, QPlatformTextureList *textures, QOpenGLContext *context);
virtual QImage toImage() const;
virtual GLuint toTexture(const QRegion &dirtyRegion) const;
#endif
virtual void resize(const QSize &size, const QRegion &staticContents) = 0;

View File

@ -328,7 +328,7 @@ QGLXContext::~QGLXContext()
bool QGLXContext::makeCurrent(QPlatformSurface *surface)
{
bool success = false;
Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
Q_ASSERT(surface->surface()->supportsOpenGL());
Display *dpy = DISPLAY_FROM_XCB(m_screen);
GLXDrawable glxDrawable = 0;

View File

@ -280,6 +280,11 @@ void QXcbBackingStore::beginPaint(const QRegion &region)
}
}
QImage QXcbBackingStore::toImage() const
{
return m_image && m_image->image() ? *m_image->image() : QImage();
}
void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
if (!m_image || m_image->size().isEmpty())
@ -319,6 +324,25 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
}
}
#ifndef QT_NO_OPENGL
void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures, QOpenGLContext *context)
{
QPlatformBackingStore::composeAndFlush(window, region, offset, textures, context);
Q_XCB_NOOP(connection());
if (m_syncingResize) {
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
connection()->sync();
m_syncingResize = false;
platformWindow->updateSyncRequestCounter();
} else {
xcb_flush(xcb_connection());
}
}
#endif // QT_NO_OPENGL
void QXcbBackingStore::resize(const QSize &size, const QRegion &)
{
if (m_image && size == m_image->size())

View File

@ -60,6 +60,11 @@ public:
QPaintDevice *paintDevice();
void flush(QWindow *window, const QRegion &region, const QPoint &offset);
#ifndef QT_NO_OPENGL
void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures, QOpenGLContext *context);
#endif
QImage toImage() const;
void resize(const QSize &size, const QRegion &staticContents);
bool scroll(const QRegion &area, int dx, int dy);

View File

@ -284,6 +284,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
case MultipleWindows: return true;
case ForeignWindows: return true;
case SyncState: return true;
case RasterGLSurface: return true;
default: return QPlatformIntegration::hasCapability(cap);
}
}

View File

@ -292,8 +292,6 @@ void QXcbWindow::create()
if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) {
#if defined(XCB_USE_GLX)
XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), &m_format);
if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
qFatal("Could not initialize GLX");
#elif defined(XCB_USE_EGL)
EGLDisplay eglDisplay = connection()->egl_display();
EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, m_format, true);
@ -308,9 +306,14 @@ void QXcbWindow::create()
XVisualInfo *visualInfo;
int matchingCount = 0;
visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount);
if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
qFatal("Could not initialize EGL");
#endif //XCB_USE_GLX
if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
qFatal("Could not initialize OpenGL");
if (!visualInfo && window()->surfaceType() == QSurface::RasterGLSurface) {
qWarning("Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface.");
window()->setSurfaceType(QSurface::RasterSurface);
}
if (visualInfo) {
m_depth = visualInfo->depth;
m_imageFormat = imageFormatForDepth(m_depth);

View File

@ -79,3 +79,8 @@ wince*: {
SOURCES += \
kernel/qwidgetsfunctions_wince.cpp
}
contains(QT_CONFIG, opengl) {
HEADERS += kernel/qopenglwidget_p.h
SOURCES += kernel/qopenglwidget.cpp
}

View File

@ -0,0 +1,183 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtWidgets module 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 "qopenglwidget_p.h"
#include <QOpenGLContext>
#include <QtWidgets/private/qwidget_p.h>
#include <QOpenGLFramebufferObject>
#include <QWindow>
#include <qpa/qplatformwindow.h>
#include <QDebug>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
QT_BEGIN_NAMESPACE
class QOpenGLWidgetPrivate : public QWidgetPrivate
{
Q_DECLARE_PUBLIC(QOpenGLWidget)
public:
QOpenGLWidgetPrivate()
: fbo(0), uninitialized(true)
{
setRenderToTexture();
}
GLuint textureId() const { return fbo ? fbo->texture() : 0; }
const QSurface *surface() const { return q_func()->window()->windowHandle(); }
QSurface *surface() { return q_func()->window()->windowHandle(); }
void initialize();
QOpenGLContext context;
QOpenGLFramebufferObject *fbo;
bool uninitialized;
int w,h;
};
void QOpenGLWidgetPrivate::initialize()
{
Q_Q(QOpenGLWidget);
if (!uninitialized)
return;
context.setShareContext(get(q->window())->shareContext());
context.setFormat(surface()->format());
context.create();
context.makeCurrent(surface());
q->initializeGL();
uninitialized = false;
}
QOpenGLWidget::QOpenGLWidget(QWidget *parent, Qt::WindowFlags f)
: QWidget(*(new QOpenGLWidgetPrivate), parent, f)
{
}
QOpenGLWidget::~QOpenGLWidget()
{
}
bool QOpenGLWidget::isValid() const
{
Q_D(const QOpenGLWidget);
return d->context.isValid();
}
void QOpenGLWidget::makeCurrent()
{
Q_D(QOpenGLWidget);
d->context.makeCurrent(d->surface());
d->fbo->bind();
}
void QOpenGLWidget::doneCurrent()
{
Q_D(QOpenGLWidget);
d->context.doneCurrent();
}
QSurfaceFormat QOpenGLWidget::format() const
{
Q_D(const QOpenGLWidget);
return d->surface()->format();
}
GLuint QOpenGLWidget::defaultFramebufferObject() const
{
Q_D(const QOpenGLWidget);
return d->fbo ? d->fbo->handle() : 0;
}
void QOpenGLWidget::initializeGL()
{
}
void QOpenGLWidget::resizeGL(int w, int h)
{
Q_UNUSED(w);
Q_UNUSED(h);
}
void QOpenGLWidget::paintGL()
{
}
void QOpenGLWidget::updateGL()
{
makeCurrent();
paintGL();
glFlush();
doneCurrent();
update();
}
void QOpenGLWidget::resizeEvent(QResizeEvent *)
{
Q_D(QOpenGLWidget);
d->w = width();
d->h = height();
d->initialize();
d->context.makeCurrent(d->surface());
delete d->fbo; // recreate when resized
d->fbo = new QOpenGLFramebufferObject(size());
d->fbo->bind();
glBindTexture(GL_TEXTURE_2D, d->fbo->texture());
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
resizeGL(width(), height());
paintGL();
glFlush();
}
void QOpenGLWidget::paintEvent(QPaintEvent *)
{
qWarning("QOpenGLWidget does not support paintEvent() yet.");
return;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,135 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtWidgets module 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$
**
****************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It may change from version to version
// without notice, or even be removed.
//
// We mean it.
//
#ifndef QOPENGLWIDGET_H
#define QOPENGLWIDGET_H
#include <QWidget>
#include <QSurfaceFormat>
#include <QtGui/qopengl.h>
QT_BEGIN_NAMESPACE
class QOpenGLWidgetPrivate;
class Q_WIDGETS_EXPORT QOpenGLWidget : public QWidget
{
Q_OBJECT
Q_DECLARE_PRIVATE(QOpenGLWidget)
public:
explicit QOpenGLWidget(QWidget* parent=0,
Qt::WindowFlags f=0);
// This API is not finalized yet. The commented-out functions below are
// QGLWidget functions that have not been implemented for QOpenGLWidget.
// Some of them may not end up in the final version (which is planned for a
// future release of Qt).
// explicit QOpenGLWidget(const QSurfaceFormat& format, QWidget* parent=0,
// Qt::WindowFlags f=0);
~QOpenGLWidget();
// void qglClearColor(const QColor& c) const;
bool isValid() const;
// bool isSharing() const;
void makeCurrent();
void doneCurrent();
// void swapBuffers();
QSurfaceFormat format() const;
GLuint defaultFramebufferObject() const;
// QPixmap renderPixmap(int w = 0, int h = 0, bool useContext = false);
QImage grabFrameBuffer(bool withAlpha = false);
// static QImage convertToGLFormat(const QImage& img);
// QPaintEngine *paintEngine() const;
// void drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget = GL_TEXTURE_2D);
// void drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget = GL_TEXTURE_2D);
public Q_SLOTS:
void updateGL();
protected:
// bool event(QEvent *);
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
// void setAutoBufferSwap(bool on);
// bool autoBufferSwap() const;
void paintEvent(QPaintEvent*);
void resizeEvent(QResizeEvent*);
// virtual void glInit();
// virtual void glDraw();
// QOpenGLWidget(QOpenGLWidgetPrivate &dd,
// const QGLFormat &format = QGLFormat(),
// QWidget *parent = 0,
// const QOpenGLWidget* shareWidget = 0,
// Qt::WindowFlags f = 0);
private:
Q_DISABLE_COPY(QOpenGLWidget)
};
QT_END_NAMESPACE
#endif // QOPENGLWIDGET_H

View File

@ -78,6 +78,7 @@
#include "private/qstyle_p.h"
#include "qfileinfo.h"
#include <QtGui/qinputmethod.h>
#include <QtGui/qopenglcontext.h>
#include <private/qgraphicseffect_p.h>
#include <qbackingstore.h>
@ -270,6 +271,8 @@ QWidgetPrivate::QWidgetPrivate(int version)
, isMoved(0)
, usesDoubleBufferedGLContext(0)
, mustHaveWindowHandle(0)
, renderToTexture(0)
, textureChildSeen(0)
#ifndef QT_NO_IM
, inheritsInputMethodHints(0)
#endif
@ -1558,6 +1561,7 @@ void QWidgetPrivate::createTLExtra()
x->inRepaint = false;
x->embedded = 0;
x->window = 0;
x->shareContext = 0;
x->screenIndex = 0;
#ifdef Q_WS_MAC
x->wasMaximized = false;
@ -5133,9 +5137,17 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
<< "geometry ==" << QRect(q->mapTo(q->window(), QPoint(0, 0)), q->size());
#endif
if (renderToTexture) {
// This widget renders into a texture which is composed later. We just need to
// punch a hole in the backingstore, so the texture will be visible.
QPainter p(q);
p.setCompositionMode(QPainter::CompositionMode_Source);
p.fillRect(q->rect(), Qt::transparent);
} else {
//actually send the paint event
QPaintEvent e(toBePainted);
QCoreApplication::sendSpontaneousEvent(q, &e);
}
// Native widgets need to be marked dirty on screen so painting will be done in correct context
if (backingStore && !onScreen && !asRoot && (q->internalWinId() || !q->nativeParentWidget()->isWindow()))
@ -9637,6 +9649,13 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
if (desktopWidget)
parent = 0;
#ifndef QT_NO_OPENGL
if (d->textureChildSeen && parent) {
// set the textureChildSeen flag up the whole parent chain
QWidgetPrivate::get(parent)->setTextureChildSeen();
}
#endif
if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) {
if (newParent)
oldBs->removeDirtyWidget(this);
@ -11108,7 +11127,25 @@ void QWidgetPrivate::adjustQuitOnCloseAttribute()
}
}
QOpenGLContext *QWidgetPrivate::shareContext() const
{
#ifdef QT_NO_OPENGL
return 0;
#else
if (!extra || !extra->topextra || !extra->topextra->window) {
qWarning() << "Asking for share context for widget that does not have a window handle";
return 0;
}
QWidgetPrivate *that = const_cast<QWidgetPrivate *>(this);
if (!extra->topextra->shareContext) {
QOpenGLContext *ctx = new QOpenGLContext();
ctx->setFormat(extra->topextra->window->format());
ctx->create();
that->extra->topextra->shareContext = ctx;
}
return that->extra->topextra->shareContext;
#endif // QT_NO_OPENGL
}
Q_WIDGETS_EXPORT QWidgetData *qt_qwidget_data(QWidget *widget)
{

View File

@ -60,6 +60,7 @@
#include "QtCore/qset.h"
#include "QtGui/qregion.h"
#include "QtGui/qinputmethod.h"
#include "QtGui/qopengl.h"
#include "QtWidgets/qsizepolicy.h"
#include "QtWidgets/qstyle.h"
#include "QtWidgets/qapplication.h"
@ -80,6 +81,7 @@ class QPixmap;
class QWidgetBackingStore;
class QGraphicsProxyWidget;
class QWidgetItemV2;
class QOpenGLContext;
class QStyle;
@ -216,6 +218,7 @@ struct QTLWExtra {
bool wasMaximized;
#endif
QWidgetWindow *window;
QOpenGLContext *shareContext;
quint32 screenIndex; // index in qplatformscreenlist
};
@ -324,6 +327,8 @@ public:
explicit QWidgetPrivate(int version = QObjectPrivateVersion);
~QWidgetPrivate();
static QWidgetPrivate *get(QWidget *w) { return w->d_func(); }
QWExtra *extraData() const;
QTLWExtra *topData() const;
QTLWExtra *maybeTopData() const;
@ -618,6 +623,27 @@ public:
inline QRect mapFromWS(const QRect &r) const
{ QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; }
QOpenGLContext *shareContext() const;
#ifndef QT_NO_OPENGL
virtual GLuint textureId() const { return 0; }
void setRenderToTexture() { renderToTexture = true; textureChildSeen = true; }
void setTextureChildSeen()
{
Q_Q(QWidget);
if (textureChildSeen)
return;
textureChildSeen = 1;
if (!q->isWindow()) {
QWidget *parent = q->parentWidget();
if (parent)
get(parent)->setTextureChildSeen();
}
}
#endif
// Variables.
// Regular pointers (keep them together to avoid gaps on 64 bit architectures).
QWExtra *extra;
@ -698,6 +724,8 @@ public:
uint isMoved : 1;
uint usesDoubleBufferedGLContext : 1;
uint mustHaveWindowHandle : 1;
uint renderToTexture : 1;
uint textureChildSeen : 1;
#ifndef QT_NO_IM
uint inheritsInputMethodHints : 1;
#endif

View File

@ -49,6 +49,7 @@
#include "QtWidgets/qdesktopwidget.h"
#include <qpa/qplatformwindow.h>
#include "QtGui/qsurfaceformat.h"
#include <QtGui/qopenglcontext.h>
#include <qpa/qplatformopenglcontext.h>
#include <qpa/qplatformintegration.h>
#include "QtGui/private/qwindow_p.h"
@ -953,6 +954,10 @@ void QWidgetPrivate::deleteTLSysExtra()
delete extra->topextra->backingStore;
extra->topextra->backingStore = 0;
#ifndef QT_NO_OPENGL
delete extra->topextra->shareContext;
extra->topextra->shareContext = 0;
#endif
}
}

View File

@ -57,6 +57,8 @@
#include <private/qpaintengine_raster_p.h>
#include <private/qgraphicseffect_p.h>
#include <qpa/qplatformbackingstore.h>
#if defined(Q_OS_WIN) && !defined(QT_NO_PAINT_DEBUG)
# include <QtCore/qt_windows.h>
# include <qpa/qplatformnativeinterface.h>
@ -72,10 +74,15 @@ extern QRegion qt_dirtyRegion(QWidget *);
* \a region is the region to be updated in \a widget coordinates.
*/
static inline void qt_flush(QWidget *widget, const QRegion &region, QBackingStore *backingStore,
QWidget *tlw, const QPoint &tlwOffset)
QWidget *tlw, const QPoint &tlwOffset, QPlatformTextureList *widgetTextures = 0,
QOpenGLContext *context = 0)
{
#ifdef QT_NO_OPENGL
Q_UNUSED(widgetTextures);
Q_UNUSED(context);
#endif
Q_ASSERT(widget);
Q_ASSERT(!region.isEmpty());
Q_ASSERT(!region.isEmpty() || (context && widgetTextures && widgetTextures->count()));
Q_ASSERT(backingStore);
Q_ASSERT(tlw);
@ -104,10 +111,16 @@ static inline void qt_flush(QWidget *widget, const QRegion &region, QBackingStor
if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen))
return;
QPoint offset = tlwOffset;
if (widget != tlw)
backingStore->flush(region, widget->windowHandle(), tlwOffset + widget->mapTo(tlw, QPoint()));
offset += widget->mapTo(tlw, QPoint());
#ifndef QT_NO_OPENGL
if (widgetTextures)
backingStore->handle()->composeAndFlush(widget->windowHandle(), region, offset, widgetTextures, context);
else
backingStore->flush(region, widget->windowHandle(), tlwOffset);
#endif
backingStore->flush(region, widget->windowHandle(), offset);
}
#ifndef QT_NO_PAINT_DEBUG
@ -430,7 +443,7 @@ QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &within
return region;
}
static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
void QWidgetBackingStore::sendUpdateRequest(QWidget *widget, bool updateImmediately)
{
if (!widget)
return;
@ -439,6 +452,7 @@ static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
QEvent event(QEvent::UpdateRequest);
QApplication::sendEvent(widget, &event);
} else {
updateRequestSent = true;
QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
}
}
@ -488,6 +502,7 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
return;
}
//### FIXME fullUpdatePending seems to be always false????
if (fullUpdatePending) {
if (updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
@ -495,6 +510,13 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
}
const QPoint offset = widget->mapTo(tlw, QPoint());
if (QWidgetPrivate::get(widget)->renderToTexture) {
if (!updateRequestSent || updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
return;
}
const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect());
if (qt_region_strictContains(dirty, widgetRect.translated(offset))) {
if (updateImmediately)
@ -503,7 +525,7 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
}
if (invalidateBuffer) {
const bool eventAlreadyPosted = !dirty.isEmpty();
const bool eventAlreadyPosted = !dirty.isEmpty() || updateRequestSent;
#ifndef QT_NO_GRAPHICSEFFECT
if (widget->d_func()->graphicsEffect)
dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset);
@ -583,6 +605,13 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd
return;
}
if (QWidgetPrivate::get(widget)->renderToTexture) {
if (!updateRequestSent || updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
return;
}
const QRect widgetRect = widget->d_func()->effectiveRectFor(rect);
const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
if (qt_region_strictContains(dirty, translatedRect)) {
@ -703,7 +732,11 @@ void QWidgetBackingStore::updateLists(QWidget *cur)
}
QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel)
: tlw(topLevel), dirtyOnScreenWidgets(0), fullUpdatePending(0)
: tlw(topLevel),
dirtyOnScreenWidgets(0),
widgetTextures(0),
fullUpdatePending(0),
updateRequestSent(0)
{
store = tlw->backingStore();
Q_ASSERT(store);
@ -902,7 +935,7 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg
// Nothing to repaint.
if (!isDirty()) {
qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset);
qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext());
return;
}
@ -914,11 +947,27 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg
doSync();
}
#ifndef QT_NO_OPENGL
static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatformTextureList *widgetTextures)
{
QWidgetPrivate *wd = QWidgetPrivate::get(widget);
if (wd->renderToTexture)
widgetTextures->appendTexture(wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size()));
for (int i = 0; i < wd->children.size(); ++i) {
QWidget *w = qobject_cast<QWidget *>(wd->children.at(i));
if (w && !w->isWindow() && !w->isHidden() && QWidgetPrivate::get(w)->textureChildSeen)
findTextureWidgetsRecursively(tlw, w, widgetTextures);
}
}
#endif
/*!
Synchronizes the backing store, i.e. dirty areas are repainted and flushed.
*/
void QWidgetBackingStore::sync()
{
updateRequestSent = false;
QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
if (discardSyncRequest(tlw, tlwExtra)) {
// If the top-level is minimized, it's not visible on the screen so we can delay the
@ -1024,7 +1073,15 @@ void QWidgetBackingStore::doSync()
}
dirtyWidgets.clear();
#ifndef QT_NO_OPENGL
delete widgetTextures;
widgetTextures = 0;
if (tlw->d_func()->textureChildSeen) {
widgetTextures = new QPlatformTextureList; // TODO: implement support for locking
findTextureWidgetsRecursively(tlw, tlw, widgetTextures);
}
fullUpdatePending = false;
#endif
if (toClean.isEmpty()) {
// Nothing to repaint. However, we might have newly exposed areas on the
@ -1038,6 +1095,7 @@ void QWidgetBackingStore::doSync()
if (tlw->d_func()->extra->proxyWidget) {
updateStaticContentsSize();
dirty = QRegion();
updateRequestSent = false;
const QVector<QRect> rects(toClean.rects());
for (int i = 0; i < rects.size(); ++i)
tlw->d_func()->extra->proxyWidget->update(rects.at(i));
@ -1051,6 +1109,7 @@ void QWidgetBackingStore::doSync()
for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i)
resetWidget(opaqueNonOverlappedWidgets[i]);
dirty = QRegion();
updateRequestSent = false;
return;
}
@ -1059,6 +1118,7 @@ void QWidgetBackingStore::doSync()
updateStaticContentsSize();
const QRegion dirtyCopy(dirty);
dirty = QRegion();
updateRequestSent = false;
// Paint opaque non overlapped widgets.
for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) {
@ -1099,12 +1159,19 @@ void QWidgetBackingStore::flush(QWidget *widget)
{
if (!dirtyOnScreen.isEmpty()) {
QWidget *target = widget ? widget : tlw;
qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset);
qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext());
dirtyOnScreen = QRegion();
}
if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty())
if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) {
#ifndef QT_NO_OPENGL
if (widgetTextures && widgetTextures->count()) {
QWidget *target = widget ? widget : tlw;
qt_flush(target, QRegion(), store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext());
}
#endif
return;
}
for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
QWidget *w = dirtyOnScreenWidgets->at(i);

View File

@ -60,6 +60,8 @@
QT_BEGIN_NAMESPACE
class QPlatformTextureList;
struct BeginPaintInfo {
inline BeginPaintInfo() : wasFlushed(0), nothingToPaint(0), backingStoreRecreated(0) {}
uint wasFlushed : 1;
@ -102,11 +104,15 @@ private:
QVector<QWidget *> dirtyWidgets;
QVector<QWidget *> *dirtyOnScreenWidgets;
QList<QWidget *> staticWidgets;
QPlatformTextureList *widgetTextures;
QBackingStore *store;
uint fullUpdatePending : 1;
uint updateRequestSent : 1;
QPoint tlwOffset;
void sendUpdateRequest(QWidget *widget, bool updateImmediately);
static bool flushPaint(QWidget *widget, const QRegion &rgn);
static void unflushPaint(QWidget *widget, const QRegion &rgn);

View File

@ -92,6 +92,12 @@ QWidgetWindow::QWidgetWindow(QWidget *widget)
, m_widget(widget)
{
updateObjectName();
// Enable QOpenGLWidget/QQuickWidget children if the platform plugin supports it,
// and the application developer has not explicitly disabled it.
if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)
&& !QApplication::testAttribute(Qt::AA_ForceRasterWidgets)) {
setSurfaceType(QSurface::RasterGLSurface);
}
connect(m_widget, &QObject::objectNameChanged, this, &QWidgetWindow::updateObjectName);
}

View File

@ -0,0 +1,73 @@
/****************************************************************************
**
** Copyright (C) 2013 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 "openglwidget.h"
#include <QApplication>
#include <QPushButton>
#include <QMdiArea>
#include <QLCDNumber>
#include <QTimer>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMdiArea w;
w.resize(400,400);
OpenGLWidget *glw = new OpenGLWidget;
w.addSubWindow(glw);
glw->setMinimumSize(100,100);
OpenGLWidget *glw2 = new OpenGLWidget;
glw2->setMinimumSize(100,100);
w.addSubWindow(glw2);
QLCDNumber *lcd = new QLCDNumber;
lcd->display(1337);
lcd->setMinimumSize(300,100);
w.addSubWindow(lcd);
w.show();
return a.exec();
}

View File

@ -0,0 +1,193 @@
/****************************************************************************
**
** Copyright (C) 2013 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$
**
****************************************************************************/
#define GL_GLEXT_PROTOTYPES
#include "openglwidget.h"
#include <QtWidgets/private/qwidget_p.h>
#include <QOpenGLFramebufferObject>
#include <QWindow>
#include <qpa/qplatformwindow.h>
#include <QDebug>
#include <QTimer>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QGuiApplication>
#include <QtGui/QMatrix4x4>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QScreen>
#include <QtCore/qmath.h>
#include <qopengl.h>
#include <GL/glext.h>
class OpenGLWidgetPrivate
{
public:
OpenGLWidgetPrivate()
: m_program(0), m_frame(0)
{
}
void initialize();
void render();
int width() {return w;}
int height() {return h;}
GLuint m_posAttr;
GLuint m_colAttr;
GLuint m_matrixUniform;
QOpenGLShaderProgram *m_program;
int m_frame;
int w,h;
};
OpenGLWidget::OpenGLWidget(QWidget *parent)
: QOpenGLWidget(parent)
{
d = new OpenGLWidgetPrivate;
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
timer->start(30);
}
OpenGLWidget::~OpenGLWidget()
{
}
void OpenGLWidget::initializeGL()
{
// qDebug("*initializeGL*");
d->initialize();
}
void OpenGLWidget::resizeGL(int w, int h)
{
// qDebug("*resizeGL*");
d->w = w;
d->h = h;
}
void OpenGLWidget::paintGL()
{
// qDebug("*paintGL* %d", d->m_frame);
d->render();
}
static const char *vertexShaderSource =
"attribute highp vec4 posAttr;\n"
"attribute lowp vec4 colAttr;\n"
"varying lowp vec4 col;\n"
"uniform highp mat4 matrix;\n"
"void main() {\n"
" col = colAttr;\n"
" gl_Position = matrix * posAttr;\n"
"}\n";
static const char *fragmentShaderSource =
"varying lowp vec4 col;\n"
"void main() {\n"
" gl_FragColor = col;\n"
"}\n";
void OpenGLWidgetPrivate::initialize()
{
m_program = new QOpenGLShaderProgram;
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
m_program->link();
m_posAttr = m_program->attributeLocation("posAttr");
m_colAttr = m_program->attributeLocation("colAttr");
m_matrixUniform = m_program->uniformLocation("matrix");
}
void OpenGLWidgetPrivate::render()
{
const qreal retinaScale = 1.0;//devicePixelRatio();
glViewport(0, 0, width() * retinaScale, height() * retinaScale);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
m_program->bind();
QMatrix4x4 matrix;
matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
matrix.translate(0, 0, -2);
matrix.rotate(100.0f * m_frame / 30/*screen()->refreshRate()*/, 0, 1, 0);
m_program->setUniformValue(m_matrixUniform, matrix);
GLfloat vertices[] = {
0.0f, 0.707f,
-0.5f, -0.5f,
0.5f, -0.5f
};
GLfloat colors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
m_program->release();
++m_frame;
}

View File

@ -0,0 +1,63 @@
/****************************************************************************
**
** Copyright (C) 2013 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$
**
****************************************************************************/
#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H
#include <QtWidgets/private/qopenglwidget_p.h>
class OpenGLWidgetPrivate;
class OpenGLWidget : public QOpenGLWidget
{
Q_OBJECT
public:
OpenGLWidget(QWidget *parent = 0);
~OpenGLWidget();
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
private:
OpenGLWidgetPrivate *d;
};
#endif // OPENGLWIDGET_H

View File

@ -0,0 +1,9 @@
QT += widgets widgets-private gui-private core-private
TARGET = openglwidget
TEMPLATE = app
SOURCES += main.cpp \
openglwidget.cpp
HEADERS += openglwidget.h