diff options
author | Gunnar Sletta <gunnar@trolltech.com> | 2009-04-17 07:25:44 (GMT) |
---|---|---|
committer | Gunnar Sletta <gunnar@trolltech.com> | 2009-04-17 07:25:44 (GMT) |
commit | 537c26b2125994b42a5d00540ca4644582111573 (patch) | |
tree | 4e45938e156da093b45a161051888885f511b4d6 | |
parent | 58f8796ae4d9dcb9e741d2a07c87e6b82a2a4d9b (diff) | |
parent | a241ebac49f01ba0e26a177f1aadbd18c7e9cae7 (diff) | |
download | Qt-537c26b2125994b42a5d00540ca4644582111573.zip Qt-537c26b2125994b42a5d00540ca4644582111573.tar.gz Qt-537c26b2125994b42a5d00540ca4644582111573.tar.bz2 |
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt-graphics-team
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 68 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h | 1 | ||||
-rw-r--r-- | src/opengl/qgl.cpp | 56 | ||||
-rw-r--r-- | src/opengl/qgl.h | 2 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 8 | ||||
-rw-r--r-- | src/opengl/qglframebufferobject.cpp | 28 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_gl.cpp | 236 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_gl_p.h | 19 | ||||
-rw-r--r-- | src/opengl/qwindowsurface_gl.cpp | 96 |
9 files changed, 363 insertions, 151 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 89ed1f7..fe70020 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 9f84a25..10e5337 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 02cf641..64048f2 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 32fbce2..19d779a 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 0cb6dc2..f7b9392 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 270f415..b210285 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 ec71fa6..0656880 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 97f4959..b1b31f7 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 23bb3b9..e4c38fa 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); |