diff options
Diffstat (limited to 'src/openvg')
-rw-r--r-- | src/openvg/openvg.pro | 1 | ||||
-rw-r--r-- | src/openvg/qpaintengine_vg.cpp | 234 | ||||
-rw-r--r-- | src/openvg/qpaintengine_vg_p.h | 2 | ||||
-rw-r--r-- | src/openvg/qpixmapdata_vg.cpp | 96 | ||||
-rw-r--r-- | src/openvg/qpixmapdata_vg_p.h | 36 | ||||
-rw-r--r-- | src/openvg/qpixmapfilter_vg.cpp | 12 | ||||
-rw-r--r-- | src/openvg/qpixmapfilter_vg_p.h | 8 | ||||
-rw-r--r-- | src/openvg/qvg_p.h | 10 | ||||
-rw-r--r-- | src/openvg/qvgcompositionhelper_p.h | 5 | ||||
-rw-r--r-- | src/openvg/qwindowsurface_vg.cpp | 18 | ||||
-rw-r--r-- | src/openvg/qwindowsurface_vgegl.cpp | 232 | ||||
-rw-r--r-- | src/openvg/qwindowsurface_vgegl_p.h | 19 |
12 files changed, 419 insertions, 254 deletions
diff --git a/src/openvg/openvg.pro b/src/openvg/openvg.pro index bf224b4..8927c4c 100644 --- a/src/openvg/openvg.pro +++ b/src/openvg/openvg.pro @@ -34,6 +34,7 @@ contains(QT_CONFIG, egl) { include(../qbase.pri) unix:QMAKE_PKGCONFIG_REQUIRES = QtCore QtGui +symbian:TARGET.UID3 = 0x2001E62F !isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG !isEmpty(QMAKE_LIBDIR_OPENVG): LIBS_PRIVATE += -L$$QMAKE_LIBDIR_OPENVG diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index da07c1d..6b829dd 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -1178,6 +1178,8 @@ VGPaintType QVGPaintEnginePrivate::setBrush case Qt::TexturePattern: { // The brush is a texture specified by a QPixmap/QImage. QPixmapData *pd = brush.texture().pixmapData(); + if (!pd) + break; // null QPixmap VGImage vgImg; bool deref = false; if (pd->pixelType() == QPixmapData::BitmapType) { @@ -1568,12 +1570,6 @@ void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) d->dirty |= QPaintEngine::DirtyClipRegion; - // If we have a non-simple transform, then use path-based clipping. - if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) { - QPaintEngineEx::clip(rect, op); - return; - } - switch (op) { case Qt::NoClip: { @@ -1610,12 +1606,6 @@ void QVGPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) d->dirty |= QPaintEngine::DirtyClipRegion; - // If we have a non-simple transform, then use path-based clipping. - if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) { - QPaintEngineEx::clip(region, op); - return; - } - switch (op) { case Qt::NoClip: { @@ -1751,13 +1741,13 @@ void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) // QRegion copy on the heap for the test if we can. QRegion clip = d->systemClip; // Reference-counted, no alloc. QRect clipRect; - if (clip.numRects() == 1) { + if (clip.rectCount() == 1) { clipRect = clip.boundingRect().intersected(r); } else if (clip.isEmpty()) { clipRect = r; } else { clip = clip.intersect(r); - if (clip.numRects() != 1) { + if (clip.rectCount() != 1) { d->maskValid = false; d->maskIsSet = false; d->maskRect = QRect(); @@ -1808,7 +1798,7 @@ void QVGPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) Q_D(QVGPaintEngine); // Use the QRect case if the region consists of a single rectangle. - if (region.numRects() == 1) { + if (region.rectCount() == 1) { clip(region.boundingRect(), op); return; } @@ -1851,7 +1841,7 @@ void QVGPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) clip = r; else clip = clip.intersect(r); - if (clip.numRects() == 1) { + if (clip.rectCount() == 1) { d->maskValid = false; d->maskIsSet = false; d->maskRect = clip.boundingRect(); @@ -1869,7 +1859,7 @@ void QVGPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) case Qt::IntersectClip: { - if (region.numRects() != 1) { + if (region.rectCount() != 1) { // If there is more than one rectangle, then intersecting // the rectangles one by one in modifyMask() will not give // the desired result. So fall back to path-based clipping. @@ -2146,7 +2136,7 @@ QRegion QVGPaintEngine::defaultClipRegion() bool QVGPaintEngine::isDefaultClipRegion(const QRegion& region) { - if (region.numRects() != 1) + if (region.rectCount() != 1) return false; QPaintDevice *pdev = paintDevice(); @@ -2893,6 +2883,8 @@ void qt_vg_drawVGImageStencil void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) { QPixmapData *pd = pm.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { Q_D(QVGPaintEngine); QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd); @@ -2910,6 +2902,8 @@ void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) { QPixmapData *pd = pm.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { Q_D(QVGPaintEngine); QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd); @@ -2985,6 +2979,8 @@ void QVGPaintEngine::drawPixmaps // If the pixmap is not VG, or the transformation is projective, // then fall back to the default implementation. QPixmapData *pd = pixmap.pixmapData(); + if (!pd) + return; // null QPixmap if (pd->classId() != QPixmapData::OpenVGClass || !d->simpleTransform) { QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints); return; @@ -3399,6 +3395,34 @@ void QVGPaintEngine::restoreState(QPaintEngine::DirtyFlags dirty) #endif } +void QVGPaintEngine::fillRegion + (const QRegion& region, const QColor& color, const QSize& surfaceSize) +{ + Q_D(QVGPaintEngine); + if (d->clearColor != color || d->clearOpacity != 1.0f) { + VGfloat values[4]; + values[0] = color.redF(); + values[1] = color.greenF(); + values[2] = color.blueF(); + values[3] = color.alphaF(); + vgSetfv(VG_CLEAR_COLOR, 4, values); + d->clearColor = color; + d->clearOpacity = 1.0f; + } + if (region.rectCount() == 1) { + QRect r = region.boundingRect(); + vgClear(r.x(), surfaceSize.height() - r.y() - r.height(), + r.width(), r.height()); + } else { + const QVector<QRect> rects = region.rects(); + for (int i = 0; i < rects.size(); ++i) { + QRect r = rects.at(i); + vgClear(r.x(), surfaceSize.height() - r.y() - r.height(), + r.width(), r.height()); + } + } +} + #if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QT_NO_EGL) QVGCompositionHelper::QVGCompositionHelper() @@ -3423,14 +3447,11 @@ void QVGCompositionHelper::endCompositing() } void QVGCompositionHelper::blitWindow - (QVGEGLWindowSurfacePrivate *surface, const QRect& rect, - const QPoint& topLeft, int opacity) + (VGImage image, const QSize& imageSize, + const QRect& rect, const QPoint& topLeft, int opacity) { - // Get the VGImage that is acting as a back buffer for the window. - VGImage image = surface->surfaceImage(); if (image == VG_INVALID_HANDLE) return; - QSize imageSize = surface->surfaceSize(); // Determine which sub rectangle of the window to draw. QRect sr = rect.translated(-topLeft); @@ -3455,28 +3476,24 @@ void QVGCompositionHelper::blitWindow // Set the image transform. QTransform transform; int y = screenSize.height() - (rect.bottom() + 1); - transform.translate(rect.x() + 0.5f, y + 0.5f); + transform.translate(rect.x() - 0.5f, y - 0.5f); d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); // Enable opacity for image drawing if necessary. - if (opacity < 255) { - if (opacity != d->paintOpacity) { - VGfloat values[4]; - values[0] = 1.0f; - values[1] = 1.0f; - values[2] = 1.0f; - values[3] = ((VGfloat)opacity) / 255.0f; - vgSetParameterfv(d->opacityPaint, VG_PAINT_COLOR, 4, values); - d->paintOpacity = values[3]; - } - if (d->fillPaint != d->opacityPaint) { - vgSetPaint(d->opacityPaint, VG_FILL_PATH); - d->fillPaint = d->opacityPaint; - } - d->setImageMode(VG_DRAW_IMAGE_MULTIPLY); - } else { - d->setImageMode(VG_DRAW_IMAGE_NORMAL); + if (opacity != d->paintOpacity) { + VGfloat values[4]; + values[0] = 1.0f; + values[1] = 1.0f; + values[2] = 1.0f; + values[3] = ((VGfloat)opacity) / 255.0f; + vgSetParameterfv(d->opacityPaint, VG_PAINT_COLOR, 4, values); + d->paintOpacity = values[3]; } + if (d->fillPaint != d->opacityPaint) { + vgSetPaint(d->opacityPaint, VG_FILL_PATH); + d->fillPaint = d->opacityPaint; + } + d->setImageMode(VG_DRAW_IMAGE_MULTIPLY); // Draw the child image. vgDrawImage(child); @@ -3527,74 +3544,101 @@ static void fillBackgroundRect(const QRect& rect, QVGPaintEnginePrivate *d) void QVGCompositionHelper::fillBackground (const QRegion& region, const QBrush& brush) { - // Set the path transform to the default viewport transformation. - VGfloat devh = screenSize.height() - 1; - QTransform viewport(1.0f, 0.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.5f, devh + 0.5f, 1.0f); - d->setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, viewport); - - // Set the brush to use to fill the background. - d->ensureBrush(brush); - d->setFillRule(VG_EVEN_ODD); + if (brush.style() == Qt::SolidPattern) { + // Use vgClear() to quickly fill the background. + QColor color = brush.color(); + if (d->clearColor != color || d->clearOpacity != 1.0f) { + VGfloat values[4]; + values[0] = color.redF(); + values[1] = color.greenF(); + values[2] = color.blueF(); + values[3] = color.alphaF(); + vgSetfv(VG_CLEAR_COLOR, 4, values); + d->clearColor = color; + d->clearOpacity = 1.0f; + } + if (region.rectCount() == 1) { + QRect r = region.boundingRect(); + vgClear(r.x(), screenSize.height() - r.y() - r.height(), + r.width(), r.height()); + } else { + const QVector<QRect> rects = region.rects(); + for (int i = 0; i < rects.size(); ++i) { + QRect r = rects.at(i); + vgClear(r.x(), screenSize.height() - r.y() - r.height(), + r.width(), r.height()); + } + } - if (region.numRects() == 1) { - fillBackgroundRect(region.boundingRect(), d); } else { - const QVector<QRect> rects = region.rects(); - for (int i = 0; i < rects.size(); ++i) - fillBackgroundRect(rects.at(i), d); - } + // Set the path transform to the default viewport transformation. + VGfloat devh = screenSize.height() - 1; + QTransform viewport(1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + -0.5f, devh + 0.5f, 1.0f); + d->setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, viewport); + + // Set the brush to use to fill the background. + d->ensureBrush(brush); + d->setFillRule(VG_EVEN_ODD); + + if (region.rectCount() == 1) { + fillBackgroundRect(region.boundingRect(), d); + } else { + const QVector<QRect> rects = region.rects(); + for (int i = 0; i < rects.size(); ++i) + fillBackgroundRect(rects.at(i), d); + } - // We will need to reset the path transform during the next paint. - d->pathTransformSet = false; + // We will need to reset the path transform during the next paint. + d->pathTransformSet = false; + } } -void QVGCompositionHelper::drawCursorImage - (const QImage& image, const QPoint& offset) +void QVGCompositionHelper::drawCursorPixmap + (const QPixmap& pixmap, const QPoint& offset) { - QImage img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + VGImage vgImage = VG_INVALID_HANDLE; - VGImage vgImg = vgCreateImage - (VG_sARGB_8888_PRE, img.width(), img.height(), - VG_IMAGE_QUALITY_FASTER); - vgImageSubData - (vgImg, img.bits() + img.bytesPerLine() * (img.height() - 1), - -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0, - img.width(), img.height()); + // Fetch the VGImage from the pixmap if possible. + QPixmapData *pd = pixmap.pixmapData(); + if (!pd) + return; // null QPixmap + if (pd->classId() == QPixmapData::OpenVGClass) { + QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd); + if (vgpd->isValid()) + vgImage = vgpd->toVGImage(); + } - QTransform transform; - int y = screenSize.height() - (offset.y() + img.height()); - transform.translate(offset.x() + 0.5f, y + 0.5f); + // Set the image transformation and modes. + VGfloat devh = screenSize.height() - 1; + QTransform transform(1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + -0.5f, devh + 0.5f, 1.0f); + transform.translate(offset.x(), offset.y()); d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); - d->setImageMode(VG_DRAW_IMAGE_NORMAL); - vgDrawImage(vgImg); - vgDestroyImage(vgImg); -} + // Draw the VGImage. + if (vgImage != VG_INVALID_HANDLE) { + vgDrawImage(vgImage); + } else { + QImage img = pixmap.toImage().convertToFormat + (QImage::Format_ARGB32_Premultiplied); -void QVGCompositionHelper::drawCursorPixmap - (const QPixmap& pixmap, const QPoint& offset) -{ - QPixmapData *pd = pixmap.pixmapData(); - if (pd->classId() == QPixmapData::OpenVGClass) { - QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd); - if (vgpd->isValid()) { - VGfloat devh = screenSize.height() - 1; - QTransform transform(1.0f, 0.0f, 0.0f, - 0.0f, -1.0f, 0.0f, - 0.5f, devh + 0.5f, 1.0f); - transform.translate(offset.x(), offset.y()); - d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); - - d->setImageMode(VG_DRAW_IMAGE_NORMAL); - vgDrawImage(vgpd->toVGImage()); + vgImage = vgCreateImage + (VG_sARGB_8888_PRE, img.width(), img.height(), + VG_IMAGE_QUALITY_FASTER); + if (vgImage == VG_INVALID_HANDLE) return; - } - } + vgImageSubData + (vgImage, img.bits() + img.bytesPerLine() * (img.height() - 1), + -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0, + img.width(), img.height()); - drawCursorImage(pixmap.toImage(), offset); + vgDrawImage(vgImage); + vgDestroyImage(vgImage); + } } void QVGCompositionHelper::setScissor(const QRegion& region) diff --git a/src/openvg/qpaintengine_vg_p.h b/src/openvg/qpaintengine_vg_p.h index 1202b55..86a522a 100644 --- a/src/openvg/qpaintengine_vg_p.h +++ b/src/openvg/qpaintengine_vg_p.h @@ -151,6 +151,8 @@ public: QVGPaintEnginePrivate *vgPrivate() { Q_D(QVGPaintEngine); return d; } + void fillRegion(const QRegion& region, const QColor& color, const QSize& surfaceSize); + protected: QVGPaintEngine(QVGPaintEnginePrivate &data); diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index f86e116..af6f0f0 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -65,12 +65,21 @@ QVGPixmapData::QVGPixmapData(PixelType type) recreate = true; #if !defined(QT_NO_EGL) context = 0; + qt_vg_register_pixmap(this); #endif setSerialNumber(++qt_vg_pixmap_serial); } QVGPixmapData::~QVGPixmapData() { + destroyImageAndContext(); +#if !defined(QT_NO_EGL) + qt_vg_unregister_pixmap(this); +#endif +} + +void QVGPixmapData::destroyImageAndContext() +{ if (vgImage != VG_INVALID_HANDLE) { // We need to have a context current to destroy the image. #if !defined(QT_NO_EGL) @@ -92,13 +101,17 @@ QVGPixmapData::~QVGPixmapData() vgDestroyImage(vgImage); if (vgImageOpacity != VG_INVALID_HANDLE) vgDestroyImage(vgImageOpacity); - } else { #endif + vgImage = VG_INVALID_HANDLE; + vgImageOpacity = VG_INVALID_HANDLE; } #if !defined(QT_NO_EGL) - if (context) - qt_vg_destroy_context(context); + if (context) { + qt_vg_destroy_context(context, QInternal::Pixmap); + context = 0; + } #endif + recreate = true; } QPixmapData *QVGPixmapData::createCompatiblePixmapData() const @@ -202,6 +215,14 @@ QPaintEngine* QVGPixmapData::paintEngine() const return source.paintEngine(); } +// This function works around QImage::bits() making a deep copy if the +// QImage is not const. We force it to be const and then get the bits. +// XXX: Should add a QImage::constBits() in the future to replace this. +static inline const uchar *qt_vg_imageBits(const QImage& image) +{ + return image.bits(); +} + VGImage QVGPixmapData::toVGImage() { if (!isValid()) @@ -210,10 +231,10 @@ VGImage QVGPixmapData::toVGImage() #if !defined(QT_NO_EGL) // Increase the reference count on the shared context. if (!context) - context = qt_vg_create_context(0); + context = qt_vg_create_context(0, QInternal::Pixmap); #endif - if (recreate) { + if (recreate && prevSize != QSize(w, h)) { if (vgImage != VG_INVALID_HANDLE) { vgDestroyImage(vgImage); vgImage = VG_INVALID_HANDLE; @@ -222,21 +243,28 @@ VGImage QVGPixmapData::toVGImage() vgDestroyImage(vgImageOpacity); vgImageOpacity = VG_INVALID_HANDLE; } + } else if (recreate) { + cachedOpacity = -1.0f; // Force opacity image to be refreshed later. } if (vgImage == VG_INVALID_HANDLE) { vgImage = vgCreateImage (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + + // Bail out if we run out of GPU memory - try again next time. + if (vgImage == VG_INVALID_HANDLE) + return VG_INVALID_HANDLE; } if (!source.isNull() && recreate) { vgImageSubData (vgImage, - source.bits(), source.bytesPerLine(), + qt_vg_imageBits(source), source.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, w, h); } recreate = false; + prevSize = QSize(w, h); return vgImage; } @@ -244,47 +272,22 @@ VGImage QVGPixmapData::toVGImage() VGImage QVGPixmapData::toVGImage(qreal opacity) { #if !defined(QT_SHIVAVG) - if (!isValid()) + // Force the primary VG image to be recreated if necessary. + if (toVGImage() == VG_INVALID_HANDLE) return VG_INVALID_HANDLE; -#if !defined(QT_NO_EGL) - // Increase the reference count on the shared context. - if (!context) - context = qt_vg_create_context(0); -#endif - - if (recreate) { - if (vgImage != VG_INVALID_HANDLE) { - vgDestroyImage(vgImage); - vgImage = VG_INVALID_HANDLE; - } - if (vgImageOpacity != VG_INVALID_HANDLE) { - vgDestroyImage(vgImageOpacity); - vgImageOpacity = VG_INVALID_HANDLE; - } - } - - if (vgImage == VG_INVALID_HANDLE) { - vgImage = vgCreateImage - (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); - } - - if (!source.isNull() && recreate) { - vgImageSubData - (vgImage, - source.bits(), source.bytesPerLine(), - VG_sARGB_8888_PRE, 0, 0, w, h); - } - - recreate = false; - if (opacity == 1.0f) return vgImage; + // Create an alternative image for the selected opacity. if (vgImageOpacity == VG_INVALID_HANDLE || cachedOpacity != opacity) { if (vgImageOpacity == VG_INVALID_HANDLE) { vgImageOpacity = vgCreateImage (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + + // Bail out if we run out of GPU memory - try again next time. + if (vgImageOpacity == VG_INVALID_HANDLE) + return VG_INVALID_HANDLE; } VGfloat matrix[20] = { 1.0f, 0.0f, 0.0f, 0.0f, @@ -305,6 +308,17 @@ VGImage QVGPixmapData::toVGImage(qreal opacity) #endif } +void QVGPixmapData::hibernate() +{ + // If the image was imported (e.g, from an SgImage under Symbian), + // then we cannot copy it back to main memory for storage. + if (vgImage != VG_INVALID_HANDLE && source.isNull()) + return; + + forceToImage(); + destroyImageAndContext(); +} + extern int qt_defaultDpiX(); extern int qt_defaultDpiY(); @@ -369,6 +383,8 @@ QImage::Format QVGPixmapData::sourceFormat() const Q_OPENVG_EXPORT VGImage qPixmapToVGImage(const QPixmap& pixmap) { QPixmapData *pd = pixmap.pixmapData(); + if (!pd) + return VG_INVALID_HANDLE; // null QPixmap if (pd->classId() == QPixmapData::OpenVGClass) { QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd); if (vgpd->isValid()) @@ -393,7 +409,7 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) // when "0" used as argument then // default display, context are used if (!context) - context = qt_vg_create_context(0); + context = qt_vg_create_context(0, QInternal::Pixmap); if (vgImage != VG_INVALID_HANDLE) { vgDestroyImage(vgImage); @@ -403,6 +419,7 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) vgDestroyImage(vgImageOpacity); vgImageOpacity = VG_INVALID_HANDLE; } + prevSize = QSize(); TInt err = 0; @@ -463,6 +480,7 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) is_null = (w <= 0 || h <= 0); source = QImage(); recreate = false; + prevSize = QSize(w, h); setSerialNumber(++qt_vg_pixmap_serial); // release stuff eglDestroyImageKHR(context->display(), eglImage); diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h index f552c7b..c0bb098 100644 --- a/src/openvg/qpixmapdata_vg_p.h +++ b/src/openvg/qpixmapdata_vg_p.h @@ -55,8 +55,6 @@ #include <QtGui/private/qpixmap_raster_p.h> #include <private/qvg_p.h> -#if !defined(QT_NO_EGL) -#endif #if defined(Q_OS_SYMBIAN) class RSGImage; @@ -66,6 +64,15 @@ QT_BEGIN_NAMESPACE class QEglContext; +#if !defined(QT_NO_EGL) +class QVGPixmapData; +class QVGSharedContext; + +void qt_vg_register_pixmap(QVGPixmapData *pd); +void qt_vg_unregister_pixmap(QVGPixmapData *pd); +void qt_vg_hibernate_pixmaps(QVGSharedContext *context); +#endif + class Q_OPENVG_EXPORT QVGPixmapData : public QPixmapData { public: @@ -89,10 +96,18 @@ public: // Return the VGImage form of this pixmap, creating it if necessary. // This assumes that there is a VG context current. - VGImage toVGImage(); + virtual VGImage toVGImage(); // Return the VGImage form for a specific opacity setting. - VGImage toVGImage(qreal opacity); + virtual VGImage toVGImage(qreal opacity); + + // Release the VG resources associated with this pixmap and copy + // the pixmap's contents out of the GPU back into main memory. + // The VG resource will be automatically recreated the next time + // toVGImage() is called. Does nothing if the pixmap cannot be + // hibernated for some reason (e.g. VGImage is shared with another + // process via a SgImage). + virtual void hibernate(); QSize size() const { return QSize(w, h); } @@ -108,7 +123,18 @@ protected: void cleanup(); #endif +#if !defined(QT_NO_EGL) private: + QVGPixmapData *next; + QVGPixmapData *prev; + + friend void qt_vg_register_pixmap(QVGPixmapData *pd); + friend void qt_vg_unregister_pixmap(QVGPixmapData *pd); + friend void qt_vg_hibernate_pixmaps(QVGSharedContext *context); +#endif + +protected: + QSize prevSize; VGImage vgImage; VGImage vgImageOpacity; qreal cachedOpacity; @@ -120,6 +146,8 @@ private: void forceToImage(); QImage::Format sourceFormat() const; + + void destroyImageAndContext(); }; QT_END_NAMESPACE diff --git a/src/openvg/qpixmapfilter_vg.cpp b/src/openvg/qpixmapfilter_vg.cpp index 8e104db..e17c728 100644 --- a/src/openvg/qpixmapfilter_vg.cpp +++ b/src/openvg/qpixmapfilter_vg.cpp @@ -65,6 +65,9 @@ void QVGPixmapConvolutionFilter::draw (QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default convolution filter implementation. @@ -135,6 +138,9 @@ QVGPixmapColorizeFilter::~QVGPixmapColorizeFilter() void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default colorize filter implementation. @@ -225,6 +231,9 @@ QVGPixmapDropShadowFilter::~QVGPixmapDropShadowFilter() void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default drop shadow filter implementation. @@ -290,6 +299,9 @@ QVGPixmapBlurFilter::~QVGPixmapBlurFilter() void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const { + if (src.isNull()) + return; + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { // The pixmap data is not an instance of QVGPixmapData, so fall // back to the default blur filter implementation. diff --git a/src/openvg/qpixmapfilter_vg_p.h b/src/openvg/qpixmapfilter_vg_p.h index efbbc7b..29dd37e 100644 --- a/src/openvg/qpixmapfilter_vg_p.h +++ b/src/openvg/qpixmapfilter_vg_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE #if !defined(QT_SHIVAVG) -class Q_OPENVG_EXPORT QVGPixmapConvolutionFilter : public QPixmapConvolutionFilter +class QVGPixmapConvolutionFilter : public QPixmapConvolutionFilter { Q_OBJECT public: @@ -71,7 +71,7 @@ public: void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const; }; -class Q_OPENVG_EXPORT QVGPixmapColorizeFilter : public QPixmapColorizeFilter +class QVGPixmapColorizeFilter : public QPixmapColorizeFilter { Q_OBJECT public: @@ -81,7 +81,7 @@ public: void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const; }; -class Q_OPENVG_EXPORT QVGPixmapDropShadowFilter : public QPixmapDropShadowFilter +class QVGPixmapDropShadowFilter : public QPixmapDropShadowFilter { Q_OBJECT public: @@ -91,7 +91,7 @@ public: void draw(QPainter *p, const QPointF &pos, const QPixmap &px, const QRectF &src) const; }; -class Q_OPENVG_EXPORT QVGPixmapBlurFilter : public QPixmapBlurFilter +class QVGPixmapBlurFilter : public QPixmapBlurFilter { Q_OBJECT public: diff --git a/src/openvg/qvg_p.h b/src/openvg/qvg_p.h index 04e2bab..3577013 100644 --- a/src/openvg/qvg_p.h +++ b/src/openvg/qvg_p.h @@ -71,11 +71,17 @@ class QEglContext; // Create an EGL context, but don't bind it to a surface. If single-context // mode is enabled, this will return the previously-created context. -Q_OPENVG_EXPORT QEglContext *qt_vg_create_context(QPaintDevice *device); +// "devType" indicates the type of device using the context, usually +// QInternal::Widget or QInternal::Pixmap. +Q_OPENVG_EXPORT QEglContext *qt_vg_create_context + (QPaintDevice *device, int devType); // Destroy an EGL context that was created by qt_vg_create_context(). // If single-context mode is enabled, this will decrease the reference count. -Q_OPENVG_EXPORT void qt_vg_destroy_context(QEglContext *context); +// "devType" indicates the type of device destroying the context, usually +// QInternal::Widget or QInternal::Pixmap. +Q_OPENVG_EXPORT void qt_vg_destroy_context + (QEglContext *context, int devType); // Return the shared pbuffer surface that can be made current to // destroy VGImage objects when there is no other surface available. diff --git a/src/openvg/qvgcompositionhelper_p.h b/src/openvg/qvgcompositionhelper_p.h index 6317c3f..ed24e73 100644 --- a/src/openvg/qvgcompositionhelper_p.h +++ b/src/openvg/qvgcompositionhelper_p.h @@ -71,10 +71,9 @@ public: void startCompositing(const QSize& screenSize); void endCompositing(); - void blitWindow(QVGEGLWindowSurfacePrivate *surface, const QRect& rect, - const QPoint& topLeft, int opacity); + void blitWindow(VGImage image, const QSize& imageSize, + const QRect& rect, const QPoint& topLeft, int opacity); void fillBackground(const QRegion& region, const QBrush& brush); - void drawCursorImage(const QImage& image, const QPoint& offset); void drawCursorPixmap(const QPixmap& pixmap, const QPoint& offset); void setScissor(const QRegion& region); void clearScissor(); diff --git a/src/openvg/qwindowsurface_vg.cpp b/src/openvg/qwindowsurface_vg.cpp index 661e06a..a1301e3 100644 --- a/src/openvg/qwindowsurface_vg.cpp +++ b/src/openvg/qwindowsurface_vg.cpp @@ -48,14 +48,15 @@ #if !defined(QT_NO_EGL) #include <QtGui/private/qegl_p.h> +#include <QtGui/private/qwidget_p.h> QT_BEGIN_NAMESPACE QVGWindowSurface::QVGWindowSurface(QWidget *window) : QWindowSurface(window) { - d_ptr = QVGEGLWindowSurfacePrivate::create - (QVGEGLWindowSurfacePrivate::WindowSurface, this); + // Create the default type of EGL window surface for windows. + d_ptr = new QVGEGLWindowSurfaceDirect(this); } QVGWindowSurface::QVGWindowSurface @@ -71,7 +72,6 @@ QVGWindowSurface::~QVGWindowSurface() QPaintDevice *QVGWindowSurface::paintDevice() { - d_ptr->beginPaint(window()); return this; } @@ -94,8 +94,16 @@ bool QVGWindowSurface::scroll(const QRegion &area, int dx, int dy) void QVGWindowSurface::beginPaint(const QRegion ®ion) { - // Nothing to do here. - Q_UNUSED(region); + d_ptr->beginPaint(window()); + + // If the window is not opaque, then fill the region we are about + // to paint with the transparent color. + if (!qt_widget_private(window())->isOpaque && + window()->testAttribute(Qt::WA_TranslucentBackground)) { + QVGPaintEngine *engine = static_cast<QVGPaintEngine *> + (d_ptr->paintEngine()); + engine->fillRegion(region, Qt::transparent, d_ptr->surfaceSize()); + } } void QVGWindowSurface::endPaint(const QRegion ®ion) diff --git a/src/openvg/qwindowsurface_vgegl.cpp b/src/openvg/qwindowsurface_vgegl.cpp index d622c1f..1571083 100644 --- a/src/openvg/qwindowsurface_vgegl.cpp +++ b/src/openvg/qwindowsurface_vgegl.cpp @@ -101,18 +101,6 @@ QImage::Format qt_vg_config_to_image_format(QEglContext *context) return argbFormat; // XXX } -static void copySubImage(QImage *image, VGImage vgImage, const QRect& rect) -{ - vgGetImageSubData - (vgImage, - image->bits() + rect.bottom() * image->bytesPerLine() + - rect.x() * (image->depth() / 8), - -(image->bytesPerLine()), - qt_vg_image_to_vg_format(image->format()), - rect.x(), (image->height() - 1) - rect.bottom(), - rect.width(), rect.height()); -} - #if !defined(QVG_NO_SINGLE_CONTEXT) class QVGSharedContext @@ -123,15 +111,19 @@ public: QEglContext *context; int refCount; + int widgetRefCount; QVGPaintEngine *engine; EGLSurface surface; + QVGPixmapData *firstPixmap; }; QVGSharedContext::QVGSharedContext() : context(0) , refCount(0) + , widgetRefCount(0) , engine(0) , surface(EGL_NO_SURFACE) + , firstPixmap(0) { } @@ -166,6 +158,28 @@ void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) Q_UNUSED(engine); } +void qt_vg_register_pixmap(QVGPixmapData *pd) +{ + QVGSharedContext *shared = sharedContext(); + pd->next = shared->firstPixmap; + pd->prev = 0; + if (shared->firstPixmap) + shared->firstPixmap->prev = pd; + shared->firstPixmap = pd; +} + +void qt_vg_unregister_pixmap(QVGPixmapData *pd) +{ + if (pd->next) + pd->next->prev = pd->prev; + if (pd->prev) { + pd->prev->next = pd->next; + } else { + QVGSharedContext *shared = sharedContext(); + shared->firstPixmap = pd->next; + } +} + #else QVGPaintEngine *qt_vg_create_paint_engine(void) @@ -178,6 +192,16 @@ void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) delete engine; } +void qt_vg_register_pixmap(QVGPixmapData *pd) +{ + Q_UNUSED(pd); +} + +void qt_vg_unregister_pixmap(QVGPixmapData *pd) +{ + Q_UNUSED(pd); +} + #endif #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT @@ -205,6 +229,49 @@ static QEglContext *createContext(QPaintDevice *device) return 0; } + // Set the swap interval for the display. + QByteArray interval = qgetenv("QT_VG_SWAP_INTERVAL"); + if (!interval.isEmpty()) + eglSwapInterval(context->display(), interval.toInt()); + else + eglSwapInterval(context->display(), 1); + +#ifdef EGL_RENDERABLE_TYPE + // Has the user specified an explicit EGL configuration to use? + QByteArray configId = qgetenv("QT_VG_EGL_CONFIG"); + if (!configId.isEmpty()) { + EGLint cfgId = configId.toInt(); + EGLint properties[] = { + EGL_CONFIG_ID, cfgId, + EGL_NONE + }; + EGLint matching = 0; + EGLConfig cfg; + if (eglChooseConfig + (context->display(), properties, &cfg, 1, &matching) && + matching > 0) { + // Check that the selected configuration actually supports OpenVG + // and then create the context with it. + EGLint id = 0; + EGLint type = 0; + eglGetConfigAttrib + (context->display(), cfg, EGL_CONFIG_ID, &id); + eglGetConfigAttrib + (context->display(), cfg, EGL_RENDERABLE_TYPE, &type); + if (cfgId == id && (type & EGL_OPENVG_BIT) != 0) { + context->setConfig(cfg); + if (!context->createContext()) { + delete context; + return 0; + } + return context; + } else { + qWarning("QT_VG_EGL_CONFIG: %d is not a valid OpenVG configuration", int(cfgId)); + } + } + } +#endif + // Choose an appropriate configuration for rendering into the device. QEglProperties configProps; configProps.setPaintDeviceFormat(device); @@ -216,19 +283,19 @@ static QEglContext *createContext(QPaintDevice *device) configProps.setValue(EGL_ALPHA_MASK_SIZE, 1); #endif #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT | + configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT); configProps.setRenderableType(QEgl::OpenVG); if (!context->chooseConfig(configProps)) { // Try again without the "pre" bit. - configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); + configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); if (!context->chooseConfig(configProps)) { delete context; return 0; } } #else - configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); + configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); configProps.setRenderableType(QEgl::OpenVG); if (!context->chooseConfig(configProps)) { delete context; @@ -247,9 +314,11 @@ static QEglContext *createContext(QPaintDevice *device) #if !defined(QVG_NO_SINGLE_CONTEXT) -QEglContext *qt_vg_create_context(QPaintDevice *device) +QEglContext *qt_vg_create_context(QPaintDevice *device, int devType) { QVGSharedContext *shared = sharedContext(); + if (devType == QInternal::Widget) + ++(shared->widgetRefCount); if (shared->context) { ++(shared->refCount); return shared->context; @@ -260,23 +329,65 @@ QEglContext *qt_vg_create_context(QPaintDevice *device) } } -void qt_vg_destroy_context(QEglContext *context) +static void qt_vg_destroy_shared_context(QVGSharedContext *shared) +{ + shared->context->makeCurrent(qt_vg_shared_surface()); + delete shared->engine; + shared->engine = 0; + shared->context->doneCurrent(); + if (shared->surface != EGL_NO_SURFACE) { + eglDestroySurface(shared->context->display(), shared->surface); + shared->surface = EGL_NO_SURFACE; + } + delete shared->context; + shared->context = 0; +} + +void qt_vg_hibernate_pixmaps(QVGSharedContext *shared) +{ + // Artificially increase the reference count to prevent the + // context from being destroyed until after we have finished + // the hibernation process. + ++(shared->refCount); + + // We need a context current to hibernate the VGImage objects. + shared->context->makeCurrent(qt_vg_shared_surface()); + + // Scan all QVGPixmapData objects in the system and hibernate them. + QVGPixmapData *pd = shared->firstPixmap; + while (pd != 0) { + pd->hibernate(); + pd = pd->next; + } + + // Don't need the current context any more. + shared->context->lazyDoneCurrent(); + + // Decrease the reference count and destroy the context if necessary. + if (--(shared->refCount) <= 0) + qt_vg_destroy_shared_context(shared); +} + +void qt_vg_destroy_context(QEglContext *context, int devType) { QVGSharedContext *shared = sharedContext(); if (shared->context != context) { // This is not the shared context. Shouldn't happen! delete context; - } else if (--(shared->refCount) <= 0) { - shared->context->makeCurrent(qt_vg_shared_surface()); - delete shared->engine; - shared->engine = 0; - shared->context->doneCurrent(); - if (shared->surface != EGL_NO_SURFACE) { - eglDestroySurface(shared->context->display(), shared->surface); - shared->surface = EGL_NO_SURFACE; - } - delete shared->context; - shared->context = 0; + return; + } + if (devType == QInternal::Widget) + --(shared->widgetRefCount); + if (--(shared->refCount) <= 0) { + qt_vg_destroy_shared_context(shared); + } else if (shared->widgetRefCount <= 0 && devType == QInternal::Widget) { + // All of the widget window surfaces have been destroyed + // but we still have VG 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_vg_hibernate_pixmaps(shared); } } @@ -307,13 +418,15 @@ EGLSurface qt_vg_shared_surface(void) #else -QEglContext *qt_vg_create_context(QPaintDevice *device) +QEglContext *qt_vg_create_context(QPaintDevice *device, int devType) { + Q_UNUSED(devType); return createContext(device); } -void qt_vg_destroy_context(QEglContext *context) +void qt_vg_destroy_context(QEglContext *context, int devType) { + Q_UNUSED(devType); delete context; } @@ -336,20 +449,6 @@ QVGEGLWindowSurfacePrivate::~QVGEGLWindowSurfacePrivate() destroyPaintEngine(); } -QVGEGLWindowSurfacePrivate *QVGEGLWindowSurfacePrivate::create - (SurfaceType type, QWindowSurface *win) -{ -#if defined(QVG_VGIMAGE_BACKBUFFERS) - if (type == VGImageSurface) - return new QVGEGLWindowSurfaceVGImage(win); - else if (type == QImageSurface) - return new QVGEGLWindowSurfaceQImage(win); -#endif - if (type == WindowSurface) - return new QVGEGLWindowSurfaceDirect(win); - return 0; -} - QVGPaintEngine *QVGEGLWindowSurfacePrivate::paintEngine() { if (!engine) @@ -417,7 +516,7 @@ QVGEGLWindowSurfaceVGImage::~QVGEGLWindowSurfaceVGImage() } if (windowSurface != EGL_NO_SURFACE) context->destroySurface(windowSurface); - qt_vg_destroy_context(context); + qt_vg_destroy_context(context, QInternal::Widget); } } @@ -436,7 +535,7 @@ QEglContext *QVGEGLWindowSurfaceVGImage::ensureContext(QWidget *widget) if (!context) { // Create a new EGL context. We create the surface in beginPaint(). size = newSize; - context = qt_vg_create_context(widget); + context = qt_vg_create_context(widget, QInternal::Widget); if (!context) return 0; isPaintingActive = false; @@ -514,39 +613,6 @@ EGLSurface QVGEGLWindowSurfaceVGImage::mainSurface() const return qt_vg_shared_surface(); } -QVGEGLWindowSurfaceQImage::QVGEGLWindowSurfaceQImage(QWindowSurface *win) - : QVGEGLWindowSurfaceVGImage(win) -{ -} - -QVGEGLWindowSurfaceQImage::~QVGEGLWindowSurfaceQImage() -{ -} - -void QVGEGLWindowSurfaceQImage::endPaint - (QWidget *widget, const QRegion& region, QImage *image) -{ - QEglContext *context = ensureContext(widget); - if (context) { - if (backBufferSurface != EGL_NO_SURFACE) { - if (isPaintingActive) - vgFlush(); - context->makeCurrent(mainSurface()); - QRegion rgn = region.intersected - (QRect(0, 0, image->width(), image->height())); - if (rgn.numRects() == 1) { - copySubImage(image, backBuffer, rgn.boundingRect()); - } else { - QVector<QRect> rects = rgn.rects(); - for (int index = 0; index < rects.size(); ++index) - copySubImage(image, backBuffer, rects[index]); - } - context->lazyDoneCurrent(); - } - isPaintingActive = false; - } -} - #endif // QVG_VGIMAGE_BACKBUFFERS QVGEGLWindowSurfaceDirect::QVGEGLWindowSurfaceDirect(QWindowSurface *win) @@ -564,7 +630,7 @@ QVGEGLWindowSurfaceDirect::~QVGEGLWindowSurfaceDirect() if (context) { if (windowSurface != EGL_NO_SURFACE) context->destroySurface(windowSurface); - qt_vg_destroy_context(context); + qt_vg_destroy_context(context, QInternal::Widget); } } @@ -603,7 +669,7 @@ QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget) qt_vg_destroy_paint_engine(engine); engine = 0; context->destroySurface(windowSurface); - qt_vg_destroy_context(context); + qt_vg_destroy_context(context, QInternal::Widget); context = 0; windowSurface = EGL_NO_SURFACE; } @@ -612,7 +678,7 @@ QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget) if (!context) { // Create a new EGL context and bind it to the widget surface. size = newSize; - context = qt_vg_create_context(widget); + context = qt_vg_create_context(widget, QInternal::Widget); if (!context) return 0; // We want a direct to window rendering surface if possible. @@ -629,7 +695,7 @@ QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget) #endif EGLSurface surface = context->createSurface(widget, &surfaceProps); if (surface == EGL_NO_SURFACE) { - qt_vg_destroy_context(context); + qt_vg_destroy_context(context, QInternal::Widget); context = 0; return 0; } diff --git a/src/openvg/qwindowsurface_vgegl_p.h b/src/openvg/qwindowsurface_vgegl_p.h index fa36b94..7fa60ea 100644 --- a/src/openvg/qwindowsurface_vgegl_p.h +++ b/src/openvg/qwindowsurface_vgegl_p.h @@ -70,16 +70,6 @@ public: QVGEGLWindowSurfacePrivate(QWindowSurface *win); virtual ~QVGEGLWindowSurfacePrivate(); - enum SurfaceType - { - WindowSurface, - VGImageSurface, - QImageSurface - }; - - static QVGEGLWindowSurfacePrivate *create - (SurfaceType type, QWindowSurface *win); - QVGPaintEngine *paintEngine(); virtual QEglContext *ensureContext(QWidget *widget) = 0; virtual void beginPaint(QWidget *widget) = 0; @@ -126,15 +116,6 @@ protected: EGLSurface mainSurface() const; }; -class Q_OPENVG_EXPORT QVGEGLWindowSurfaceQImage : public QVGEGLWindowSurfaceVGImage -{ -public: - QVGEGLWindowSurfaceQImage(QWindowSurface *win); - virtual ~QVGEGLWindowSurfaceQImage(); - - void endPaint(QWidget *widget, const QRegion& region, QImage *image); -}; - #endif // EGL_OPENVG_IMAGE class Q_OPENVG_EXPORT QVGEGLWindowSurfaceDirect : public QVGEGLWindowSurfacePrivate |