summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar@trolltech.com>2009-04-17 09:25:44 +0200
committerGunnar Sletta <gunnar@trolltech.com>2009-04-17 09:25:44 +0200
commit537c26b2125994b42a5d00540ca4644582111573 (patch)
tree4e45938e156da093b45a161051888885f511b4d6
parent58f8796ae4d9dcb9e741d2a07c87e6b82a2a4d9b (diff)
parenta241ebac49f01ba0e26a177f1aadbd18c7e9cae7 (diff)
downloadqt4-tools-537c26b2125994b42a5d00540ca4644582111573.tar.gz
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt-graphics-team
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp68
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h1
-rw-r--r--src/opengl/qgl.cpp56
-rw-r--r--src/opengl/qgl.h2
-rw-r--r--src/opengl/qgl_p.h8
-rw-r--r--src/opengl/qglframebufferobject.cpp28
-rw-r--r--src/opengl/qpixmapdata_gl.cpp236
-rw-r--r--src/opengl/qpixmapdata_gl_p.h19
-rw-r--r--src/opengl/qwindowsurface_gl.cpp96
9 files changed, 363 insertions, 151 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 89ed1f7d58..fe70020f03 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -175,6 +175,8 @@ public:
// Clipping & state stuff stolen from QOpenGLPaintEngine:
void updateDepthClip();
uint use_system_clip : 1;
+
+ QPaintEngine *last_engine;
};
@@ -616,7 +618,6 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
-
// Check to see if there's any hints
if (path.shape() == QVectorPath::RectangleHint) {
QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y());
@@ -1034,6 +1035,14 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
qt_resolve_version_1_3_functions(d->ctx);
qt_resolve_glsl_extensions(d->ctx);
+ d->last_engine = d->ctx->d_ptr->active_engine;
+ d->ctx->d_ptr->active_engine = this;
+
+ if (d->last_engine) {
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(d->last_engine);
+ static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr)->transferMode(DefaultMode);
+ }
+
if (!d->shaderManager)
d->shaderManager = new QGLPEXShaderManager(d->ctx);
@@ -1054,6 +1063,19 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
d->use_system_clip = !systemClip().isEmpty();
glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+
+ QGLPixmapData *source = d->drawable.copyOnBegin();
+ if (source) {
+ d->transferMode(ImageDrawingMode);
+
+ source->bind();
+
+ glDisable(GL_BLEND);
+
+ QRect rect(0, 0, source->width(), source->height());
+ d->drawTexture(QRectF(rect), QRectF(rect), rect.size());
+ }
updateClipRegion(QRegion(), Qt::NoClip);
return true;
@@ -1067,6 +1089,20 @@ bool QGL2PaintEngineEx::end()
d->transferMode(DefaultMode);
d->drawable.swapBuffers();
d->drawable.doneCurrent();
+ d->ctx->d_ptr->active_engine = d->last_engine;
+
+ if (d->last_engine) {
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(d->last_engine);
+ QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr);
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+
+ glViewport(0, 0, p->width, p->height);
+ engine->setState(engine->state());
+ p->updateDepthClip();
+ }
+
return false;
}
@@ -1200,11 +1236,6 @@ void QGL2PaintEngineEx::updateClipRegion(const QRegion &clipRegion, Qt::ClipOper
state()->hasClipping = op != Qt::NoClip || d->use_system_clip;
}
- if (state()->hasClipping && state()->clipRegion.rects().size() == 1)
- state()->fastClip = state()->clipRegion.rects().at(0);
- else
- state()->fastClip = QRect();
-
d->updateDepthClip();
}
@@ -1221,14 +1252,10 @@ void QGL2PaintEngineExPrivate::updateDepthClip()
if (!q->state()->hasClipping)
return;
- QRect fastClip;
- if (q->state()->clipEnabled) {
- fastClip = q->state()->fastClip;
- } else if (use_system_clip && q->systemClip().rects().count() == 1) {
- fastClip = q->systemClip().rects().at(0);
- }
+ const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects();
+ if (rects.size() == 1) {
+ QRect fastClip = rects.at(0);
- if (!fastClip.isEmpty()) {
glEnable(GL_SCISSOR_TEST);
const int left = fastClip.left();
@@ -1245,7 +1272,6 @@ void QGL2PaintEngineExPrivate::updateDepthClip()
glClear(GL_DEPTH_BUFFER_BIT);
glClearDepthf(0x1);
- const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects();
glEnable(GL_SCISSOR_TEST);
for (int i = 0; i < rects.size(); ++i) {
QRect rect = rects.at(i);
@@ -1268,14 +1294,23 @@ void QGL2PaintEngineExPrivate::updateDepthClip()
-void QGL2PaintEngineEx::setState(QPainterState *s)
+void QGL2PaintEngineEx::setState(QPainterState *new_state)
{
// qDebug("QGL2PaintEngineEx::setState()");
Q_D(QGL2PaintEngineEx);
+
+ QOpenGLPaintEngineState *s = static_cast<QOpenGLPaintEngineState *>(new_state);
+
+ QOpenGLPaintEngineState *old_state = state();
+ const bool needsDepthClipUpdate = !old_state
+ || s->clipEnabled != old_state->clipEnabled
+ || s->clipEnabled && s->clipRegion != old_state->clipRegion;
+
QPaintEngineEx::setState(s);
- d->updateDepthClip();
+ if (needsDepthClipUpdate)
+ d->updateDepthClip();
d->matrixDirty = true;
d->compositionModeDirty = true;
@@ -1303,7 +1338,6 @@ QOpenGLPaintEngineState::QOpenGLPaintEngineState(QOpenGLPaintEngineState &other)
{
clipRegion = other.clipRegion;
hasClipping = other.hasClipping;
- fastClip = other.fastClip;
}
QOpenGLPaintEngineState::QOpenGLPaintEngineState()
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 9f84a25e62..10e5337439 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -67,7 +67,6 @@ public:
QRegion clipRegion;
bool hasClipping;
- QRect fastClip;
};
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 02cf641d3b..64048f29e2 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -1295,6 +1295,7 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
eglContext = 0;
#endif
pbo = 0;
+ fbo = 0;
crWin = false;
initDone = false;
sharing = false;
@@ -1303,6 +1304,7 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
version_flags_cached = false;
version_flags = QGLFormat::OpenGL_Version_None;
current_fbo = 0;
+ active_engine = 0;
}
QGLContext* QGLContext::currentCtx = 0;
@@ -1313,12 +1315,8 @@ QGLContext* QGLContext::currentCtx = 0;
QGLFramebufferObject::toImage()
*/
-QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)
+static void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, bool include_alpha)
{
- QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32);
- int w = size.width();
- int h = size.height();
- glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
// OpenGL gives RGBA; Qt wants ARGB
uint *p = (uint*)img.bits();
@@ -1341,7 +1339,27 @@ QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include
// OpenGL gives ABGR (i.e. RGBA backwards); Qt wants ARGB
img = img.rgbSwapped();
}
- return img.mirrored();
+ img = img.mirrored();
+}
+
+QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)
+{
+ QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32);
+ int w = size.width();
+ int h = size.height();
+ glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
+ convertFromGLImage(img, w, h, alpha_format, include_alpha);
+ return img;
+}
+
+QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha)
+{
+ QImage img(size, alpha_format ? QImage::Format_ARGB32 : QImage::Format_RGB32);
+ int w = size.width();
+ int h = size.height();
+ glGetTexImage(qt_gl_preferredTextureTarget(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
+ convertFromGLImage(img, w, h, alpha_format, include_alpha);
+ return img;
}
// returns the highest number closest to v, which is a power of 2
@@ -4243,6 +4261,15 @@ void QGLDrawable::setDevice(QPaintDevice *pdev)
#ifdef Q_WS_QWS
wsurf = 0;
#endif
+
+ if (pdev->devType() == QInternal::Pixmap) {
+ QPixmapData *data = static_cast<QPixmap *>(pdev)->pixmapData();
+ Q_ASSERT(data->classId() == QPixmapData::OpenGLClass);
+ pixmapData = static_cast<QGLPixmapData *>(data);
+
+ fbo = pixmapData->fbo();
+ }
+
if (pdev->devType() == QInternal::Widget)
widget = static_cast<QGLWidget *>(pdev);
else if (pdev->devType() == QInternal::Pbuffer)
@@ -4269,7 +4296,9 @@ void QGLDrawable::swapBuffers()
void QGLDrawable::makeCurrent()
{
- if (widget)
+ if (pixmapData)
+ pixmapData->beginPaint();
+ else if (widget)
widget->makeCurrent();
else if (buffer)
buffer->makeCurrent();
@@ -4282,9 +4311,18 @@ void QGLDrawable::makeCurrent()
}
}
+QGLPixmapData *QGLDrawable::copyOnBegin() const
+{
+ if (!pixmapData || pixmapData->isUninitialized())
+ return 0;
+ return pixmapData;
+}
+
void QGLDrawable::doneCurrent()
{
- if (fbo && !wasBound)
+ if (pixmapData)
+ pixmapData->endPaint();
+ else if (fbo && !wasBound)
fbo->release();
}
@@ -4293,6 +4331,8 @@ QSize QGLDrawable::size() const
if (widget) {
return QSize(widget->d_func()->glcx->device()->width(),
widget->d_func()->glcx->device()->height());
+ } else if (pixmapData) {
+ return pixmapData->size();
} else if (buffer) {
return buffer->size();
} else if (fbo) {
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index 32fbce207b..19d779a53d 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -372,8 +372,8 @@ private:
friend QGLContextPrivate *qt_phonon_get_dptr(const QGLContext *);
#endif
friend class QGLFramebufferObject;
-#ifdef Q_WS_WIN
friend class QGLFramebufferObjectPrivate;
+#ifdef Q_WS_WIN
friend bool qt_resolve_GLSL_functions(QGLContext *ctx);
friend bool qt_createGLSLProgram(QGLContext *ctx, GLuint &program, const char *shader_src, GLuint &shader);
#endif
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index 0cb6dc2afd..f7b939281a 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -60,6 +60,7 @@
#include "QtCore/qthreadstorage.h"
#include "QtCore/qhash.h"
#include "private/qwidget_p.h"
+#include "private/qpixmapdata_gl_p.h"
#ifndef QT_OPENGL_ES_1_CL
#define q_vertexType float
@@ -239,6 +240,7 @@ public:
QGLFormat glFormat;
QGLFormat reqFormat;
GLuint pbo;
+ GLuint fbo;
uint valid : 1;
uint sharing : 1;
@@ -256,6 +258,7 @@ public:
GLint max_texture_size;
GLuint current_fbo;
+ QPaintEngine *active_engine;
#ifdef Q_WS_WIN
static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->extensionFuncs; }
@@ -290,7 +293,7 @@ class QGLWindowSurface;
class QGLDrawable {
public:
QGLDrawable() : widget(0), buffer(0), fbo(0)
- , wsurf(0)
+ , wsurf(0), pixmapData(0)
{}
void setDevice(QPaintDevice *pdev);
void swapBuffers();
@@ -304,6 +307,8 @@ public:
QGLContext *context() const;
bool autoFillBackground() const;
+ QGLPixmapData *copyOnBegin() const;
+
private:
bool wasBound;
QGLWidget *widget;
@@ -314,6 +319,7 @@ private:
#else
QGLWindowSurface *wsurf;
#endif
+ QGLPixmapData *pixmapData;
};
// GL extension definitions
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index 270f41562b..b210285a3c 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -479,7 +479,7 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
fbo_attachment = QGLFramebufferObject::NoAttachment;
}
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
if (!valid) {
if (color_buffer)
glDeleteRenderbuffersEXT(1, &color_buffer);
@@ -829,18 +829,17 @@ bool QGLFramebufferObject::release()
return false;
Q_D(QGLFramebufferObject);
QGL_FUNC_CONTEXT;
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- d->valid = d->checkFramebufferStatus();
d->bound = false;
+
const QGLContext *context = QGLContext::currentContext();
- if (d->valid && context) {
+ if (context) {
// Restore the previous setting for stacked framebuffer objects.
context->d_ptr->current_fbo = d->previous_fbo;
- if (d->previous_fbo)
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->previous_fbo);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->previous_fbo);
d->previous_fbo = 0;
}
- return d->valid;
+
+ return true;
}
/*!
@@ -1136,14 +1135,14 @@ void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const Q
const int th = target ? target->height() : height;
const int sx0 = sourceRect.left();
- const int sx1 = sourceRect.right();
- const int sy0 = sh - sourceRect.bottom() - 1;
- const int sy1 = sh - sourceRect.top() - 1;
+ const int sx1 = sourceRect.left() + sourceRect.width();
+ const int sy0 = sh - (sourceRect.top() + sourceRect.height());
+ const int sy1 = sh - sourceRect.top();
const int tx0 = targetRect.left();
- const int tx1 = targetRect.right();
- const int ty0 = th - targetRect.bottom() - 1;
- const int ty1 = th - targetRect.top() - 1;
+ const int tx1 = targetRect.left() + targetRect.width();
+ const int ty0 = th - (targetRect.top() + targetRect.height());
+ const int ty1 = th - targetRect.top();
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0);
@@ -1152,8 +1151,7 @@ void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const Q
tx0, ty0, tx1, ty1,
buffers, filter);
- glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
- glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
}
QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index ec71fa6908..0656880c95 100644
--- a/src/opengl/qpixmapdata_gl.cpp
+++ b/src/opengl/qpixmapdata_gl.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qpixmap.h"
+#include "qglframebufferobject.h"
#include <private/qpaintengine_raster_p.h>
@@ -48,6 +49,12 @@
#include <private/qgl_p.h>
#include <private/qdrawhelper_p.h>
+#if 1 || defined(QT_OPENGL_ES_2)
+#include <private/qpaintengineex_opengl2_p.h>
+#else
+#include <private/qpaintengine_opengl_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
extern QGLWidget* qt_gl_share_widget();
@@ -89,48 +96,16 @@ private:
QGLContext *m_ctx;
};
-void qt_gl_convertFromGLImage(QImage *img)
-{
- const int w = img->width();
- const int h = img->height();
-
- if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- uint *p = (uint*)img->bits();
- uint *end = p + w*h;
-
- while (p < end) {
- uint a = *p << 24;
- *p = (*p >> 8) | a;
- p++;
- }
-
- *img = img->mirrored();
- } else {
- // mirror image
- uint *data = (uint *)img->bits();
-
- const int mid = h/2;
-
- for (int y = 0; y < mid; ++y) {
- uint *p = data + y * w;
- uint *end = p + w;
- uint *q = data + (h - y - 1) * w;
-
- while (p < end)
- qSwap(*p++, *q++);
- }
- }
-}
-
-
static int qt_gl_pixmap_serial = 0;
QGLPixmapData::QGLPixmapData(PixelType type)
: QPixmapData(type, OpenGLClass)
, m_width(0)
, m_height(0)
+ , m_renderFbo(0)
+ , m_textureId(0)
+ , m_engine(0)
, m_ctx(0)
- , m_texture(0)
, m_dirty(false)
{
setSerialNumber(++qt_gl_pixmap_serial);
@@ -138,10 +113,11 @@ QGLPixmapData::QGLPixmapData(PixelType type)
QGLPixmapData::~QGLPixmapData()
{
- if (m_texture && qt_gl_share_widget()) {
- QGLShareContextScope ctx(qt_gl_share_widget()->context());
- glDeleteTextures(1, &m_texture);
- }
+ QGLWidget *shareWidget = qt_gl_share_widget();
+ if (!shareWidget)
+ return;
+ QGLShareContextScope ctx(shareWidget->context());
+ glDeleteTextures(1, &m_textureId);
}
bool QGLPixmapData::isValid() const
@@ -166,6 +142,12 @@ void QGLPixmapData::resize(int width, int height)
m_width = width;
m_height = height;
+ if (m_textureId) {
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ glDeleteTextures(1, &m_textureId);
+ m_textureId = 0;
+ }
+
m_source = QImage();
m_dirty = isValid();
setSerialNumber(++qt_gl_pixmap_serial);
@@ -184,24 +166,30 @@ void QGLPixmapData::ensureCreated() const
const GLenum format = qt_gl_preferredTextureFormat();
const GLenum target = qt_gl_preferredTextureTarget();
- if (!m_texture)
- glGenTextures(1, &m_texture);
-
- glBindTexture(target, m_texture);
+ if (!m_textureId) {
+ glGenTextures(1, &m_textureId);
+ glBindTexture(target, m_textureId);
+ glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ }
- if (m_source.isNull()) {
- glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format, GL_UNSIGNED_BYTE, 0);
- } else {
+ if (!m_source.isNull()) {
const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, format);
- glBindTexture(target, m_texture);
- glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format,
- GL_UNSIGNED_BYTE, tx.bits());
+ glBindTexture(target, m_textureId);
+ glTexSubImage2D(target, 0, 0, 0, m_width, m_height, format,
+ GL_UNSIGNED_BYTE, tx.bits());
- m_source = QImage();
+ if (useFramebufferObjects())
+ m_source = QImage();
}
}
+QGLFramebufferObject *QGLPixmapData::fbo() const
+{
+ return m_renderFbo;
+}
+
void QGLPixmapData::fromImage(const QImage &image,
Qt::ImageConversionFlags)
{
@@ -220,6 +208,17 @@ bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect)
return false;
}
+void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect)
+{
+ if (data->classId() != QPixmapData::OpenGLClass) {
+ QPixmapData::copy(data, rect);
+ return;
+ }
+
+ // can be optimized to do a framebuffer blit or similar ...
+ QPixmapData::copy(data, rect);
+}
+
void QGLPixmapData::fill(const QColor &color)
{
if (!isValid())
@@ -246,7 +245,9 @@ QImage QGLPixmapData::toImage() const
if (!isValid())
return QImage();
- if (!m_source.isNull())
+ if (m_renderFbo)
+ return m_renderFbo->toImage().copy(0, m_renderFbo->height() - m_height, m_width, m_height);
+ else if (!m_source.isNull())
return m_source;
else if (m_dirty)
return QImage(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
@@ -254,21 +255,84 @@ QImage QGLPixmapData::toImage() const
ensureCreated();
QGLShareContextScope ctx(qt_gl_share_widget()->context());
- QImage img(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
+ extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha);
+ glBindTexture(qt_gl_preferredTextureTarget(), m_textureId);
+ return qt_gl_read_texture(QSize(m_width, m_height), true, true);
+}
- GLenum format = qt_gl_preferredTextureFormat();
- GLenum target = qt_gl_preferredTextureTarget();
+struct TextureBuffer
+{
+ QGLFramebufferObject *fbo;
+ QGL2PaintEngineEx *engine;
+};
- glBindTexture(target, m_texture);
-#ifndef QT_OPENGL_ES
- glGetTexImage(target, 0, format, GL_UNSIGNED_BYTE, img.bits());
-#else
- // XXX - cannot download textures this way on OpenGL/ES.
-#endif
+static QVector<TextureBuffer> textureBufferStack;
+static int currentTextureBuffer = 0;
- qt_gl_convertFromGLImage(&img);
+void QGLPixmapData::beginPaint()
+{
+ if (!isValid())
+ return;
- return img;
+ m_renderFbo->bind();
+}
+
+void QGLPixmapData::endPaint()
+{
+ if (!isValid())
+ return;
+
+ const QGLContext *share_ctx = qt_gl_share_widget()->context();
+ QGLShareContextScope ctx(share_ctx);
+
+ ensureCreated();
+
+ if (!ctx->d_ptr->fbo)
+ glGenFramebuffersEXT(1, &ctx->d_ptr->fbo);
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ qt_gl_preferredTextureTarget(), m_textureId, 0);
+
+ const int x0 = 0;
+ const int x1 = m_width;
+ const int y0 = 0;
+ const int y1 = m_height;
+
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle());
+
+ glDisable(GL_SCISSOR_TEST);
+
+ glBlitFramebufferEXT(x0, y0, x1, y1,
+ x0, y0, x1, y1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ m_renderFbo->release();
+
+ --currentTextureBuffer;
+
+ m_renderFbo = 0;
+ m_engine = 0;
+}
+
+static TextureBuffer createTextureBuffer(const QSize &size, QGL2PaintEngineEx *engine = 0)
+{
+ TextureBuffer buffer;
+ QGLFramebufferObjectFormat fmt;
+ fmt.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ fmt.setSamples(4);
+
+ buffer.fbo = new QGLFramebufferObject(size, fmt);
+ buffer.engine = engine ? engine : new QGL2PaintEngineEx;
+
+ return buffer;
+}
+
+bool QGLPixmapData::useFramebufferObjects()
+{
+ return QGLFramebufferObject::hasOpenGLFramebufferObjects()
+ && QGLFramebufferObject::hasOpenGLFramebufferBlit();
}
QPaintEngine* QGLPixmapData::paintEngine() const
@@ -276,23 +340,59 @@ QPaintEngine* QGLPixmapData::paintEngine() const
if (!isValid())
return 0;
- m_source = toImage();
- m_dirty = true;
+ if (m_engine)
+ return m_engine;
+ else if (!useFramebufferObjects()) {
+ m_dirty = true;
+
+ if (m_source.size() != size())
+ m_source = QImage(size(), QImage::Format_ARGB32_Premultiplied);
+ return m_source.paintEngine();
+ }
- return m_source.paintEngine();
+ extern QGLWidget* qt_gl_share_widget();
+
+ if (!QGLContext::currentContext())
+ qt_gl_share_widget()->makeCurrent();
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+
+ if (textureBufferStack.size() <= currentTextureBuffer) {
+ textureBufferStack << createTextureBuffer(size());
+ } else {
+ QSize sz = textureBufferStack.at(currentTextureBuffer).fbo->size();
+ if (sz.width() < m_width || sz.height() < m_height) {
+ if (sz.width() < m_width)
+ sz.setWidth(qMax(m_width, qRound(sz.width() * 1.5)));
+ if (sz.height() < m_height)
+ sz.setHeight(qMax(m_height, qRound(sz.height() * 1.5)));
+ delete textureBufferStack.at(currentTextureBuffer).fbo;
+ textureBufferStack[currentTextureBuffer] =
+ createTextureBuffer(sz, textureBufferStack.at(currentTextureBuffer).engine);
+ qDebug() << "Creating new pixmap texture buffer:" << sz;
+ }
+ }
+
+ m_renderFbo = textureBufferStack.at(currentTextureBuffer).fbo;
+ m_engine = textureBufferStack.at(currentTextureBuffer).engine;
+
+ ++currentTextureBuffer;
+
+ return m_engine;
}
GLuint QGLPixmapData::bind() const
{
ensureCreated();
- glBindTexture(qt_gl_preferredTextureTarget(), m_texture);
- return m_texture;
+
+ GLuint id = m_textureId;
+ glBindTexture(qt_gl_preferredTextureTarget(), id);
+ return id;
}
GLuint QGLPixmapData::textureId() const
{
ensureCreated();
- return m_texture;
+ return m_textureId;
}
extern int qt_defaultDpiX();
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index 97f4959eac..b1b31f7029 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -60,6 +60,7 @@
QT_BEGIN_NAMESPACE
class QPaintEngine;
+class QGLFramebufferObject;
class QGLPixmapData : public QPixmapData
{
@@ -72,6 +73,7 @@ public:
void resize(int width, int height);
void fromImage(const QImage &image,
Qt::ImageConversionFlags flags);
+ void copy(const QPixmapData *data, const QRect &rect);
bool scroll(int dx, int dy, const QRect &rect);
@@ -87,6 +89,17 @@ public:
void ensureCreated() const;
+ bool isUninitialized() const { return m_dirty && m_source.isNull(); }
+
+ QSize size() const { return QSize(m_width, m_height); }
+ int width() const { return m_width; }
+ int height() const { return m_height; }
+
+ QGLFramebufferObject *fbo() const;
+
+ void beginPaint();
+ void endPaint();
+
protected:
int metric(QPaintDevice::PaintDeviceMetric metric) const;
@@ -94,11 +107,15 @@ private:
QGLPixmapData(const QGLPixmapData &other);
QGLPixmapData &operator=(const QGLPixmapData &other);
+ static bool useFramebufferObjects();
+
int m_width;
int m_height;
+ mutable QGLFramebufferObject *m_renderFbo;
+ mutable uint m_textureId;
+ mutable QPaintEngine *m_engine;
mutable QGLContext *m_ctx;
- mutable GLuint m_texture;
mutable bool m_dirty;
mutable QImage m_source;
};
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp
index 23bb3b964f..e4c38fa2f3 100644
--- a/src/opengl/qwindowsurface_gl.cpp
+++ b/src/opengl/qwindowsurface_gl.cpp
@@ -104,8 +104,8 @@ QGLGraphicsSystem::QGLGraphicsSystem()
int i = 0;
int spec[16];
spec[i++] = GLX_RGBA;
-#if 0
spec[i++] = GLX_DOUBLEBUFFER;
+#if 0
spec[i++] = GLX_DEPTH_SIZE;
spec[i++] = 8;
spec[i++] = GLX_STENCIL_SIZE;
@@ -191,9 +191,10 @@ public:
}
void cleanup() {
- delete widget;
- widget = 0;
+ QGLWidget *w = widget;
cleanedUp = true;
+ widget = 0;
+ delete w;
}
static bool cleanedUp;
@@ -436,19 +437,35 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &
size = parent->size();
}
- ctx->makeCurrent();
-#ifdef Q_WS_MAC
- ctx->updatePaintDevice();
-#endif
- glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
if (d_ptr->fbo && QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit) {
- QGLFramebufferObject::blitFramebuffer(0, rect, d_ptr->fbo, rect);
- d_ptr->fbo->bind();
+ const int h = d_ptr->fbo->height();
+
+ const int x0 = rect.left();
+ const int x1 = rect.left() + rect.width();
+ const int y0 = h - (rect.top() + rect.height());
+ const int y1 = h - rect.top();
+
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+
+ glBlitFramebufferEXT(x0, y0, x1, y1,
+ x0, y0, x1, y1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
} else {
- if (d_ptr->fbo)
+ glDisable(GL_DEPTH_TEST);
+
+ if (d_ptr->fbo) {
d_ptr->fbo->release();
+ } else {
+ ctx->makeCurrent();
+#ifdef Q_WS_MAC
+ ctx->updatePaintDevice();
+#endif
+ }
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
@@ -496,6 +513,35 @@ void QGLWindowSurface::updateGeometry()
return;
}
+ if ((QGLExtensions::glExtensions & QGLExtensions::FramebufferObject) && (d_ptr->fbo || !d_ptr->tried_fbo)) {
+ d_ptr->tried_fbo = true;
+ hijackWindow(window());
+ QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
+ ctx->d_ptr->internal_context = true;
+ ctx->makeCurrent();
+ delete d_ptr->fbo;
+
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setInternalFormat(GL_RGBA);
+ format.setTextureTarget(target);
+
+ if (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)
+ format.setSamples(8);
+
+ d_ptr->fbo = new QGLFramebufferObject(rect.size(), format);
+ d_ptr->fbo->bind();
+ if (d_ptr->fbo->isValid()) {
+ qDebug() << "Created Window Surface FBO" << rect.size()
+ << "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 (d_ptr->pb || !d_ptr->tried_pb) {
d_ptr->tried_pb = true;
@@ -539,34 +585,6 @@ void QGLWindowSurface::updateGeometry()
}
}
- if ((QGLExtensions::glExtensions & QGLExtensions::FramebufferObject) && (d_ptr->fbo || !d_ptr->tried_fbo)) {
- d_ptr->tried_fbo = true;
- hijackWindow(window());
- QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
- ctx->d_ptr->internal_context = true;
- ctx->makeCurrent();
- delete d_ptr->fbo;
-
- QGLFramebufferObjectFormat format;
- format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
- format.setInternalFormat(GL_RGBA);
- format.setTextureTarget(target);
-
- if (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)
- format.setSamples(8);
-
- d_ptr->fbo = new QGLFramebufferObject(rect.size(), format);
- d_ptr->fbo->bind();
- if (d_ptr->fbo->isValid()) {
- qDebug() << "Created Window Surface FBO" << rect.size()
- << "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;
- }
- }
hijackWindow(window());
QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);