summaryrefslogtreecommitdiffstats
path: root/src/opengl/qwindowsurface_gl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl/qwindowsurface_gl.cpp')
-rw-r--r--src/opengl/qwindowsurface_gl.cpp1104
1 files changed, 0 insertions, 1104 deletions
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp
deleted file mode 100644
index d3e7e5178e..0000000000
--- a/src/opengl/qwindowsurface_gl.cpp
+++ /dev/null
@@ -1,1104 +0,0 @@
-/****************************************************************************
-**
-** 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 <QtWidgets/QApplication>
-#include <QtGui/QColormap>
-#include <QtWidgets/QDesktopWidget>
-#include <QtGui/QPaintDevice>
-#include <QtWidgets/QWidget>
-
-#include <qglframebufferobject.h>
-#include <qglpixelbuffer.h>
-#include <qcolormap.h>
-#include <qdesktopwidget.h>
-#include <private/qwidget_p.h>
-#include "qdebug.h"
-
-#ifdef Q_WS_X11
-#include <private/qt_x11_p.h>
-#include <qx11info_x11.h>
-
-#ifndef QT_OPENGL_ES
-#include <GL/glx.h>
-#include <X11/Xlib.h>
-#endif
-#endif //Q_WS_X11
-
-#include <private/qglextensions_p.h>
-#include <private/qwindowsurface_gl_p.h>
-
-#include <private/qgl_p.h>
-
-#include <private/qglpixelbuffer_p.h>
-
-#include <private/qpaintengineex_opengl2_p.h>
-#include <private/qpixmapdata_gl_p.h>
-
-#ifndef QT_OPENGL_ES_2
-#include <private/qpaintengine_opengl_p.h>
-#endif
-
-#ifndef GLX_ARB_multisample
-#define GLX_SAMPLE_BUFFERS_ARB 100000
-#define GLX_SAMPLES_ARB 100001
-#endif
-
-#ifndef QT_NO_EGL
-#include <private/qeglcontext_p.h>
-#endif
-
-#ifdef Q_WS_QPA
-#include <qplatformscreen_qpa.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-//
-// QGLWindowSurface
-//
-class QGLGlobalShareWidget
-{
-public:
- QGLGlobalShareWidget() : firstPixmap(0), widgetRefCount(0), widget(0), initializing(false) {
- created = true;
- }
-
- QGLWidget *shareWidget() {
- if (!initializing && !widget && !cleanedUp) {
- initializing = true;
- widget = new QGLWidget(QGLFormat(QGL::SingleBuffer | QGL::NoDepthBuffer | QGL::NoStencilBuffer));
- widget->resize(1, 1);
-
- // We don't need this internal widget to appear in QApplication::topLevelWidgets()
- if (QWidgetPrivate::allWidgets)
- QWidgetPrivate::allWidgets->remove(widget);
- initializing = false;
- }
- return widget;
- }
-
- // destroys the share widget and prevents recreation
- void cleanup() {
- QGLWidget *w = widget;
- cleanedUp = true;
- widget = 0;
- delete w;
- }
-
- // destroys the share widget, but allows it to be recreated later on
- void destroy() {
- if (cleanedUp)
- return;
-
- QGLWidget *w = widget;
-
- // prevent potential recursions
- cleanedUp = true;
- widget = 0;
- delete w;
- cleanedUp = false;
- }
-
- static bool cleanedUp;
- static bool created;
-
- QGLPixmapData *firstPixmap;
- int widgetRefCount;
-
-private:
- QGLWidget *widget;
- bool initializing;
-};
-
-bool QGLGlobalShareWidget::cleanedUp = false;
-bool QGLGlobalShareWidget::created = false;
-
-static void qt_cleanup_gl_share_widget();
-Q_GLOBAL_STATIC_WITH_INITIALIZER(QGLGlobalShareWidget, _qt_gl_share_widget,
- {
- qAddPostRoutine(qt_cleanup_gl_share_widget);
- })
-
-static void qt_cleanup_gl_share_widget()
-{
- if (QGLGlobalShareWidget::created)
- _qt_gl_share_widget()->cleanup();
-}
-
-QGLWidget* qt_gl_share_widget()
-{
- if (QGLGlobalShareWidget::cleanedUp)
- return 0;
- return _qt_gl_share_widget()->shareWidget();
-}
-
-void qt_destroy_gl_share_widget()
-{
- if (QGLGlobalShareWidget::created)
- _qt_gl_share_widget()->destroy();
-}
-
-const QGLContext *qt_gl_share_context()
-{
- QGLWidget *widget = qt_gl_share_widget();
- if (widget)
- return widget->context();
- return 0;
-}
-
-#ifdef QGL_USE_TEXTURE_POOL
-void qt_gl_register_pixmap(QGLPixmapData *pd)
-{
- QGLGlobalShareWidget *shared = _qt_gl_share_widget();
- pd->next = shared->firstPixmap;
- pd->prev = 0;
- if (shared->firstPixmap)
- shared->firstPixmap->prev = pd;
- shared->firstPixmap = pd;
-}
-
-void qt_gl_unregister_pixmap(QGLPixmapData *pd)
-{
- if (pd->next)
- pd->next->prev = pd->prev;
- if (pd->prev) {
- pd->prev->next = pd->next;
- } else {
- QGLGlobalShareWidget *shared = _qt_gl_share_widget();
- if (shared)
- shared->firstPixmap = pd->next;
- }
-}
-
-void qt_gl_hibernate_pixmaps()
-{
- QGLGlobalShareWidget *shared = _qt_gl_share_widget();
-
- // Scan all QGLPixmapData objects in the system and hibernate them.
- QGLPixmapData *pd = shared->firstPixmap;
- while (pd != 0) {
- pd->hibernate();
- pd = pd->next;
- }
-}
-#endif
-
-struct QGLWindowSurfacePrivate
-{
- QGLFramebufferObject *fbo;
- QGLPixelBuffer *pb;
- GLuint tex_id;
- GLuint pb_tex_id;
-
- int tried_fbo : 1;
- int tried_pb : 1;
- int destructive_swap_buffers : 1;
- int geometry_updated : 1;
- int did_paint : 1;
-
- QGLContext *ctx;
-
- QList<QGLContext **> contexts;
-
- QRegion paintedRegion;
- QSize size;
-
- QSize textureSize;
-
- QList<QImage> buffers;
- QGLWindowSurfaceGLPaintDevice glDevice;
- QGLWindowSurface* q_ptr;
-
- bool swap_region_support;
-};
-
-QGLFormat QGLWindowSurface::surfaceFormat;
-QGLWindowSurface::SwapMode QGLWindowSurface::swapBehavior = QGLWindowSurface::AutomaticSwap;
-
-void QGLWindowSurfaceGLPaintDevice::endPaint()
-{
- glFlush();
- QGLPaintDevice::endPaint();
-}
-
-QSize QGLWindowSurfaceGLPaintDevice::size() const
-{
- return d->size;
-}
-
-QGLContext* QGLWindowSurfaceGLPaintDevice::context() const
-{
- return d->ctx;
-}
-
-
-int QGLWindowSurfaceGLPaintDevice::metric(PaintDeviceMetric m) const
-{
- QWindow *window = d->q_ptr->window();
- QPlatformScreen *screen = QPlatformScreen::platformScreenForWindow(window);
- if (!screen) {
- if (m == PdmDpiX || m == PdmDpiY)
- return 72;
- }
- int val;
- if (m == PdmWidth) {
- val = window->geometry().width();
- } else if (m == PdmWidthMM) {
- val = window->geometry().width() * screen->physicalSize().width() / screen->geometry().width();
- } else if (m == PdmHeight) {
- val = window->geometry().height();
- } else if (m == PdmHeightMM) {
- val = window->geometry().height() * screen->physicalSize().height() / screen->geometry().height();
- } else if (m == PdmDepth) {
- val = screen->depth();
- } else if (m == PdmDpiX || m == PdmPhysicalDpiX) {
- val = qRound(screen->geometry().width() / double(screen->physicalSize().width() / 25.4));
- } else if (m == PdmDpiY || m == PdmPhysicalDpiY) {
- val = qRound(screen->geometry().height() / double(screen->physicalSize().height() / 25.4));
- } else {
- val = 1 << qMax(24, screen->depth());
- }
- return val;
-}
-
-QPaintEngine *QGLWindowSurfaceGLPaintDevice::paintEngine() const
-{
- return qt_qgl_paint_engine();
-}
-
-QGLWindowSurface::QGLWindowSurface(QWindow *window)
- : QWindowSurface(window), d_ptr(new QGLWindowSurfacePrivate)
-{
-// Q_ASSERT(window->isTopLevel());
- d_ptr->pb = 0;
- d_ptr->fbo = 0;
- d_ptr->ctx = 0;
- d_ptr->tex_id = 0;
-#if defined (QT_OPENGL_ES_2)
- d_ptr->tried_fbo = true;
- d_ptr->tried_pb = true;
-#else
- d_ptr->tried_fbo = false;
- d_ptr->tried_pb = false;
-#endif
- d_ptr->destructive_swap_buffers = qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull();
- d_ptr->glDevice.d = d_ptr;
- d_ptr->q_ptr = this;
- d_ptr->geometry_updated = false;
- d_ptr->did_paint = false;
- d_ptr->swap_region_support = false;
-}
-
-QGLWindowSurface::~QGLWindowSurface()
-{
- if (d_ptr->ctx)
- glDeleteTextures(1, &d_ptr->tex_id);
-#ifndef Q_WS_QPA // Dont delete the contexts. Destroying the window does that for us
- foreach(QGLContext **ctx, d_ptr->contexts) {
- delete *ctx;
- *ctx = 0;
- }
-#endif
- delete d_ptr->pb;
- delete d_ptr->fbo;
- delete d_ptr;
-
- if (QGLGlobalShareWidget::cleanedUp)
- return;
-
- --(_qt_gl_share_widget()->widgetRefCount);
-
-#ifdef QGL_USE_TEXTURE_POOL
- if (_qt_gl_share_widget()->widgetRefCount <= 0) {
- // All of the widget window surfaces have been destroyed
- // but we still have GL pixmaps active. Ask them to hibernate
- // to free up GPU resources until a widget is shown again.
- // This may eventually cause the EGLContext to be destroyed
- // because nothing in the system needs a context, which will
- // free up even more GPU resources.
- qt_gl_hibernate_pixmaps();
-
- // Destroy the context if necessary.
- if (!qt_gl_share_widget()->context()->isSharing())
- qt_destroy_gl_share_widget();
- }
-#endif // QGL_USE_TEXTURE_POOL
-}
-
-void QGLWindowSurface::deleted(QObject *object)
-{
-#if 0
- QWidget *widget = qobject_cast<QWidget *>(object);
- if (widget) {
- if (widget == window()) {
- // Make sure that the fbo is destroyed before destroying its context.
- delete d_ptr->fbo;
- d_ptr->fbo = 0;
- }
-
-#ifndef Q_WS_QPA //no need to specifically delete the QGLContext as it will be deleted by QWidget
- QWidgetPrivate *widgetPrivate = widget->d_func();
- if (widgetPrivate->extraData()) {
- union { QGLContext **ctxPtrPtr; void **voidPtrPtr; };
- voidPtrPtr = &widgetPrivate->extraData()->glContext;
- int index = d_ptr->contexts.indexOf(ctxPtrPtr);
- if (index != -1) {
- delete *ctxPtrPtr;
- *ctxPtrPtr = 0;
- d_ptr->contexts.removeAt(index);
- }
- }
-#endif
- }
-#endif
-}
-
-void QGLWindowSurface::hijackWindow(QWindow *window)
-{
-#if 0
- QWidgetPrivate *widgetPrivate = widget->d_func();
- widgetPrivate->createExtra();
- if (widgetPrivate->extraData()->glContext)
- return;
-
- QGLContext *ctx = NULL;
-
- // For translucent top-level widgets we need alpha in the format.
- if (widget->testAttribute(Qt::WA_TranslucentBackground)) {
- QGLFormat modFormat(surfaceFormat);
- modFormat.setSampleBuffers(false);
- modFormat.setSamples(0);
- modFormat.setAlpha(true);
- ctx = new QGLContext(modFormat, widget);
- } else
- ctx = new QGLContext(surfaceFormat, widget);
-
- ctx->create(qt_gl_share_context());
-
- if (widget != qt_gl_share_widget())
- ++(_qt_gl_share_widget()->widgetRefCount);
-
-#ifndef QT_NO_EGL
- static bool checkedForNOKSwapRegion = false;
- static bool haveNOKSwapRegion = false;
-
- if (!checkedForNOKSwapRegion) {
- haveNOKSwapRegion = QEgl::hasExtension("EGL_NOK_swap_region2");
- checkedForNOKSwapRegion = true;
-
- if (haveNOKSwapRegion)
- qDebug() << "Found EGL_NOK_swap_region2 extension. Using partial updates.";
- }
-
- d_ptr->destructive_swap_buffers = true;
- if (ctx->d_func()->eglContext->configAttrib(EGL_SURFACE_TYPE)&EGL_SWAP_BEHAVIOR_PRESERVED_BIT) {
- EGLint swapBehavior;
- if (eglQuerySurface(ctx->d_func()->eglContext->display(), ctx->d_func()->eglSurface
- , EGL_SWAP_BEHAVIOR, &swapBehavior)) {
- d_ptr->destructive_swap_buffers = (swapBehavior != EGL_BUFFER_PRESERVED);
- }
- }
-
- d_ptr->swap_region_support = haveNOKSwapRegion;
-#endif
-
- widgetPrivate->extraData()->glContext = ctx;
-
- union { QGLContext **ctxPtrPtr; void **voidPtrPtr; };
-
- connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(deleted(QObject*)));
-
- voidPtrPtr = &widgetPrivate->extraData()->glContext;
- d_ptr->contexts << ctxPtrPtr;
-#ifndef Q_OS_SYMBIAN
- qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size();
-#endif
-#endif
-}
-
-QGLContext *QGLWindowSurface::context() const
-{
- return d_ptr->ctx;
-}
-
-QPaintDevice *QGLWindowSurface::paintDevice()
-{
- updateGeometry();
-
- if (d_ptr->pb)
- return d_ptr->pb;
-
- if (d_ptr->ctx)
- return &d_ptr->glDevice;
-
-#if 0
- QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
- ctx->makeCurrent();
-#endif
-
- Q_ASSERT(d_ptr->fbo);
- return d_ptr->fbo;
-}
-
-static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &src = QRectF());
-
-void QGLWindowSurface::beginPaint(const QRegion &)
-{
- d_ptr->did_paint = true;
- updateGeometry();
-
- int clearFlags = 0;
-
-#if 0
- QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
-#endif
- const QGLContext *ctx = QGLContext::currentContext();
-
- if (!ctx)
- return;
-
- if (ctx->d_func()->workaround_needsFullClearOnEveryFrame)
- clearFlags = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
- else if (ctx->format().alpha())
- clearFlags = GL_COLOR_BUFFER_BIT;
-
- if (clearFlags) {
- if (d_ptr->fbo)
- d_ptr->fbo->bind();
-
- glClearColor(0.0, 0.0, 0.0, 0.0);
- glClear(clearFlags);
-
- if (d_ptr->fbo)
- d_ptr->fbo->release();
- }
-}
-
-void QGLWindowSurface::endPaint(const QRegion &rgn)
-{
- if (context())
- d_ptr->paintedRegion |= rgn;
-
- d_ptr->buffers.clear();
-}
-
-static void blitTexture(QGLContext *ctx, GLuint texture, const QSize &viewport, const QSize &texSize, const QRect &targetRect, const QRect &sourceRect)
-{
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
- glDisable(GL_BLEND);
-
- glViewport(0, 0, viewport.width(), viewport.height());
-
- QGLShaderProgram *blitProgram =
- QGLEngineSharedShaders::shadersForContext(ctx)->blitProgram();
- blitProgram->bind();
- blitProgram->setUniformValue("imageTexture", 0 /*QT_IMAGE_TEXTURE_UNIT*/);
-
- // The shader manager's blit program does not multiply the
- // vertices by the pmv matrix, so we need to do the effect
- // of the orthographic projection here ourselves.
- QRectF r;
- qreal w = viewport.width();
- qreal h = viewport.height();
- r.setLeft((targetRect.left() / w) * 2.0f - 1.0f);
- if (targetRect.right() == (viewport.width() - 1))
- r.setRight(1.0f);
- else
- r.setRight((targetRect.right() / w) * 2.0f - 1.0f);
- r.setBottom((targetRect.top() / h) * 2.0f - 1.0f);
- if (targetRect.bottom() == (viewport.height() - 1))
- r.setTop(1.0f);
- else
- r.setTop((targetRect.bottom() / w) * 2.0f - 1.0f);
-
- drawTexture(r, texture, texSize, sourceRect);
-}
-
-
-void QGLWindowSurface::flush(QWindow *window, const QRegion &rgn, const QPoint &offset)
-{
-#if 0
- //### Find out why d_ptr->geometry_updated isn't always false.
- // flush() should not be called when d_ptr->geometry_updated is true. It assumes that either
- // d_ptr->fbo or d_ptr->pb is allocated and has the correct size.
- if (d_ptr->geometry_updated)
- return;
-
- // did_paint is set to true in ::beginPaint. ::beginPaint means that we
- // at least cleared the background (= painted something). In EGL API it's a
- // mistake to call swapBuffers if nothing was painted unless
- // EGL_BUFFER_PRESERVED is set. This check protects the flush func from
- // being executed if it's for nothing.
- if (!d_ptr->destructive_swap_buffers && !d_ptr->did_paint)
- return;
-
-#ifdef Q_OS_SYMBIAN
- if (window() != widget) {
- // For performance reasons we don't support
- // flushing native child widgets on Symbian.
- // It breaks overlapping native child widget
- // rendering in some cases but we prefer performance.
- return;
- }
-#endif
-
-
- QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget();
- Q_ASSERT(parent);
-
-#if !defined(Q_WS_QPA)
- if (!geometry().isValid())
- return;
-#else
- if (!size().isValid())
- return;
-#endif
-
- // Needed to support native child-widgets...
- hijackWindow(parent);
-
- QRect br = rgn.boundingRect().translated(offset);
- br = br.intersected(window()->rect());
- QPoint wOffset = qt_qwidget_data(parent)->wrect.topLeft();
- QRect rect = br.translated(-offset - wOffset);
-
- const GLenum target = GL_TEXTURE_2D;
- Q_UNUSED(target);
-
- if (QGLWindowSurface::swapBehavior == QGLWindowSurface::KillSwap)
- return;
-
- if (context()) {
- context()->makeCurrent();
-
- if (context()->format().doubleBuffer()) {
-#if !defined(QT_OPENGL_ES_2)
- if (d_ptr->destructive_swap_buffers) {
- glBindTexture(target, d_ptr->tex_id);
-
- QVector<QRect> rects = d_ptr->paintedRegion.rects();
- for (int i = 0; i < rects.size(); ++i) {
- QRect br = rects.at(i);
- if (br.isEmpty())
- continue;
-
- const uint bottom = window()->height() - (br.y() + br.height());
- glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height());
- }
-
- glBindTexture(target, 0);
-
- QRegion dirtyRegion = QRegion(window()->rect()) - d_ptr->paintedRegion;
-
- if (!dirtyRegion.isEmpty()) {
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
-#ifndef QT_OPENGL_ES
- glOrtho(0, window()->width(), window()->height(), 0, -999999, 999999);
-#else
- glOrthof(0, window()->width(), window()->height(), 0, -999999, 999999);
-#endif
- glViewport(0, 0, window()->width(), window()->height());
-
- QVector<QRect> rects = dirtyRegion.rects();
- glColor4f(1, 1, 1, 1);
- for (int i = 0; i < rects.size(); ++i) {
- QRect rect = rects.at(i);
- if (rect.isEmpty())
- continue;
-
- drawTexture(rect, d_ptr->tex_id, window()->size(), rect);
- }
- }
- }
-#endif
- bool doingPartialUpdate = false;
- if (d_ptr->swap_region_support) {
- if (QGLWindowSurface::swapBehavior == QGLWindowSurface::AutomaticSwap)
- doingPartialUpdate = br.width() * br.height() < parent->geometry().width() * parent->geometry().height() * 0.2;
- else if (QGLWindowSurface::swapBehavior == QGLWindowSurface::AlwaysPartialSwap)
- doingPartialUpdate = true;
- }
-
- QGLContext *ctx = reinterpret_cast<QGLContext *>(parent->d_func()->extraData()->glContext);
- if (widget != window()) {
- if (initializeOffscreenTexture(window()->size()))
- qWarning() << "QGLWindowSurface: Flushing to native child widget, may lead to significant performance loss";
- glBindTexture(target, d_ptr->tex_id);
-
- const uint bottom = window()->height() - (br.y() + br.height());
- glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height());
-
- glBindTexture(target, 0);
-
- ctx->makeCurrent();
- if (doingPartialUpdate)
- blitTexture(ctx, d_ptr->tex_id, parent->size(), window()->size(), rect, br);
- else
- blitTexture(ctx, d_ptr->tex_id, parent->size(), window()->size(), parent->rect(), parent->rect().translated(offset + wOffset));
- }
-
- if (doingPartialUpdate)
- ctx->d_func()->swapRegion(br);
- else
- ctx->swapBuffers();
-
- d_ptr->paintedRegion = QRegion();
- } else {
- glFlush();
- }
- return;
- }
-
- QGLContext *previous_ctx = const_cast<QGLContext *>(QGLContext::currentContext());
- QGLContext *ctx = reinterpret_cast<QGLContext *>(parent->d_func()->extraData()->glContext);
-
- // QPainter::end() should have unbound the fbo, otherwise something is very wrong...
- Q_ASSERT(!d_ptr->fbo || !d_ptr->fbo->isBound());
-
- if (ctx != previous_ctx) {
- ctx->makeCurrent();
- }
-
- QSize size = widget->rect().size();
- if (d_ptr->destructive_swap_buffers && ctx->format().doubleBuffer()) {
- rect = parent->rect();
- br = rect.translated(wOffset + offset);
- size = parent->size();
- }
-
- glDisable(GL_SCISSOR_TEST);
-
- if (d_ptr->fbo && (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit)) {
- const int h = d_ptr->fbo->height();
-
- const int sx0 = br.left();
- const int sx1 = br.left() + br.width();
- const int sy0 = h - (br.top() + br.height());
- const int sy1 = h - br.top();
-
- const int tx0 = rect.left();
- const int tx1 = rect.left() + rect.width();
- const int ty0 = parent->height() - (rect.top() + rect.height());
- const int ty1 = parent->height() - rect.top();
-
- if (window() == parent || d_ptr->fbo->format().samples() <= 1) {
- if (ctx->d_ptr->current_fbo != 0)
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
-
- glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
- tx0, ty0, tx1, ty1,
- GL_COLOR_BUFFER_BIT,
- GL_NEAREST);
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
- } else {
- // can't do sub-region blits with multisample FBOs
- QGLFramebufferObject *temp = qgl_fbo_pool()->acquire(d_ptr->fbo->size(), QGLFramebufferObjectFormat());
-
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, temp->handle());
- glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
-
- glBlitFramebufferEXT(0, 0, d_ptr->fbo->width(), d_ptr->fbo->height(),
- 0, 0, d_ptr->fbo->width(), d_ptr->fbo->height(),
- GL_COLOR_BUFFER_BIT,
- GL_NEAREST);
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, temp->handle());
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
-
- glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
- tx0, ty0, tx1, ty1,
- GL_COLOR_BUFFER_BIT,
- GL_NEAREST);
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
-
- qgl_fbo_pool()->release(temp);
- }
-
- ctx->d_ptr->current_fbo = 0;
- }
-#if !defined(QT_OPENGL_ES_2)
- else {
- GLuint texture;
- if (d_ptr->fbo) {
- texture = d_ptr->fbo->texture();
- } else {
- d_ptr->pb->makeCurrent();
- glBindTexture(target, d_ptr->pb_tex_id);
- const uint bottom = window()->height() - (br.y() + br.height());
- glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height());
- texture = d_ptr->pb_tex_id;
- glBindTexture(target, 0);
- }
-
- glDisable(GL_DEPTH_TEST);
-
- if (d_ptr->fbo) {
- d_ptr->fbo->release();
- } else {
- ctx->makeCurrent();
- }
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
-#ifndef QT_OPENGL_ES
- glOrtho(0, size.width(), size.height(), 0, -999999, 999999);
-#else
- glOrthof(0, size.width(), size.height(), 0, -999999, 999999);
-#endif
- glViewport(0, 0, size.width(), size.height());
-
- glColor4f(1, 1, 1, 1);
- drawTexture(rect, texture, window()->size(), br);
-
- if (d_ptr->fbo)
- d_ptr->fbo->bind();
- }
-#else
- // OpenGL/ES 2.0 version of the fbo blit.
- else if (d_ptr->fbo) {
- Q_UNUSED(target);
-
- if (d_ptr->fbo->isBound())
- d_ptr->fbo->release();
-
- blitTexture(ctx, d_ptr->fbo->texture(), size, window()->size(), rect, br);
- }
-#endif
-
- if (ctx->format().doubleBuffer())
- ctx->swapBuffers();
- else
- glFlush();
-#endif
- d_ptr->did_paint = false;
-}
-
-
-#if !defined(Q_WS_QPA)
-void QGLWindowSurface::setGeometry(const QRect &rect)
-{
- QWindowSurface::setGeometry(rect);
- d_ptr->geometry_updated = true;
-}
-#else
-void QGLWindowSurface::resize(const QSize &size)
-{
- QWindowSurface::resize(size);
- d_ptr->geometry_updated = true;
-}
-#endif
-
-void QGLWindowSurface::updateGeometry() {
-#if 0
- if (!d_ptr->geometry_updated)
- return;
- d_ptr->geometry_updated = false;
-
- bool hijack(true);
- QWidgetPrivate *wd = window()->d_func();
- if (wd->extraData() && wd->extraData()->glContext) {
-#ifdef Q_OS_SYMBIAN // Symbian needs to recreate the context when native window size changes
- if (d_ptr->size != geometry().size()) {
- if (window() != qt_gl_share_widget())
- --(_qt_gl_share_widget()->widgetRefCount);
-
- delete wd->extraData()->glContext;
- wd->extraData()->glContext = 0;
- d_ptr->ctx = 0;
- }
- else
-#endif
- {
- hijack = false; // we already have gl context for widget
- }
- }
-
- if (hijack)
- hijackWindow(window());
-
- QGLContext *ctx = reinterpret_cast<QGLContext *>(wd->extraData()->glContext);
-
-#ifdef Q_WS_MAC
- ctx->updatePaintDevice();
-#endif
-
- QSize surfSize = geometry().size();
-
- if (surfSize.width() <= 0 || surfSize.height() <= 0)
- return;
-
- if (d_ptr->size == surfSize)
- return;
-
- d_ptr->size = surfSize;
-
- if (d_ptr->ctx) {
-#ifndef QT_OPENGL_ES_2
- if (d_ptr->destructive_swap_buffers)
- initializeOffscreenTexture(surfSize);
-#endif
- return;
- }
-
- const GLenum target = GL_TEXTURE_2D;
- if (d_ptr->destructive_swap_buffers
- && (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject)
- && (d_ptr->fbo || !d_ptr->tried_fbo)
- && qt_gl_preferGL2Engine())
- {
- d_ptr->tried_fbo = true;
- ctx->d_ptr->internal_context = true;
- ctx->makeCurrent();
- delete d_ptr->fbo;
-
- QGLFramebufferObjectFormat format;
- format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
- format.setInternalTextureFormat(GLenum(GL_RGBA));
- format.setTextureTarget(target);
-
- if (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit)
- format.setSamples(8);
-
- d_ptr->fbo = new QGLFramebufferObject(surfSize, format);
-
- if (d_ptr->fbo->isValid()) {
- qDebug() << "Created Window Surface FBO" << surfSize
- << "with samples" << d_ptr->fbo->format().samples();
- return;
- } else {
- qDebug() << "QGLWindowSurface: Failed to create valid FBO, falling back";
- delete d_ptr->fbo;
- d_ptr->fbo = 0;
- }
- }
-
-#if !defined(QT_OPENGL_ES_2) && !defined(Q_WS_QPA) //QPA doesn't support pixelbuffers
- if (d_ptr->destructive_swap_buffers && (d_ptr->pb || !d_ptr->tried_pb)) {
- d_ptr->tried_pb = true;
-
- if (d_ptr->pb) {
- d_ptr->pb->makeCurrent();
- glDeleteTextures(1, &d_ptr->pb_tex_id);
- }
-
- delete d_ptr->pb;
-
- d_ptr->pb = new QGLPixelBuffer(surfSize.width(), surfSize.height(),
- QGLFormat(QGL::SampleBuffers | QGL::StencilBuffer | QGL::DepthBuffer),
- qt_gl_share_widget());
-
- if (d_ptr->pb->isValid()) {
- qDebug() << "Created Window Surface Pixelbuffer, Sample buffers:" << d_ptr->pb->format().sampleBuffers();
- d_ptr->pb->makeCurrent();
-
- glGenTextures(1, &d_ptr->pb_tex_id);
- glBindTexture(target, d_ptr->pb_tex_id);
- glTexImage2D(target, 0, GL_RGBA, surfSize.width(), surfSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
-
- glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glBindTexture(target, 0);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0, d_ptr->pb->width(), d_ptr->pb->height(), 0, -999999, 999999);
-
- d_ptr->pb->d_ptr->qctx->d_func()->internal_context = true;
- return;
- } else {
- qDebug() << "QGLWindowSurface: Failed to create valid pixelbuffer, falling back";
- delete d_ptr->pb;
- d_ptr->pb = 0;
- }
- }
-#endif // !defined(QT_OPENGL_ES_2) !defined(Q_WS_QPA)
-
- ctx->makeCurrent();
-
-#ifndef QT_OPENGL_ES_2
- if (d_ptr->destructive_swap_buffers)
- initializeOffscreenTexture(surfSize);
-#endif
-#ifndef Q_OS_SYMBIAN
- qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this;
-#endif
- d_ptr->ctx = ctx;
- d_ptr->ctx->d_ptr->internal_context = true;
-#endif
-}
-
-bool QGLWindowSurface::initializeOffscreenTexture(const QSize &size)
-{
- if (size == d_ptr->textureSize)
- return false;
-
- glGenTextures(1, &d_ptr->tex_id);
- glBindTexture(GL_TEXTURE_2D, d_ptr->tex_id);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
-
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glBindTexture(GL_TEXTURE_2D, 0);
-
- d_ptr->textureSize = size;
- return true;
-}
-
-bool QGLWindowSurface::scroll(const QRegion &area, int dx, int dy)
-{
-#if 0
- // this code randomly fails currently for unknown reasons
- return false;
-
- if (!d_ptr->pb)
- return false;
-
- d_ptr->pb->makeCurrent();
-
- QRect br = area.boundingRect();
-
-#if 0
- // ## workaround driver issue (scrolling by these deltas is unbearably slow for some reason)
- // ## maybe we should use glCopyTexSubImage insteadk
- if (dx == 1 || dx == -1 || dy == 1 || dy == -1 || dy == 2)
- return false;
-
- glRasterPos2i(br.x() + dx, br.y() + br.height() + dy);
- glCopyPixels(br.x(), d_ptr->pb->height() - (br.y() + br.height()), br.width(), br.height(), GL_COLOR);
- return true;
-#endif
-
- const GLenum target = GL_TEXTURE_2D;
-
- glBindTexture(target, d_ptr->tex_id);
- glCopyTexImage2D(target, 0, GL_RGBA, br.x(), d_ptr->pb->height() - (br.y() + br.height()), br.width(), br.height(), 0);
- glBindTexture(target, 0);
-
- drawTexture(br.translated(dx, dy), d_ptr->tex_id, window()->size());
-#endif
- return true;
-}
-
-static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &br)
-{
- const GLenum target = GL_TEXTURE_2D;
- QRectF src = br.isEmpty()
- ? QRectF(QPointF(), texSize)
- : QRectF(QPointF(br.x(), texSize.height() - br.bottom()), br.size());
-
- if (target == GL_TEXTURE_2D) {
- qreal width = texSize.width();
- qreal height = texSize.height();
-
- src.setLeft(src.left() / width);
- src.setRight(src.right() / width);
- src.setTop(src.top() / height);
- src.setBottom(src.bottom() / height);
- }
-
- const GLfloat tx1 = src.left();
- const GLfloat tx2 = src.right();
- const GLfloat ty1 = src.top();
- const GLfloat ty2 = src.bottom();
-
- GLfloat texCoordArray[4*2] = {
- tx1, ty2, tx2, ty2, tx2, ty1, tx1, ty1
- };
-
- GLfloat vertexArray[4*2];
- extern void qt_add_rect_to_array(const QRectF &r, GLfloat *array); // qpaintengine_opengl.cpp
- qt_add_rect_to_array(rect, vertexArray);
-
-#if !defined(QT_OPENGL_ES_2)
- glVertexPointer(2, GL_FLOAT, 0, vertexArray);
- glTexCoordPointer(2, GL_FLOAT, 0, texCoordArray);
-
- glBindTexture(target, tex_id);
- glEnable(target);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
- glDisable(target);
- glBindTexture(target, 0);
-#else
- glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray);
- glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, texCoordArray);
-
- glBindTexture(target, tex_id);
-
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
-
- glBindTexture(target, 0);
-#endif
-}
-
-QWindowSurface::WindowSurfaceFeatures QGLWindowSurface::features() const
-{
- WindowSurfaceFeatures features = 0;
- if (!d_ptr->destructive_swap_buffers || d_ptr->swap_region_support)
- features |= PartialUpdates;
- if (!d_ptr->destructive_swap_buffers)
- features |= PreservedContents;
- return features;
-}
-
-QT_END_NAMESPACE
-