src/openvg/qpixmapdata_vg.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtOpenVG module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qpixmapdata_vg_p.h"
       
    43 #include "qpaintengine_vg_p.h"
       
    44 #include <QtGui/private/qdrawhelper_p.h>
       
    45 #include "qvg_p.h"
       
    46 
       
    47 #ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE
       
    48 #include <graphics/sgimage.h>
       
    49 typedef EGLImageKHR (*pfnEglCreateImageKHR)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, EGLint*);
       
    50 typedef EGLBoolean (*pfnEglDestroyImageKHR)(EGLDisplay, EGLImageKHR);
       
    51 typedef VGImage (*pfnVgCreateEGLImageTargetKHR)(VGeglImageKHR);
       
    52 #endif
       
    53 
       
    54 QT_BEGIN_NAMESPACE
       
    55 
       
    56 static int qt_vg_pixmap_serial = 0;
       
    57 
       
    58 QVGPixmapData::QVGPixmapData(PixelType type)
       
    59     : QPixmapData(type, OpenVGClass)
       
    60 {
       
    61     Q_ASSERT(type == QPixmapData::PixmapType);
       
    62     vgImage = VG_INVALID_HANDLE;
       
    63     vgImageOpacity = VG_INVALID_HANDLE;
       
    64     cachedOpacity = 1.0f;
       
    65     recreate = true;
       
    66 #if !defined(QT_NO_EGL)
       
    67     context = 0;
       
    68 #endif
       
    69     setSerialNumber(++qt_vg_pixmap_serial);
       
    70 }
       
    71 
       
    72 QVGPixmapData::~QVGPixmapData()
       
    73 {
       
    74     if (vgImage != VG_INVALID_HANDLE) {
       
    75         // We need to have a context current to destroy the image.
       
    76 #if !defined(QT_NO_EGL)
       
    77         if (context->isCurrent()) {
       
    78             vgDestroyImage(vgImage);
       
    79             if (vgImageOpacity != VG_INVALID_HANDLE)
       
    80                 vgDestroyImage(vgImageOpacity);
       
    81         } else {
       
    82             // We don't currently have a widget surface active, but we
       
    83             // need a surface to make the context current.  So use the
       
    84             // shared pbuffer surface instead.
       
    85             context->makeCurrent(qt_vg_shared_surface());
       
    86             vgDestroyImage(vgImage);
       
    87             if (vgImageOpacity != VG_INVALID_HANDLE)
       
    88                 vgDestroyImage(vgImageOpacity);
       
    89             context->lazyDoneCurrent();
       
    90         }
       
    91 #else
       
    92         vgDestroyImage(vgImage);
       
    93         if (vgImageOpacity != VG_INVALID_HANDLE)
       
    94             vgDestroyImage(vgImageOpacity);
       
    95         } else {
       
    96 #endif
       
    97     }
       
    98 #if !defined(QT_NO_EGL)
       
    99     if (context)
       
   100         qt_vg_destroy_context(context);
       
   101 #endif
       
   102 }
       
   103 
       
   104 QPixmapData *QVGPixmapData::createCompatiblePixmapData() const
       
   105 {
       
   106     return new QVGPixmapData(pixelType());
       
   107 }
       
   108 
       
   109 bool QVGPixmapData::isValid() const
       
   110 {
       
   111     return (w > 0 && h > 0);
       
   112 }
       
   113 
       
   114 void QVGPixmapData::resize(int wid, int ht)
       
   115 {
       
   116     if (w == wid && h == ht)
       
   117         return;
       
   118 
       
   119     w = wid;
       
   120     h = ht;
       
   121     d = 32; // We always use ARGB_Premultiplied for VG pixmaps.
       
   122     is_null = (w <= 0 || h <= 0);
       
   123     source = QImage();
       
   124     recreate = true;
       
   125 
       
   126     setSerialNumber(++qt_vg_pixmap_serial);
       
   127 }
       
   128 
       
   129 void QVGPixmapData::fromImage
       
   130         (const QImage &image, Qt::ImageConversionFlags flags)
       
   131 {
       
   132     if (image.size() == QSize(w, h))
       
   133         setSerialNumber(++qt_vg_pixmap_serial);
       
   134     else
       
   135         resize(image.width(), image.height());
       
   136     source = image.convertToFormat(sourceFormat(), flags);
       
   137     recreate = true;
       
   138 }
       
   139 
       
   140 void QVGPixmapData::fill(const QColor &color)
       
   141 {
       
   142     if (!isValid())
       
   143         return;
       
   144 
       
   145     if (source.isNull())
       
   146         source = QImage(w, h, sourceFormat());
       
   147 
       
   148     if (source.depth() == 1) {
       
   149         // Pick the best approximate color in the image's colortable.
       
   150         int gray = qGray(color.rgba());
       
   151         if (qAbs(qGray(source.color(0)) - gray) < qAbs(qGray(source.color(1)) - gray))
       
   152             source.fill(0);
       
   153         else
       
   154             source.fill(1);
       
   155     } else {
       
   156         source.fill(PREMUL(color.rgba()));
       
   157     }
       
   158 
       
   159     // Re-upload the image to VG the next time toVGImage() is called.
       
   160     recreate = true;
       
   161 }
       
   162 
       
   163 bool QVGPixmapData::hasAlphaChannel() const
       
   164 {
       
   165     if (!source.isNull())
       
   166         return source.hasAlphaChannel();
       
   167     else
       
   168         return isValid();
       
   169 }
       
   170 
       
   171 void QVGPixmapData::setAlphaChannel(const QPixmap &alphaChannel)
       
   172 {
       
   173     forceToImage();
       
   174     source.setAlphaChannel(alphaChannel.toImage());
       
   175 }
       
   176 
       
   177 QImage QVGPixmapData::toImage() const
       
   178 {
       
   179     if (!isValid())
       
   180         return QImage();
       
   181 
       
   182     if (source.isNull()) {
       
   183         source = QImage(w, h, sourceFormat());
       
   184         recreate = true;
       
   185     }
       
   186 
       
   187     return source;
       
   188 }
       
   189 
       
   190 QImage *QVGPixmapData::buffer()
       
   191 {
       
   192     forceToImage();
       
   193     return &source;
       
   194 }
       
   195 
       
   196 QPaintEngine* QVGPixmapData::paintEngine() const
       
   197 {
       
   198     // If the application wants to paint into the QPixmap, we first
       
   199     // force it to QImage format and then paint into that.
       
   200     // This is simpler than juggling multiple VG contexts.
       
   201     const_cast<QVGPixmapData *>(this)->forceToImage();
       
   202     return source.paintEngine();
       
   203 }
       
   204 
       
   205 VGImage QVGPixmapData::toVGImage()
       
   206 {
       
   207     if (!isValid())
       
   208         return VG_INVALID_HANDLE;
       
   209 
       
   210 #if !defined(QT_NO_EGL)
       
   211     // Increase the reference count on the shared context.
       
   212     if (!context)
       
   213         context = qt_vg_create_context(0);
       
   214 #endif
       
   215 
       
   216     if (recreate) {
       
   217         if (vgImage != VG_INVALID_HANDLE) {
       
   218             vgDestroyImage(vgImage);
       
   219             vgImage = VG_INVALID_HANDLE;
       
   220         }
       
   221         if (vgImageOpacity != VG_INVALID_HANDLE) {
       
   222             vgDestroyImage(vgImageOpacity);
       
   223             vgImageOpacity = VG_INVALID_HANDLE;
       
   224         }
       
   225     }
       
   226 
       
   227     if (vgImage == VG_INVALID_HANDLE) {
       
   228         vgImage = vgCreateImage
       
   229             (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER);
       
   230     }
       
   231 
       
   232     if (!source.isNull() && recreate) {
       
   233         vgImageSubData
       
   234             (vgImage,
       
   235              source.bits(), source.bytesPerLine(),
       
   236              VG_sARGB_8888_PRE, 0, 0, w, h);
       
   237     }
       
   238 
       
   239     recreate = false;
       
   240 
       
   241     return vgImage;
       
   242 }
       
   243 
       
   244 VGImage QVGPixmapData::toVGImage(qreal opacity)
       
   245 {
       
   246 #if !defined(QT_SHIVAVG)
       
   247     if (!isValid())
       
   248         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 
       
   281     if (opacity == 1.0f)
       
   282         return vgImage;
       
   283 
       
   284     if (vgImageOpacity == VG_INVALID_HANDLE || cachedOpacity != opacity) {
       
   285         if (vgImageOpacity == VG_INVALID_HANDLE) {
       
   286             vgImageOpacity = vgCreateImage
       
   287                 (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER);
       
   288         }
       
   289         VGfloat matrix[20] = {
       
   290             1.0f, 0.0f, 0.0f, 0.0f,
       
   291             0.0f, 1.0f, 0.0f, 0.0f,
       
   292             0.0f, 0.0f, 1.0f, 0.0f,
       
   293             0.0f, 0.0f, 0.0f, opacity,
       
   294             0.0f, 0.0f, 0.0f, 0.0f
       
   295         };
       
   296         vgColorMatrix(vgImageOpacity, vgImage, matrix);
       
   297         cachedOpacity = opacity;
       
   298     }
       
   299 
       
   300     return vgImageOpacity;
       
   301 #else
       
   302     // vgColorMatrix() doesn't work with ShivaVG, so ignore the opacity.
       
   303     Q_UNUSED(opacity);
       
   304     return toVGImage();
       
   305 #endif
       
   306 }
       
   307 
       
   308 extern int qt_defaultDpiX();
       
   309 extern int qt_defaultDpiY();
       
   310 
       
   311 int QVGPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
       
   312 {
       
   313     switch (metric) {
       
   314     case QPaintDevice::PdmWidth:
       
   315         return w;
       
   316     case QPaintDevice::PdmHeight:
       
   317         return h;
       
   318     case QPaintDevice::PdmNumColors:
       
   319         return 0;
       
   320     case QPaintDevice::PdmDepth:
       
   321         return d;
       
   322     case QPaintDevice::PdmWidthMM:
       
   323         return qRound(w * 25.4 / qt_defaultDpiX());
       
   324     case QPaintDevice::PdmHeightMM:
       
   325         return qRound(h * 25.4 / qt_defaultDpiY());
       
   326     case QPaintDevice::PdmDpiX:
       
   327     case QPaintDevice::PdmPhysicalDpiX:
       
   328         return qt_defaultDpiX();
       
   329     case QPaintDevice::PdmDpiY:
       
   330     case QPaintDevice::PdmPhysicalDpiY:
       
   331         return qt_defaultDpiY();
       
   332     default:
       
   333         qWarning("QVGPixmapData::metric(): Invalid metric");
       
   334         return 0;
       
   335     }
       
   336 }
       
   337 
       
   338 // Force the pixmap data to be in QImage format.
       
   339 void QVGPixmapData::forceToImage()
       
   340 {
       
   341     if (!isValid())
       
   342         return;
       
   343 
       
   344     if (source.isNull())
       
   345         source = QImage(w, h, sourceFormat());
       
   346 
       
   347     recreate = true;
       
   348 }
       
   349 
       
   350 QImage::Format QVGPixmapData::sourceFormat() const
       
   351 {
       
   352     return QImage::Format_ARGB32_Premultiplied;
       
   353 }
       
   354 
       
   355 /*
       
   356     \internal
       
   357 
       
   358     Returns the VGImage that is storing the contents of \a pixmap.
       
   359     Returns VG_INVALID_HANDLE if \a pixmap is not owned by the OpenVG
       
   360     graphics system or \a pixmap is invalid.
       
   361 
       
   362     This function is typically used to access the backing store
       
   363     for a pixmap when executing raw OpenVG calls.  It must only
       
   364     be used when a QPainter is active and the OpenVG paint engine
       
   365     is in use by the QPainter.
       
   366 
       
   367     \sa {QtOpenVG Module}
       
   368 */
       
   369 Q_OPENVG_EXPORT VGImage qPixmapToVGImage(const QPixmap& pixmap)
       
   370 {
       
   371     QPixmapData *pd = pixmap.pixmapData();
       
   372     if (pd->classId() == QPixmapData::OpenVGClass) {
       
   373         QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
       
   374         if (vgpd->isValid())
       
   375             return vgpd->toVGImage();
       
   376     }
       
   377     return VG_INVALID_HANDLE;
       
   378 }
       
   379 
       
   380 #if defined(Q_OS_SYMBIAN)
       
   381 void QVGPixmapData::cleanup()
       
   382 {
       
   383     is_null = w = h = 0;
       
   384     recreate = false;
       
   385     source = QImage();
       
   386 }
       
   387 
       
   388 void QVGPixmapData::fromNativeType(void* pixmap, NativeType type)
       
   389 {
       
   390 #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL)
       
   391     if (type == QPixmapData::SgImage && pixmap) {
       
   392         RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap);
       
   393         // when "0" used as argument then
       
   394         // default display, context are used
       
   395         if (!context)
       
   396             context = qt_vg_create_context(0);
       
   397 
       
   398         if (vgImage != VG_INVALID_HANDLE) {
       
   399             vgDestroyImage(vgImage);
       
   400             vgImage = VG_INVALID_HANDLE;
       
   401         }
       
   402         if (vgImageOpacity != VG_INVALID_HANDLE) {
       
   403             vgDestroyImage(vgImageOpacity);
       
   404             vgImageOpacity = VG_INVALID_HANDLE;
       
   405         }
       
   406 
       
   407         TInt err = 0;
       
   408 
       
   409         err = SgDriver::Open();
       
   410         if(err != KErrNone) {
       
   411             cleanup();
       
   412             return;
       
   413         }
       
   414 
       
   415         if(sgImage->IsNull()) {
       
   416             cleanup();
       
   417             SgDriver::Close();
       
   418             return;
       
   419         }
       
   420 
       
   421         TSgImageInfo sgImageInfo;
       
   422         err = sgImage->GetInfo(sgImageInfo);
       
   423         if(err != KErrNone) {
       
   424             cleanup();
       
   425             SgDriver::Close();
       
   426             return;
       
   427         }
       
   428 
       
   429         pfnEglCreateImageKHR eglCreateImageKHR = (pfnEglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR");
       
   430         pfnEglDestroyImageKHR eglDestroyImageKHR = (pfnEglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR");
       
   431         pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR");
       
   432 
       
   433         if(eglGetError() != EGL_SUCCESS || !eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateEGLImageTargetKHR) {
       
   434             cleanup();
       
   435             SgDriver::Close();
       
   436             return;
       
   437         }
       
   438 
       
   439         const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE};
       
   440         EGLImageKHR eglImage = eglCreateImageKHR(context->display(),
       
   441                 EGL_NO_CONTEXT,
       
   442                 EGL_NATIVE_PIXMAP_KHR,
       
   443                 (EGLClientBuffer)sgImage,
       
   444                 (EGLint*)KEglImageAttribs);
       
   445 
       
   446         if(eglGetError() != EGL_SUCCESS) {
       
   447             cleanup();
       
   448             SgDriver::Close();
       
   449             return;
       
   450         }
       
   451 
       
   452         vgImage = vgCreateEGLImageTargetKHR(eglImage);
       
   453         if(vgGetError() != VG_NO_ERROR) {
       
   454             cleanup();
       
   455             eglDestroyImageKHR(context->display(), eglImage);
       
   456             SgDriver::Close();
       
   457             return;
       
   458         }
       
   459 
       
   460         w = sgImageInfo.iSizeInPixels.iWidth;
       
   461         h = sgImageInfo.iSizeInPixels.iHeight;
       
   462         d = 32; // We always use ARGB_Premultiplied for VG pixmaps.
       
   463         is_null = (w <= 0 || h <= 0);
       
   464         source = QImage();
       
   465         recreate = false;
       
   466         setSerialNumber(++qt_vg_pixmap_serial);
       
   467         // release stuff
       
   468         eglDestroyImageKHR(context->display(), eglImage);
       
   469         SgDriver::Close();
       
   470     } else if (type == QPixmapData::FbsBitmap) {
       
   471 
       
   472     }
       
   473 #else
       
   474     Q_UNUSED(pixmap);
       
   475     Q_UNUSED(type);
       
   476 #endif
       
   477 }
       
   478 
       
   479 void* QVGPixmapData::toNativeType(NativeType type)
       
   480 {
       
   481 #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL)
       
   482     if (type == QPixmapData::SgImage) {
       
   483         toVGImage();
       
   484 
       
   485         if(!isValid() || vgImage == VG_INVALID_HANDLE)
       
   486             return 0;
       
   487 
       
   488         TInt err = 0;
       
   489 
       
   490         err = SgDriver::Open();
       
   491         if(err != KErrNone)
       
   492             return 0;
       
   493 
       
   494         TSgImageInfo sgInfo;
       
   495         sgInfo.iPixelFormat = EUidPixelFormatARGB_8888_PRE;
       
   496         sgInfo.iSizeInPixels.SetSize(w, h);
       
   497         sgInfo.iUsage = ESgUsageOpenVgImage | ESgUsageOpenVgTarget;
       
   498         sgInfo.iShareable = ETrue;
       
   499         sgInfo.iCpuAccess = ESgCpuAccessNone;
       
   500         sgInfo.iScreenId = KSgScreenIdMain; //KSgScreenIdAny;
       
   501         sgInfo.iUserAttributes = NULL;
       
   502         sgInfo.iUserAttributeCount = 0;
       
   503 
       
   504         RSgImage *sgImage = q_check_ptr(new RSgImage());
       
   505         err = sgImage->Create(sgInfo, NULL, NULL);
       
   506         if(err != KErrNone) {
       
   507             SgDriver::Close();
       
   508             return 0;
       
   509         }
       
   510 
       
   511         pfnEglCreateImageKHR eglCreateImageKHR = (pfnEglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR");
       
   512         pfnEglDestroyImageKHR eglDestroyImageKHR = (pfnEglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR");
       
   513         pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR");
       
   514 
       
   515         if(eglGetError() != EGL_SUCCESS || !eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateEGLImageTargetKHR) {
       
   516             SgDriver::Close();
       
   517             return 0;
       
   518         }
       
   519 
       
   520         const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE};
       
   521         EGLImageKHR eglImage = eglCreateImageKHR(context->display(),
       
   522                 EGL_NO_CONTEXT,
       
   523                 EGL_NATIVE_PIXMAP_KHR,
       
   524                 (EGLClientBuffer)sgImage,
       
   525                 (EGLint*)KEglImageAttribs);
       
   526         if(eglGetError() != EGL_SUCCESS) {
       
   527             sgImage->Close();
       
   528             SgDriver::Close();
       
   529             return 0;
       
   530         }
       
   531 
       
   532         VGImage dstVgImage = vgCreateEGLImageTargetKHR(eglImage);
       
   533         if(vgGetError() != VG_NO_ERROR) {
       
   534             eglDestroyImageKHR(context->display(), eglImage);
       
   535             sgImage->Close();
       
   536             SgDriver::Close();
       
   537             return 0;
       
   538         }
       
   539 
       
   540         vgCopyImage(dstVgImage, 0, 0,
       
   541                 vgImage, 0, 0,
       
   542                 w, h, VG_FALSE);
       
   543 
       
   544         if(vgGetError() != VG_NO_ERROR) {
       
   545             sgImage->Close();
       
   546             sgImage = 0;
       
   547         }
       
   548         // release stuff
       
   549         vgDestroyImage(dstVgImage);
       
   550         eglDestroyImageKHR(context->display(), eglImage);
       
   551         SgDriver::Close();
       
   552         return reinterpret_cast<void*>(sgImage);
       
   553     } else if (type == QPixmapData::FbsBitmap) {
       
   554         return 0;
       
   555     }
       
   556 #else
       
   557     Q_UNUSED(type);
       
   558     return 0;
       
   559 #endif
       
   560 }
       
   561 #endif //Q_OS_SYMBIAN
       
   562 
       
   563 QT_END_NAMESPACE