From 2b6cf174153c6a680bac94eb666a131a3aad3891 Mon Sep 17 00:00:00 2001 From: Jani Hautakangas Date: Thu, 30 Jun 2011 14:28:39 +0300 Subject: Introduce QPixmap::fromSymbianRSgImage(RSgImage*) to GL engine Initial implementation of QPixmap::fromSymbianRSgImage(RSgImage*) on OpenGL graphics system. Task-number: QTBUG-15254 Reviewed-by: Laszlo Agocs --- mkspecs/common/symbian/symbian.conf | 3 + src/opengl/qgl.cpp | 1 + src/opengl/qgl_symbian.cpp | 109 +----- src/opengl/qpixmapdata_gl_p.h | 15 +- src/opengl/qpixmapdata_symbiangl.cpp | 627 ++++++++++++++++------------------- src/opengl/qwindowsurface_gl.cpp | 55 ++- 6 files changed, 339 insertions(+), 471 deletions(-) diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index 0288ada..e30347b 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -88,6 +88,9 @@ QMAKE_LIBS_S60 = -lavkon -leikcoctl -lgfxtrans exists($${EPOCROOT}epoc32/include/platform/sgresource/sgimage.h) { QMAKE_LIBS_OPENVG += -lsgresource + QMAKE_LIBS_OPENGL_QT += -lsgresource + QMAKE_LIBS_OPENGL_ES1_QT += -lsgresource + QMAKE_LIBS_OPENGL_ES2_QT += -lsgresource } contains(QMAKE_HOST.os,Windows) { diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 4fee886..161e099 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -5920,6 +5920,7 @@ void QGLTexture::freeTexture() } id = 0; + boundPixmap = 0; boundKey = 0; } #endif diff --git a/src/opengl/qgl_symbian.cpp b/src/opengl/qgl_symbian.cpp index 21671a6..b8e5c22 100644 --- a/src/opengl/qgl_symbian.cpp +++ b/src/opengl/qgl_symbian.cpp @@ -40,7 +40,6 @@ ****************************************************************************/ #include "qgl.h" -#include #include #include #include @@ -55,7 +54,7 @@ #include "qpixmapdata_gl_p.h" #include "qgltexturepool_p.h" #include "qcolormap.h" -#include + QT_BEGIN_NAMESPACE @@ -73,7 +72,7 @@ QT_BEGIN_NAMESPACE #endif #endif -extern int qt_gl_pixmap_serial; +Q_OPENGL_EXPORT extern QGLWidget* qt_gl_share_widget(); /* QGLTemporaryContext implementation @@ -266,6 +265,11 @@ void QGLWidget::resizeEvent(QResizeEvent *) if (!isValid()) return; + // Shared widget can ignore resize events which + // may happen due to orientation change + if (this == qt_gl_share_widget()) + return; + if (QGLContext::currentContext()) doneCurrent(); @@ -378,103 +382,4 @@ void QGLWidgetPrivate::recreateEglSurface() eglSurfaceWindowId = currentId; } -static inline bool knownGoodFormat(QImage::Format format) -{ - switch (format) { - case QImage::Format_RGB16: // EColor64K - case QImage::Format_RGB32: // EColor16MU - case QImage::Format_ARGB32_Premultiplied: // EColor16MAP - return true; - default: - return false; - } -} - -void QGLPixmapData::fromNativeType(void* pixmap, NativeType type) -{ - if (type == QPixmapData::FbsBitmap) { - CFbsBitmap *bitmap = reinterpret_cast(pixmap); - QSize size(bitmap->SizeInPixels().iWidth, bitmap->SizeInPixels().iHeight); - if (size.width() == w && size.height() == h) - setSerialNumber(++qt_gl_pixmap_serial); - resize(size.width(), size.height()); - m_source = QVolatileImage(bitmap); - if (pixelType() == BitmapType) { - m_source.ensureFormat(QImage::Format_MonoLSB); - } else if (!knownGoodFormat(m_source.format())) { - m_source.beginDataAccess(); - QImage::Format format = idealFormat(m_source.imageRef(), Qt::AutoColor); - m_source.endDataAccess(true); - m_source.ensureFormat(format); - } - m_hasAlpha = m_source.hasAlphaChannel(); - m_hasFillColor = false; - m_dirty = true; - - } else if (type == QPixmapData::VolatileImage && pixmap) { - // Support QS60Style in more efficient skin graphics retrieval. - QVolatileImage *img = static_cast(pixmap); - if (img->width() == w && img->height() == h) - setSerialNumber(++qt_gl_pixmap_serial); - resize(img->width(), img->height()); - m_source = *img; - m_hasAlpha = m_source.hasAlphaChannel(); - m_hasFillColor = false; - m_dirty = true; - } else if (type == QPixmapData::NativeImageHandleProvider && pixmap) { - destroyTexture(); - nativeImageHandleProvider = static_cast(pixmap); - // Cannot defer the retrieval, we need at least the size right away. - createFromNativeImageHandleProvider(); - } -} - -void* QGLPixmapData::toNativeType(NativeType type) -{ - if (type == QPixmapData::FbsBitmap) { - if (m_source.isNull()) - m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); - return m_source.duplicateNativeImage(); - } - return 0; -} - -bool QGLPixmapData::initFromNativeImageHandle(void *handle, const QString &type) -{ - if (type == QLatin1String("RSgImage")) { - fromNativeType(handle, QPixmapData::SgImage); - return true; - } else if (type == QLatin1String("CFbsBitmap")) { - fromNativeType(handle, QPixmapData::FbsBitmap); - return true; - } - return false; -} - -void QGLPixmapData::createFromNativeImageHandleProvider() -{ - void *handle = 0; - QString type; - nativeImageHandleProvider->get(&handle, &type); - if (handle) { - if (initFromNativeImageHandle(handle, type)) { - nativeImageHandle = handle; - nativeImageType = type; - } else { - qWarning("QGLPixmapData: Unknown native image type '%s'", qPrintable(type)); - } - } else { - qWarning("QGLPixmapData: Native handle is null"); - } -} - -void QGLPixmapData::releaseNativeImageHandle() -{ - if (nativeImageHandleProvider && nativeImageHandle) { - nativeImageHandleProvider->release(nativeImageHandle, nativeImageType); - nativeImageHandle = 0; - nativeImageType = QString(); - } -} - QT_END_NAMESPACE diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h index bf1a303..3d22ad1 100644 --- a/src/opengl/qpixmapdata_gl_p.h +++ b/src/opengl/qpixmapdata_gl_p.h @@ -61,6 +61,9 @@ #ifdef Q_OS_SYMBIAN #include "private/qvolatileimage_p.h" +#ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE +# include +#endif #endif QT_BEGIN_NAMESPACE @@ -72,8 +75,7 @@ class QGLPixmapData; #ifdef Q_OS_SYMBIAN class QNativeImageHandleProvider; -#endif - +#else class QGLFramebufferObjectPool { public: @@ -102,7 +104,7 @@ public: private: QGLPixmapData *data; }; - +#endif class Q_OPENGL_EXPORT QGLPixmapData : public QPixmapData { @@ -194,6 +196,9 @@ private: mutable QNativeImageHandleProvider *nativeImageHandleProvider; void *nativeImageHandle; QString nativeImageType; +#ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE + RSgImage *m_sgImage; +#endif #else mutable QImage m_source; #endif @@ -208,9 +213,9 @@ private: mutable bool m_hasFillColor; mutable bool m_hasAlpha; - +#ifndef Q_OS_SYMBIAN mutable QGLPixmapGLPaintDevice m_glDevice; - +#endif friend class QGLPixmapGLPaintDevice; friend class QMeeGoPixmapData; friend class QMeeGoLivePixmapData; diff --git a/src/opengl/qpixmapdata_symbiangl.cpp b/src/opengl/qpixmapdata_symbiangl.cpp index 8c3d61a..372b5ca 100644 --- a/src/opengl/qpixmapdata_symbiangl.cpp +++ b/src/opengl/qpixmapdata_symbiangl.cpp @@ -58,181 +58,61 @@ #include #include +#include + #include "qgltexturepool_p.h" QT_BEGIN_NAMESPACE Q_OPENGL_EXPORT extern QGLWidget* qt_gl_share_widget(); -static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo) -{ - return qAbs(size.width() * size.height() - fbo->width() * fbo->height()); -} - -extern int qt_next_power_of_two(int v); - -static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz) -{ -#ifdef QT_OPENGL_ES_2 - QSize rounded(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height())); - if (rounded.width() * rounded.height() < 1.20 * sz.width() * sz.height()) - return rounded; -#endif - return sz; -} - - -QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize) +class QGLSgImageTextureCleanup { - QGLFramebufferObject *chosen = 0; - QGLFramebufferObject *candidate = 0; - for (int i = 0; !chosen && i < m_fbos.size(); ++i) { - QGLFramebufferObject *fbo = m_fbos.at(i); +public: + QGLSgImageTextureCleanup() {} - if (strictSize) { - if (fbo->size() == requestSize && fbo->format() == requestFormat) { - chosen = fbo; - break; - } else { - continue; - } - } - - if (fbo->format() == requestFormat) { - // choose the fbo with a matching format and the closest size - if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo)) - candidate = fbo; - } - - if (candidate) { - m_fbos.removeOne(candidate); - - const QSize fboSize = candidate->size(); - QSize sz = fboSize; - - if (sz.width() < requestSize.width()) - sz.setWidth(qMax(requestSize.width(), qRound(sz.width() * 1.5))); - if (sz.height() < requestSize.height()) - sz.setHeight(qMax(requestSize.height(), qRound(sz.height() * 1.5))); - - // wasting too much space? - if (sz.width() * sz.height() > requestSize.width() * requestSize.height() * 4) - sz = requestSize; - - if (sz != fboSize) { - delete candidate; - candidate = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(sz), requestFormat); - } - - chosen = candidate; + ~QGLSgImageTextureCleanup() + { + QList keys = m_cache.keys(); + while(keys.size() > 0) { + QGLPixmapData *data = m_cache.take(keys.takeAt(0)); + if (data) + data->destroyTexture(); } } - if (!chosen) { - if (strictSize) - chosen = new QGLFramebufferObject(requestSize, requestFormat); - else - chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat); - } + static QGLSgImageTextureCleanup *cleanupForContext(const QGLContext *context); - if (!chosen->isValid()) { - delete chosen; - chosen = 0; + void insert(quint64 key, QGLPixmapData *data) + { + m_cache.insert(key, data); } - return chosen; -} - -void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo) -{ - if (fbo) - m_fbos << fbo; -} - - -QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const -{ - return data->paintEngine(); -} - -void QGLPixmapGLPaintDevice::beginPaint() -{ - if (!data->isValid()) - return; - - // QGLPaintDevice::beginPaint will store the current binding and replace - // it with m_thisFBO: - m_thisFBO = data->m_renderFbo->handle(); - QGLPaintDevice::beginPaint(); - - Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2); - - // QPixmap::fill() is deferred until now, where we actually need to do the fill: - if (data->needsFill()) { - const QColor &c = data->fillColor(); - float alpha = c.alphaF(); - glDisable(GL_SCISSOR_TEST); - glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); - glClear(GL_COLOR_BUFFER_BIT); + void remove(quint64 key) + { + m_cache.take(key); } - else if (!data->isUninitialized()) { - // If the pixmap (GL Texture) has valid content (it has been - // uploaded from an image or rendered into before), we need to - // copy it from the texture to the render FBO. - - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - -#if !defined(QT_OPENGL_ES_2) - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, data->width(), data->height(), 0, -999999, 999999); -#endif - - glViewport(0, 0, data->width(), data->height()); - - // Pass false to bind so it doesn't copy the FBO into the texture! - context()->drawTexture(QRect(0, 0, data->width(), data->height()), data->bind(false)); - } -} - -void QGLPixmapGLPaintDevice::endPaint() -{ - if (!data->isValid()) - return; - data->copyBackFromRenderFbo(false); +private: - // Base's endPaint will restore the previous FBO binding - QGLPaintDevice::endPaint(); - - qgl_fbo_pool()->release(data->m_renderFbo); - data->m_renderFbo = 0; -} + QCache m_cache; +}; -QGLContext* QGLPixmapGLPaintDevice::context() const +static void qt_sgimage_texture_cleanup_free(void *data) { - data->ensureCreated(); - return data->m_ctx; + delete reinterpret_cast(data); } -QSize QGLPixmapGLPaintDevice::size() const -{ - return data->size(); -} +Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_sgimage_texture_cleanup, (qt_sgimage_texture_cleanup_free)) -bool QGLPixmapGLPaintDevice::alphaRequested() const +QGLSgImageTextureCleanup *QGLSgImageTextureCleanup::cleanupForContext(const QGLContext *context) { - return data->m_hasAlpha; -} - -void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d) -{ - data = d; + QGLSgImageTextureCleanup *p = reinterpret_cast(qt_sgimage_texture_cleanup()->value(context)); + if (!p) { + QGLShareContextScope scope(context); + qt_sgimage_texture_cleanup()->insert(context, p = new QGLSgImageTextureCleanup); + } + return p; } int qt_gl_pixmap_serial = 0; @@ -244,16 +124,28 @@ QGLPixmapData::QGLPixmapData(PixelType type) , m_ctx(0) , nativeImageHandleProvider(0) , nativeImageHandle(0) +#ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE + , m_sgImage(0) +#endif , m_dirty(false) , m_hasFillColor(false) , m_hasAlpha(false) { setSerialNumber(++qt_gl_pixmap_serial); - m_glDevice.setPixmapData(this); } QGLPixmapData::~QGLPixmapData() { + if (m_sgImage) { + if (m_texture.id) { + QGLSgImageTextureCleanup::cleanupForContext(m_ctx)->remove(m_texture.id); + destroyTexture(); + } + + m_sgImage->Close(); + delete m_sgImage; + m_sgImage = 0; + } delete m_engine; } @@ -275,6 +167,16 @@ bool QGLPixmapData::isValidContext(const QGLContext *ctx) const // That's why if source pixels are valid we return false // to simulate raster pixmaps. Only QPixmaps created from // SgImage will enable usage of QGLPixmapData. +#ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE + if (m_sgImage) { + // SgImage texture + if (ctx == m_ctx) + return true; + + const QGLContext *share_ctx = qt_gl_share_widget()->context(); + return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx); + } +#endif return false; } @@ -313,72 +215,45 @@ void QGLPixmapData::ensureCreated() const QGLShareContextScope ctx(qt_gl_share_widget()->context()); m_ctx = ctx; - const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB; -#ifdef QT_OPENGL_ES_2 - const GLenum external_format = internal_format; -#else - const GLenum external_format = qt_gl_preferredTextureFormat(); -#endif - const GLenum target = GL_TEXTURE_2D; - - GLenum type = GL_UNSIGNED_BYTE; - // Avoid conversion when pixmap is created from CFbsBitmap of EColor64K. - if (!m_source.isNull() && m_source.format() == QImage::Format_RGB16) - type = GL_UNSIGNED_SHORT_5_6_5; - - if (!m_texture.id) { - m_texture.id = QGLTexturePool::instance()->createTexture( - target, - 0, internal_format, - w, h, - external_format, - type, - &m_texture); - if (!m_texture.id) { - m_texture.failedToAlloc = true; - return; - } - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +#ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE + if (m_sgImage) { + qt_resolve_eglimage_gl_extensions(ctx); // ensure initialized - m_texture.inTexturePool = true; - } else if (m_texture.inTexturePool) { - glBindTexture(target, m_texture.id); - QGLTexturePool::instance()->useTexture(&m_texture); - } + bool textureIsBound = false; + GLuint newTextureId; - if (!m_source.isNull() && m_texture.id) { - if (external_format == GL_RGB) { - m_source.beginDataAccess(); - QImage tx; - if (type == GL_UNSIGNED_BYTE) - tx = m_source.imageRef().convertToFormat(QImage::Format_RGB888).mirrored(false, true); - else if (type == GL_UNSIGNED_SHORT_5_6_5) - tx = m_source.imageRef().mirrored(false, true); - m_source.endDataAccess(true); + EGLint imgAttr[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; + EGLImageKHR image = QEgl::eglCreateImageKHR(QEgl::display() + , EGL_NO_CONTEXT + , EGL_NATIVE_PIXMAP_KHR + , (EGLClientBuffer)m_sgImage + , imgAttr); - glBindTexture(target, m_texture.id); - if (!tx.isNull()) - glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - type, tx.constBits()); - else - qWarning("QGLPixmapData: Failed to create GL_RGB image of size %dx%d", w, h); - } else { - // do byte swizzling ARGB -> RGBA - m_source.beginDataAccess(); - const QImage tx = ctx->d_func()->convertToGLFormat(m_source.imageRef(), true, external_format); - m_source.endDataAccess(true); - glBindTexture(target, m_texture.id); - if (!tx.isNull()) - glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - type, tx.constBits()); - else - qWarning("QGLPixmapData: Failed to create GL_RGBA image of size %dx%d", w, h); + glGenTextures(1, &newTextureId); + glBindTexture( GL_TEXTURE_2D, newTextureId); + + if (image != EGL_NO_IMAGE_KHR) { + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); + GLint err = glGetError(); + if (err == GL_NO_ERROR) + textureIsBound = true; + + QEgl::eglDestroyImageKHR(QEgl::display(), image); } - if (useFramebufferObjects()) - m_source = QVolatileImage(); + if (textureIsBound) { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + m_texture.id = newTextureId; + m_texture.boundPixmap = const_cast(this); + QGLSgImageTextureCleanup::cleanupForContext(m_ctx)->insert(m_texture.id, const_cast(this)); + } else { + qWarning("QGLPixmapData: Failed to create texture from a SgImage image of size %dx%d", w, h); + glDeleteTextures(1, &newTextureId); + } } +#endif } @@ -538,42 +413,7 @@ bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect) void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect) { - if (data->classId() != QPixmapData::OpenGLClass || !static_cast(data)->useFramebufferObjects()) { - QPixmapData::copy(data, rect); - return; - } - - const QGLPixmapData *other = static_cast(data); - if (other->m_renderFbo) { - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - - resize(rect.width(), rect.height()); - m_hasAlpha = other->m_hasAlpha; - ensureCreated(); - - if (!ctx->d_ptr->fbo) - glGenFramebuffers(1, &ctx->d_ptr->fbo); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_texture.id, 0); - - if (!other->m_renderFbo->isBound()) - glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, other->m_renderFbo->handle()); - - glDisable(GL_SCISSOR_TEST); - if (ctx->d_ptr->active_engine && ctx->d_ptr->active_engine->type() == QPaintEngine::OpenGL2) - static_cast(ctx->d_ptr->active_engine)->invalidateState(); - - glBlitFramebufferEXT(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height(), - 0, 0, w, h, - GL_COLOR_BUFFER_BIT, - GL_NEAREST); - - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); - } else { - QPixmapData::copy(data, rect); - } + QPixmapData::copy(data, rect); } void QGLPixmapData::fill(const QColor &color) @@ -590,11 +430,6 @@ void QGLPixmapData::fill(const QColor &color) m_hasAlpha = color.alpha() != 255; } - if (useFramebufferObjects()) { - m_source = QVolatileImage(); - m_hasFillColor = true; - m_fillColor = color; - } else { forceToImage(); if (m_source.depth() == 32) { @@ -605,7 +440,6 @@ void QGLPixmapData::fill(const QColor &color) m_source.fill(1); else m_source.fill(0); - } } } @@ -645,9 +479,7 @@ QImage QGLPixmapData::toImage() const if (!isValid()) return QImage(); - if (m_renderFbo) { - copyBackFromRenderFbo(true); - } else if (!m_source.isNull()) { + if (!m_source.isNull()) { // QVolatileImage::toImage() will make a copy always so no check // for active painting is needed. QImage img = m_source.toImage(); @@ -668,58 +500,9 @@ QImage QGLPixmapData::toImage() const return qt_gl_read_texture(QSize(w, h), true, true); } -struct TextureBuffer -{ - QGLFramebufferObject *fbo; - QGL2PaintEngineEx *engine; -}; - -Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool) -QGLFramebufferObjectPool* qgl_fbo_pool() -{ - return _qgl_fbo_pool(); -} - void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const { - if (!isValid()) - return; - - m_hasFillColor = false; - - const QGLContext *share_ctx = qt_gl_share_widget()->context(); - QGLShareContextScope ctx(share_ctx); - - ensureCreated(); - - if (!ctx->d_ptr->fbo) - glGenFramebuffers(1, &ctx->d_ptr->fbo); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, m_texture.id, 0); - - const int x0 = 0; - const int x1 = w; - const int y0 = 0; - const int y1 = h; - - if (!m_renderFbo->isBound()) - glBindFramebuffer(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); - - if (keepCurrentFboBound) { - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); - } else { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_renderFbo->handle()); - ctx->d_ptr->current_fbo = m_renderFbo->handle(); - } + // We don't use FBOs on Symbian } bool QGLPixmapData::useFramebufferObjects() const @@ -733,32 +516,6 @@ QPaintEngine* QGLPixmapData::paintEngine() const if (!isValid()) return 0; - if (m_renderFbo) - return m_engine; - - if (useFramebufferObjects()) { - extern QGLWidget* qt_gl_share_widget(); - - if (!QGLContext::currentContext()) - qt_gl_share_widget()->makeCurrent(); - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - - QGLFramebufferObjectFormat format; - format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); - format.setSamples(4); - format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB)); - - m_renderFbo = qgl_fbo_pool()->acquire(size(), format); - - if (m_renderFbo) { - if (!m_engine) - m_engine = new QGL2PaintEngineEx; - return m_engine; - } - - qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine"; - } - // If the application wants to paint into the QPixmap, we first // force it to QImage format and then paint into that. // This is simpler than juggling multiple GL contexts. @@ -773,25 +530,16 @@ QPaintEngine* QGLPixmapData::paintEngine() const extern QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format); -// If copyBack is true, bind will copy the contents of the render -// FBO to the texture (which is not bound to the texture, as it's -// a multisample FBO). GLuint QGLPixmapData::bind(bool copyBack) const { - if (m_renderFbo && copyBack) { - copyBackFromRenderFbo(true); - } else { - ensureCreated(); - } + ensureCreated(); GLuint id = m_texture.id; glBindTexture(GL_TEXTURE_2D, id); if (m_hasFillColor) { - if (!useFramebufferObjects()) { m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); m_source.fill(PREMUL(m_fillColor.rgba())); - } m_hasFillColor = false; @@ -860,7 +608,21 @@ void QGLPixmapData::forceToImage() void QGLPixmapData::destroyTexture() { - // Destroy SgImage texture + if (m_texture.id) { + QGLWidget *shareWidget = qt_gl_share_widget(); + if (shareWidget) { + m_texture.options |= QGLContext::MemoryManagedBindOption; + m_texture.freeTexture(); + m_texture.options &= ~QGLContext::MemoryManagedBindOption; + } else if(QGLContext::currentContext()) { + glDeleteTextures(1, &m_texture.id); + m_texture.id = 0; + m_texture.boundPixmap = 0; + m_texture.boundKey = 0; + } + m_ctx = 0; + m_dirty = true; + } } void QGLPixmapData::detachTextureFromPool() @@ -885,7 +647,180 @@ void QGLPixmapData::reclaimTexture() QGLPaintDevice *QGLPixmapData::glDevice() const { - return &m_glDevice; + return 0; +} + +static inline bool knownGoodFormat(QImage::Format format) +{ + switch (format) { + case QImage::Format_RGB16: // EColor64K + case QImage::Format_RGB32: // EColor16MU + case QImage::Format_ARGB32_Premultiplied: // EColor16MAP + return true; + default: + return false; + } +} + +static inline int symbianPixeFormatBitsPerPixel(TUidPixelFormat pixelFormat) +{ + switch (pixelFormat) { + case EUidPixelFormatP_1: + case EUidPixelFormatL_1: + return 1; + case EUidPixelFormatP_2: + case EUidPixelFormatL_2: + return 2; + case EUidPixelFormatP_4: + case EUidPixelFormatL_4: + return 4; + case EUidPixelFormatRGB_332: + case EUidPixelFormatA_8: + case EUidPixelFormatBGR_332: + case EUidPixelFormatP_8: + case EUidPixelFormatL_8: + return 8; + case EUidPixelFormatRGB_565: + case EUidPixelFormatBGR_565: + case EUidPixelFormatARGB_1555: + case EUidPixelFormatXRGB_1555: + case EUidPixelFormatARGB_4444: + case EUidPixelFormatARGB_8332: + case EUidPixelFormatBGRX_5551: + case EUidPixelFormatBGRA_5551: + case EUidPixelFormatBGRA_4444: + case EUidPixelFormatBGRX_4444: + case EUidPixelFormatAP_88: + case EUidPixelFormatXRGB_4444: + case EUidPixelFormatXBGR_4444: + return 16; + case EUidPixelFormatBGR_888: + case EUidPixelFormatRGB_888: + return 24; + case EUidPixelFormatXRGB_8888: + case EUidPixelFormatBGRX_8888: + case EUidPixelFormatXBGR_8888: + case EUidPixelFormatBGRA_8888: + case EUidPixelFormatARGB_8888: + case EUidPixelFormatABGR_8888: + case EUidPixelFormatARGB_8888_PRE: + case EUidPixelFormatABGR_8888_PRE: + case EUidPixelFormatBGRA_8888_PRE: + case EUidPixelFormatARGB_2101010: + case EUidPixelFormatABGR_2101010: + return 32; + default: + return 32; + }; +} + +void QGLPixmapData::fromNativeType(void* pixmap, NativeType type) +{ + if (type == QPixmapData::SgImage && pixmap) { +#if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) + RSgImage *sgImage = reinterpret_cast(pixmap); + + m_sgImage = new RSgImage; + m_sgImage->Open(sgImage->Id()); + + TSgImageInfo info; + sgImage->GetInfo(info); + + w = info.iSizeInPixels.iWidth; + h = info.iSizeInPixels.iHeight; + d = symbianPixeFormatBitsPerPixel((TUidPixelFormat)info.iPixelFormat); + + m_source = QVolatileImage(); + m_hasAlpha = true; + m_hasFillColor = false; + m_dirty = true; + is_null = (w <= 0 || h <= 0); +#endif + } else if (type == QPixmapData::FbsBitmap && pixmap) { + CFbsBitmap *bitmap = reinterpret_cast(pixmap); + QSize size(bitmap->SizeInPixels().iWidth, bitmap->SizeInPixels().iHeight); + if (size.width() == w && size.height() == h) + setSerialNumber(++qt_gl_pixmap_serial); + resize(size.width(), size.height()); + m_source = QVolatileImage(bitmap); + if (pixelType() == BitmapType) { + m_source.ensureFormat(QImage::Format_MonoLSB); + } else if (!knownGoodFormat(m_source.format())) { + m_source.beginDataAccess(); + QImage::Format format = idealFormat(m_source.imageRef(), Qt::AutoColor); + m_source.endDataAccess(true); + m_source.ensureFormat(format); + } + m_hasAlpha = m_source.hasAlphaChannel(); + m_hasFillColor = false; + m_dirty = true; + d = m_source.depth(); + } else if (type == QPixmapData::VolatileImage && pixmap) { + // Support QS60Style in more efficient skin graphics retrieval. + QVolatileImage *img = static_cast(pixmap); + if (img->width() == w && img->height() == h) + setSerialNumber(++qt_gl_pixmap_serial); + resize(img->width(), img->height()); + m_source = *img; + m_hasAlpha = m_source.hasAlphaChannel(); + m_hasFillColor = false; + m_dirty = true; + d = m_source.depth(); + } else if (type == QPixmapData::NativeImageHandleProvider && pixmap) { + destroyTexture(); + nativeImageHandleProvider = static_cast(pixmap); + // Cannot defer the retrieval, we need at least the size right away. + createFromNativeImageHandleProvider(); + } +} + +void* QGLPixmapData::toNativeType(NativeType type) +{ + if (type == QPixmapData::FbsBitmap) { + if (m_source.isNull()) + m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); + return m_source.duplicateNativeImage(); + } + + return 0; +} + +bool QGLPixmapData::initFromNativeImageHandle(void *handle, const QString &type) +{ + if (type == QLatin1String("RSgImage")) { + fromNativeType(handle, QPixmapData::SgImage); + return true; + } else if (type == QLatin1String("CFbsBitmap")) { + fromNativeType(handle, QPixmapData::FbsBitmap); + return true; + } + return false; +} + +void QGLPixmapData::createFromNativeImageHandleProvider() +{ + void *handle = 0; + QString type; + nativeImageHandleProvider->get(&handle, &type); + if (handle) { + if (initFromNativeImageHandle(handle, type)) { + nativeImageHandle = handle; + nativeImageType = type; + } else { + qWarning("QGLPixmapData: Unknown native image type '%s'", qPrintable(type)); + } + } else { + qWarning("QGLPixmapData: Native handle is null"); + } +} + +void QGLPixmapData::releaseNativeImageHandle() +{ + if (nativeImageHandleProvider && nativeImageHandle) { + nativeImageHandleProvider->release(nativeImageHandle, nativeImageType); + nativeImageHandle = 0; + nativeImageType = QString(); + } } QT_END_NAMESPACE diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index 17b2044..b48fe2c 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -184,7 +184,7 @@ QGLGraphicsSystem::QGLGraphicsSystem(bool useX11GL) class QGLGlobalShareWidget { public: - QGLGlobalShareWidget() : refCount(0), widget(0), initializing(false) {} + QGLGlobalShareWidget() : widget(0), initializing(false) {} QGLWidget *shareWidget() { if (!initializing && !widget && !cleanedUp) { @@ -223,7 +223,6 @@ public: } static bool cleanedUp; - int refCount; private: QGLWidget *widget; @@ -354,14 +353,10 @@ QGLWindowSurface::~QGLWindowSurface() if (QGLGlobalShareWidget::cleanedUp) return; - --(_qt_gl_share_widget()->refCount); - #ifdef Q_OS_SYMBIAN - if (_qt_gl_share_widget()->refCount <= 0) { // Destroy the context if necessary. if (!qt_gl_share_widget()->context()->isSharing()) qt_destroy_gl_share_widget(); - } #endif } @@ -410,9 +405,6 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) ctx->create(qt_gl_share_widget()->context()); - if (widget != qt_gl_share_widget()) - ++(_qt_gl_share_widget()->refCount); - #ifndef QT_NO_EGL static bool checkedForNOKSwapRegion = false; static bool haveNOKSwapRegion = false; @@ -719,6 +711,7 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint & glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0); } else { +#ifndef Q_OS_SYMBIAN // We don't have FBO pool on Symbian // can't do sub-region blits with multisample FBOs QGLFramebufferObject *temp = qgl_fbo_pool()->acquire(d_ptr->fbo->size(), QGLFramebufferObjectFormat()); @@ -741,6 +734,7 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint & glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0); qgl_fbo_pool()->release(temp); +#endif // Q_OS_SYMBIAN } ctx->d_ptr->current_fbo = 0; @@ -823,18 +817,43 @@ void QGLWindowSurface::updateGeometry() { 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()->refCount); + QGLContext *ctx = reinterpret_cast(wd->extraData()->glContext); + + if (ctx == QGLContext::currentContext()) + ctx->doneCurrent(); - delete wd->extraData()->glContext; - wd->extraData()->glContext = 0; - d_ptr->ctx = 0; + ctx->d_func()->destroyEglSurfaceForDevice(); + + // Delete other contexts (shouldn't happen too often, if at all) + while (d_ptr->contexts.size()) { + QGLContext **ctxPtrPtr = d_ptr->contexts.takeFirst(); + if ((*ctxPtrPtr) != ctx) + delete *ctxPtrPtr; + } + union { QGLContext **ctxPtrPtr; void **voidPtrPtr; }; + voidPtrPtr = &wd->extraData()->glContext; + d_ptr->contexts << ctxPtrPtr; + + ctx->d_func()->eglSurface = ctx->d_func()->eglContext->createSurface(window()); + + // Partial update supported has been decided already in previous hijackWindow call. + // Reset swap behaviour based on that flag. + if (hasPartialUpdateSupport()) { + eglSurfaceAttrib(QEgl::display(), ctx->d_func()->eglSurfaceForDevice(), + EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLWindowSurface::updateGeometry() - could not re-enable preserved swap behaviour"); + } else { + eglSurfaceAttrib(QEgl::display(), ctx->d_func()->eglSurfaceForDevice(), + EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLWindowSurface::updateGeometry() - could not re-enable destroyed swap behaviour"); + } } - else #endif - { - hijack = false; // we already have gl context for widget - } + hijack = false; // we already have gl context for widget } if (hijack) -- cgit v0.12