src/openvg/qpixmapdata_vg.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
--- a/src/openvg/qpixmapdata_vg.cpp	Tue Jan 26 12:42:25 2010 +0200
+++ b/src/openvg/qpixmapdata_vg.cpp	Tue Feb 02 00:43:10 2010 +0200
@@ -43,6 +43,7 @@
 #include "qpaintengine_vg_p.h"
 #include <QtGui/private/qdrawhelper_p.h>
 #include "qvg_p.h"
+#include "qvgimagepool_p.h"
 
 #ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE
 #include <graphics/sgimage.h>
@@ -63,42 +64,68 @@
     vgImageOpacity = VG_INVALID_HANDLE;
     cachedOpacity = 1.0f;
     recreate = true;
+    inImagePool = false;
+    inLRU = false;
 #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::destroyImages()
+{
+    if (inImagePool) {
+        QVGImagePool *pool = QVGImagePool::instance();
+        if (vgImage != VG_INVALID_HANDLE)
+            pool->releaseImage(this, vgImage);
+        if (vgImageOpacity != VG_INVALID_HANDLE)
+            pool->releaseImage(this, vgImageOpacity);
+    } else {
+        if (vgImage != VG_INVALID_HANDLE)
+            vgDestroyImage(vgImage);
+        if (vgImageOpacity != VG_INVALID_HANDLE)
+            vgDestroyImage(vgImageOpacity);
+    }
+    vgImage = VG_INVALID_HANDLE;
+    vgImageOpacity = VG_INVALID_HANDLE;
+    inImagePool = false;
+}
+
+void QVGPixmapData::destroyImageAndContext()
+{
     if (vgImage != VG_INVALID_HANDLE) {
         // We need to have a context current to destroy the image.
 #if !defined(QT_NO_EGL)
         if (context->isCurrent()) {
-            vgDestroyImage(vgImage);
-            if (vgImageOpacity != VG_INVALID_HANDLE)
-                vgDestroyImage(vgImageOpacity);
+            destroyImages();
         } else {
             // We don't currently have a widget surface active, but we
             // need a surface to make the context current.  So use the
             // shared pbuffer surface instead.
             context->makeCurrent(qt_vg_shared_surface());
-            vgDestroyImage(vgImage);
-            if (vgImageOpacity != VG_INVALID_HANDLE)
-                vgDestroyImage(vgImageOpacity);
+            destroyImages();
             context->lazyDoneCurrent();
         }
 #else
-        vgDestroyImage(vgImage);
-        if (vgImageOpacity != VG_INVALID_HANDLE)
-            vgDestroyImage(vgImageOpacity);
-        } else {
+        destroyImages();
 #endif
     }
 #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 +229,14 @@
     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,33 +245,36 @@
 #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 (vgImage != VG_INVALID_HANDLE) {
-            vgDestroyImage(vgImage);
-            vgImage = VG_INVALID_HANDLE;
-        }
-        if (vgImageOpacity != VG_INVALID_HANDLE) {
-            vgDestroyImage(vgImageOpacity);
-            vgImageOpacity = VG_INVALID_HANDLE;
-        }
-    }
+    if (recreate && prevSize != QSize(w, h))
+        destroyImages();
+    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);
+        vgImage = QVGImagePool::instance()->createImageForPixmap
+            (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this);
+
+        // Bail out if we run out of GPU memory - try again next time.
+        if (vgImage == VG_INVALID_HANDLE)
+            return VG_INVALID_HANDLE;
+
+        inImagePool = true;
+    } else if (inImagePool) {
+        QVGImagePool::instance()->useImage(this);
     }
 
     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 +282,27 @@
 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);
+            if (inImagePool) {
+                vgImageOpacity = QVGImagePool::instance()->createImageForPixmap
+                    (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this);
+            } else {
+                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 +323,33 @@
 #endif
 }
 
+void QVGPixmapData::detachImageFromPool()
+{
+    if (inImagePool) {
+        QVGImagePool::instance()->detachImage(this);
+        inImagePool = false;
+    }
+}
+
+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();
+}
+
+void QVGPixmapData::reclaimImages()
+{
+    if (!inImagePool)
+        return;
+    forceToImage();
+    destroyImages();
+}
+
 extern int qt_defaultDpiX();
 extern int qt_defaultDpiY();
 
@@ -369,6 +414,8 @@
 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,16 +440,10 @@
         // 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);
-            vgImage = VG_INVALID_HANDLE;
-        }
-        if (vgImageOpacity != VG_INVALID_HANDLE) {
-            vgDestroyImage(vgImageOpacity);
-            vgImageOpacity = VG_INVALID_HANDLE;
-        }
+        destroyImages();
+        prevSize = QSize();
 
         TInt err = 0;
 
@@ -463,6 +504,7 @@
         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);