diff options
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 63 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp | 30 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h | 2 | ||||
-rw-r--r-- | src/opengl/opengl.pro | 2 | ||||
-rw-r--r-- | src/opengl/qgl.cpp | 79 | ||||
-rw-r--r-- | src/opengl/qgl_egl.cpp | 34 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 51 | ||||
-rw-r--r-- | src/opengl/qgl_symbian.cpp | 197 | ||||
-rw-r--r-- | src/opengl/qgl_x11egl.cpp | 13 | ||||
-rw-r--r-- | src/opengl/qglframebufferobject.cpp | 4 | ||||
-rw-r--r-- | src/opengl/qglfunctions.cpp | 4 | ||||
-rw-r--r-- | src/opengl/qglpaintdevice.cpp | 2 | ||||
-rw-r--r-- | src/opengl/qglpixelbuffer.cpp | 4 | ||||
-rw-r--r-- | src/opengl/qgltexturepool.cpp | 7 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_gl.cpp | 4 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_gl_p.h | 19 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_poolgl.cpp | 156 | ||||
-rw-r--r-- | src/opengl/qwindowsurface_gl.cpp | 69 | ||||
-rw-r--r-- | src/opengl/qwindowsurface_gl_p.h | 2 |
19 files changed, 479 insertions, 263 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index a134078..18c684f 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -90,10 +90,6 @@ QT_BEGIN_NAMESPACE -#if defined(Q_OS_SYMBIAN) -#define QT_GL_NO_SCISSOR_TEST -#endif - #if defined(Q_WS_WIN) extern Q_GUI_EXPORT bool qt_cleartype_enabled; #endif @@ -102,6 +98,10 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled; extern bool qt_applefontsmoothing_enabled; #endif +#if !defined(QT_MAX_CACHED_GLYPH_SIZE) +# define QT_MAX_CACHED_GLYPH_SIZE 64 +#endif + Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); ////////////////////////////////// Private Methods ////////////////////////////////////////// @@ -540,27 +540,32 @@ void QGL2PaintEngineEx::beginNativePainting() glDisableVertexAttribArray(i); #ifndef QT_OPENGL_ES_2 - // be nice to people who mix OpenGL 1.x code with QPainter commands - // by setting modelview and projection matrices to mirror the GL 1 - // paint engine - const QTransform& mtx = state()->matrix; - - float mv_matrix[4][4] = + const QGLFormat &fmt = d->device->format(); + if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 1) + || fmt.profile() == QGLFormat::CompatibilityProfile) { - { float(mtx.m11()), float(mtx.m12()), 0, float(mtx.m13()) }, - { float(mtx.m21()), float(mtx.m22()), 0, float(mtx.m23()) }, - { 0, 0, 1, 0 }, - { float(mtx.dx()), float(mtx.dy()), 0, float(mtx.m33()) } - }; + // be nice to people who mix OpenGL 1.x code with QPainter commands + // by setting modelview and projection matrices to mirror the GL 1 + // paint engine + const QTransform& mtx = state()->matrix; - const QSize sz = d->device->size(); + float mv_matrix[4][4] = + { + { float(mtx.m11()), float(mtx.m12()), 0, float(mtx.m13()) }, + { float(mtx.m21()), float(mtx.m22()), 0, float(mtx.m23()) }, + { 0, 0, 1, 0 }, + { float(mtx.dx()), float(mtx.dy()), 0, float(mtx.m33()) } + }; + + const QSize sz = d->device->size(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(&mv_matrix[0][0]); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(&mv_matrix[0][0]); + } #else Q_UNUSED(ctx); #endif @@ -591,7 +596,9 @@ void QGL2PaintEngineExPrivate::resetGLState() ctx->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false); ctx->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); #ifndef QT_OPENGL_ES_2 - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // color may have been changed by glVertexAttrib() + // gl_Color, corresponding to vertex attribute 3, may have been changed + float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + glVertexAttrib4fv(3, color); #endif } @@ -1477,7 +1484,8 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem // don't try to cache huge fonts or vastly transformed fonts const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(det) >= 64 * 64 || det < 0.25f || det > 4.f) + if (pixelSize * pixelSize * qAbs(det) >= QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE || + det < 0.25f || det > 4.f) drawCached = false; QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 @@ -1581,8 +1589,13 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp // cache so this text is performed before we test if the cache size has changed. if (recreateVertexArrays) { cache->setPaintEnginePrivate(this); - cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs, - staticTextItem->glyphs, staticTextItem->glyphPositions); + if (!cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs, + staticTextItem->glyphs, staticTextItem->glyphPositions)) { + // No space for glyphs in cache. We need to reset it and try again. + cache->clear(); + cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs, + staticTextItem->glyphs, staticTextItem->glyphPositions); + } cache->fillInPendingGlyphs(); } diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 4362c0a..c867d60 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -339,8 +339,19 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed sub // by converting it to a format with four bytes per pixel. Another is to copy one line at a // time. - for (int i = 0; i < maskHeight; ++i) - glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i)); + if (!ctx->d_ptr->workaround_brokenAlphaTexSubImage_init) { + // don't know which driver versions exhibit this bug, so be conservative for now + const QByteArray versionString(reinterpret_cast<const char*>(glGetString(GL_VERSION))); + ctx->d_ptr->workaround_brokenAlphaTexSubImage = versionString.indexOf("NVIDIA") >= 0; + ctx->d_ptr->workaround_brokenAlphaTexSubImage_init = true; + } + + if (ctx->d_ptr->workaround_brokenAlphaTexSubImage) { + for (int i = 0; i < maskHeight; ++i) + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i)); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits()); + } } } @@ -367,4 +378,19 @@ int QGLTextureGlyphCache::maxTextureHeight() const else return ctx->d_ptr->maxTextureSize(); } + +void QGLTextureGlyphCache::clear() +{ + if (ctx != 0) { + m_textureResource.cleanup(ctx); + + m_w = 0; + m_h = 0; + m_cx = 0; + m_cy = 0; + m_currentRowHeight = 0; + coords.clear(); + } +} + QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h index cc6de28..133289e 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h @@ -142,6 +142,8 @@ public: FilterMode filterMode() const { return m_filterMode; } void setFilterMode(FilterMode m) { m_filterMode = m; } + void clear(); + void freeResource(void *) { ctx = 0; } private: diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 0d65b25..e7c1c44 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -157,7 +157,7 @@ embedded { } symbian { - DEFINES += QGL_USE_TEXTURE_POOL + DEFINES += QGL_USE_TEXTURE_POOL QGL_NO_PRESERVED_SWAP SOURCES -= qpixmapdata_gl.cpp SOURCES += qgl_symbian.cpp \ qpixmapdata_poolgl.cpp \ diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 9e39389..b3b459d 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -69,6 +69,7 @@ #if !defined(QT_OPENGL_ES_1) #include "gl2paintengineex/qpaintengineex_opengl2_p.h" +#include <private/qwindowsurface_gl_p.h> #endif #ifndef QT_OPENGL_ES_2 @@ -90,7 +91,6 @@ #include <private/qpixmapdata_p.h> #include <private/qpixmapdata_gl_p.h> #include <private/qglpixelbuffer_p.h> -#include <private/qwindowsurface_gl_p.h> #include <private/qimagepixmapcleanuphooks_p.h> #include "qcolormap.h" #include "qfile.h" @@ -1738,6 +1738,9 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format) workaround_brokenTextureFromPixmap = false; workaround_brokenTextureFromPixmap_init = false; + workaround_brokenAlphaTexSubImage = false; + workaround_brokenAlphaTexSubImage_init = false; + for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) vertexAttributeArraysEnabledState[i] = false; } @@ -5356,12 +5359,69 @@ QGLWidget::QGLWidget(QGLContext *context, QWidget *parent, #endif // QT3_SUPPORT +typedef GLubyte * (*qt_glGetStringi)(GLenum, GLuint); + +#ifndef GL_NUM_EXTENSIONS +#define GL_NUM_EXTENSIONS 0x821D +#endif + +QGLExtensionMatcher::QGLExtensionMatcher(const char *str) +{ + init(str); +} + +QGLExtensionMatcher::QGLExtensionMatcher() +{ + const char *extensionStr = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)); + + if (extensionStr) { + init(extensionStr); + } else { + // clear error state + while (glGetError()) {} + + const QGLContext *ctx = QGLContext::currentContext(); + if (ctx) { + qt_glGetStringi glGetStringi = (qt_glGetStringi)ctx->getProcAddress(QLatin1String("glGetStringi")); + + GLint numExtensions; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); + + for (int i = 0; i < numExtensions; ++i) { + const char *str = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i)); + + m_offsets << m_extensions.size(); + + while (*str != 0) + m_extensions.append(*str++); + m_extensions.append(' '); + } + } + } +} + +void QGLExtensionMatcher::init(const char *str) +{ + m_extensions = str; + + // make sure extension string ends with a space + if (!m_extensions.endsWith(' ')) + m_extensions.append(' '); + + int index = 0; + int next = 0; + while ((next = m_extensions.indexOf(' ', index)) >= 0) { + m_offsets << index; + index = next + 1; + } +} + /* Returns the GL extensions for the current context. */ QGLExtensions::Extensions QGLExtensions::currentContextExtensions() { - QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); + QGLExtensionMatcher extensions; Extensions glExtensions; if (extensions.match("GL_ARB_texture_rectangle")) @@ -5603,6 +5663,21 @@ void *QGLContextGroupResourceBase::value(const QGLContext *context) return group->m_resources.value(this, 0); } +void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx) +{ + void *resource = value(ctx); + + if (resource != 0) { + QGLShareContextScope scope(ctx); + freeResource(resource); + + QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx); + group->m_resources.remove(this); + m_groups.removeOne(group); + active.deref(); + } +} + void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx, void *value) { #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp index 674d80d..ef36eb9 100644 --- a/src/opengl/qgl_egl.cpp +++ b/src/opengl/qgl_egl.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include <QtCore/qdebug.h> #include <QtOpenGL/qgl.h> #include <QtOpenGL/qglpixelbuffer.h> #include "qgl_p.h" @@ -51,6 +52,8 @@ QT_BEGIN_NAMESPACE +QEglProperties *QGLContextPrivate::extraWindowSurfaceCreationProps = NULL; + void qt_eglproperties_set_glformat(QEglProperties& eglProperties, const QGLFormat& glFormat) { int redSize = glFormat.redBufferSize(); @@ -195,6 +198,7 @@ void QGLContext::makeCurrent() // PowerVR MBX/SGX chips needs to clear all buffers when starting to render // a new frame, otherwise there will be a performance penalty to pay for // each frame. + qDebug() << "Found SGX/MBX driver, enabling FullClearOnEveryFrame"; d->workaround_needsFullClearOnEveryFrame = true; // Older PowerVR SGX drivers (like the one in the N900) have a @@ -202,10 +206,31 @@ void QGLContext::makeCurrent() // or GL_ALPHA texture bound to an FBO. The only way to // identify that driver is to check the EGL version number for it. const char *egl_version = eglQueryString(d->eglContext->display(), EGL_VERSION); - if (egl_version && strstr(egl_version, "1.3")) + + if (egl_version && strstr(egl_version, "1.3")) { + qDebug() << "Found v1.3 driver, enabling brokenFBOReadBack"; d->workaround_brokenFBOReadBack = true; - else if (egl_version && strstr(egl_version, "1.4")) + } else if (egl_version && strstr(egl_version, "1.4")) { + qDebug() << "Found v1.4 driver, enabling brokenTexSubImage"; d->workaround_brokenTexSubImage = true; + + // this is a bit complicated; 1.4 version SGX drivers from + // Nokia have fixed the brokenFBOReadBack problem, but + // official drivers from TI haven't, meaning that things + // like the beagleboard are broken unless we hack around it + // - but at the same time, we want to not reduce performance + // by not enabling this elsewhere. + // + // so, let's check for a Nokia-specific addon, and only + // enable if it isn't present. + // (see MeeGo bug #5616) + if (!QEgl::hasExtension("EGL_NOK_image_shared")) { + // no Nokia extension, this is probably a standard SGX + // driver, so enable the workaround + qDebug() << "Found non-Nokia v1.4 driver, enabling brokenFBOReadBack"; + d->workaround_brokenFBOReadBack = true; + } + } } } } @@ -286,6 +311,11 @@ void QGLContextPrivate::swapRegion(const QRegion ®ion) eglContext->swapBuffersRegion2NOK(eglSurfaceForDevice(), ®ion); } +void QGLContextPrivate::setExtraWindowSurfaceCreationProps(QEglProperties *props) +{ + extraWindowSurfaceCreationProps = props; +} + void QGLWidget::setMouseTracking(bool enable) { QWidget::setMouseTracking(enable); diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 5508598..50d13c9 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -369,11 +369,14 @@ public: EGLSurface eglSurface; void destroyEglSurfaceForDevice(); EGLSurface eglSurfaceForDevice() const; + static QEglProperties *extraWindowSurfaceCreationProps; + static void setExtraWindowSurfaceCreationProps(QEglProperties *props); #endif #if defined(Q_WS_QPA) QPlatformGLContext *platformContext; void setupSharing(); + #elif defined(Q_WS_X11) || defined(Q_WS_MAC) void* cx; #endif @@ -416,6 +419,9 @@ public: uint workaround_brokenTextureFromPixmap : 1; uint workaround_brokenTextureFromPixmap_init : 1; + uint workaround_brokenAlphaTexSubImage : 1; + uint workaround_brokenAlphaTexSubImage_init : 1; + #ifndef QT_NO_EGL uint ownsEglContext : 1; #endif @@ -684,6 +690,7 @@ public: virtual ~QGLContextGroupResourceBase(); void insert(const QGLContext *context, void *value); void *value(const QGLContext *context); + void cleanup(const QGLContext *context); void cleanup(const QGLContext *context, void *value); virtual void freeResource(void *value) = 0; @@ -845,46 +852,32 @@ private: }; -// This class can be used to match GL extensions without doing any mallocs. The -// class assumes that the GL extension string ends with a space character, -// which it should do on all conformant platforms. Create the object and pass -// in a pointer to the extension string, then call match() on each extension -// that should be matched. The match() function takes the extension name -// *without* the terminating space character as input. - class QGLExtensionMatcher { public: - QGLExtensionMatcher(const char *str) - : gl_extensions(str), gl_extensions_length(qstrlen(str)) - {} + QGLExtensionMatcher(const char *str); + QGLExtensionMatcher(); - bool match(const char *str) { + bool match(const char *str) const { int str_length = qstrlen(str); - const char *extensions = gl_extensions; - int extensions_length = gl_extensions_length; - - while (1) { - // the total length that needs to be matched is the str_length + - // the space character that terminates the extension name - if (extensions_length < str_length + 1) - return false; - if (qstrncmp(extensions, str, str_length) == 0 && extensions[str_length] == ' ') - return true; - int split_pos = 0; - while (split_pos < extensions_length && extensions[split_pos] != ' ') - ++split_pos; - ++split_pos; // added for the terminating space character - extensions += split_pos; - extensions_length -= split_pos; + Q_ASSERT(str); + Q_ASSERT(str_length > 0); + Q_ASSERT(str[str_length-1] != ' '); + + for (int i = 0; i < m_offsets.size(); ++i) { + const char *extension = m_extensions.constData() + m_offsets.at(i); + if (qstrncmp(extension, str, str_length) == 0 && extension[str_length] == ' ') + return true; } return false; } private: - const char *gl_extensions; - int gl_extensions_length; + void init(const char *str); + + QByteArray m_extensions; + QVector<int> m_offsets; }; diff --git a/src/opengl/qgl_symbian.cpp b/src/opengl/qgl_symbian.cpp index 2978514..1b41db4 100644 --- a/src/opengl/qgl_symbian.cpp +++ b/src/opengl/qgl_symbian.cpp @@ -41,15 +41,14 @@ #include "qgl.h" -#include <coemain.h> -#include <coecntrl.h> -#include <w32std.h> +#include <fbs.h> #include <private/qt_s60_p.h> #include <private/qpixmap_s60_p.h> #include <private/qimagepixmapcleanuphooks_p.h> #include <private/qgl_p.h> #include <private/qpaintengine_opengl_p.h> #include <private/qwidget_p.h> // to access QWExtra +#include <private/qnativeimagehandleprovider_p.h> #include "qgl_egl_p.h" #include "qpixmapdata_gl_p.h" #include "qgltexturepool_p.h" @@ -72,6 +71,8 @@ QT_BEGIN_NAMESPACE #endif #endif +extern int qt_gl_pixmap_serial; + /* QGLTemporaryContext implementation */ @@ -228,13 +229,20 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) // almost same as d->eglSurface = QEgl::createSurface(device(), d->eglContext->config()); -#if !defined(QGL_NO_PRESERVED_SWAP) - eglGetError(); // Clear error state first. - eglSurfaceAttrib(QEgl::display(), d->eglSurface, - EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); - if (eglGetError() != EGL_SUCCESS) { - qWarning("QGLContext: could not enable preserved swap"); - } + eglGetError(); // Clear error state first. + +#ifdef QGL_NO_PRESERVED_SWAP + eglSurfaceAttrib(QEgl::display(), d->eglSurface, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLContext: could not enable destroyed swap behaviour"); +#else + eglSurfaceAttrib(QEgl::display(), d->eglSurface, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLContext: could not enable preserved swap behaviour"); #endif setWindowCreated(true); @@ -361,117 +369,104 @@ void QGLWidgetPrivate::recreateEglSurface() eglSurfaceWindowId = currentId; } -/* - * Symbian specific QGLPixmapData functions - */ - -static CFbsBitmap* createBlitCopy(CFbsBitmap* bitmap) +static inline bool knownGoodFormat(QImage::Format format) { - CFbsBitmap *copy = q_check_ptr(new CFbsBitmap); - if (!copy) - return 0; - - if (copy->Create(bitmap->SizeInPixels(), bitmap->DisplayMode()) != KErrNone) { - delete copy; - copy = 0; - - return 0; + switch (format) { + case QImage::Format_RGB16: // EColor64K + case QImage::Format_RGB32: // EColor16MU + case QImage::Format_ARGB32_Premultiplied: // EColor16MAP + return true; + default: + return false; } - - CFbsBitmapDevice* bitmapDevice = 0; - CFbsBitGc *bitmapGc = 0; - QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(copy)); - QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); - bitmapGc->Activate(bitmapDevice); - - bitmapGc->BitBlt(TPoint(), bitmap); - - delete bitmapGc; - delete bitmapDevice; - - return copy; } void QGLPixmapData::fromNativeType(void* pixmap, NativeType type) { if (type == QPixmapData::FbsBitmap) { - CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap); - - bool deleteSourceBitmap = false; -#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE - - // Rasterize extended bitmaps - - TUid extendedBitmapType = bitmap->ExtendedBitmapType(); - if (extendedBitmapType != KNullUid) { - bitmap = createBlitCopy(bitmap); - deleteSourceBitmap = true; - } -#endif - - if (bitmap->IsCompressedInRAM()) { - bitmap = createBlitCopy(bitmap); - deleteSourceBitmap = true; + CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap *>(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); } - - TDisplayMode displayMode = bitmap->DisplayMode(); - QImage::Format format = qt_TDisplayMode2Format(displayMode); - - TSize size = bitmap->SizeInPixels(); - int bytesPerLine = bitmap->ScanLineLength(size.iWidth, displayMode); - - bitmap->BeginDataAccess(); - uchar *bytes = (uchar*)bitmap->DataAddress(); - QImage img = QImage(bytes, size.iWidth, size.iHeight, bytesPerLine, format); - img = img.copy(); - bitmap->EndDataAccess(); - - if (displayMode == EGray2) { - //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid - //So invert mono bitmaps so that masks work correctly. - img.invertPixels(); - } else if (displayMode == EColor16M) { - img = img.rgbSwapped(); // EColor16M is BGR - } - - fromImage(img, Qt::AutoColor); - - if (deleteSourceBitmap) - delete bitmap; + 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<QVolatileImage *>(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<QNativeImageHandleProvider *>(pixmap); + // Cannot defer the retrieval, we need at least the size right away. + createFromNativeImageHandleProvider(); } } void* QGLPixmapData::toNativeType(NativeType type) { if (type == QPixmapData::FbsBitmap) { - CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); - - if (bitmap) { - QImage image = toImage(); - - TDisplayMode displayMode(EColor16MU); - if (image.format()==QImage::Format_ARGB32_Premultiplied) - displayMode = EColor16MAP; + if (m_source.isNull()) + m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); + return m_source.duplicateNativeImage(); + } - if (bitmap->Create(TSize(image.width(), image.height()), - displayMode) == KErrNone) { - const uchar *sptr = const_cast<const QImage&>(image).bits(); - bitmap->BeginDataAccess(); + return 0; +} - uchar *dptr = (uchar*)bitmap->DataAddress(); - Mem::Copy(dptr, sptr, image.byteCount()); +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; +} - bitmap->EndDataAccess(); - } else { - delete bitmap; - bitmap = 0; - } +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"); + } +} - return reinterpret_cast<void*>(bitmap); +void QGLPixmapData::releaseNativeImageHandle() +{ + if (nativeImageHandleProvider && nativeImageHandle) { + nativeImageHandleProvider->release(nativeImageHandle, nativeImageType); + nativeImageHandle = 0; + nativeImageType = QString(); } - return 0; } QT_END_NAMESPACE - diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index 93f17ae..2ddfd35 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -105,10 +105,18 @@ QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *) return; } + XSetWindowAttributes attr; + unsigned long mask; + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap(X11->display, DefaultRootWindow(X11->display), vi->visual, AllocNone); + attr.event_mask = StructureNotifyMask | ExposureMask; + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + d->window = XCreateWindow(X11->display, RootWindow(X11->display, screen), 0, 0, 1, 1, 0, vi->depth, InputOutput, vi->visual, - 0, 0); + mask, &attr); d->surface = eglCreateWindowSurface(d->display, config, (EGLNativeWindowType) d->window, NULL); @@ -232,7 +240,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) if (devType == QInternal::Widget) { if (d->eglSurface != EGL_NO_SURFACE) eglDestroySurface(d->eglContext->display(), d->eglSurface); - d->eglSurface = QEgl::createSurface(device(), d->eglContext->config()); + // extraWindowSurfaceCreationProps default to NULL unless were specifically set before + d->eglSurface = QEgl::createSurface(device(), d->eglContext->config(), d->extraWindowSurfaceCreationProps); XFlush(X11->display); setWindowCreated(true); } diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index cda1c79..8eda222 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -44,6 +44,7 @@ #include <qdebug.h> #include <private/qgl_p.h> +#include <private/qfont_p.h> #if !defined(QT_OPENGL_ES_1) #include <private/qpaintengineex_opengl2_p.h> #endif @@ -1216,9 +1217,6 @@ void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint te } #endif -Q_GUI_EXPORT int qt_defaultDpiX(); -Q_GUI_EXPORT int qt_defaultDpiY(); - /*! \reimp */ int QGLFramebufferObject::metric(PaintDeviceMetric metric) const { diff --git a/src/opengl/qglfunctions.cpp b/src/opengl/qglfunctions.cpp index 29e32ff..be8219a 100644 --- a/src/opengl/qglfunctions.cpp +++ b/src/opengl/qglfunctions.cpp @@ -229,7 +229,7 @@ static int qt_gl_resolve_features() QGLFunctions::Buffers | QGLFunctions::CompressedTextures | QGLFunctions::Multisample; - QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); + QGLExtensionMatcher extensions; if (extensions.match("GL_OES_framebuffer_object")) features |= QGLFunctions::Framebuffers; if (extensions.match("GL_OES_blend_equation_separate")) @@ -244,7 +244,7 @@ static int qt_gl_resolve_features() #else int features = 0; QGLFormat::OpenGLVersionFlags versions = QGLFormat::openGLVersionFlags(); - QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); + QGLExtensionMatcher extensions; // Recognize features by extension name. if (extensions.match("GL_ARB_multitexture")) diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp index 7d0eb5b..61d8f26 100644 --- a/src/opengl/qglpaintdevice.cpp +++ b/src/opengl/qglpaintdevice.cpp @@ -43,13 +43,13 @@ #include <private/qgl_p.h> #include <private/qglpixelbuffer_p.h> #include <private/qglframebufferobject_p.h> -#include <private/qwindowsurface_gl_p.h> #ifdef Q_WS_X11 #include <private/qpixmapdata_x11gl_p.h> #endif #if !defined(QT_OPENGL_ES_1) #include <private/qpixmapdata_gl_p.h> +#include <private/qwindowsurface_gl_p.h> #endif QT_BEGIN_NAMESPACE diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index ec6ac4c..3278596 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -98,6 +98,7 @@ #include <qglpixelbuffer.h> #include <private/qglpixelbuffer_p.h> +#include <private/qfont_p.h> #include <qimage.h> #ifndef QT_OPENGL_ES_2 @@ -424,9 +425,6 @@ QPaintEngine *QGLPixelBuffer::paintEngine() const #endif } -Q_GUI_EXPORT int qt_defaultDpiX(); -Q_GUI_EXPORT int qt_defaultDpiY(); - /*! \reimp */ int QGLPixelBuffer::metric(PaintDeviceMetric metric) const { diff --git a/src/opengl/qgltexturepool.cpp b/src/opengl/qgltexturepool.cpp index 61a88c3..a5472ec 100644 --- a/src/opengl/qgltexturepool.cpp +++ b/src/opengl/qgltexturepool.cpp @@ -135,8 +135,11 @@ void QGLTexturePool::releaseTexture(QGLPixmapData *data, GLuint texture) if (data) removeFromLRU(data); - QGLShareContextScope ctx(qt_gl_share_widget()->context()); - glDeleteTextures(1, &texture); + QGLWidget *shareWidget = qt_gl_share_widget(); + if (shareWidget) { + QGLShareContextScope ctx(shareWidget->context()); + glDeleteTextures(1, &texture); + } } void QGLTexturePool::useTexture(QGLPixmapData *data) diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index db9f8c8..45722d1 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -49,6 +49,7 @@ #include <private/qgl_p.h> #include <private/qdrawhelper_p.h> #include <private/qimage_p.h> +#include <private/qfont_p.h> #include <private/qpaintengineex_opengl2_p.h> @@ -790,9 +791,6 @@ QGLTexture* QGLPixmapData::texture() const return &m_texture; } -Q_GUI_EXPORT int qt_defaultDpiX(); -Q_GUI_EXPORT int qt_defaultDpiY(); - int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const { if (w == 0) diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h index 55cc29d..8855c20 100644 --- a/src/opengl/qpixmapdata_gl_p.h +++ b/src/opengl/qpixmapdata_gl_p.h @@ -59,6 +59,10 @@ #include "private/qpixmapdata_p.h" #include "private/qglpaintdevice_p.h" +#ifdef Q_OS_SYMBIAN +#include "private/qvolatileimage_p.h" +#endif + QT_BEGIN_NAMESPACE class QPaintEngine; @@ -72,6 +76,10 @@ void qt_gl_unregister_pixmap(QGLPixmapData *pd); void qt_gl_hibernate_pixmaps(); #endif +#ifdef Q_OS_SYMBIAN +class QNativeImageHandleProvider; +#endif + class QGLFramebufferObjectPool { public: @@ -153,8 +161,12 @@ public: #endif #ifdef Q_OS_SYMBIAN + QImage::Format idealFormat(QImage &image, Qt::ImageConversionFlags flags); void* toNativeType(NativeType type); void fromNativeType(void* pixmap, NativeType type); + bool initFromNativeImageHandle(void *handle, const QString &type); + void createFromNativeImageHandleProvider(); + void releaseNativeImageHandle(); #endif private: @@ -184,7 +196,14 @@ private: mutable QGLFramebufferObject *m_renderFbo; mutable QPaintEngine *m_engine; mutable QGLContext *m_ctx; +#ifdef Q_OS_SYMBIAN + mutable QVolatileImage m_source; + mutable QNativeImageHandleProvider *nativeImageHandleProvider; + void *nativeImageHandle; + QString nativeImageType; +#else mutable QImage m_source; +#endif mutable QGLTexture m_texture; // the texture is not in sync with the source image diff --git a/src/opengl/qpixmapdata_poolgl.cpp b/src/opengl/qpixmapdata_poolgl.cpp index f1220b1..041210d 100644 --- a/src/opengl/qpixmapdata_poolgl.cpp +++ b/src/opengl/qpixmapdata_poolgl.cpp @@ -49,6 +49,8 @@ #include <private/qgl_p.h> #include <private/qdrawhelper_p.h> #include <private/qimage_p.h> +#include <private/qnativeimagehandleprovider_p.h> +#include <private/qfont_p.h> #include <private/qpaintengineex_opengl2_p.h> @@ -63,19 +65,6 @@ QT_BEGIN_NAMESPACE Q_OPENGL_EXPORT extern QGLWidget* qt_gl_share_widget(); -/*! - \class QGLFramebufferObjectPool - \since 4.6 - - \brief The QGLFramebufferObject class provides a pool of framebuffer - objects for offscreen rendering purposes. - - When requesting an FBO of a given size and format, an FBO of the same - format and a size at least as big as the requested size will be returned. - - \internal -*/ - static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo) { return qAbs(size.width() * size.height() - fbo->width() * fbo->height()); @@ -247,13 +236,15 @@ void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d) data = d; } -static int qt_gl_pixmap_serial = 0; +int qt_gl_pixmap_serial = 0; QGLPixmapData::QGLPixmapData(PixelType type) : QPixmapData(type, OpenGLClass) , m_renderFbo(0) , m_engine(0) , m_ctx(0) + , nativeImageHandleProvider(0) + , nativeImageHandle(0) , m_dirty(false) , m_hasFillColor(false) , m_hasAlpha(false) @@ -292,6 +283,8 @@ void QGLPixmapData::destroyTexture() } m_texture.id = 0; inTexturePool = false; + + releaseNativeImageHandle(); } QPixmapData *QGLPixmapData::createCompatiblePixmapData() const @@ -330,7 +323,7 @@ void QGLPixmapData::resize(int width, int height) destroyTexture(); - m_source = QImage(); + m_source = QVolatileImage(); m_dirty = isValid(); setSerialNumber(++qt_gl_pixmap_serial); } @@ -342,6 +335,9 @@ void QGLPixmapData::ensureCreated() const m_dirty = false; + if (nativeImageHandleProvider && !nativeImageHandle) + const_cast<QGLPixmapData *>(this)->createFromNativeImageHandleProvider(); + QGLShareContextScope ctx(qt_gl_share_widget()->context()); m_ctx = ctx; @@ -353,6 +349,11 @@ void QGLPixmapData::ensureCreated() const #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; + m_texture.options &= ~QGLContext::MemoryManagedBindOption; if (!m_texture.id) { @@ -361,7 +362,7 @@ void QGLPixmapData::ensureCreated() const 0, internal_format, w, h, external_format, - GL_UNSIGNED_BYTE, + type, const_cast<QGLPixmapData*>(this)); if (!m_texture.id) { failedToAlloc = true; @@ -378,21 +379,35 @@ void QGLPixmapData::ensureCreated() const if (!m_source.isNull() && m_texture.id) { if (external_format == GL_RGB) { - const QImage tx = m_source.convertToFormat(QImage::Format_RGB888).mirrored(false, true); + 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); glBindTexture(target, m_texture.id); - glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - GL_UNSIGNED_BYTE, tx.bits()); + 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 - const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, external_format); + 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); - glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - GL_UNSIGNED_BYTE, tx.bits()); + 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); } if (useFramebufferObjects()) - m_source = QImage(); + m_source = QVolatileImage(); } } @@ -437,7 +452,7 @@ bool QGLPixmapData::fromFile(const QString &filename, const char *format, is_null = false; d = 32; m_hasAlpha = alpha; - m_source = QImage(); + m_source = QVolatileImage(); m_dirty = isValid(); return true; } @@ -469,7 +484,7 @@ bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format, is_null = false; d = 32; m_hasAlpha = alpha; - m_source = QImage(); + m_source = QVolatileImage(); m_dirty = isValid(); return true; } @@ -487,9 +502,20 @@ bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format, return !isNull(); } -/*! - out-of-place conversion (inPlace == false) will always detach() - */ +QImage::Format QGLPixmapData::idealFormat(QImage &image, Qt::ImageConversionFlags flags) +{ + QImage::Format format = QImage::Format_RGB32; + if (qApp->desktop()->depth() == 16) + format = QImage::Format_RGB16; + + if (image.hasAlphaChannel() + && ((flags & Qt::NoOpaqueDetection) + || const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels())) + format = QImage::Format_ARGB32_Premultiplied; + + return format; +} + void QGLPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) { if (image.size() == QSize(w, h)) @@ -498,26 +524,25 @@ void QGLPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags resize(image.width(), image.height()); if (pixelType() == BitmapType) { - m_source = image.convertToFormat(QImage::Format_MonoLSB); + QImage convertedImage = image.convertToFormat(QImage::Format_MonoLSB); + if (image.format() == QImage::Format_MonoLSB) + convertedImage.detach(); - } else { - QImage::Format format = QImage::Format_RGB32; - if (qApp->desktop()->depth() == 16) - format = QImage::Format_RGB16; + m_source = QVolatileImage(convertedImage); - if (image.hasAlphaChannel() - && ((flags & Qt::NoOpaqueDetection) - || const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels())) - format = QImage::Format_ARGB32_Premultiplied; + } else { + QImage::Format format = idealFormat(image, flags); if (inPlace && image.data_ptr()->convertInPlace(format, flags)) { - m_source = image; + m_source = QVolatileImage(image); } else { - m_source = image.convertToFormat(format); + QImage convertedImage = image.convertToFormat(format); // convertToFormat won't detach the image if format stays the same. if (image.format() == format) - m_source.detach(); + convertedImage.detach(); + + m_source = QVolatileImage(convertedImage); } } @@ -596,16 +621,13 @@ void QGLPixmapData::fill(const QColor &color) } if (useFramebufferObjects()) { - m_source = QImage(); + m_source = QVolatileImage(); m_hasFillColor = true; m_fillColor = color; } else { + forceToImage(); - if (m_source.isNull()) { - m_fillColor = color; - m_hasFillColor = true; - - } else if (m_source.depth() == 32) { + if (m_source.depth() == 32) { m_source.fill(PREMUL(color.rgba())); } else if (m_source.depth() == 1) { @@ -656,13 +678,15 @@ QImage QGLPixmapData::toImage() const if (m_renderFbo) { copyBackFromRenderFbo(true); } else if (!m_source.isNull()) { - QImageData *data = const_cast<QImage &>(m_source).data_ptr(); - if (data->paintEngine && data->paintEngine->isActive() - && data->paintEngine->paintDevice() == &m_source) - { - return m_source.copy(); + // QVolatileImage::toImage() will make a copy always so no check + // for active painting is needed. + QImage img = m_source.toImage(); + if (img.format() == QImage::Format_MonoLSB) { + img.setColorCount(2); + img.setColor(0, QColor(Qt::color0).rgba()); + img.setColor(1, QColor(Qt::color1).rgba()); } - return m_source; + return img; } else if (m_dirty || m_hasFillColor) { return fillImage(m_fillColor); } else { @@ -802,7 +826,7 @@ GLuint QGLPixmapData::bind(bool copyBack) const if (m_hasFillColor) { if (!useFramebufferObjects()) { - m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied); + m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); m_source.fill(PREMUL(m_fillColor.rgba())); } @@ -811,7 +835,7 @@ GLuint QGLPixmapData::bind(bool copyBack) const GLenum format = qt_gl_preferredTextureFormat(); QImage tx(w, h, QImage::Format_ARGB32_Premultiplied); tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format)); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.bits()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.constBits()); } return id; @@ -832,9 +856,16 @@ void QGLPixmapData::detachTextureFromPool() void QGLPixmapData::hibernate() { - // If the texture was imported (e.g, from an SgImage under Symbian), - // then we cannot copy it back to main memory for storage. - if (m_texture.id && m_source.isNull()) + // If the image was imported (e.g, from an SgImage under Symbian), then + // skip the hibernation, there is no sense in copying it back to main + // memory because the data is most likely shared between several processes. + bool skipHibernate = (m_texture.id && m_source.isNull()); +#if defined(Q_OS_SYMBIAN) + // However we have to proceed normally if the image was retrieved via + // a handle provider. + skipHibernate &= !nativeImageHandleProvider; +#endif + if (skipHibernate) return; forceToImage(); @@ -849,9 +880,6 @@ void QGLPixmapData::reclaimTexture() destroyTexture(); } -Q_GUI_EXPORT int qt_defaultDpiX(); -Q_GUI_EXPORT int qt_defaultDpiY(); - int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const { if (w == 0) @@ -888,8 +916,12 @@ void QGLPixmapData::forceToImage() if (!isValid()) return; - if (m_source.isNull()) - m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied); + if (m_source.isNull()) { + QImage::Format format = QImage::Format_ARGB32_Premultiplied; + if (pixelType() == BitmapType) + format = QImage::Format_MonoLSB; + m_source = QVolatileImage(w, h, format); + } m_dirty = true; } diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index a6489a6..70c1fde 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -327,6 +327,8 @@ struct QGLWindowSurfacePrivate QList<QImage> buffers; QGLWindowSurfaceGLPaintDevice glDevice; QGLWindowSurface* q_ptr; + + bool swap_region_support; }; QGLFormat QGLWindowSurface::surfaceFormat; @@ -379,6 +381,7 @@ QGLWindowSurface::QGLWindowSurface(QWidget *window) d_ptr->q_ptr = this; d_ptr->geometry_updated = false; d_ptr->did_paint = false; + d_ptr->swap_region_support = false; } QGLWindowSurface::~QGLWindowSurface() @@ -478,14 +481,17 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) if (haveNOKSwapRegion) qDebug() << "Found EGL_NOK_swap_region2 extension. Using partial updates."; } - bool swapBehaviourPreserved = (ctx->d_func()->eglContext->configAttrib(EGL_SWAP_BEHAVIOR) - || (ctx->d_func()->eglContext->configAttrib(EGL_SURFACE_TYPE)&EGL_SWAP_BEHAVIOR_PRESERVED_BIT)); - if (!swapBehaviourPreserved && !haveNOKSwapRegion) - setPartialUpdateSupport(false); // Force full-screen updates - else - setPartialUpdateSupport(true); -#else - setPartialUpdateSupport(false); + + d_ptr->destructive_swap_buffers = true; + if (ctx->d_func()->eglContext->configAttrib(EGL_SURFACE_TYPE)&EGL_SWAP_BEHAVIOR_PRESERVED_BIT) { + EGLint swapBehavior; + if (eglQuerySurface(ctx->d_func()->eglContext->display(), ctx->d_func()->eglSurface + , EGL_SWAP_BEHAVIOR, &swapBehavior)) { + d_ptr->destructive_swap_buffers = (swapBehavior != EGL_BUFFER_PRESERVED); + } + } + + d_ptr->swap_region_support = haveNOKSwapRegion; #endif widgetPrivate->extraData()->glContext = ctx; @@ -528,6 +534,7 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, void QGLWindowSurface::beginPaint(const QRegion &) { d_ptr->did_paint = true; + updateGeometry(); if (!context()) return; @@ -600,7 +607,7 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint & // mistake to call swapBuffers if nothing was painted unless // EGL_BUFFER_PRESERVED is set. This check protects the flush func from // being executed if it's for nothing. - if (!hasPartialUpdateSupport() && !d_ptr->did_paint) + if (!d_ptr->destructive_swap_buffers && !d_ptr->did_paint) return; QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget(); @@ -676,12 +683,12 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint & } #endif bool doingPartialUpdate = false; - if (QGLWindowSurface::swapBehavior == QGLWindowSurface::AutomaticSwap) - doingPartialUpdate = hasPartialUpdateSupport() && br.width() * br.height() < parent->geometry().width() * parent->geometry().height() * 0.2; - else if (QGLWindowSurface::swapBehavior == QGLWindowSurface::AlwaysFullSwap) - doingPartialUpdate = false; - else if (QGLWindowSurface::swapBehavior == QGLWindowSurface::AlwaysPartialSwap) - doingPartialUpdate = hasPartialUpdateSupport(); + if (d_ptr->swap_region_support) { + if (QGLWindowSurface::swapBehavior == QGLWindowSurface::AutomaticSwap) + doingPartialUpdate = br.width() * br.height() < parent->geometry().width() * parent->geometry().height() * 0.2; + else if (QGLWindowSurface::swapBehavior == QGLWindowSurface::AlwaysPartialSwap) + doingPartialUpdate = true; + } QGLContext *ctx = reinterpret_cast<QGLContext *>(parent->d_func()->extraData()->glContext); if (widget != window()) { @@ -899,14 +906,22 @@ void QGLWindowSurface::updateGeometry() { ctx->d_func()->eglSurface = QEgl::createSurface(ctx->device(), ctx->d_func()->eglContext->config()); -#if !defined(QGL_NO_PRESERVED_SWAP) - eglGetError(); // Clear error state first. - eglSurfaceAttrib(QEgl::display(), ctx->d_func()->eglSurface, - EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); - if (eglGetError() != EGL_SUCCESS) { - qWarning("QGLWindowSurface: could not restore preserved swap behaviour"); + eglGetError(); // Clear error state. + if (!d_ptr->destructive_swap_buffers) { + eglSurfaceAttrib(ctx->d_func()->eglContext->display(), + ctx->d_func()->eglSurface, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLWindowSurface: could not enable preserved swap behaviour"); + } else { + eglSurfaceAttrib(ctx->d_func()->eglContext->display(), + ctx->d_func()->eglSurface, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLWindowSurface: could not enable destroyed swap behaviour"); } -#endif } #endif @@ -1136,7 +1151,15 @@ QImage *QGLWindowSurface::buffer(const QWidget *widget) return &d_ptr->buffers.last(); } - +QWindowSurface::WindowSurfaceFeatures QGLWindowSurface::features() const +{ + WindowSurfaceFeatures features = 0; + if (!d_ptr->destructive_swap_buffers || d_ptr->swap_region_support) + features |= PartialUpdates; + if (!d_ptr->destructive_swap_buffers) + features |= PreservedContents; + return features; +} QT_END_NAMESPACE diff --git a/src/opengl/qwindowsurface_gl_p.h b/src/opengl/qwindowsurface_gl_p.h index a8d8381..c71ce59 100644 --- a/src/opengl/qwindowsurface_gl_p.h +++ b/src/opengl/qwindowsurface_gl_p.h @@ -104,6 +104,8 @@ public: QImage *buffer(const QWidget *widget); + WindowSurfaceFeatures features() const; + QGLContext *context() const; static QGLFormat surfaceFormat; |