src/openvg/qpixmapdata_vg.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
    41 
    41 
    42 #include "qpixmapdata_vg_p.h"
    42 #include "qpixmapdata_vg_p.h"
    43 #include "qpaintengine_vg_p.h"
    43 #include "qpaintengine_vg_p.h"
    44 #include <QtGui/private/qdrawhelper_p.h>
    44 #include <QtGui/private/qdrawhelper_p.h>
    45 #include "qvg_p.h"
    45 #include "qvg_p.h"
       
    46 #include "qvgimagepool_p.h"
    46 
    47 
    47 #ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE
    48 #ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE
    48 #include <graphics/sgimage.h>
    49 #include <graphics/sgimage.h>
    49 typedef EGLImageKHR (*pfnEglCreateImageKHR)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, EGLint*);
    50 typedef EGLImageKHR (*pfnEglCreateImageKHR)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, EGLint*);
    50 typedef EGLBoolean (*pfnEglDestroyImageKHR)(EGLDisplay, EGLImageKHR);
    51 typedef EGLBoolean (*pfnEglDestroyImageKHR)(EGLDisplay, EGLImageKHR);
    61     Q_ASSERT(type == QPixmapData::PixmapType);
    62     Q_ASSERT(type == QPixmapData::PixmapType);
    62     vgImage = VG_INVALID_HANDLE;
    63     vgImage = VG_INVALID_HANDLE;
    63     vgImageOpacity = VG_INVALID_HANDLE;
    64     vgImageOpacity = VG_INVALID_HANDLE;
    64     cachedOpacity = 1.0f;
    65     cachedOpacity = 1.0f;
    65     recreate = true;
    66     recreate = true;
       
    67     inImagePool = false;
       
    68     inLRU = false;
    66 #if !defined(QT_NO_EGL)
    69 #if !defined(QT_NO_EGL)
    67     context = 0;
    70     context = 0;
       
    71     qt_vg_register_pixmap(this);
    68 #endif
    72 #endif
    69     setSerialNumber(++qt_vg_pixmap_serial);
    73     setSerialNumber(++qt_vg_pixmap_serial);
    70 }
    74 }
    71 
    75 
    72 QVGPixmapData::~QVGPixmapData()
    76 QVGPixmapData::~QVGPixmapData()
       
    77 {
       
    78     destroyImageAndContext();
       
    79 #if !defined(QT_NO_EGL)
       
    80     qt_vg_unregister_pixmap(this);
       
    81 #endif
       
    82 }
       
    83 
       
    84 void QVGPixmapData::destroyImages()
       
    85 {
       
    86     if (inImagePool) {
       
    87         QVGImagePool *pool = QVGImagePool::instance();
       
    88         if (vgImage != VG_INVALID_HANDLE)
       
    89             pool->releaseImage(this, vgImage);
       
    90         if (vgImageOpacity != VG_INVALID_HANDLE)
       
    91             pool->releaseImage(this, vgImageOpacity);
       
    92     } else {
       
    93         if (vgImage != VG_INVALID_HANDLE)
       
    94             vgDestroyImage(vgImage);
       
    95         if (vgImageOpacity != VG_INVALID_HANDLE)
       
    96             vgDestroyImage(vgImageOpacity);
       
    97     }
       
    98     vgImage = VG_INVALID_HANDLE;
       
    99     vgImageOpacity = VG_INVALID_HANDLE;
       
   100     inImagePool = false;
       
   101 }
       
   102 
       
   103 void QVGPixmapData::destroyImageAndContext()
    73 {
   104 {
    74     if (vgImage != VG_INVALID_HANDLE) {
   105     if (vgImage != VG_INVALID_HANDLE) {
    75         // We need to have a context current to destroy the image.
   106         // We need to have a context current to destroy the image.
    76 #if !defined(QT_NO_EGL)
   107 #if !defined(QT_NO_EGL)
    77         if (context->isCurrent()) {
   108         if (context->isCurrent()) {
    78             vgDestroyImage(vgImage);
   109             destroyImages();
    79             if (vgImageOpacity != VG_INVALID_HANDLE)
       
    80                 vgDestroyImage(vgImageOpacity);
       
    81         } else {
   110         } else {
    82             // We don't currently have a widget surface active, but we
   111             // We don't currently have a widget surface active, but we
    83             // need a surface to make the context current.  So use the
   112             // need a surface to make the context current.  So use the
    84             // shared pbuffer surface instead.
   113             // shared pbuffer surface instead.
    85             context->makeCurrent(qt_vg_shared_surface());
   114             context->makeCurrent(qt_vg_shared_surface());
    86             vgDestroyImage(vgImage);
   115             destroyImages();
    87             if (vgImageOpacity != VG_INVALID_HANDLE)
       
    88                 vgDestroyImage(vgImageOpacity);
       
    89             context->lazyDoneCurrent();
   116             context->lazyDoneCurrent();
    90         }
   117         }
    91 #else
   118 #else
    92         vgDestroyImage(vgImage);
   119         destroyImages();
    93         if (vgImageOpacity != VG_INVALID_HANDLE)
       
    94             vgDestroyImage(vgImageOpacity);
       
    95         } else {
       
    96 #endif
   120 #endif
    97     }
   121     }
    98 #if !defined(QT_NO_EGL)
   122 #if !defined(QT_NO_EGL)
    99     if (context)
   123     if (context) {
   100         qt_vg_destroy_context(context);
   124         qt_vg_destroy_context(context, QInternal::Pixmap);
   101 #endif
   125         context = 0;
       
   126     }
       
   127 #endif
       
   128     recreate = true;
   102 }
   129 }
   103 
   130 
   104 QPixmapData *QVGPixmapData::createCompatiblePixmapData() const
   131 QPixmapData *QVGPixmapData::createCompatiblePixmapData() const
   105 {
   132 {
   106     return new QVGPixmapData(pixelType());
   133     return new QVGPixmapData(pixelType());
   200     // This is simpler than juggling multiple VG contexts.
   227     // This is simpler than juggling multiple VG contexts.
   201     const_cast<QVGPixmapData *>(this)->forceToImage();
   228     const_cast<QVGPixmapData *>(this)->forceToImage();
   202     return source.paintEngine();
   229     return source.paintEngine();
   203 }
   230 }
   204 
   231 
       
   232 // This function works around QImage::bits() making a deep copy if the
       
   233 // QImage is not const.  We force it to be const and then get the bits.
       
   234 // XXX: Should add a QImage::constBits() in the future to replace this.
       
   235 static inline const uchar *qt_vg_imageBits(const QImage& image)
       
   236 {
       
   237     return image.bits();
       
   238 }
       
   239 
   205 VGImage QVGPixmapData::toVGImage()
   240 VGImage QVGPixmapData::toVGImage()
   206 {
   241 {
   207     if (!isValid())
   242     if (!isValid())
   208         return VG_INVALID_HANDLE;
   243         return VG_INVALID_HANDLE;
   209 
   244 
   210 #if !defined(QT_NO_EGL)
   245 #if !defined(QT_NO_EGL)
   211     // Increase the reference count on the shared context.
   246     // Increase the reference count on the shared context.
   212     if (!context)
   247     if (!context)
   213         context = qt_vg_create_context(0);
   248         context = qt_vg_create_context(0, QInternal::Pixmap);
   214 #endif
   249 #endif
   215 
   250 
   216     if (recreate) {
   251     if (recreate && prevSize != QSize(w, h))
   217         if (vgImage != VG_INVALID_HANDLE) {
   252         destroyImages();
   218             vgDestroyImage(vgImage);
   253     else if (recreate)
   219             vgImage = VG_INVALID_HANDLE;
   254         cachedOpacity = -1.0f;  // Force opacity image to be refreshed later.
   220         }
       
   221         if (vgImageOpacity != VG_INVALID_HANDLE) {
       
   222             vgDestroyImage(vgImageOpacity);
       
   223             vgImageOpacity = VG_INVALID_HANDLE;
       
   224         }
       
   225     }
       
   226 
   255 
   227     if (vgImage == VG_INVALID_HANDLE) {
   256     if (vgImage == VG_INVALID_HANDLE) {
   228         vgImage = vgCreateImage
   257         vgImage = QVGImagePool::instance()->createImageForPixmap
   229             (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER);
   258             (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this);
       
   259 
       
   260         // Bail out if we run out of GPU memory - try again next time.
       
   261         if (vgImage == VG_INVALID_HANDLE)
       
   262             return VG_INVALID_HANDLE;
       
   263 
       
   264         inImagePool = true;
       
   265     } else if (inImagePool) {
       
   266         QVGImagePool::instance()->useImage(this);
   230     }
   267     }
   231 
   268 
   232     if (!source.isNull() && recreate) {
   269     if (!source.isNull() && recreate) {
   233         vgImageSubData
   270         vgImageSubData
   234             (vgImage,
   271             (vgImage,
   235              source.bits(), source.bytesPerLine(),
   272              qt_vg_imageBits(source), source.bytesPerLine(),
   236              VG_sARGB_8888_PRE, 0, 0, w, h);
   273              VG_sARGB_8888_PRE, 0, 0, w, h);
   237     }
   274     }
   238 
   275 
   239     recreate = false;
   276     recreate = false;
       
   277     prevSize = QSize(w, h);
   240 
   278 
   241     return vgImage;
   279     return vgImage;
   242 }
   280 }
   243 
   281 
   244 VGImage QVGPixmapData::toVGImage(qreal opacity)
   282 VGImage QVGPixmapData::toVGImage(qreal opacity)
   245 {
   283 {
   246 #if !defined(QT_SHIVAVG)
   284 #if !defined(QT_SHIVAVG)
   247     if (!isValid())
   285     // Force the primary VG image to be recreated if necessary.
       
   286     if (toVGImage() == VG_INVALID_HANDLE)
   248         return VG_INVALID_HANDLE;
   287         return VG_INVALID_HANDLE;
   249 
       
   250 #if !defined(QT_NO_EGL)
       
   251     // Increase the reference count on the shared context.
       
   252     if (!context)
       
   253         context = qt_vg_create_context(0);
       
   254 #endif
       
   255 
       
   256     if (recreate) {
       
   257         if (vgImage != VG_INVALID_HANDLE) {
       
   258             vgDestroyImage(vgImage);
       
   259             vgImage = VG_INVALID_HANDLE;
       
   260         }
       
   261         if (vgImageOpacity != VG_INVALID_HANDLE) {
       
   262             vgDestroyImage(vgImageOpacity);
       
   263             vgImageOpacity = VG_INVALID_HANDLE;
       
   264         }
       
   265     }
       
   266 
       
   267     if (vgImage == VG_INVALID_HANDLE) {
       
   268         vgImage = vgCreateImage
       
   269             (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER);
       
   270     }
       
   271 
       
   272     if (!source.isNull() && recreate) {
       
   273         vgImageSubData
       
   274             (vgImage,
       
   275              source.bits(), source.bytesPerLine(),
       
   276              VG_sARGB_8888_PRE, 0, 0, w, h);
       
   277     }
       
   278 
       
   279     recreate = false;
       
   280 
   288 
   281     if (opacity == 1.0f)
   289     if (opacity == 1.0f)
   282         return vgImage;
   290         return vgImage;
   283 
   291 
       
   292     // Create an alternative image for the selected opacity.
   284     if (vgImageOpacity == VG_INVALID_HANDLE || cachedOpacity != opacity) {
   293     if (vgImageOpacity == VG_INVALID_HANDLE || cachedOpacity != opacity) {
   285         if (vgImageOpacity == VG_INVALID_HANDLE) {
   294         if (vgImageOpacity == VG_INVALID_HANDLE) {
   286             vgImageOpacity = vgCreateImage
   295             if (inImagePool) {
   287                 (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER);
   296                 vgImageOpacity = QVGImagePool::instance()->createImageForPixmap
       
   297                     (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this);
       
   298             } else {
       
   299                 vgImageOpacity = vgCreateImage
       
   300                     (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER);
       
   301             }
       
   302 
       
   303             // Bail out if we run out of GPU memory - try again next time.
       
   304             if (vgImageOpacity == VG_INVALID_HANDLE)
       
   305                 return VG_INVALID_HANDLE;
   288         }
   306         }
   289         VGfloat matrix[20] = {
   307         VGfloat matrix[20] = {
   290             1.0f, 0.0f, 0.0f, 0.0f,
   308             1.0f, 0.0f, 0.0f, 0.0f,
   291             0.0f, 1.0f, 0.0f, 0.0f,
   309             0.0f, 1.0f, 0.0f, 0.0f,
   292             0.0f, 0.0f, 1.0f, 0.0f,
   310             0.0f, 0.0f, 1.0f, 0.0f,
   301 #else
   319 #else
   302     // vgColorMatrix() doesn't work with ShivaVG, so ignore the opacity.
   320     // vgColorMatrix() doesn't work with ShivaVG, so ignore the opacity.
   303     Q_UNUSED(opacity);
   321     Q_UNUSED(opacity);
   304     return toVGImage();
   322     return toVGImage();
   305 #endif
   323 #endif
       
   324 }
       
   325 
       
   326 void QVGPixmapData::detachImageFromPool()
       
   327 {
       
   328     if (inImagePool) {
       
   329         QVGImagePool::instance()->detachImage(this);
       
   330         inImagePool = false;
       
   331     }
       
   332 }
       
   333 
       
   334 void QVGPixmapData::hibernate()
       
   335 {
       
   336     // If the image was imported (e.g, from an SgImage under Symbian),
       
   337     // then we cannot copy it back to main memory for storage.
       
   338     if (vgImage != VG_INVALID_HANDLE && source.isNull())
       
   339         return;
       
   340 
       
   341     forceToImage();
       
   342     destroyImageAndContext();
       
   343 }
       
   344 
       
   345 void QVGPixmapData::reclaimImages()
       
   346 {
       
   347     if (!inImagePool)
       
   348         return;
       
   349     forceToImage();
       
   350     destroyImages();
   306 }
   351 }
   307 
   352 
   308 extern int qt_defaultDpiX();
   353 extern int qt_defaultDpiX();
   309 extern int qt_defaultDpiY();
   354 extern int qt_defaultDpiY();
   310 
   355 
   367     \sa {QtOpenVG Module}
   412     \sa {QtOpenVG Module}
   368 */
   413 */
   369 Q_OPENVG_EXPORT VGImage qPixmapToVGImage(const QPixmap& pixmap)
   414 Q_OPENVG_EXPORT VGImage qPixmapToVGImage(const QPixmap& pixmap)
   370 {
   415 {
   371     QPixmapData *pd = pixmap.pixmapData();
   416     QPixmapData *pd = pixmap.pixmapData();
       
   417     if (!pd)
       
   418         return VG_INVALID_HANDLE; // null QPixmap
   372     if (pd->classId() == QPixmapData::OpenVGClass) {
   419     if (pd->classId() == QPixmapData::OpenVGClass) {
   373         QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
   420         QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
   374         if (vgpd->isValid())
   421         if (vgpd->isValid())
   375             return vgpd->toVGImage();
   422             return vgpd->toVGImage();
   376     }
   423     }
   391     if (type == QPixmapData::SgImage && pixmap) {
   438     if (type == QPixmapData::SgImage && pixmap) {
   392         RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap);
   439         RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap);
   393         // when "0" used as argument then
   440         // when "0" used as argument then
   394         // default display, context are used
   441         // default display, context are used
   395         if (!context)
   442         if (!context)
   396             context = qt_vg_create_context(0);
   443             context = qt_vg_create_context(0, QInternal::Pixmap);
   397 
   444 
   398         if (vgImage != VG_INVALID_HANDLE) {
   445         destroyImages();
   399             vgDestroyImage(vgImage);
   446         prevSize = QSize();
   400             vgImage = VG_INVALID_HANDLE;
       
   401         }
       
   402         if (vgImageOpacity != VG_INVALID_HANDLE) {
       
   403             vgDestroyImage(vgImageOpacity);
       
   404             vgImageOpacity = VG_INVALID_HANDLE;
       
   405         }
       
   406 
   447 
   407         TInt err = 0;
   448         TInt err = 0;
   408 
   449 
   409         err = SgDriver::Open();
   450         err = SgDriver::Open();
   410         if(err != KErrNone) {
   451         if(err != KErrNone) {
   461         h = sgImageInfo.iSizeInPixels.iHeight;
   502         h = sgImageInfo.iSizeInPixels.iHeight;
   462         d = 32; // We always use ARGB_Premultiplied for VG pixmaps.
   503         d = 32; // We always use ARGB_Premultiplied for VG pixmaps.
   463         is_null = (w <= 0 || h <= 0);
   504         is_null = (w <= 0 || h <= 0);
   464         source = QImage();
   505         source = QImage();
   465         recreate = false;
   506         recreate = false;
       
   507         prevSize = QSize(w, h);
   466         setSerialNumber(++qt_vg_pixmap_serial);
   508         setSerialNumber(++qt_vg_pixmap_serial);
   467         // release stuff
   509         // release stuff
   468         eglDestroyImageKHR(context->display(), eglImage);
   510         eglDestroyImageKHR(context->display(), eglImage);
   469         SgDriver::Close();
   511         SgDriver::Close();
   470     } else if (type == QPixmapData::FbsBitmap) {
   512     } else if (type == QPixmapData::FbsBitmap) {