QGraphicsView: Improve high-DPI item caching
Scale cache size by target paint device devicePixelRatio. Add manual test for the cache modes. Change-Id: I9f3a2b4c4cf12571aefe54ebf534009a2448fb48 Done-with: MihailNaydenov <garfieldhq@yahoo.com> Task-number: QTBUG-26795 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
parent
19950b3267
commit
18d2619224
@ -4331,7 +4331,8 @@ static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion &
|
|||||||
pix->fill(Qt::transparent);
|
pix->fill(Qt::transparent);
|
||||||
pixmapPainter.begin(pix);
|
pixmapPainter.begin(pix);
|
||||||
} else {
|
} else {
|
||||||
subPix = QPixmap(br.size());
|
subPix = QPixmap(br.size() * pix->devicePixelRatio());
|
||||||
|
subPix.setDevicePixelRatio(pix->devicePixelRatio());
|
||||||
subPix.fill(Qt::transparent);
|
subPix.fill(Qt::transparent);
|
||||||
pixmapPainter.begin(&subPix);
|
pixmapPainter.begin(&subPix);
|
||||||
pixmapPainter.translate(-br.topLeft());
|
pixmapPainter.translate(-br.topLeft());
|
||||||
@ -4409,6 +4410,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const qreal devicePixelRatio = painter->device()->devicePixelRatio();
|
||||||
const qreal oldPainterOpacity = painter->opacity();
|
const qreal oldPainterOpacity = painter->opacity();
|
||||||
qreal newPainterOpacity = oldPainterOpacity;
|
qreal newPainterOpacity = oldPainterOpacity;
|
||||||
QGraphicsProxyWidget *proxy = item->isWidget() ? qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(item)) : 0;
|
QGraphicsProxyWidget *proxy = item->isWidget() ? qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(item)) : 0;
|
||||||
@ -4428,6 +4430,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
|
|||||||
// Fetch the off-screen transparent buffer and exposed area info.
|
// Fetch the off-screen transparent buffer and exposed area info.
|
||||||
QPixmapCache::Key pixmapKey;
|
QPixmapCache::Key pixmapKey;
|
||||||
QPixmap pix;
|
QPixmap pix;
|
||||||
|
|
||||||
bool pixmapFound;
|
bool pixmapFound;
|
||||||
QGraphicsItemCache *itemCache = itemd->extraItemCache();
|
QGraphicsItemCache *itemCache = itemd->extraItemCache();
|
||||||
if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
|
if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
|
||||||
@ -4442,18 +4445,20 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
|
|||||||
// Render using item coordinate cache mode.
|
// Render using item coordinate cache mode.
|
||||||
if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
|
if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
|
||||||
QSize pixmapSize;
|
QSize pixmapSize;
|
||||||
bool fixedCacheSize = false;
|
bool fixedCacheSize = itemCache->fixedSize.isValid();
|
||||||
QRect br = brect.toAlignedRect();
|
QRect br = brect.toAlignedRect();
|
||||||
if ((fixedCacheSize = itemCache->fixedSize.isValid())) {
|
if (fixedCacheSize) {
|
||||||
pixmapSize = itemCache->fixedSize;
|
pixmapSize = itemCache->fixedSize;
|
||||||
} else {
|
} else {
|
||||||
pixmapSize = br.size();
|
pixmapSize = br.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pixmapSize *= devicePixelRatio;
|
||||||
|
|
||||||
// Create or recreate the pixmap.
|
// Create or recreate the pixmap.
|
||||||
int adjust = itemCache->fixedSize.isValid() ? 0 : 2;
|
int adjust = itemCache->fixedSize.isValid() ? 0 : 2;
|
||||||
QSize adjustSize(adjust*2, adjust*2);
|
QSize adjustSize(adjust*2, adjust*2);
|
||||||
br.adjust(-adjust, -adjust, adjust, adjust);
|
br.adjust(-adjust / devicePixelRatio, -adjust / devicePixelRatio, adjust / devicePixelRatio, adjust / devicePixelRatio);
|
||||||
if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) {
|
if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) {
|
||||||
pix = QPixmap(pixmapSize + adjustSize);
|
pix = QPixmap(pixmapSize + adjustSize);
|
||||||
itemCache->boundingRect = br;
|
itemCache->boundingRect = br;
|
||||||
@ -4476,7 +4481,8 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
|
|||||||
// Fit the item's bounding rect into the pixmap's coordinates.
|
// Fit the item's bounding rect into the pixmap's coordinates.
|
||||||
QTransform itemToPixmap;
|
QTransform itemToPixmap;
|
||||||
if (fixedCacheSize) {
|
if (fixedCacheSize) {
|
||||||
const QPointF scale(pixmapSize.width() / brect.width(), pixmapSize.height() / brect.height());
|
const QPointF scale((pixmapSize.width() / devicePixelRatio) / brect.width(),
|
||||||
|
(pixmapSize.height() / devicePixelRatio) / brect.height());
|
||||||
itemToPixmap.scale(scale.x(), scale.y());
|
itemToPixmap.scale(scale.x(), scale.y());
|
||||||
}
|
}
|
||||||
itemToPixmap.translate(-br.x(), -br.y());
|
itemToPixmap.translate(-br.x(), -br.y());
|
||||||
@ -4498,6 +4504,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
|
|||||||
styleOptionTmp.exposedRect = exposedRect;
|
styleOptionTmp.exposedRect = exposedRect;
|
||||||
|
|
||||||
// Render.
|
// Render.
|
||||||
|
pix.setDevicePixelRatio(devicePixelRatio);
|
||||||
_q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
|
_q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
|
||||||
&styleOptionTmp, painterStateProtection);
|
&styleOptionTmp, painterStateProtection);
|
||||||
|
|
||||||
@ -4595,21 +4602,22 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
|
|||||||
|
|
||||||
// Copy / "scroll" the old pixmap onto the new ole and calculate
|
// Copy / "scroll" the old pixmap onto the new ole and calculate
|
||||||
// scrolled exposure.
|
// scrolled exposure.
|
||||||
if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size()) {
|
if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size() / devicePixelRatio) {
|
||||||
QPoint diff = newCacheIndent - deviceData->cacheIndent;
|
QPoint diff = newCacheIndent - deviceData->cacheIndent;
|
||||||
QPixmap newPix(deviceRect.size());
|
QPixmap newPix(deviceRect.size() * devicePixelRatio);
|
||||||
// ### Investigate removing this fill (test with Plasma and
|
// ### Investigate removing this fill (test with Plasma and
|
||||||
// graphicssystem raster).
|
// graphicssystem raster).
|
||||||
newPix.fill(Qt::transparent);
|
newPix.fill(Qt::transparent);
|
||||||
if (!pix.isNull()) {
|
if (!pix.isNull()) {
|
||||||
|
newPix.setDevicePixelRatio(devicePixelRatio);
|
||||||
QPainter newPixPainter(&newPix);
|
QPainter newPixPainter(&newPix);
|
||||||
newPixPainter.drawPixmap(-diff, pix);
|
newPixPainter.drawPixmap(-diff, pix);
|
||||||
newPixPainter.end();
|
newPixPainter.end();
|
||||||
}
|
}
|
||||||
QRegion exposed;
|
QRegion exposed;
|
||||||
exposed += newPix.rect();
|
exposed += QRect(QPoint(0,0), newPix.size() / devicePixelRatio);
|
||||||
if (!pix.isNull())
|
if (!pix.isNull())
|
||||||
exposed -= QRect(-diff, pix.size());
|
exposed -= QRect(-diff, pix.size() / devicePixelRatio);
|
||||||
scrollExposure = exposed;
|
scrollExposure = exposed;
|
||||||
|
|
||||||
pix = newPix;
|
pix = newPix;
|
||||||
@ -4621,9 +4629,9 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
|
|||||||
deviceData->cacheIndent = QPoint();
|
deviceData->cacheIndent = QPoint();
|
||||||
|
|
||||||
// Auto-adjust the pixmap size.
|
// Auto-adjust the pixmap size.
|
||||||
if (deviceRect.size() != pix.size()) {
|
if (deviceRect.size() != pix.size() / devicePixelRatio) {
|
||||||
// exposed needs to cover the whole pixmap
|
// exposed needs to cover the whole pixmap
|
||||||
pix = QPixmap(deviceRect.size());
|
pix = QPixmap(deviceRect.size() * devicePixelRatio);
|
||||||
pixModified = true;
|
pixModified = true;
|
||||||
itemCache->allExposed = true;
|
itemCache->allExposed = true;
|
||||||
itemCache->exposed.clear();
|
itemCache->exposed.clear();
|
||||||
@ -4667,6 +4675,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte
|
|||||||
styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1);
|
styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1);
|
||||||
|
|
||||||
// Render the exposed areas.
|
// Render the exposed areas.
|
||||||
|
pix.setDevicePixelRatio(devicePixelRatio);
|
||||||
_q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
|
_q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
|
||||||
&styleOptionTmp, painterStateProtection);
|
&styleOptionTmp, painterStateProtection);
|
||||||
|
|
||||||
|
@ -45,6 +45,8 @@
|
|||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
|
#include <QGraphicsView>
|
||||||
|
#include <QGraphicsTextItem>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
@ -1151,6 +1153,30 @@ void PhysicalSizeTest::paintEvent(QPaintEvent *)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GraphicsViewCaching : public QGraphicsView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GraphicsViewCaching() {
|
||||||
|
QGraphicsScene *scene = new QGraphicsScene(0, 0, 400, 400);
|
||||||
|
|
||||||
|
QGraphicsTextItem *item = 0;
|
||||||
|
|
||||||
|
item = scene->addText("NoCache");
|
||||||
|
item->setCacheMode(QGraphicsItem::NoCache);
|
||||||
|
item->setPos(10, 10);
|
||||||
|
|
||||||
|
item = scene->addText("ItemCoordinateCache");
|
||||||
|
item->setCacheMode(QGraphicsItem::ItemCoordinateCache);
|
||||||
|
item->setPos(10, 30);
|
||||||
|
|
||||||
|
item = scene->addText("DeviceCoordinateCache");
|
||||||
|
item->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
|
||||||
|
item->setPos(10, 50);
|
||||||
|
|
||||||
|
setScene(scene);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
@ -1186,7 +1212,7 @@ int main(int argc, char **argv)
|
|||||||
demoList << new DemoContainer<CursorTester>("cursorpos", "Test cursor and window positioning");
|
demoList << new DemoContainer<CursorTester>("cursorpos", "Test cursor and window positioning");
|
||||||
demoList << new DemoContainer<ScreenDisplayer>("screens", "Test screen and window positioning");
|
demoList << new DemoContainer<ScreenDisplayer>("screens", "Test screen and window positioning");
|
||||||
demoList << new DemoContainer<PhysicalSizeTest>("physicalsize", "Test manual highdpi support using physicalDotsPerInch");
|
demoList << new DemoContainer<PhysicalSizeTest>("physicalsize", "Test manual highdpi support using physicalDotsPerInch");
|
||||||
|
demoList << new DemoContainer<GraphicsViewCaching>("graphicsview", "Test QGraphicsView caching");
|
||||||
|
|
||||||
foreach (DemoContainerBase *demo, demoList)
|
foreach (DemoContainerBase *demo, demoList)
|
||||||
parser.addOption(demo->option());
|
parser.addOption(demo->option());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user