summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@nokia.com>2011-03-17 13:21:42 (GMT)
committerOswald Buddenhagen <oswald.buddenhagen@nokia.com>2011-03-17 13:21:42 (GMT)
commit2e7a049ee698698842cd269f91d04044667c0487 (patch)
treec530637dbb144ec94f0a75f5ab7defb2f9d4f2c4 /src
parent65ae717b2c8fc979ccb30c967335999a6d90eb4f (diff)
parentcbf6c5b810316efba3ccfb27f05576b8dbfe3890 (diff)
downloadQt-2e7a049ee698698842cd269f91d04044667c0487.zip
Qt-2e7a049ee698698842cd269f91d04044667c0487.tar.gz
Qt-2e7a049ee698698842cd269f91d04044667c0487.tar.bz2
Merge remote-tracking branch 'mainline/master'
Diffstat (limited to 'src')
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflickable.cpp8
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview.cpp6
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview.cpp6
-rw-r--r--src/declarative/graphicsitems/qdeclarativerectangle.cpp4
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp63
-rw-r--r--src/gui/inputmethod/qcoefepinputcontext_s60.cpp3
-rw-r--r--src/gui/kernel/qdesktopwidget_s60.cpp14
-rw-r--r--src/gui/kernel/qwidget.cpp4
-rw-r--r--src/gui/painting/qgraphicssystem_runtime.cpp5
-rw-r--r--src/gui/painting/qpainterpath.cpp8
-rw-r--r--src/gui/styles/qs60style.cpp41
-rw-r--r--src/gui/styles/qs60style_p.h6
-rw-r--r--src/gui/styles/qs60style_s60.cpp16
-rw-r--r--src/gui/text/qtextlayout.cpp47
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp28
-rw-r--r--src/network/socket/qabstractsocket.cpp2
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp13
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp28
-rw-r--r--src/opengl/opengl.pro9
-rw-r--r--src/opengl/qgl.cpp18
-rw-r--r--src/opengl/qgl.h1
-rw-r--r--src/opengl/qgl_symbian.cpp1
-rw-r--r--src/opengl/qgltexturepool.cpp241
-rw-r--r--src/opengl/qgltexturepool_p.h147
-rw-r--r--src/opengl/qgraphicssystem_gl.cpp11
-rw-r--r--src/opengl/qgraphicssystem_gl_p.h4
-rw-r--r--src/opengl/qpixmapdata_gl_p.h42
-rw-r--r--src/opengl/qpixmapdata_poolgl.cpp902
-rw-r--r--src/opengl/qwindowsurface_gl.cpp81
-rw-r--r--src/plugins/graphicssystems/meego/qmeegographicssystem.cpp170
-rw-r--r--src/plugins/graphicssystems/meego/qmeegographicssystem.h18
-rw-r--r--src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp2
32 files changed, 1834 insertions, 115 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
index 1e2b70c..bfebff6 100644
--- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
@@ -1409,8 +1409,10 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
QGraphicsScene *s = scene();
QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
+ QGraphicsItem *grabberItem = s ? s->mouseGrabberItem() : 0;
+ bool disabledItem = grabberItem && !grabberItem->isEnabled();
bool stealThisEvent = d->stealMouse;
- if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
mouseEvent.setAccepted(false);
for (int i = 0x1; i <= 0x10; i <<= 1) {
if (event->buttons() & i) {
@@ -1457,12 +1459,12 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
break;
}
grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
- if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) {
+ if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || disabledItem) {
d->clearDelayedPress();
grabMouse();
}
- return stealThisEvent || d->delayedPressEvent;
+ return stealThisEvent || d->delayedPressEvent || disabledItem;
} else if (d->lastPosTime.isValid()) {
d->lastPosTime.invalidate();
}
diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp
index 5c2f781..c0cbed0 100644
--- a/src/declarative/graphicsitems/qdeclarativegridview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp
@@ -2834,11 +2834,9 @@ void QDeclarativeGridView::itemsInserted(int modelIndex, int count)
if (d->currentItem) {
d->currentItem->index = d->currentIndex;
d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
- } else if (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared)) {
- d->updateCurrent(0);
}
emit currentIndexChanged();
- } else if (d->itemCount == 0 && d->currentIndex == -1) {
+ } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
setCurrentIndex(0);
}
@@ -2906,6 +2904,8 @@ void QDeclarativeGridView::itemsRemoved(int modelIndex, int count)
d->currentIndex = -1;
if (d->itemCount)
d->updateCurrent(qMin(modelIndex, d->itemCount-1));
+ else
+ emit currentIndexChanged();
}
// update visibleIndex
diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp
index 2c23a1b..6ae1ddc 100644
--- a/src/declarative/graphicsitems/qdeclarativelistview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp
@@ -3272,10 +3272,10 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count)
if (d->currentItem) {
d->currentItem->index = d->currentIndex;
d->currentItem->setPosition(d->currentItem->position() + diff);
- } else if (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared)) {
- d->updateCurrent(0);
}
emit currentIndexChanged();
+ } else if (!d->itemCount && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
+ d->updateCurrent(0);
}
// Update the indexes of the following visible items.
for (; index < d->visibleItems.count(); ++index) {
@@ -3356,6 +3356,8 @@ void QDeclarativeListView::itemsRemoved(int modelIndex, int count)
d->currentIndex = -1;
if (d->itemCount)
d->updateCurrent(qMin(modelIndex, d->itemCount-1));
+ else
+ emit currentIndexChanged();
}
// update visibleIndex
diff --git a/src/declarative/graphicsitems/qdeclarativerectangle.cpp b/src/declarative/graphicsitems/qdeclarativerectangle.cpp
index d962919..8f59073 100644
--- a/src/declarative/graphicsitems/qdeclarativerectangle.cpp
+++ b/src/declarative/graphicsitems/qdeclarativerectangle.cpp
@@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE
void QDeclarativePen::setColor(const QColor &c)
{
_color = c;
- _valid = _color.alpha() ? true : false;
+ _valid = (_color.alpha() && _width >= 1) ? true : false;
emit penChanged();
}
@@ -80,7 +80,7 @@ void QDeclarativePen::setWidth(int w)
return;
_width = w;
- _valid = (_width < 1) ? false : true;
+ _valid = (_color.alpha() && _width >= 1) ? true : false;
emit penChanged();
}
diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp
index 2d551f2..781e1b8 100644
--- a/src/declarative/qml/qdeclarativevme.cpp
+++ b/src/declarative/qml/qdeclarativevme.cpp
@@ -127,6 +127,22 @@ void QDeclarativeVME::runDeferred(QObject *object)
run(stack, ctxt, comp, start, count, QBitField());
}
+inline bool fastHasBinding(QObject *o, int index)
+{
+ QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(o)->declarativeData);
+
+ return ddata && (ddata->bindingBitsSize > index) &&
+ (ddata->bindingBits[index / 32] & (1 << (index % 32)));
+}
+
+static void removeBindingOnProperty(QObject *o, int index)
+{
+ QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(o, index, -1, 0);
+ if (binding) binding->destroy();
+}
+
+#define CLEAN_PROPERTY(o, index) if (fastHasBinding(o, index)) removeBindingOnProperty(o, index)
+
QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
QDeclarativeContextData *ctxt,
QDeclarativeCompiledData *comp,
@@ -336,6 +352,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreVariant:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
+
// XXX - can be more efficient
QVariant v = QDeclarativeStringConverters::variantFromString(primitives.at(instr.storeString.value));
void *a[] = { &v, 0, &status, &flags };
@@ -347,6 +365,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreVariantInteger:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
+
QVariant v(instr.storeInteger.value);
void *a[] = { &v, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
@@ -357,6 +377,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreVariantDouble:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
+
QVariant v(instr.storeDouble.value);
void *a[] = { &v, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
@@ -367,6 +389,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreVariantBool:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
+
QVariant v(instr.storeBool.value);
void *a[] = { &v, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
@@ -377,6 +401,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreString:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeString.propertyIndex);
+
void *a[] = { (void *)&primitives.at(instr.storeString.value), 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.storeString.propertyIndex, a);
@@ -386,6 +412,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreUrl:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeUrl.propertyIndex);
+
void *a[] = { (void *)&urls.at(instr.storeUrl.value), 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.storeUrl.propertyIndex, a);
@@ -395,6 +423,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreFloat:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeFloat.propertyIndex);
+
float f = instr.storeFloat.value;
void *a[] = { &f, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
@@ -405,6 +435,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreDouble:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeDouble.propertyIndex);
+
double d = instr.storeDouble.value;
void *a[] = { &d, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
@@ -415,6 +447,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreBool:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeBool.propertyIndex);
+
void *a[] = { (void *)&instr.storeBool.value, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.storeBool.propertyIndex, a);
@@ -424,6 +458,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreInteger:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeInteger.propertyIndex);
+
void *a[] = { (void *)&instr.storeInteger.value, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
instr.storeInteger.propertyIndex, a);
@@ -433,6 +469,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreColor:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeColor.propertyIndex);
+
QColor c = QColor::fromRgba(instr.storeColor.value);
void *a[] = { &c, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
@@ -443,6 +481,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreDate:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeDate.propertyIndex);
+
QDate d = QDate::fromJulianDay(instr.storeDate.value);
void *a[] = { &d, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
@@ -453,6 +493,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreTime:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeTime.propertyIndex);
+
QTime t;
t.setHMS(intData.at(instr.storeTime.valueIndex),
intData.at(instr.storeTime.valueIndex+1),
@@ -467,6 +509,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreDateTime:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeDateTime.propertyIndex);
+
QTime t;
t.setHMS(intData.at(instr.storeDateTime.valueIndex+1),
intData.at(instr.storeDateTime.valueIndex+2),
@@ -482,6 +526,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StorePoint:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
+
QPoint p = QPointF(floatData.at(instr.storeRealPair.valueIndex),
floatData.at(instr.storeRealPair.valueIndex+1)).toPoint();
void *a[] = { &p, 0, &status, &flags };
@@ -493,6 +539,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StorePointF:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
+
QPointF p(floatData.at(instr.storeRealPair.valueIndex),
floatData.at(instr.storeRealPair.valueIndex+1));
void *a[] = { &p, 0, &status, &flags };
@@ -504,6 +552,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreSize:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
+
QSize p = QSizeF(floatData.at(instr.storeRealPair.valueIndex),
floatData.at(instr.storeRealPair.valueIndex+1)).toSize();
void *a[] = { &p, 0, &status, &flags };
@@ -515,6 +565,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreSizeF:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex);
+
QSizeF s(floatData.at(instr.storeRealPair.valueIndex),
floatData.at(instr.storeRealPair.valueIndex+1));
void *a[] = { &s, 0, &status, &flags };
@@ -526,6 +578,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreRect:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRect.propertyIndex);
+
QRect r = QRectF(floatData.at(instr.storeRect.valueIndex),
floatData.at(instr.storeRect.valueIndex+1),
floatData.at(instr.storeRect.valueIndex+2),
@@ -539,6 +593,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreRectF:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeRect.propertyIndex);
+
QRectF r(floatData.at(instr.storeRect.valueIndex),
floatData.at(instr.storeRect.valueIndex+1),
floatData.at(instr.storeRect.valueIndex+2),
@@ -552,6 +608,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::StoreVector3D:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeVector3D.propertyIndex);
+
QVector3D p(floatData.at(instr.storeVector3D.valueIndex),
floatData.at(instr.storeVector3D.valueIndex+1),
floatData.at(instr.storeVector3D.valueIndex+2));
@@ -565,6 +623,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
{
QObject *assignObj = stack.pop();
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeObject.propertyIndex);
void *a[] = { (void *)&assignObj, 0, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty,
@@ -576,6 +635,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
case QDeclarativeInstruction::AssignCustomType:
{
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.assignCustomType.propertyIndex);
+
QDeclarativeCompiledData::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex);
const QString &primitive = primitives.at(data.index);
QDeclarativeMetaType::StringConverter converter =
@@ -780,6 +841,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
{
QObject *assign = stack.pop();
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeObject.propertyIndex);
QVariant v = QVariant::fromValue(assign);
void *a[] = { &v, 0, &status, &flags };
@@ -792,6 +854,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack,
{
QObject *assign = stack.pop();
QObject *target = stack.top();
+ CLEAN_PROPERTY(target, instr.storeObject.propertyIndex);
int coreIdx = instr.storeObject.propertyIndex;
QMetaProperty prop = target->metaObject()->property(coreIdx);
diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp
index 73aa982..9d8dd41 100644
--- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp
+++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp
@@ -394,7 +394,8 @@ void QCoeFepInputContext::resetSplitViewWidget(bool keepInputWidget)
if (!alwaysResize) {
if (gv->scene()) {
- disconnect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget()));
+ if (gv->scene()->focusItem())
+ disconnect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget()));
QGraphicsItem *rootItem;
foreach (QGraphicsItem *item, gv->scene()->items()) {
if (!item->parentItem()) {
diff --git a/src/gui/kernel/qdesktopwidget_s60.cpp b/src/gui/kernel/qdesktopwidget_s60.cpp
index c3963f4..62a4d40 100644
--- a/src/gui/kernel/qdesktopwidget_s60.cpp
+++ b/src/gui/kernel/qdesktopwidget_s60.cpp
@@ -188,12 +188,14 @@ void QDesktopWidgetPrivate::cleanup()
void QDesktopWidgetPrivate::init_sys()
{
#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
- CWsScreenDevice *dev = S60->screenDevice(1);
- if (dev) {
- displayControl = static_cast<MDisplayControl *>(
- dev->GetInterface(MDisplayControl::ETypeId));
- if (displayControl) {
- displayControl->EnableDisplayChangeEvents(ETrue);
+ if (S60->screenCount() > 1) {
+ CWsScreenDevice *dev = S60->screenDevice(1);
+ if (dev) {
+ displayControl = static_cast<MDisplayControl *>(
+ dev->GetInterface(MDisplayControl::ETypeId));
+ if (displayControl) {
+ displayControl->EnableDisplayChangeEvents(ETrue);
+ }
}
}
#endif
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 37d7147..adb5fe1 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -1342,8 +1342,8 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
//give potential windows a bigger "pre-initial" size; create_sys() will give them a new size later
#ifdef Q_OS_SYMBIAN
if (isGLWidget) {
- // Don't waste GPU mem for unnecessary large egl surface
- data.crect = QRect(0,0,2,2);
+ // Don't waste GPU mem for unnecessary large egl surface until resized by application
+ data.crect = QRect(0,0,1,1);
} else {
data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,360,640);
}
diff --git a/src/gui/painting/qgraphicssystem_runtime.cpp b/src/gui/painting/qgraphicssystem_runtime.cpp
index 5841d40..33652ee 100644
--- a/src/gui/painting/qgraphicssystem_runtime.cpp
+++ b/src/gui/painting/qgraphicssystem_runtime.cpp
@@ -394,7 +394,10 @@ void QRuntimeGraphicsSystem::setGraphicsSystem(const QString &name)
if(m_windowSurfaceDestroyPolicy == DestroyAfterFirstFlush)
proxy->m_pendingWindowSurface.reset(proxy->m_windowSurface.take());
- proxy->m_windowSurface.reset(m_graphicsSystem->createWindowSurface(widget));
+ QWindowSurface *newWindowSurface = m_graphicsSystem->createWindowSurface(widget);
+ newWindowSurface->setGeometry(proxy->geometry());
+
+ proxy->m_windowSurface.reset(newWindowSurface);
qt_widget_private(widget)->invalidateBuffer(widget->rect());
}
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index 8bff021..49f1a5f 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -1724,7 +1724,7 @@ static void qt_painterpath_isect_line(const QPointF &p1,
}
static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
- int *winding)
+ int *winding, int depth = 0)
{
qreal y = pt.y();
qreal x = pt.x();
@@ -1739,7 +1739,7 @@ static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
// hit lower limit... This is a rough threshold, but its a
// tradeoff between speed and precision.
const qreal lower_bound = qreal(.001);
- if (bounds.width() < lower_bound && bounds.height() < lower_bound) {
+ if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) {
// We make the assumption here that the curve starts to
// approximate a line after while (i.e. that it doesn't
// change direction drastically during its slope)
@@ -1752,8 +1752,8 @@ static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
// split curve and try again...
QBezier first_half, second_half;
bezier.split(&first_half, &second_half);
- qt_painterpath_isect_curve(first_half, pt, winding);
- qt_painterpath_isect_curve(second_half, pt, winding);
+ qt_painterpath_isect_curve(first_half, pt, winding, depth + 1);
+ qt_painterpath_isect_curve(second_half, pt, winding, depth + 1);
}
}
diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp
index c107511..6a35027 100644
--- a/src/gui/styles/qs60style.cpp
+++ b/src/gui/styles/qs60style.cpp
@@ -118,6 +118,7 @@ const short *QS60StylePrivate::m_pmPointer = QS60StylePrivate::data[0];
// theme background texture
QPixmap *QS60StylePrivate::m_background = 0;
+QPixmap *QS60StylePrivate::m_placeHolderTexture = 0;
// theme palette
QPalette *QS60StylePrivate::m_themePalette = 0;
@@ -155,6 +156,10 @@ const double KTabFontMul = 0.72;
QS60StylePrivate::~QS60StylePrivate()
{
clearCaches(); //deletes also background image
+ if (m_placeHolderTexture) {
+ delete m_placeHolderTexture;
+ m_placeHolderTexture = 0;
+ }
deleteThemePalette();
#ifdef Q_WS_S60
removeAnimations();
@@ -505,7 +510,10 @@ void QS60StylePrivate::setBackgroundTexture(QApplication *app) const
{
Q_UNUSED(app)
QPalette applicationPalette = QApplication::palette();
- applicationPalette.setBrush(QPalette::Window, backgroundTexture());
+ // The initial QPalette::Window is just a placeHolder QPixmap to save RAM
+ // if the actual texture is not needed. The real texture is created just before
+ // painting it in qt_s60_fill_background().
+ applicationPalette.setBrush(QPalette::Window, placeHolderTexture());
setThemePalette(&applicationPalette);
}
@@ -630,25 +638,6 @@ QPixmap QS60StylePrivate::cachedFrame(SkinFrameElements frame, const QSize &size
return result;
}
-void QS60StylePrivate::refreshUI()
-{
- QList<QWidget *> widgets = QApplication::allWidgets();
-
- for (int i = 0; i < widgets.size(); ++i) {
- QWidget *widget = widgets.at(i);
- if (widget == 0)
- continue;
-
- if (widget->style()) {
- widget->style()->polish(widget);
- QEvent event(QEvent::StyleChange);
- qApp->sendEvent(widget, &event);
- }
- widget->update();
- widget->updateGeometry();
- }
-}
-
void QS60StylePrivate::setFont(QWidget *widget) const
{
QS60StyleEnums::FontCategories fontCategory = QS60StyleEnums::FC_Undefined;
@@ -719,8 +708,10 @@ void QS60StylePrivate::setThemePalette(QPalette *palette) const
palette->setColor(QPalette::LinkVisited, palette->color(QPalette::Link).darker());
palette->setColor(QPalette::Highlight,
s60Color(QS60StyleEnums::CL_QsnHighlightColors, 2, 0));
- // set background image as a texture brush
- palette->setBrush(QPalette::Window, backgroundTexture());
+ // The initial QPalette::Window is just a placeHolder QPixmap to save RAM
+ // if the actual texture is not needed. The real texture is created just before
+ // painting it in qt_s60_fill_background().
+ palette->setBrush(QPalette::Window, placeHolderTexture());
// set as transparent so that styled full screen theme background is visible
palette->setBrush(QPalette::Base, Qt::transparent);
// set button color based on pixel colors
@@ -3548,10 +3539,12 @@ extern QPoint qt_s60_fill_background_offset(const QWidget *targetWidget);
bool qt_s60_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush)
{
- const QPixmap backgroundTexture(QS60StylePrivate::backgroundTexture());
- if (backgroundTexture.cacheKey() != brush.texture().cacheKey())
+ const QPixmap placeHolder(QS60StylePrivate::placeHolderTexture());
+ if (placeHolder.cacheKey() != brush.texture().cacheKey())
return false;
+ const QPixmap backgroundTexture(QS60StylePrivate::backgroundTexture());
+
const QPaintDevice *target = painter->device();
if (target->devType() == QInternal::Widget) {
const QWidget *widget = static_cast<const QWidget *>(target);
diff --git a/src/gui/styles/qs60style_p.h b/src/gui/styles/qs60style_p.h
index 242c451..8c023bf 100644
--- a/src/gui/styles/qs60style_p.h
+++ b/src/gui/styles/qs60style_p.h
@@ -555,6 +555,7 @@ public:
static QPixmap frame(SkinFrameElements frame, const QSize &size,
SkinElementFlags flags = KDefaultSkinElementFlags);
static QPixmap backgroundTexture();
+ static QPixmap placeHolderTexture();
#ifdef Q_WS_S60
void handleDynamicLayoutVariantSwitch();
@@ -592,8 +593,6 @@ private:
static QPixmap cachedFrame(SkinFrameElements frame, const QSize &size,
SkinElementFlags flags = KDefaultSkinElementFlags);
- static void refreshUI();
-
// set S60 font for widget
void setFont(QWidget *widget) const;
void setThemePalette(QWidget *widget) const;
@@ -616,6 +615,9 @@ private:
// Contains background texture.
static QPixmap *m_background;
+ // Placeholder pixmap for the real background texture.
+ static QPixmap *m_placeHolderTexture;
+
const static SkinElementFlags KDefaultSkinElementFlags;
// defined theme palette
static QPalette *m_themePalette;
diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp
index 600c631..1ff195d 100644
--- a/src/gui/styles/qs60style_s60.cpp
+++ b/src/gui/styles/qs60style_s60.cpp
@@ -66,7 +66,6 @@
#include <aknnavi.h>
#include <gulicon.h>
#include <AknBitmapAnimation.h>
-
#include <centralrepository.h>
#if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN)
@@ -1408,12 +1407,23 @@ QPixmap QS60StylePrivate::backgroundTexture()
if (createNewBackground) {
QPixmap background = part(QS60StyleEnums::SP_QsnBgScreen,
- QSize(applicationRect.Width(), applicationRect.Height()), 0, SkinElementFlags());
+ QSize(applicationRect.Width(), applicationRect.Height()), 0, SkinElementFlags());
m_background = new QPixmap(background);
}
return *m_background;
}
+// Generates 1*1 red pixmap as a placeholder for real texture.
+// The actual theme texture is drawn in qt_s60_fill_background().
+QPixmap QS60StylePrivate::placeHolderTexture()
+{
+ if (!m_placeHolderTexture) {
+ m_placeHolderTexture = new QPixmap(1,1);
+ m_placeHolderTexture->fill(Qt::red);
+ }
+ return *m_placeHolderTexture;
+}
+
QSize QS60StylePrivate::screenSize()
{
return QSize(S60->screenWidthInPixels, S60->screenHeightInPixels);
@@ -1428,8 +1438,8 @@ QS60Style::QS60Style()
void QS60StylePrivate::handleDynamicLayoutVariantSwitch()
{
clearCaches(QS60StylePrivate::CC_LayoutChange);
+ setBackgroundTexture(qApp);
setActiveLayout();
- refreshUI();
foreach (QWidget *widget, QApplication::allWidgets())
widget->ensurePolished();
}
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index 354e8a9..8eff7d2 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -1754,6 +1754,7 @@ namespace {
int glyphCount;
int maxGlyphs;
int currentPosition;
+ glyph_t previousGlyph;
QFixed minw;
QFixed softHyphenWidth;
@@ -1781,6 +1782,15 @@ namespace {
return glyphs.glyphs[logClusters[currentPosition - 1]];
}
+ inline void saveCurrentGlyph()
+ {
+ previousGlyph = 0;
+ if (currentPosition > 0 &&
+ logClusters[currentPosition - 1] < glyphs.numGlyphs) {
+ previousGlyph = currentGlyph(); // needed to calculate right bearing later
+ }
+ }
+
inline void adjustRightBearing(glyph_t glyph)
{
qreal rb;
@@ -1795,6 +1805,12 @@ namespace {
adjustRightBearing(currentGlyph());
}
+ inline void adjustPreviousRightBearing()
+ {
+ if (previousGlyph > 0)
+ adjustRightBearing(previousGlyph);
+ }
+
inline void resetRightBearing()
{
rightBearing = QFixed(1); // Any positive number is defined as invalid since only
@@ -1871,22 +1887,7 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);
int item = -1;
- int newItem = -1;
- int left = 0;
- int right = eng->layoutData->items.size()-1;
- while(left <= right) {
- int middle = ((right-left)/2)+left;
- if (line.from > eng->layoutData->items[middle].position)
- left = middle+1;
- else if(line.from < eng->layoutData->items[middle].position)
- right = middle-1;
- else {
- newItem = middle;
- break;
- }
- }
- if (newItem == -1)
- newItem = right;
+ int newItem = eng->findItem(line.from);
LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal());
@@ -1898,6 +1899,7 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.currentPosition = line.from;
int end = 0;
lbh.logClusters = eng->layoutData->logClustersPtr;
+ lbh.previousGlyph = 0;
while (newItem < eng->layoutData->items.size()) {
lbh.resetRightBearing();
@@ -1958,6 +1960,7 @@ void QTextLine::layout_helper(int maxGlyphs)
current, lbh.logClusters, lbh.glyphs);
} else {
lbh.tmpData.length++;
+ lbh.adjustPreviousRightBearing();
}
line += lbh.tmpData;
goto found;
@@ -1988,9 +1991,7 @@ void QTextLine::layout_helper(int maxGlyphs)
} else {
lbh.whiteSpaceOrObject = false;
bool sb_or_ws = false;
- glyph_t previousGlyph = 0;
- if (lbh.currentPosition > 0 && lbh.logClusters[lbh.currentPosition - 1] <lbh.glyphs.numGlyphs)
- previousGlyph = lbh.currentGlyph(); // needed to calculate right bearing later
+ lbh.saveCurrentGlyph();
do {
addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
current, lbh.logClusters, lbh.glyphs);
@@ -2015,7 +2016,7 @@ void QTextLine::layout_helper(int maxGlyphs)
// b) if we are so short of available width that the
// soft hyphen is the first breakable position, then
// we don't want to show it. However we initially
- // have to take the width for it into accoun so that
+ // have to take the width for it into account so that
// the text document layout sees the overflow and
// switch to break-anywhere mode, in which we
// want the soft-hyphen to slip into the next line
@@ -2043,8 +2044,9 @@ void QTextLine::layout_helper(int maxGlyphs)
// we are too wide, fix right bearing
if (rightBearing <= 0)
lbh.rightBearing = rightBearing; // take from cache
- else if (previousGlyph > 0)
- lbh.adjustRightBearing(previousGlyph);
+ else
+ lbh.adjustPreviousRightBearing();
+
if (!breakany) {
line.textWidth += lbh.softHyphenWidth;
}
@@ -2052,6 +2054,7 @@ void QTextLine::layout_helper(int maxGlyphs)
goto found;
}
}
+ lbh.saveCurrentGlyph();
}
if (lbh.currentPosition == end)
newItem = item + 1;
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 23dd518..62c6fab 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -915,15 +915,18 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const
//private slots
void QHttpNetworkConnectionChannel::_q_readyRead()
{
- // We got a readyRead but no bytes are available..
- // This happens for the Unbuffered QTcpSocket
- // Also check if socket is in ConnectedState since
- // this function may also be invoked via the event loop.
if (socket->state() == QAbstractSocket::ConnectedState && socket->bytesAvailable() == 0) {
+ // We got a readyRead but no bytes are available..
+ // This happens for the Unbuffered QTcpSocket
+ // Also check if socket is in ConnectedState since
+ // this function may also be invoked via the event loop.
char c;
qint64 ret = socket->peek(&c, 1);
if (ret < 0) {
- socket->disconnectFromHost();
+ _q_error(socket->error());
+ // We still need to handle the reply so it emits its signals etc.
+ if (reply)
+ _q_receiveReply();
return;
}
}
@@ -1020,8 +1023,20 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
} else {
errorCode = QNetworkReply::RemoteHostClosedError;
}
+ } else if (state == QHttpNetworkConnectionChannel::ReadingState) {
+ if (!reply->d_func()->expectContent()) {
+ // No content expected, this is a valid way to have the connection closed by the server
+ return;
+ }
+ if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
+ // There was no content-length header and it's not chunked encoding,
+ // so this is a valid way to have the connection closed by the server
+ return;
+ }
+ // ok, we got a disconnect even though we did not expect it
+ errorCode = QNetworkReply::RemoteHostClosedError;
} else {
- return;
+ errorCode = QNetworkReply::RemoteHostClosedError;
}
break;
case QAbstractSocket::SocketTimeoutError:
@@ -1052,6 +1067,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
if (reply) {
reply->d_func()->errorString = errorString;
emit reply->finishedWithError(errorCode, errorString);
+ reply = 0;
}
// send the next request
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 2a942cc..c7c2e82 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -2210,6 +2210,8 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize)
} else if (readBytes < 0) {
d->socketError = d->socketEngine->error();
setErrorString(d->socketEngine->errorString());
+ d->resetSocketLayer();
+ d->state = QAbstractSocket::UnconnectedState;
} else if (!d->socketEngine->isReadNotificationEnabled()) {
// Only do this when there was no error
d->socketEngine->setReadNotificationEnabled(true);
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 3d7612a..c1b1712 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -325,9 +325,18 @@ init_context:
q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());
}
}
+
+ bool addExpiredCerts = true;
+#if defined(Q_OS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5)
+ //On Leopard SSL does not work if we add the expired certificates.
+ if (QSysInfo::MacintoshVersion == QSysInfo::MV_10_5)
+ addExpiredCerts = false;
+#endif
// now add the expired certs
- foreach (const QSslCertificate &caCertificate, expiredCerts) {
- q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());
+ if (addExpiredCerts) {
+ foreach (const QSslCertificate &caCertificate, expiredCerts) {
+ q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());
+ }
}
if (s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) {
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index fa38b5d..a134078 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -1349,11 +1349,14 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c
ensureActive();
d->transferMode(ImageDrawingMode);
+ QGLContext::BindOptions bindOptions = QGLContext::InternalBindOption|QGLContext::CanFlipNativePixmapBindOption;
+#ifdef QGL_USE_TEXTURE_POOL
+ bindOptions |= QGLContext::TemporarilyCachedBindOption;
+#endif
+
glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
QGLTexture *texture =
- ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
- QGLContext::InternalBindOption
- | QGLContext::CanFlipNativePixmapBindOption);
+ ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, bindOptions);
GLfloat top = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.top()) : src.top();
GLfloat bottom = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.bottom()) : src.bottom();
@@ -1365,6 +1368,12 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c
d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap);
+
+ if (texture->options&QGLContext::TemporarilyCachedBindOption) {
+ // pixmap was temporarily cached as a QImage texture by pooling system
+ // and should be destroyed immediately
+ QGLTextureCache::instance()->remove(ctx, texture->id);
+ }
}
void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src,
@@ -1389,12 +1398,23 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const
glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
- QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
+ QGLContext::BindOptions bindOptions = QGLContext::InternalBindOption;
+#ifdef QGL_USE_TEXTURE_POOL
+ bindOptions |= QGLContext::TemporarilyCachedBindOption;
+#endif
+
+ QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, bindOptions);
GLuint id = texture->id;
d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
state()->renderHints & QPainter::SmoothPixmapTransform, id);
d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel());
+
+ if (texture->options&QGLContext::TemporarilyCachedBindOption) {
+ // image was temporarily cached by texture pooling system
+ // and should be destroyed immediately
+ QGLTextureCache::instance()->remove(ctx, texture->id);
+ }
}
void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem)
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index 08ae774..b512146 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -157,11 +157,16 @@ embedded {
}
symbian {
+ DEFINES += QGL_USE_TEXTURE_POOL
+ SOURCES -= qpixmapdata_gl.cpp
SOURCES += qgl_symbian.cpp \
+ qpixmapdata_poolgl.cpp \
qglpixelbuffer_egl.cpp \
- qgl_egl.cpp
+ qgl_egl.cpp \
+ qgltexturepool.cpp
- HEADERS += qgl_egl_p.h
+ HEADERS += qgl_egl_p.h \
+ qgltexturepool_p.h
contains(QT_CONFIG, freetype) {
DEFINES += QT_NO_FONTCONFIG
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 76621e9..a769f2c 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -100,6 +100,9 @@
#ifdef QT_OPENGL_ES
#include <EGL/egl.h>
#endif
+#ifdef QGL_USE_TEXTURE_POOL
+#include <private/qgltexturepool_p.h>
+#endif
// #define QT_GL_CONTEXT_RESOURCE_DEBUG
@@ -2033,6 +2036,10 @@ struct DDSFormat {
the pixmap/image that it stems from, e.g. installing destruction
hooks in them.
+ \omitvalue TemporarilyCachedBindOption Used by paint engines on some
+ platforms to indicate that the pixmap or image texture is possibly
+ cached only temporarily and must be destroyed immediately after the use.
+
\omitvalue InternalBindOption
*/
@@ -2537,8 +2544,18 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
#endif
const QImage &constRef = img; // to avoid detach in bits()...
+#ifdef QGL_USE_TEXTURE_POOL
+ QGLTexturePool::instance()->createPermanentTexture(tx_id,
+ target,
+ 0, internalFormat,
+ img.width(), img.height(),
+ externalFormat,
+ pixel_type,
+ constRef.bits());
+#else
glTexImage2D(target, 0, internalFormat, img.width(), img.height(), 0, externalFormat,
pixel_type, constRef.bits());
+#endif
#if defined(QT_OPENGL_ES_2)
if (genMipmap)
glGenerateMipmap(target);
@@ -2577,7 +2594,6 @@ QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum targe
return 0;
}
-
/*! \internal */
QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, QGLContext::BindOptions options)
{
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index 9a51a77..ff73d88 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -333,6 +333,7 @@ public:
MemoryManagedBindOption = 0x0010, // internal flag
CanFlipNativePixmapBindOption = 0x0020, // internal flag
+ TemporarilyCachedBindOption = 0x0040, // internal flag
DefaultBindOption = LinearFilteringBindOption
| InvertedYBindOption
diff --git a/src/opengl/qgl_symbian.cpp b/src/opengl/qgl_symbian.cpp
index a9e2248..2978514 100644
--- a/src/opengl/qgl_symbian.cpp
+++ b/src/opengl/qgl_symbian.cpp
@@ -52,6 +52,7 @@
#include <private/qwidget_p.h> // to access QWExtra
#include "qgl_egl_p.h"
#include "qpixmapdata_gl_p.h"
+#include "qgltexturepool_p.h"
#include "qcolormap.h"
#include <QDebug>
diff --git a/src/opengl/qgltexturepool.cpp b/src/opengl/qgltexturepool.cpp
new file mode 100644
index 0000000..61a88c3
--- /dev/null
+++ b/src/opengl/qgltexturepool.cpp
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenVG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgltexturepool_p.h"
+#include "qpixmapdata_gl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_OPENGL_EXPORT extern QGLWidget* qt_gl_share_widget();
+
+static QGLTexturePool *qt_gl_texture_pool = 0;
+
+class QGLTexturePoolPrivate
+{
+public:
+ QGLTexturePoolPrivate() : lruFirst(0), lruLast(0) {}
+
+ QGLPixmapData *lruFirst;
+ QGLPixmapData *lruLast;
+};
+
+QGLTexturePool::QGLTexturePool()
+ : d_ptr(new QGLTexturePoolPrivate())
+{
+}
+
+QGLTexturePool::~QGLTexturePool()
+{
+}
+
+QGLTexturePool *QGLTexturePool::instance()
+{
+ if (!qt_gl_texture_pool)
+ qt_gl_texture_pool = new QGLTexturePool();
+ return qt_gl_texture_pool;
+}
+
+GLuint QGLTexturePool::createTextureForPixmap(GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ QGLPixmapData *data)
+{
+ GLuint texture;
+ glGenTextures(1, &texture);
+ glBindTexture(target, texture);
+ do {
+ glTexImage2D(target, level, internalformat, width, height, 0, format, type, 0);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ if (data)
+ moveToHeadOfLRU(data);
+ return texture;
+ } else if (error != GL_OUT_OF_MEMORY) {
+ qWarning("QGLTexturePool: cannot create temporary texture because of invalid params");
+ return 0;
+ }
+ } while (reclaimSpace(internalformat, width, height, format, type, data));
+ qWarning("QGLTexturePool: cannot reclaim sufficient space for a %dx%d pixmap",
+ width, height);
+ return 0;
+}
+
+bool QGLTexturePool::createPermanentTexture(GLuint texture,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const GLvoid *data)
+{
+ glBindTexture(target, texture);
+ do {
+ glTexImage2D(target, level, internalformat, width, height, 0, format, type, data);
+
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ return true;
+ } else if (error != GL_OUT_OF_MEMORY) {
+ qWarning("QGLTexturePool: cannot create permanent texture because of invalid params");
+ return false;
+ }
+ } while (reclaimSpace(internalformat, width, height, format, type, 0));
+ qWarning("QGLTexturePool: cannot reclaim sufficient space for a %dx%d pixmap",
+ width, height);
+ return 0;
+}
+
+void QGLTexturePool::releaseTexture(QGLPixmapData *data, GLuint texture)
+{
+ // Very simple strategy at the moment: just destroy the texture.
+ if (data)
+ removeFromLRU(data);
+
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ glDeleteTextures(1, &texture);
+}
+
+void QGLTexturePool::useTexture(QGLPixmapData *data)
+{
+ moveToHeadOfLRU(data);
+}
+
+void QGLTexturePool::detachTexture(QGLPixmapData *data)
+{
+ removeFromLRU(data);
+}
+
+bool QGLTexturePool::reclaimSpace(GLint internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ QGLPixmapData *data)
+{
+ Q_UNUSED(internalformat); // For future use in picking the best texture to eject.
+ Q_UNUSED(width);
+ Q_UNUSED(height);
+ Q_UNUSED(format);
+ Q_UNUSED(type);
+
+ bool succeeded = false;
+ bool wasInLRU = false;
+ if (data) {
+ wasInLRU = data->inLRU;
+ moveToHeadOfLRU(data);
+ }
+
+ QGLPixmapData *lrudata = pixmapLRU();
+ if (lrudata && lrudata != data) {
+ lrudata->reclaimTexture();
+ succeeded = true;
+ }
+
+ if (data && !wasInLRU)
+ removeFromLRU(data);
+
+ return succeeded;
+}
+
+void QGLTexturePool::hibernate()
+{
+ Q_D(QGLTexturePool);
+ QGLPixmapData *pd = d->lruLast;
+ while (pd) {
+ QGLPixmapData *prevLRU = pd->prevLRU;
+ pd->inTexturePool = false;
+ pd->inLRU = false;
+ pd->nextLRU = 0;
+ pd->prevLRU = 0;
+ pd->hibernate();
+ pd = prevLRU;
+ }
+ d->lruFirst = 0;
+ d->lruLast = 0;
+}
+
+void QGLTexturePool::moveToHeadOfLRU(QGLPixmapData *data)
+{
+ Q_D(QGLTexturePool);
+ if (data->inLRU) {
+ if (!data->prevLRU)
+ return; // Already at the head of the list.
+ removeFromLRU(data);
+ }
+ data->inLRU = true;
+ data->nextLRU = d->lruFirst;
+ data->prevLRU = 0;
+ if (d->lruFirst)
+ d->lruFirst->prevLRU = data;
+ else
+ d->lruLast = data;
+ d->lruFirst = data;
+}
+
+void QGLTexturePool::removeFromLRU(QGLPixmapData *data)
+{
+ Q_D(QGLTexturePool);
+ if (!data->inLRU)
+ return;
+ if (data->nextLRU)
+ data->nextLRU->prevLRU = data->prevLRU;
+ else
+ d->lruLast = data->prevLRU;
+ if (data->prevLRU)
+ data->prevLRU->nextLRU = data->nextLRU;
+ else
+ d->lruFirst = data->nextLRU;
+ data->inLRU = false;
+}
+
+QGLPixmapData *QGLTexturePool::pixmapLRU()
+{
+ Q_D(QGLTexturePool);
+ return d->lruLast;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qgltexturepool_p.h b/src/opengl/qgltexturepool_p.h
new file mode 100644
index 0000000..8b6f726
--- /dev/null
+++ b/src/opengl/qgltexturepool_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenVG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLTEXTUREPOOL_P_H
+#define QGLTEXTUREPOOL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qgl.h"
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLPixmapData;
+class QGLTexturePoolPrivate;
+
+class QGLTexturePool
+{
+public:
+ QGLTexturePool();
+ virtual ~QGLTexturePool();
+
+ static QGLTexturePool *instance();
+
+ // Create a new texture with the specified parameters and associate
+ // it with "data". The QGLPixmapData will be notified when the
+ // texture needs to be reclaimed by the pool.
+ //
+ // This function will call reclaimSpace() when texture creation fails.
+ GLuint createTextureForPixmap(GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ QGLPixmapData *data);
+
+ // Create a permanent texture with the specified parameters.
+ // If there is insufficient space for the texture,
+ // then this function will call reclaimSpace() and try again.
+ //
+ // The caller is responsible for calling glDeleteTextures()
+ // when it no longer needs the texture, as the texture is not
+ // recorded in the texture pool.
+ bool createPermanentTexture(GLuint texture,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const GLvoid *data);
+
+ // Release a texture that is no longer required.
+ void releaseTexture(QGLPixmapData *data, GLuint texture);
+
+ // Notify the pool that a QGLPixmapData object is using
+ // an texture again. This allows the pool to move the texture
+ // within a least-recently-used list of QGLPixmapData objects.
+ void useTexture(QGLPixmapData *data);
+
+ // Notify the pool that the texture associated with a
+ // QGLPixmapData is being detached from the pool. The caller
+ // will become responsible for calling glDeleteTextures().
+ void detachTexture(QGLPixmapData *data);
+
+ // Reclaim space for an image allocation with the specified parameters.
+ // Returns true if space was reclaimed, or false if there is no
+ // further space that can be reclaimed. The "data" parameter
+ // indicates the pixmap that is trying to obtain space which should
+ // not itself be reclaimed.
+ bool reclaimSpace(GLint internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ QGLPixmapData *data);
+
+ // Hibernate the image pool because the context is about to be
+ // destroyed. All textures left in the pool should be released.
+ void hibernate();
+
+protected:
+ // Helper functions for managing the LRU list of QGLPixmapData objects.
+ void moveToHeadOfLRU(QGLPixmapData *data);
+ void removeFromLRU(QGLPixmapData *data);
+ QGLPixmapData *pixmapLRU();
+
+private:
+ QScopedPointer<QGLTexturePoolPrivate> d_ptr;
+
+ Q_DECLARE_PRIVATE(QGLTexturePool)
+ Q_DISABLE_COPY(QGLTexturePool)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/opengl/qgraphicssystem_gl.cpp b/src/opengl/qgraphicssystem_gl.cpp
index 3574756..0aa3c2e 100644
--- a/src/opengl/qgraphicssystem_gl.cpp
+++ b/src/opengl/qgraphicssystem_gl.cpp
@@ -57,6 +57,10 @@
#include <QtGui/private/qapplication_p.h>
#endif
+#ifdef QGL_USE_TEXTURE_POOL
+#include "private/qgltexturepool_p.h"
+#endif
+
QT_BEGIN_NAMESPACE
extern QGLWidget *qt_gl_getShareWidget();
@@ -100,6 +104,11 @@ QWindowSurface *QGLGraphicsSystem::createWindowSurface(QWidget *widget) const
return new QGLWindowSurface(widget);
}
-
+#ifdef QGL_USE_TEXTURE_POOL
+void QGLGraphicsSystem::releaseCachedResources()
+{
+ QGLTexturePool::instance()->hibernate();
+}
+#endif
QT_END_NAMESPACE
diff --git a/src/opengl/qgraphicssystem_gl_p.h b/src/opengl/qgraphicssystem_gl_p.h
index 4630da1..5829dcc 100644
--- a/src/opengl/qgraphicssystem_gl_p.h
+++ b/src/opengl/qgraphicssystem_gl_p.h
@@ -66,6 +66,10 @@ public:
QPixmapData *createPixmapData(QPixmapData::PixelType type) const;
QWindowSurface *createWindowSurface(QWidget *widget) const;
+
+#ifdef QGL_USE_TEXTURE_POOL
+ void releaseCachedResources();
+#endif
private:
bool m_useX11GL;
};
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index a4066fd..55cc29d 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -66,6 +66,12 @@ class QGLFramebufferObject;
class QGLFramebufferObjectFormat;
class QGLPixmapData;
+#ifdef QGL_USE_TEXTURE_POOL
+void qt_gl_register_pixmap(QGLPixmapData *pd);
+void qt_gl_unregister_pixmap(QGLPixmapData *pd);
+void qt_gl_hibernate_pixmaps();
+#endif
+
class QGLFramebufferObjectPool
{
public:
@@ -129,7 +135,24 @@ public:
GLuint bind(bool copyBack = true) const;
QGLTexture *texture() const;
-#if defined(Q_OS_SYMBIAN)
+#ifdef QGL_USE_TEXTURE_POOL
+ void destroyTexture();
+ // Detach this image from the image pool.
+ void detachTextureFromPool();
+ // Release the GL resources associated with this pixmap and copy
+ // the pixmap's contents out of the GPU back into main memory.
+ // The GL resource will be automatically recreated the next time
+ // ensureCreated() is called. Does nothing if the pixmap cannot be
+ // hibernated for some reason (e.g. texture is shared with another
+ // process via a SgImage).
+ void hibernate();
+ // Called when the QGLTexturePool wants to reclaim this pixmap's
+ // texture objects to reuse storage.
+ void reclaimTexture();
+ void forceToImage();
+#endif
+
+#ifdef Q_OS_SYMBIAN
void* toNativeType(NativeType type);
void fromNativeType(void* pixmap, NativeType type);
#endif
@@ -176,6 +199,23 @@ private:
mutable QGLPixmapGLPaintDevice m_glDevice;
+#ifdef QGL_USE_TEXTURE_POOL
+ QGLPixmapData *nextLRU;
+ QGLPixmapData *prevLRU;
+ mutable bool inLRU;
+ mutable bool failedToAlloc;
+ mutable bool inTexturePool;
+
+ QGLPixmapData *next;
+ QGLPixmapData *prev;
+
+ friend class QGLTexturePool;
+
+ friend void qt_gl_register_pixmap(QGLPixmapData *pd);
+ friend void qt_gl_unregister_pixmap(QGLPixmapData *pd);
+ friend void qt_gl_hibernate_pixmaps();
+#endif
+
friend class QGLPixmapGLPaintDevice;
friend class QMeeGoPixmapData;
friend class QMeeGoLivePixmapData;
diff --git a/src/opengl/qpixmapdata_poolgl.cpp b/src/opengl/qpixmapdata_poolgl.cpp
new file mode 100644
index 0000000..f1220b1
--- /dev/null
+++ b/src/opengl/qpixmapdata_poolgl.cpp
@@ -0,0 +1,902 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpixmap.h"
+#include "qglframebufferobject.h"
+
+#include <private/qpaintengine_raster_p.h>
+
+#include "qpixmapdata_gl_p.h"
+
+#include <private/qgl_p.h>
+#include <private/qdrawhelper_p.h>
+#include <private/qimage_p.h>
+
+#include <private/qpaintengineex_opengl2_p.h>
+
+#include <qdesktopwidget.h>
+#include <qfile.h>
+#include <qimagereader.h>
+#include <qbuffer.h>
+
+#include "qgltexturepool_p.h"
+
+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());
+}
+
+extern int qt_next_power_of_two(int v);
+
+static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz)
+{
+#ifdef QT_OPENGL_ES_2
+ QSize rounded(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height()));
+ if (rounded.width() * rounded.height() < 1.20 * sz.width() * sz.height())
+ return rounded;
+#endif
+ return sz;
+}
+
+
+QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize)
+{
+ QGLFramebufferObject *chosen = 0;
+ QGLFramebufferObject *candidate = 0;
+ for (int i = 0; !chosen && i < m_fbos.size(); ++i) {
+ QGLFramebufferObject *fbo = m_fbos.at(i);
+
+ if (strictSize) {
+ if (fbo->size() == requestSize && fbo->format() == requestFormat) {
+ chosen = fbo;
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ if (fbo->format() == requestFormat) {
+ // choose the fbo with a matching format and the closest size
+ if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo))
+ candidate = fbo;
+ }
+
+ if (candidate) {
+ m_fbos.removeOne(candidate);
+
+ const QSize fboSize = candidate->size();
+ QSize sz = fboSize;
+
+ if (sz.width() < requestSize.width())
+ sz.setWidth(qMax(requestSize.width(), qRound(sz.width() * 1.5)));
+ if (sz.height() < requestSize.height())
+ sz.setHeight(qMax(requestSize.height(), qRound(sz.height() * 1.5)));
+
+ // wasting too much space?
+ if (sz.width() * sz.height() > requestSize.width() * requestSize.height() * 4)
+ sz = requestSize;
+
+ if (sz != fboSize) {
+ delete candidate;
+ candidate = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(sz), requestFormat);
+ }
+
+ chosen = candidate;
+ }
+ }
+
+ if (!chosen) {
+ if (strictSize)
+ chosen = new QGLFramebufferObject(requestSize, requestFormat);
+ else
+ chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat);
+ }
+
+ if (!chosen->isValid()) {
+ delete chosen;
+ chosen = 0;
+ }
+
+ return chosen;
+}
+
+void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo)
+{
+ if (fbo)
+ m_fbos << fbo;
+}
+
+
+QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const
+{
+ return data->paintEngine();
+}
+
+void QGLPixmapGLPaintDevice::beginPaint()
+{
+ if (!data->isValid())
+ return;
+
+ // QGLPaintDevice::beginPaint will store the current binding and replace
+ // it with m_thisFBO:
+ m_thisFBO = data->m_renderFbo->handle();
+ QGLPaintDevice::beginPaint();
+
+ Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2);
+
+ // QPixmap::fill() is deferred until now, where we actually need to do the fill:
+ if (data->needsFill()) {
+ const QColor &c = data->fillColor();
+ float alpha = c.alphaF();
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ else if (!data->isUninitialized()) {
+ // If the pixmap (GL Texture) has valid content (it has been
+ // uploaded from an image or rendered into before), we need to
+ // copy it from the texture to the render FBO.
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+
+#if !defined(QT_OPENGL_ES_2)
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, data->width(), data->height(), 0, -999999, 999999);
+#endif
+
+ glViewport(0, 0, data->width(), data->height());
+
+ // Pass false to bind so it doesn't copy the FBO into the texture!
+ context()->drawTexture(QRect(0, 0, data->width(), data->height()), data->bind(false));
+ }
+}
+
+void QGLPixmapGLPaintDevice::endPaint()
+{
+ if (!data->isValid())
+ return;
+
+ data->copyBackFromRenderFbo(false);
+
+ // Base's endPaint will restore the previous FBO binding
+ QGLPaintDevice::endPaint();
+
+ qgl_fbo_pool()->release(data->m_renderFbo);
+ data->m_renderFbo = 0;
+}
+
+QGLContext* QGLPixmapGLPaintDevice::context() const
+{
+ data->ensureCreated();
+ return data->m_ctx;
+}
+
+QSize QGLPixmapGLPaintDevice::size() const
+{
+ return data->size();
+}
+
+bool QGLPixmapGLPaintDevice::alphaRequested() const
+{
+ return data->m_hasAlpha;
+}
+
+void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d)
+{
+ data = d;
+}
+
+static int qt_gl_pixmap_serial = 0;
+
+QGLPixmapData::QGLPixmapData(PixelType type)
+ : QPixmapData(type, OpenGLClass)
+ , m_renderFbo(0)
+ , m_engine(0)
+ , m_ctx(0)
+ , m_dirty(false)
+ , m_hasFillColor(false)
+ , m_hasAlpha(false)
+ , inLRU(false)
+ , failedToAlloc(false)
+ , inTexturePool(false)
+{
+ setSerialNumber(++qt_gl_pixmap_serial);
+ m_glDevice.setPixmapData(this);
+
+ qt_gl_register_pixmap(this);
+}
+
+QGLPixmapData::~QGLPixmapData()
+{
+ delete m_engine;
+
+ destroyTexture();
+ qt_gl_unregister_pixmap(this);
+}
+
+void QGLPixmapData::destroyTexture()
+{
+ if (inTexturePool) {
+ QGLTexturePool *pool = QGLTexturePool::instance();
+ if (m_texture.id)
+ pool->releaseTexture(this, m_texture.id);
+ } else {
+ if (m_texture.id) {
+ QGLWidget *shareWidget = qt_gl_share_widget();
+ if (shareWidget) {
+ QGLShareContextScope ctx(shareWidget->context());
+ glDeleteTextures(1, &m_texture.id);
+ }
+ }
+ }
+ m_texture.id = 0;
+ inTexturePool = false;
+}
+
+QPixmapData *QGLPixmapData::createCompatiblePixmapData() const
+{
+ return new QGLPixmapData(pixelType());
+}
+
+bool QGLPixmapData::isValid() const
+{
+ return w > 0 && h > 0;
+}
+
+bool QGLPixmapData::isValidContext(const QGLContext *ctx) const
+{
+ if (ctx == m_ctx)
+ return true;
+
+ const QGLContext *share_ctx = qt_gl_share_widget()->context();
+ return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx);
+}
+
+void QGLPixmapData::resize(int width, int height)
+{
+ if (width == w && height == h)
+ return;
+
+ if (width <= 0 || height <= 0) {
+ width = 0;
+ height = 0;
+ }
+
+ w = width;
+ h = height;
+ is_null = (w <= 0 || h <= 0);
+ d = pixelType() == QPixmapData::PixmapType ? 32 : 1;
+
+ destroyTexture();
+
+ m_source = QImage();
+ m_dirty = isValid();
+ setSerialNumber(++qt_gl_pixmap_serial);
+}
+
+void QGLPixmapData::ensureCreated() const
+{
+ if (!m_dirty)
+ return;
+
+ m_dirty = false;
+
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ m_ctx = ctx;
+
+ const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB;
+#ifdef QT_OPENGL_ES_2
+ const GLenum external_format = internal_format;
+#else
+ const GLenum external_format = qt_gl_preferredTextureFormat();
+#endif
+ const GLenum target = GL_TEXTURE_2D;
+
+ m_texture.options &= ~QGLContext::MemoryManagedBindOption;
+
+ if (!m_texture.id) {
+ m_texture.id = QGLTexturePool::instance()->createTextureForPixmap(
+ target,
+ 0, internal_format,
+ w, h,
+ external_format,
+ GL_UNSIGNED_BYTE,
+ const_cast<QGLPixmapData*>(this));
+ if (!m_texture.id) {
+ failedToAlloc = true;
+ return;
+ }
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ inTexturePool = true;
+ } else if (inTexturePool) {
+ glBindTexture(target, m_texture.id);
+ QGLTexturePool::instance()->useTexture(const_cast<QGLPixmapData*>(this));
+ }
+
+ if (!m_source.isNull() && m_texture.id) {
+ if (external_format == GL_RGB) {
+ const QImage tx = m_source.convertToFormat(QImage::Format_RGB888).mirrored(false, true);
+
+ glBindTexture(target, m_texture.id);
+ glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
+ GL_UNSIGNED_BYTE, tx.bits());
+ } else {
+ // do byte swizzling ARGB -> RGBA
+ const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, external_format);
+ glBindTexture(target, m_texture.id);
+ glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
+ GL_UNSIGNED_BYTE, tx.bits());
+ }
+
+ if (useFramebufferObjects())
+ m_source = QImage();
+ }
+}
+
+
+void QGLPixmapData::fromImage(const QImage &image,
+ Qt::ImageConversionFlags flags)
+{
+ QImage img = image;
+ createPixmapForImage(img, flags, false);
+}
+
+void QGLPixmapData::fromImageReader(QImageReader *imageReader,
+ Qt::ImageConversionFlags flags)
+{
+ QImage image = imageReader->read();
+ if (image.isNull())
+ return;
+
+ createPixmapForImage(image, flags, true);
+}
+
+bool QGLPixmapData::fromFile(const QString &filename, const char *format,
+ Qt::ImageConversionFlags flags)
+{
+ if (pixelType() == QPixmapData::BitmapType)
+ return QPixmapData::fromFile(filename, format, flags);
+ QFile file(filename);
+ if (file.open(QIODevice::ReadOnly)) {
+ QByteArray data = file.peek(64);
+ bool alpha;
+ if (m_texture.canBindCompressedTexture
+ (data.constData(), data.size(), format, &alpha)) {
+ resize(0, 0);
+ data = file.readAll();
+ file.close();
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ QSize size = m_texture.bindCompressedTexture
+ (data.constData(), data.size(), format);
+ if (!size.isEmpty()) {
+ w = size.width();
+ h = size.height();
+ is_null = false;
+ d = 32;
+ m_hasAlpha = alpha;
+ m_source = QImage();
+ m_dirty = isValid();
+ return true;
+ }
+ return false;
+ }
+ }
+
+ QImage image = QImageReader(filename, format).read();
+ if (image.isNull())
+ return false;
+
+ createPixmapForImage(image, flags, true);
+
+ return !isNull();
+}
+
+bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format,
+ Qt::ImageConversionFlags flags)
+{
+ bool alpha;
+ const char *buf = reinterpret_cast<const char *>(buffer);
+ if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) {
+ resize(0, 0);
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ QSize size = m_texture.bindCompressedTexture(buf, int(len), format);
+ if (!size.isEmpty()) {
+ w = size.width();
+ h = size.height();
+ is_null = false;
+ d = 32;
+ m_hasAlpha = alpha;
+ m_source = QImage();
+ m_dirty = isValid();
+ return true;
+ }
+ }
+
+ QByteArray a = QByteArray::fromRawData(reinterpret_cast<const char *>(buffer), len);
+ QBuffer b(&a);
+ b.open(QIODevice::ReadOnly);
+ QImage image = QImageReader(&b, format).read();
+ if (image.isNull())
+ return false;
+
+ createPixmapForImage(image, flags, true);
+
+ return !isNull();
+}
+
+/*!
+ out-of-place conversion (inPlace == false) will always detach()
+ */
+void QGLPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace)
+{
+ if (image.size() == QSize(w, h))
+ setSerialNumber(++qt_gl_pixmap_serial);
+
+ resize(image.width(), image.height());
+
+ if (pixelType() == BitmapType) {
+ m_source = image.convertToFormat(QImage::Format_MonoLSB);
+
+ } else {
+ 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;
+
+ if (inPlace && image.data_ptr()->convertInPlace(format, flags)) {
+ m_source = image;
+ } else {
+ m_source = image.convertToFormat(format);
+
+ // convertToFormat won't detach the image if format stays the same.
+ if (image.format() == format)
+ m_source.detach();
+ }
+ }
+
+ m_dirty = true;
+ m_hasFillColor = false;
+
+ m_hasAlpha = m_source.hasAlphaChannel();
+ w = image.width();
+ h = image.height();
+ is_null = (w <= 0 || h <= 0);
+ d = m_source.depth();
+
+ destroyTexture();
+}
+
+bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect)
+{
+ Q_UNUSED(dx);
+ Q_UNUSED(dy);
+ Q_UNUSED(rect);
+ return false;
+}
+
+void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect)
+{
+ if (data->classId() != QPixmapData::OpenGLClass || !static_cast<const QGLPixmapData *>(data)->useFramebufferObjects()) {
+ QPixmapData::copy(data, rect);
+ return;
+ }
+
+ const QGLPixmapData *other = static_cast<const QGLPixmapData *>(data);
+ if (other->m_renderFbo) {
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+
+ resize(rect.width(), rect.height());
+ m_hasAlpha = other->m_hasAlpha;
+ ensureCreated();
+
+ if (!ctx->d_ptr->fbo)
+ glGenFramebuffers(1, &ctx->d_ptr->fbo);
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, m_texture.id, 0);
+
+ if (!other->m_renderFbo->isBound())
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, other->m_renderFbo->handle());
+
+ glDisable(GL_SCISSOR_TEST);
+ if (ctx->d_ptr->active_engine && ctx->d_ptr->active_engine->type() == QPaintEngine::OpenGL2)
+ static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine)->invalidateState();
+
+ glBlitFramebufferEXT(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height(),
+ 0, 0, w, h,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
+ } else {
+ QPixmapData::copy(data, rect);
+ }
+}
+
+void QGLPixmapData::fill(const QColor &color)
+{
+ if (!isValid())
+ return;
+
+ bool hasAlpha = color.alpha() != 255;
+ if (hasAlpha && !m_hasAlpha) {
+ if (m_texture.id) {
+ destroyTexture();
+ m_dirty = true;
+ }
+ m_hasAlpha = color.alpha() != 255;
+ }
+
+ if (useFramebufferObjects()) {
+ m_source = QImage();
+ m_hasFillColor = true;
+ m_fillColor = color;
+ } else {
+
+ if (m_source.isNull()) {
+ m_fillColor = color;
+ m_hasFillColor = true;
+
+ } else if (m_source.depth() == 32) {
+ m_source.fill(PREMUL(color.rgba()));
+
+ } else if (m_source.depth() == 1) {
+ if (color == Qt::color1)
+ m_source.fill(1);
+ else
+ m_source.fill(0);
+ }
+ }
+}
+
+bool QGLPixmapData::hasAlphaChannel() const
+{
+ return m_hasAlpha;
+}
+
+QImage QGLPixmapData::fillImage(const QColor &color) const
+{
+ QImage img;
+ if (pixelType() == BitmapType) {
+ img = QImage(w, h, QImage::Format_MonoLSB);
+
+ img.setColorCount(2);
+ img.setColor(0, QColor(Qt::color0).rgba());
+ img.setColor(1, QColor(Qt::color1).rgba());
+
+ if (color == Qt::color1)
+ img.fill(1);
+ else
+ img.fill(0);
+ } else {
+ img = QImage(w, h,
+ m_hasAlpha
+ ? QImage::Format_ARGB32_Premultiplied
+ : QImage::Format_RGB32);
+ img.fill(PREMUL(color.rgba()));
+ }
+ return img;
+}
+
+extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha);
+
+QImage QGLPixmapData::toImage() const
+{
+ if (!isValid())
+ return QImage();
+
+ 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();
+ }
+ return m_source;
+ } else if (m_dirty || m_hasFillColor) {
+ return fillImage(m_fillColor);
+ } else {
+ ensureCreated();
+ }
+
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+ glBindTexture(GL_TEXTURE_2D, m_texture.id);
+ return qt_gl_read_texture(QSize(w, h), true, true);
+}
+
+struct TextureBuffer
+{
+ QGLFramebufferObject *fbo;
+ QGL2PaintEngineEx *engine;
+};
+
+Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool)
+QGLFramebufferObjectPool* qgl_fbo_pool()
+{
+ return _qgl_fbo_pool();
+}
+
+void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
+{
+ if (!isValid())
+ return;
+
+ m_hasFillColor = false;
+
+ const QGLContext *share_ctx = qt_gl_share_widget()->context();
+ QGLShareContextScope ctx(share_ctx);
+
+ ensureCreated();
+
+ if (!ctx->d_ptr->fbo)
+ glGenFramebuffers(1, &ctx->d_ptr->fbo);
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, m_texture.id, 0);
+
+ const int x0 = 0;
+ const int x1 = w;
+ const int y0 = 0;
+ const int y1 = h;
+
+ if (!m_renderFbo->isBound())
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle());
+
+ glDisable(GL_SCISSOR_TEST);
+
+ glBlitFramebufferEXT(x0, y0, x1, y1,
+ x0, y0, x1, y1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ if (keepCurrentFboBound) {
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
+ } else {
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_renderFbo->handle());
+ ctx->d_ptr->current_fbo = m_renderFbo->handle();
+ }
+}
+
+bool QGLPixmapData::useFramebufferObjects() const
+{
+#ifdef Q_OS_SYMBIAN
+ // We don't want to use FBOs on Symbian
+ return false;
+#else
+ return QGLFramebufferObject::hasOpenGLFramebufferObjects()
+ && QGLFramebufferObject::hasOpenGLFramebufferBlit()
+ && qt_gl_preferGL2Engine()
+ && (w * h > 32*32); // avoid overhead of FBOs for small pixmaps
+#endif
+}
+
+QPaintEngine* QGLPixmapData::paintEngine() const
+{
+ if (!isValid())
+ return 0;
+
+ if (m_renderFbo)
+ return m_engine;
+
+ if (useFramebufferObjects()) {
+ extern QGLWidget* qt_gl_share_widget();
+
+ if (!QGLContext::currentContext())
+ qt_gl_share_widget()->makeCurrent();
+ QGLShareContextScope ctx(qt_gl_share_widget()->context());
+
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setSamples(4);
+ format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB));
+
+ m_renderFbo = qgl_fbo_pool()->acquire(size(), format);
+
+ if (m_renderFbo) {
+ if (!m_engine)
+ m_engine = new QGL2PaintEngineEx;
+ return m_engine;
+ }
+
+ qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine";
+ }
+
+ // If the application wants to paint into the QPixmap, we first
+ // force it to QImage format and then paint into that.
+ // This is simpler than juggling multiple GL contexts.
+ const_cast<QGLPixmapData *>(this)->forceToImage();
+
+ if (m_hasFillColor) {
+ m_source.fill(PREMUL(m_fillColor.rgba()));
+ m_hasFillColor = false;
+ }
+ return m_source.paintEngine();
+}
+
+extern QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format);
+
+// If copyBack is true, bind will copy the contents of the render
+// FBO to the texture (which is not bound to the texture, as it's
+// a multisample FBO).
+GLuint QGLPixmapData::bind(bool copyBack) const
+{
+ if (m_renderFbo && copyBack) {
+ copyBackFromRenderFbo(true);
+ } else {
+ ensureCreated();
+ }
+
+ GLuint id = m_texture.id;
+ glBindTexture(GL_TEXTURE_2D, id);
+
+ if (m_hasFillColor) {
+ if (!useFramebufferObjects()) {
+ m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
+ m_source.fill(PREMUL(m_fillColor.rgba()));
+ }
+
+ m_hasFillColor = false;
+
+ 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());
+ }
+
+ return id;
+}
+
+QGLTexture* QGLPixmapData::texture() const
+{
+ return &m_texture;
+}
+
+void QGLPixmapData::detachTextureFromPool()
+{
+ if (inTexturePool) {
+ QGLTexturePool::instance()->detachTexture(this);
+ inTexturePool = false;
+ }
+}
+
+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())
+ return;
+
+ forceToImage();
+ destroyTexture();
+}
+
+void QGLPixmapData::reclaimTexture()
+{
+ if (!inTexturePool)
+ return;
+ forceToImage();
+ destroyTexture();
+}
+
+Q_GUI_EXPORT int qt_defaultDpiX();
+Q_GUI_EXPORT int qt_defaultDpiY();
+
+int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
+{
+ if (w == 0)
+ return 0;
+
+ switch (metric) {
+ case QPaintDevice::PdmWidth:
+ return w;
+ case QPaintDevice::PdmHeight:
+ return h;
+ case QPaintDevice::PdmNumColors:
+ return 0;
+ case QPaintDevice::PdmDepth:
+ return d;
+ case QPaintDevice::PdmWidthMM:
+ return qRound(w * 25.4 / qt_defaultDpiX());
+ case QPaintDevice::PdmHeightMM:
+ return qRound(h * 25.4 / qt_defaultDpiY());
+ case QPaintDevice::PdmDpiX:
+ case QPaintDevice::PdmPhysicalDpiX:
+ return qt_defaultDpiX();
+ case QPaintDevice::PdmDpiY:
+ case QPaintDevice::PdmPhysicalDpiY:
+ return qt_defaultDpiY();
+ default:
+ qWarning("QGLPixmapData::metric(): Invalid metric");
+ return 0;
+ }
+}
+
+// Force the pixmap data to be backed by some valid data.
+void QGLPixmapData::forceToImage()
+{
+ if (!isValid())
+ return;
+
+ if (m_source.isNull())
+ m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
+
+ m_dirty = true;
+}
+
+QGLPaintDevice *QGLPixmapData::glDevice() const
+{
+ return &m_glDevice;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp
index 21b2f09..93e720c 100644
--- a/src/opengl/qwindowsurface_gl.cpp
+++ b/src/opengl/qwindowsurface_gl.cpp
@@ -181,17 +181,15 @@ QGLGraphicsSystem::QGLGraphicsSystem(bool useX11GL)
//
// QGLWindowSurface
//
-
#ifndef Q_WS_QPA
class QGLGlobalShareWidget
{
public:
- QGLGlobalShareWidget() : widget(0), initializing(false) {}
+ QGLGlobalShareWidget() : firstPixmap(0), widgetRefCount(0), widget(0), initializing(false) {}
QGLWidget *shareWidget() {
if (!initializing && !widget && !cleanedUp) {
initializing = true;
-
widget = new QGLWidget(QGLFormat(QGL::SingleBuffer | QGL::NoDepthBuffer | QGL::NoStencilBuffer));
widget->resize(1, 1);
@@ -227,6 +225,9 @@ public:
static bool cleanedUp;
+ QGLPixmapData *firstPixmap;
+ int widgetRefCount;
+
private:
QGLWidget *widget;
bool initializing;
@@ -274,6 +275,43 @@ const QGLContext *qt_gl_share_context()
#endif
}
+#ifdef QGL_USE_TEXTURE_POOL
+void qt_gl_register_pixmap(QGLPixmapData *pd)
+{
+ QGLGlobalShareWidget *shared = _qt_gl_share_widget();
+ pd->next = shared->firstPixmap;
+ pd->prev = 0;
+ if (shared->firstPixmap)
+ shared->firstPixmap->prev = pd;
+ shared->firstPixmap = pd;
+}
+
+void qt_gl_unregister_pixmap(QGLPixmapData *pd)
+{
+ if (pd->next)
+ pd->next->prev = pd->prev;
+ if (pd->prev) {
+ pd->prev->next = pd->next;
+ } else {
+ QGLGlobalShareWidget *shared = _qt_gl_share_widget();
+ if (shared)
+ shared->firstPixmap = pd->next;
+ }
+}
+
+void qt_gl_hibernate_pixmaps()
+{
+ QGLGlobalShareWidget *shared = _qt_gl_share_widget();
+
+ // Scan all QGLPixmapData objects in the system and hibernate them.
+ QGLPixmapData *pd = shared->firstPixmap;
+ while (pd != 0) {
+ pd->hibernate();
+ pd = pd->next;
+ }
+}
+#endif
+
struct QGLWindowSurfacePrivate
{
QGLFramebufferObject *fbo;
@@ -366,6 +404,27 @@ QGLWindowSurface::~QGLWindowSurface()
delete d_ptr->pb;
delete d_ptr->fbo;
delete d_ptr;
+
+ if (QGLGlobalShareWidget::cleanedUp)
+ return;
+
+ --(_qt_gl_share_widget()->widgetRefCount);
+
+#ifdef QGL_USE_TEXTURE_POOL
+ if (_qt_gl_share_widget()->widgetRefCount <= 0) {
+ // All of the widget window surfaces have been destroyed
+ // but we still have GL pixmaps active. Ask them to hibernate
+ // to free up GPU resources until a widget is shown again.
+ // This may eventually cause the EGLContext to be destroyed
+ // because nothing in the system needs a context, which will
+ // free up even more GPU resources.
+ qt_gl_hibernate_pixmaps();
+
+ // Destroy the context if necessary.
+ if (!qt_gl_share_widget()->context()->isSharing())
+ qt_destroy_gl_share_widget();
+ }
+#endif
}
void QGLWindowSurface::deleted(QObject *object)
@@ -415,6 +474,9 @@ void QGLWindowSurface::hijackWindow(QWidget *widget)
ctx->create(qt_gl_share_context());
+ if (widget != qt_gl_share_widget())
+ ++(_qt_gl_share_widget()->widgetRefCount);
+
#ifndef QT_NO_EGL
static bool checkedForNOKSwapRegion = false;
static bool haveNOKSwapRegion = false;
@@ -426,9 +488,9 @@ void QGLWindowSurface::hijackWindow(QWidget *widget)
if (haveNOKSwapRegion)
qDebug() << "Found EGL_NOK_swap_region2 extension. Using partial updates.";
}
-
- if (ctx->d_func()->eglContext->configAttrib(EGL_SWAP_BEHAVIOR) != EGL_BUFFER_PRESERVED &&
- ! haveNOKSwapRegion)
+ 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);
@@ -444,7 +506,9 @@ void QGLWindowSurface::hijackWindow(QWidget *widget)
voidPtrPtr = &widgetPrivate->extraData()->glContext;
d_ptr->contexts << ctxPtrPtr;
+#ifndef Q_OS_SYMBIAN
qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size();
+#endif
}
QGLContext *QGLWindowSurface::context() const
@@ -943,8 +1007,9 @@ void QGLWindowSurface::updateGeometry() {
if (d_ptr->destructive_swap_buffers)
initializeOffscreenTexture(surfSize);
#endif
-
- qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this;;
+#ifndef Q_OS_SYMBIAN
+ qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this;
+#endif
d_ptr->ctx = ctx;
d_ptr->ctx->d_ptr->internal_context = true;
}
diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp b/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp
index 13eab7f..18a0944 100644
--- a/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp
+++ b/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp
@@ -63,6 +63,8 @@ bool QMeeGoGraphicsSystem::surfaceWasCreated = false;
QHash <Qt::HANDLE, QPixmap*> QMeeGoGraphicsSystem::liveTexturePixmaps;
+QList<QMeeGoSwitchCallback> QMeeGoGraphicsSystem::switchCallbacks;
+
QMeeGoGraphicsSystem::QMeeGoGraphicsSystem()
{
qDebug("Using the meego graphics system");
@@ -74,6 +76,78 @@ QMeeGoGraphicsSystem::~QMeeGoGraphicsSystem()
qt_destroy_gl_share_widget();
}
+class QMeeGoGraphicsSystemSwitchHandler : public QObject
+{
+ Q_OBJECT
+public:
+ QMeeGoGraphicsSystemSwitchHandler();
+
+ void addWidget(QWidget *widget);
+ bool eventFilter(QObject *, QEvent *);
+
+private slots:
+ void removeWidget(QObject *object);
+
+private:
+ int visibleWidgets() const;
+
+private:
+ QList<QWidget *> m_widgets;
+};
+
+QMeeGoGraphicsSystemSwitchHandler::QMeeGoGraphicsSystemSwitchHandler()
+{
+}
+
+void QMeeGoGraphicsSystemSwitchHandler::addWidget(QWidget *widget)
+{
+ if (!m_widgets.contains(widget)) {
+ widget->installEventFilter(this);
+ connect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(removeWidget(QObject *)));
+ m_widgets << widget;
+ }
+}
+
+void QMeeGoGraphicsSystemSwitchHandler::removeWidget(QObject *object)
+{
+ m_widgets.removeOne(static_cast<QWidget *>(object));
+}
+
+int QMeeGoGraphicsSystemSwitchHandler::visibleWidgets() const
+{
+ int count = 0;
+ for (int i = 0; i < m_widgets.size(); ++i)
+ count += m_widgets.at(i)->isVisible() && !(m_widgets.at(i)->windowState() & Qt::WindowMinimized);
+ return count;
+}
+
+bool QMeeGoGraphicsSystemSwitchHandler::eventFilter(QObject *object, QEvent *event)
+{
+ if (event->type() == QEvent::WindowStateChange) {
+ QWindowStateChangeEvent *change = static_cast<QWindowStateChangeEvent *>(event);
+ QWidget *widget = static_cast<QWidget *>(object);
+
+ Qt::WindowStates current = widget->windowState();
+ Qt::WindowStates old = change->oldState();
+
+ // did minimized flag change?
+ if ((current ^ old) & Qt::WindowMinimized) {
+ if (current & Qt::WindowMinimized) {
+ if (visibleWidgets() == 0)
+ QMeeGoGraphicsSystem::switchToRaster();
+ } else {
+ if (visibleWidgets() == 1)
+ QMeeGoGraphicsSystem::switchToMeeGo();
+ }
+ }
+ }
+
+ // resume processing of event
+ return false;
+}
+
+Q_GLOBAL_STATIC(QMeeGoGraphicsSystemSwitchHandler, switch_handler)
+
QWindowSurface* QMeeGoGraphicsSystem::createWindowSurface(QWidget *widget) const
{
QGLWidget *shareWidget = qt_gl_share_widget();
@@ -83,6 +157,9 @@ QWindowSurface* QMeeGoGraphicsSystem::createWindowSurface(QWidget *widget) const
QGLShareContextScope ctx(shareWidget->context());
+ if (QApplicationPrivate::instance()->graphics_system_name == QLatin1String("runtime"))
+ switch_handler()->addWidget(widget);
+
QMeeGoGraphicsSystem::surfaceWasCreated = true;
QWindowSurface *surface = new QGLWindowSurface(widget);
return surface;
@@ -203,18 +280,7 @@ QPixmapData *QMeeGoGraphicsSystem::pixmapDataWithGLTexture(int w, int h)
bool QMeeGoGraphicsSystem::meeGoRunning()
{
- if (! QApplicationPrivate::instance()) {
- qWarning("Application not running just yet... hard to know what system running!");
- return false;
- }
-
- QString name = QApplicationPrivate::instance()->graphics_system_name;
- if (name == "runtime") {
- QRuntimeGraphicsSystem *rsystem = (QRuntimeGraphicsSystem *) QApplicationPrivate::instance()->graphics_system;
- name = rsystem->graphicsSystemName();
- }
-
- return (name == "meego");
+ return runningGraphicsSystemName() == "meego";
}
QPixmapData* QMeeGoGraphicsSystem::pixmapDataWithNewLiveTexture(int w, int h, QImage::Format format)
@@ -259,6 +325,69 @@ void QMeeGoGraphicsSystem::destroyFenceSync(void *fenceSync)
QMeeGoExtensions::eglDestroySyncKHR(QEgl::display(), fenceSync);
}
+QString QMeeGoGraphicsSystem::runningGraphicsSystemName()
+{
+ if (!QApplicationPrivate::instance()) {
+ qWarning("Querying graphics system but application not running yet!");
+ return QString();
+ }
+
+ QString name = QApplicationPrivate::instance()->graphics_system_name;
+ if (name == QLatin1String("runtime")) {
+ QRuntimeGraphicsSystem *rsystem = (QRuntimeGraphicsSystem *) QApplicationPrivate::instance()->graphics_system;
+ name = rsystem->graphicsSystemName();
+ }
+
+ return name;
+}
+
+void QMeeGoGraphicsSystem::switchToMeeGo()
+{
+ if (meeGoRunning())
+ return;
+
+ if (QApplicationPrivate::instance()->graphics_system_name != QLatin1String("runtime"))
+ qWarning("Can't switch to meego - switching only supported with 'runtime' graphics system.");
+ else {
+ triggerSwitchCallbacks(0, "meego");
+
+ QApplication *app = static_cast<QApplication *>(QCoreApplication::instance());
+ app->setGraphicsSystem(QLatin1String("meego"));
+
+ triggerSwitchCallbacks(1, "meego");
+ }
+}
+
+void QMeeGoGraphicsSystem::switchToRaster()
+{
+ if (runningGraphicsSystemName() == QLatin1String("raster"))
+ return;
+
+ if (QApplicationPrivate::instance()->graphics_system_name != QLatin1String("runtime"))
+ qWarning("Can't switch to raster - switching only supported with 'runtime' graphics system.");
+ else {
+ triggerSwitchCallbacks(0, "raster");
+
+ QApplication *app = static_cast<QApplication *>(QCoreApplication::instance());
+ app->setGraphicsSystem(QLatin1String("raster"));
+
+ QMeeGoLivePixmapData::invalidateSurfaces();
+
+ triggerSwitchCallbacks(1, "raster");
+ }
+}
+
+void QMeeGoGraphicsSystem::registerSwitchCallback(QMeeGoSwitchCallback callback)
+{
+ switchCallbacks << callback;
+}
+
+void QMeeGoGraphicsSystem::triggerSwitchCallbacks(int type, const char *name)
+{
+ for (int i = 0; i < switchCallbacks.size(); ++i)
+ switchCallbacks.at(i)(type, name);
+}
+
/* C API */
int qt_meego_image_to_egl_shared_image(const QImage &image)
@@ -340,3 +469,20 @@ void qt_meego_invalidate_live_surfaces(void)
{
return QMeeGoLivePixmapData::invalidateSurfaces();
}
+
+void qt_meego_switch_to_raster(void)
+{
+ QMeeGoGraphicsSystem::switchToRaster();
+}
+
+void qt_meego_switch_to_meego(void)
+{
+ QMeeGoGraphicsSystem::switchToMeeGo();
+}
+
+void qt_meego_register_switch_callback(QMeeGoSwitchCallback callback)
+{
+ QMeeGoGraphicsSystem::registerSwitchCallback(callback);
+}
+
+#include "qmeegographicssystem.moc"
diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystem.h b/src/plugins/graphicssystems/meego/qmeegographicssystem.h
index 27a4e7a..ecc85b2 100644
--- a/src/plugins/graphicssystems/meego/qmeegographicssystem.h
+++ b/src/plugins/graphicssystems/meego/qmeegographicssystem.h
@@ -47,6 +47,8 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+extern "C" typedef void (*QMeeGoSwitchCallback)(int type, const char *name);
+
class QMeeGoGraphicsSystem : public QGraphicsSystem
{
public:
@@ -76,13 +78,22 @@ public:
static void* createFenceSync();
static void destroyFenceSync(void* fenceSync);
+ static void switchToRaster();
+ static void switchToMeeGo();
+ static QString runningGraphicsSystemName();
+
+ static void registerSwitchCallback(QMeeGoSwitchCallback callback);
+
private:
static bool meeGoRunning();
static EGLSurface getSurfaceForLiveTexturePixmap(QPixmap *pixmap);
static void destroySurfaceForLiveTexturePixmap(QPixmapData* pmd);
+ static void triggerSwitchCallbacks(int type, const char *name);
static bool surfaceWasCreated;
- static QHash <Qt::HANDLE, QPixmap*> liveTexturePixmaps;
+ static QHash<Qt::HANDLE, QPixmap*> liveTexturePixmaps;
+ static QList<QMeeGoSwitchCallback> switchCallbacks;
+
};
/* C api */
@@ -95,7 +106,7 @@ extern "C" {
Q_DECL_EXPORT bool qt_meego_destroy_egl_shared_image(Qt::HANDLE handle);
Q_DECL_EXPORT void qt_meego_set_surface_fixed_size(int width, int height);
Q_DECL_EXPORT void qt_meego_set_surface_scaling(int x, int y, int width, int height);
- Q_DECL_EXPORT void qt_meego_set_translucent(bool translucent);
+ Q_DECL_EXPORT void qt_meego_set_translucent(bool translucent);
Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_with_new_live_texture(int w, int h, QImage::Format format);
Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_from_live_texture_handle(Qt::HANDLE handle);
Q_DECL_EXPORT QImage* qt_meego_live_texture_lock(QPixmap *pixmap, void *fenceSync);
@@ -104,6 +115,9 @@ extern "C" {
Q_DECL_EXPORT void* qt_meego_create_fence_sync(void);
Q_DECL_EXPORT void qt_meego_destroy_fence_sync(void* fs);
Q_DECL_EXPORT void qt_meego_invalidate_live_surfaces(void);
+ Q_DECL_EXPORT void qt_meego_switch_to_raster(void);
+ Q_DECL_EXPORT void qt_meego_switch_to_meego(void);
+ Q_DECL_EXPORT void qt_meego_register_switch_callback(QMeeGoSwitchCallback callback);
}
#endif
diff --git a/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp b/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp
index 2a2a098..0970b89 100644
--- a/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp
+++ b/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp
@@ -219,7 +219,7 @@ QImage* QMeeGoLivePixmapData::lock(EGLSyncKHR fenceSync)
return &lockedImage;
}
- lockedImage = QImage((uchar *) data, width(), height(), format);
+ lockedImage = QImage((uchar *) data, width(), height(), pitch, format);
return &lockedImage;
}