summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
authorJørgen Lind <jorgen.lind@nokia.com>2011-04-14 10:23:42 (GMT)
committerJørgen Lind <jorgen.lind@nokia.com>2011-04-14 10:23:42 (GMT)
commitb56444d86aa449e2da15d9b9fd08001f09ac9b25 (patch)
tree171f6c0be5cc1c2935f15757630c8583bf0b2dd9 /src/opengl
parent5f68933c9adbf2dc1d6150d5771c8443395d6780 (diff)
parent662174b78b7e08c759d0086e215e81e9e0eaf0c5 (diff)
downloadQt-b56444d86aa449e2da15d9b9fd08001f09ac9b25.zip
Qt-b56444d86aa449e2da15d9b9fd08001f09ac9b25.tar.gz
Qt-b56444d86aa449e2da15d9b9fd08001f09ac9b25.tar.bz2
Merge remote-tracking branch 'origin/master' into lighthouse-master
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp63
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp30
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h2
-rw-r--r--src/opengl/opengl.pro2
-rw-r--r--src/opengl/qgl.cpp79
-rw-r--r--src/opengl/qgl_egl.cpp34
-rw-r--r--src/opengl/qgl_p.h51
-rw-r--r--src/opengl/qgl_symbian.cpp197
-rw-r--r--src/opengl/qgl_x11egl.cpp13
-rw-r--r--src/opengl/qglframebufferobject.cpp4
-rw-r--r--src/opengl/qglfunctions.cpp4
-rw-r--r--src/opengl/qglpaintdevice.cpp2
-rw-r--r--src/opengl/qglpixelbuffer.cpp4
-rw-r--r--src/opengl/qgltexturepool.cpp7
-rw-r--r--src/opengl/qpixmapdata_gl.cpp4
-rw-r--r--src/opengl/qpixmapdata_gl_p.h19
-rw-r--r--src/opengl/qpixmapdata_poolgl.cpp156
-rw-r--r--src/opengl/qwindowsurface_gl.cpp69
-rw-r--r--src/opengl/qwindowsurface_gl_p.h2
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 &region)
eglContext->swapBuffersRegion2NOK(eglSurfaceForDevice(), &region);
}
+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;