summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Rødal <sroedal@trolltech.com>2009-04-16 10:55:12 +0200
committerSamuel Rødal <sroedal@trolltech.com>2009-04-16 17:28:26 +0200
commita241ebac49f01ba0e26a177f1aadbd18c7e9cae7 (patch)
treec7e577ecf60c990a1a5a1902ba0637bd3187a4d6
parent1e1371e19ae62a5bf57dcad8d53ac70dcd2ad0cb (diff)
downloadqt4-tools-a241ebac49f01ba0e26a177f1aadbd18c7e9cae7.tar.gz
Use FBOs as pixmap backend in GL graphics system.
We now use FBOs to implement render-to-pixmap for the GL pixmap backend. A multisample FBO is used for rendering, and is then blitted onto a non-multisample FBO dynamically bound to the relevant texture. Reviewed-by: Tom
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp38
-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.cpp16
-rw-r--r--src/opengl/qpixmapdata_gl.cpp236
-rw-r--r--src/opengl/qpixmapdata_gl_p.h19
-rw-r--r--src/opengl/qwindowsurface_gl.cpp34
8 files changed, 311 insertions, 98 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index e166b54f85..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;
}
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index fc11d90921..32531e72e3 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
@@ -4235,6 +4253,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)
@@ -4261,7 +4288,9 @@ void QGLDrawable::swapBuffers()
void QGLDrawable::makeCurrent()
{
- if (widget)
+ if (pixmapData)
+ pixmapData->beginPaint();
+ else if (widget)
widget->makeCurrent();
else if (buffer)
buffer->makeCurrent();
@@ -4274,9 +4303,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();
}
@@ -4285,6 +4323,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 8ab73d88c8..51c07b5b7f 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
@@ -238,6 +239,7 @@ public:
QGLFormat glFormat;
QGLFormat reqFormat;
GLuint pbo;
+ GLuint fbo;
uint valid : 1;
uint sharing : 1;
@@ -255,6 +257,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; }
@@ -289,7 +292,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();
@@ -303,6 +306,8 @@ public:
QGLContext *context() const;
bool autoFillBackground() const;
+ QGLPixmapData *copyOnBegin() const;
+
private:
bool wasBound;
QGLWidget *widget;
@@ -313,6 +318,7 @@ private:
#else
QGLWindowSurface *wsurf;
#endif
+ QGLPixmapData *pixmapData;
};
// GL extension definitions
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index 61d0f853f6..f86205a025 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -475,7 +475,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);
@@ -825,18 +825,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;
}
/*!
@@ -1148,8 +1147,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 c9d23d152e..e0078bb97f 100644
--- a/src/opengl/qwindowsurface_gl.cpp
+++ b/src/opengl/qwindowsurface_gl.cpp
@@ -100,8 +100,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;
@@ -433,19 +433,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();