src/openvg/qwindowsurface_vgegl.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
    40 ****************************************************************************/
    40 ****************************************************************************/
    41 
    41 
    42 #include "qwindowsurface_vgegl_p.h"
    42 #include "qwindowsurface_vgegl_p.h"
    43 #include "qpaintengine_vg_p.h"
    43 #include "qpaintengine_vg_p.h"
    44 #include "qpixmapdata_vg_p.h"
    44 #include "qpixmapdata_vg_p.h"
       
    45 #include "qvgimagepool_p.h"
    45 #include "qvg_p.h"
    46 #include "qvg_p.h"
    46 
    47 
    47 #if !defined(QT_NO_EGL)
    48 #if !defined(QT_NO_EGL)
    48 
    49 
    49 QT_BEGIN_NAMESPACE
    50 QT_BEGIN_NAMESPACE
    99         return QImage::Format_ARGB4444_Premultiplied;
   100         return QImage::Format_ARGB4444_Premultiplied;
   100     else
   101     else
   101         return argbFormat;       // XXX
   102         return argbFormat;       // XXX
   102 }
   103 }
   103 
   104 
   104 static void copySubImage(QImage *image, VGImage vgImage, const QRect& rect)
       
   105 {
       
   106     vgGetImageSubData
       
   107         (vgImage,
       
   108          image->bits() + rect.bottom() * image->bytesPerLine() +
       
   109             rect.x() * (image->depth() / 8),
       
   110          -(image->bytesPerLine()),
       
   111          qt_vg_image_to_vg_format(image->format()),
       
   112          rect.x(), (image->height() - 1) - rect.bottom(),
       
   113          rect.width(), rect.height());
       
   114 }
       
   115 
       
   116 #if !defined(QVG_NO_SINGLE_CONTEXT)
   105 #if !defined(QVG_NO_SINGLE_CONTEXT)
   117 
   106 
   118 class QVGSharedContext
   107 class QVGSharedContext
   119 {
   108 {
   120 public:
   109 public:
   121     QVGSharedContext();
   110     QVGSharedContext();
   122     ~QVGSharedContext();
   111     ~QVGSharedContext();
   123 
   112 
   124     QEglContext *context;
   113     QEglContext *context;
   125     int refCount;
   114     int refCount;
       
   115     int widgetRefCount;
   126     QVGPaintEngine *engine;
   116     QVGPaintEngine *engine;
   127     EGLSurface surface;
   117     EGLSurface surface;
       
   118     QVGPixmapData *firstPixmap;
   128 };
   119 };
   129 
   120 
   130 QVGSharedContext::QVGSharedContext()
   121 QVGSharedContext::QVGSharedContext()
   131     : context(0)
   122     : context(0)
   132     , refCount(0)
   123     , refCount(0)
       
   124     , widgetRefCount(0)
   133     , engine(0)
   125     , engine(0)
   134     , surface(EGL_NO_SURFACE)
   126     , surface(EGL_NO_SURFACE)
       
   127     , firstPixmap(0)
   135 {
   128 {
   136 }
   129 }
   137 
   130 
   138 QVGSharedContext::~QVGSharedContext()
   131 QVGSharedContext::~QVGSharedContext()
   139 {
   132 {
   164 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine)
   157 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine)
   165 {
   158 {
   166     Q_UNUSED(engine);
   159     Q_UNUSED(engine);
   167 }
   160 }
   168 
   161 
       
   162 void qt_vg_register_pixmap(QVGPixmapData *pd)
       
   163 {
       
   164     QVGSharedContext *shared = sharedContext();
       
   165     pd->next = shared->firstPixmap;
       
   166     pd->prev = 0;
       
   167     if (shared->firstPixmap)
       
   168         shared->firstPixmap->prev = pd;
       
   169     shared->firstPixmap = pd;
       
   170 }
       
   171 
       
   172 void qt_vg_unregister_pixmap(QVGPixmapData *pd)
       
   173 {
       
   174     if (pd->next)
       
   175         pd->next->prev = pd->prev;
       
   176     if (pd->prev) {
       
   177         pd->prev->next = pd->next;
       
   178     } else {
       
   179         QVGSharedContext *shared = sharedContext();
       
   180         if (shared) {
       
   181            shared->firstPixmap = pd->next;
       
   182         }
       
   183     }
       
   184 }
       
   185 
   169 #else
   186 #else
   170 
   187 
   171 QVGPaintEngine *qt_vg_create_paint_engine(void)
   188 QVGPaintEngine *qt_vg_create_paint_engine(void)
   172 {
   189 {
   173     return new QVGPaintEngine();
   190     return new QVGPaintEngine();
   174 }
   191 }
   175 
   192 
   176 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine)
   193 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine)
   177 {
   194 {
   178     delete engine;
   195     delete engine;
       
   196 }
       
   197 
       
   198 void qt_vg_register_pixmap(QVGPixmapData *pd)
       
   199 {
       
   200     Q_UNUSED(pd);
       
   201 }
       
   202 
       
   203 void qt_vg_unregister_pixmap(QVGPixmapData *pd)
       
   204 {
       
   205     Q_UNUSED(pd);
   179 }
   206 }
   180 
   207 
   181 #endif
   208 #endif
   182 
   209 
   183 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT
   210 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT
   202     context->setApi(QEgl::OpenVG);
   229     context->setApi(QEgl::OpenVG);
   203     if (!context->openDisplay(device)) {
   230     if (!context->openDisplay(device)) {
   204         delete context;
   231         delete context;
   205         return 0;
   232         return 0;
   206     }
   233     }
       
   234 
       
   235     // Set the swap interval for the display.
       
   236     QByteArray interval = qgetenv("QT_VG_SWAP_INTERVAL");
       
   237     if (!interval.isEmpty())
       
   238         eglSwapInterval(context->display(), interval.toInt());
       
   239     else
       
   240         eglSwapInterval(context->display(), 1);
       
   241 
       
   242 #ifdef EGL_RENDERABLE_TYPE
       
   243     // Has the user specified an explicit EGL configuration to use?
       
   244     QByteArray configId = qgetenv("QT_VG_EGL_CONFIG");
       
   245     if (!configId.isEmpty()) {
       
   246         EGLint cfgId = configId.toInt();
       
   247         EGLint properties[] = {
       
   248             EGL_CONFIG_ID, cfgId,
       
   249             EGL_NONE
       
   250         };
       
   251         EGLint matching = 0;
       
   252         EGLConfig cfg;
       
   253         if (eglChooseConfig
       
   254                     (context->display(), properties, &cfg, 1, &matching) &&
       
   255                 matching > 0) {
       
   256             // Check that the selected configuration actually supports OpenVG
       
   257             // and then create the context with it.
       
   258             EGLint id = 0;
       
   259             EGLint type = 0;
       
   260             eglGetConfigAttrib
       
   261                 (context->display(), cfg, EGL_CONFIG_ID, &id);
       
   262             eglGetConfigAttrib
       
   263                 (context->display(), cfg, EGL_RENDERABLE_TYPE, &type);
       
   264             if (cfgId == id && (type & EGL_OPENVG_BIT) != 0) {
       
   265                 context->setConfig(cfg);
       
   266                 if (!context->createContext()) {
       
   267                     delete context;
       
   268                     return 0;
       
   269                 }
       
   270                 return context;
       
   271             } else {
       
   272                 qWarning("QT_VG_EGL_CONFIG: %d is not a valid OpenVG configuration", int(cfgId));
       
   273             }
       
   274         }
       
   275     }
       
   276 #endif
   207 
   277 
   208     // Choose an appropriate configuration for rendering into the device.
   278     // Choose an appropriate configuration for rendering into the device.
   209     QEglProperties configProps;
   279     QEglProperties configProps;
   210     configProps.setPaintDeviceFormat(device);
   280     configProps.setPaintDeviceFormat(device);
   211     int redSize = configProps.value(EGL_RED_SIZE);
   281     int redSize = configProps.value(EGL_RED_SIZE);
   214 #ifndef QVG_SCISSOR_CLIP
   284 #ifndef QVG_SCISSOR_CLIP
   215     // If we are using the mask to clip, then explicitly request a mask.
   285     // If we are using the mask to clip, then explicitly request a mask.
   216     configProps.setValue(EGL_ALPHA_MASK_SIZE, 1);
   286     configProps.setValue(EGL_ALPHA_MASK_SIZE, 1);
   217 #endif
   287 #endif
   218 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT
   288 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT
   219     configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT |
   289     configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
   220                          EGL_VG_ALPHA_FORMAT_PRE_BIT);
   290                          EGL_VG_ALPHA_FORMAT_PRE_BIT);
   221     configProps.setRenderableType(QEgl::OpenVG);
   291     configProps.setRenderableType(QEgl::OpenVG);
   222     if (!context->chooseConfig(configProps)) {
   292     if (!context->chooseConfig(configProps)) {
   223         // Try again without the "pre" bit.
   293         // Try again without the "pre" bit.
   224         configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT);
   294         configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
   225         if (!context->chooseConfig(configProps)) {
   295         if (!context->chooseConfig(configProps)) {
   226             delete context;
   296             delete context;
   227             return 0;
   297             return 0;
   228         }
   298         }
   229     }
   299     }
   230 #else
   300 #else
   231     configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT);
   301     configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
   232     configProps.setRenderableType(QEgl::OpenVG);
   302     configProps.setRenderableType(QEgl::OpenVG);
   233     if (!context->chooseConfig(configProps)) {
   303     if (!context->chooseConfig(configProps)) {
   234         delete context;
   304         delete context;
   235         return 0;
   305         return 0;
   236     }
   306     }
   245     return context;
   315     return context;
   246 }
   316 }
   247 
   317 
   248 #if !defined(QVG_NO_SINGLE_CONTEXT)
   318 #if !defined(QVG_NO_SINGLE_CONTEXT)
   249 
   319 
   250 QEglContext *qt_vg_create_context(QPaintDevice *device)
   320 QEglContext *qt_vg_create_context(QPaintDevice *device, int devType)
   251 {
   321 {
   252     QVGSharedContext *shared = sharedContext();
   322     QVGSharedContext *shared = sharedContext();
       
   323     if (devType == QInternal::Widget)
       
   324         ++(shared->widgetRefCount);
   253     if (shared->context) {
   325     if (shared->context) {
   254         ++(shared->refCount);
   326         ++(shared->refCount);
   255         return shared->context;
   327         return shared->context;
   256     } else {
   328     } else {
   257         shared->context = createContext(device);
   329         shared->context = createContext(device);
   258         shared->refCount = 1;
   330         shared->refCount = 1;
   259         return shared->context;
   331         return shared->context;
   260     }
   332     }
   261 }
   333 }
   262 
   334 
   263 void qt_vg_destroy_context(QEglContext *context)
   335 static void qt_vg_destroy_shared_context(QVGSharedContext *shared)
       
   336 {
       
   337     shared->context->makeCurrent(qt_vg_shared_surface());
       
   338     delete shared->engine;
       
   339     shared->engine = 0;
       
   340     shared->context->doneCurrent();
       
   341     if (shared->surface != EGL_NO_SURFACE) {
       
   342         eglDestroySurface(shared->context->display(), shared->surface);
       
   343         shared->surface = EGL_NO_SURFACE;
       
   344     }
       
   345     delete shared->context;
       
   346     shared->context = 0;
       
   347 }
       
   348 
       
   349 void qt_vg_hibernate_pixmaps(QVGSharedContext *shared)
       
   350 {
       
   351     // Artificially increase the reference count to prevent the
       
   352     // context from being destroyed until after we have finished
       
   353     // the hibernation process.
       
   354     ++(shared->refCount);
       
   355 
       
   356     // We need a context current to hibernate the VGImage objects.
       
   357     shared->context->makeCurrent(qt_vg_shared_surface());
       
   358 
       
   359     // Scan all QVGPixmapData objects in the system and hibernate them.
       
   360     QVGPixmapData *pd = shared->firstPixmap;
       
   361     while (pd != 0) {
       
   362         pd->hibernate();
       
   363         pd = pd->next;
       
   364     }
       
   365 
       
   366     // Hibernate any remaining VGImage's in the image pool.
       
   367     QVGImagePool::instance()->hibernate();
       
   368 
       
   369     // Don't need the current context any more.
       
   370     shared->context->lazyDoneCurrent();
       
   371 
       
   372     // Decrease the reference count and destroy the context if necessary.
       
   373     if (--(shared->refCount) <= 0)
       
   374         qt_vg_destroy_shared_context(shared);
       
   375 }
       
   376 
       
   377 void qt_vg_destroy_context(QEglContext *context, int devType)
   264 {
   378 {
   265     QVGSharedContext *shared = sharedContext();
   379     QVGSharedContext *shared = sharedContext();
   266     if (shared->context != context) {
   380     if (shared->context != context) {
   267         // This is not the shared context.  Shouldn't happen!
   381         // This is not the shared context.  Shouldn't happen!
   268         delete context;
   382         delete context;
   269     } else if (--(shared->refCount) <= 0) {
   383         return;
   270         shared->context->makeCurrent(qt_vg_shared_surface());
   384     }
   271         delete shared->engine;
   385     if (devType == QInternal::Widget)
   272         shared->engine = 0;
   386         --(shared->widgetRefCount);
   273         shared->context->doneCurrent();
   387     if (--(shared->refCount) <= 0) {
   274         if (shared->surface != EGL_NO_SURFACE) {
   388         qt_vg_destroy_shared_context(shared);
   275             eglDestroySurface(shared->context->display(), shared->surface);
   389     } else if (shared->widgetRefCount <= 0 && devType == QInternal::Widget) {
   276             shared->surface = EGL_NO_SURFACE;
   390         // All of the widget window surfaces have been destroyed
   277         }
   391         // but we still have VG pixmaps active.  Ask them to hibernate
   278         delete shared->context;
   392         // to free up GPU resources until a widget is shown again.
   279         shared->context = 0;
   393         // This may eventually cause the EGLContext to be destroyed
       
   394         // because nothing in the system needs a context, which will
       
   395         // free up even more GPU resources.
       
   396         qt_vg_hibernate_pixmaps(shared);
   280     }
   397     }
   281 }
   398 }
   282 
   399 
   283 EGLSurface qt_vg_shared_surface(void)
   400 EGLSurface qt_vg_shared_surface(void)
   284 {
   401 {
   305     return shared->surface;
   422     return shared->surface;
   306 }
   423 }
   307 
   424 
   308 #else
   425 #else
   309 
   426 
   310 QEglContext *qt_vg_create_context(QPaintDevice *device)
   427 QEglContext *qt_vg_create_context(QPaintDevice *device, int devType)
   311 {
   428 {
       
   429     Q_UNUSED(devType);
   312     return createContext(device);
   430     return createContext(device);
   313 }
   431 }
   314 
   432 
   315 void qt_vg_destroy_context(QEglContext *context)
   433 void qt_vg_destroy_context(QEglContext *context, int devType)
   316 {
   434 {
       
   435     Q_UNUSED(devType);
   317     delete context;
   436     delete context;
   318 }
   437 }
   319 
   438 
   320 EGLSurface qt_vg_shared_surface(void)
   439 EGLSurface qt_vg_shared_surface(void)
   321 {
   440 {
   332 
   451 
   333 QVGEGLWindowSurfacePrivate::~QVGEGLWindowSurfacePrivate()
   452 QVGEGLWindowSurfacePrivate::~QVGEGLWindowSurfacePrivate()
   334 {
   453 {
   335     // Destroy the paint engine if it hasn't been destroyed already.
   454     // Destroy the paint engine if it hasn't been destroyed already.
   336     destroyPaintEngine();
   455     destroyPaintEngine();
   337 }
       
   338 
       
   339 QVGEGLWindowSurfacePrivate *QVGEGLWindowSurfacePrivate::create
       
   340     (SurfaceType type, QWindowSurface *win)
       
   341 {
       
   342 #if defined(QVG_VGIMAGE_BACKBUFFERS)
       
   343     if (type == VGImageSurface)
       
   344         return new QVGEGLWindowSurfaceVGImage(win);
       
   345     else if (type == QImageSurface)
       
   346         return new QVGEGLWindowSurfaceQImage(win);
       
   347 #endif
       
   348     if (type == WindowSurface)
       
   349         return new QVGEGLWindowSurfaceDirect(win);
       
   350     return 0;
       
   351 }
   456 }
   352 
   457 
   353 QVGPaintEngine *QVGEGLWindowSurfacePrivate::paintEngine()
   458 QVGPaintEngine *QVGEGLWindowSurfacePrivate::paintEngine()
   354 {
   459 {
   355     if (!engine)
   460     if (!engine)
   415             vgDestroyImage(backBuffer);
   520             vgDestroyImage(backBuffer);
   416             context->doneCurrent();
   521             context->doneCurrent();
   417         }
   522         }
   418         if (windowSurface != EGL_NO_SURFACE)
   523         if (windowSurface != EGL_NO_SURFACE)
   419             context->destroySurface(windowSurface);
   524             context->destroySurface(windowSurface);
   420         qt_vg_destroy_context(context);
   525         qt_vg_destroy_context(context, QInternal::Widget);
   421     }
   526     }
   422 }
   527 }
   423 
   528 
   424 QEglContext *QVGEGLWindowSurfaceVGImage::ensureContext(QWidget *widget)
   529 QEglContext *QVGEGLWindowSurfaceVGImage::ensureContext(QWidget *widget)
   425 {
   530 {
   434         recreateBackBuffer = true;
   539         recreateBackBuffer = true;
   435     }
   540     }
   436     if (!context) {
   541     if (!context) {
   437         // Create a new EGL context.  We create the surface in beginPaint().
   542         // Create a new EGL context.  We create the surface in beginPaint().
   438         size = newSize;
   543         size = newSize;
   439         context = qt_vg_create_context(widget);
   544         context = qt_vg_create_context(widget, QInternal::Widget);
   440         if (!context)
   545         if (!context)
   441             return 0;
   546             return 0;
   442         isPaintingActive = false;
   547         isPaintingActive = false;
   443     }
   548     }
   444     return context;
   549     return context;
   512         return windowSurface;
   617         return windowSurface;
   513     else
   618     else
   514         return qt_vg_shared_surface();
   619         return qt_vg_shared_surface();
   515 }
   620 }
   516 
   621 
   517 QVGEGLWindowSurfaceQImage::QVGEGLWindowSurfaceQImage(QWindowSurface *win)
       
   518     : QVGEGLWindowSurfaceVGImage(win)
       
   519 {
       
   520 }
       
   521 
       
   522 QVGEGLWindowSurfaceQImage::~QVGEGLWindowSurfaceQImage()
       
   523 {
       
   524 }
       
   525 
       
   526 void QVGEGLWindowSurfaceQImage::endPaint
       
   527         (QWidget *widget, const QRegion& region, QImage *image)
       
   528 {
       
   529     QEglContext *context = ensureContext(widget);
       
   530     if (context) {
       
   531         if (backBufferSurface != EGL_NO_SURFACE) {
       
   532             if (isPaintingActive)
       
   533                 vgFlush();
       
   534             context->makeCurrent(mainSurface());
       
   535             QRegion rgn = region.intersected
       
   536                 (QRect(0, 0, image->width(), image->height()));
       
   537             if (rgn.numRects() == 1) {
       
   538                 copySubImage(image, backBuffer, rgn.boundingRect());
       
   539             } else {
       
   540                 QVector<QRect> rects = rgn.rects();
       
   541                 for (int index = 0; index < rects.size(); ++index)
       
   542                     copySubImage(image, backBuffer, rects[index]);
       
   543             }
       
   544             context->lazyDoneCurrent();
       
   545         }
       
   546         isPaintingActive = false;
       
   547     }
       
   548 }
       
   549 
       
   550 #endif // QVG_VGIMAGE_BACKBUFFERS
   622 #endif // QVG_VGIMAGE_BACKBUFFERS
   551 
   623 
   552 QVGEGLWindowSurfaceDirect::QVGEGLWindowSurfaceDirect(QWindowSurface *win)
   624 QVGEGLWindowSurfaceDirect::QVGEGLWindowSurfaceDirect(QWindowSurface *win)
   553     : QVGEGLWindowSurfacePrivate(win)
   625     : QVGEGLWindowSurfacePrivate(win)
   554     , context(0)
   626     , context(0)
   562 {
   634 {
   563     destroyPaintEngine();
   635     destroyPaintEngine();
   564     if (context) {
   636     if (context) {
   565         if (windowSurface != EGL_NO_SURFACE)
   637         if (windowSurface != EGL_NO_SURFACE)
   566             context->destroySurface(windowSurface);
   638             context->destroySurface(windowSurface);
   567         qt_vg_destroy_context(context);
   639         qt_vg_destroy_context(context, QInternal::Widget);
   568     }
   640     }
   569 }
   641 }
   570 
   642 
   571 QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget)
   643 QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget)
   572 {
   644 {
   601         // enabled because we cannot reuse the existing paint objects
   673         // enabled because we cannot reuse the existing paint objects
   602         // in the new context.
   674         // in the new context.
   603         qt_vg_destroy_paint_engine(engine);
   675         qt_vg_destroy_paint_engine(engine);
   604         engine = 0;
   676         engine = 0;
   605         context->destroySurface(windowSurface);
   677         context->destroySurface(windowSurface);
   606         qt_vg_destroy_context(context);
   678         qt_vg_destroy_context(context, QInternal::Widget);
   607         context = 0;
   679         context = 0;
   608         windowSurface = EGL_NO_SURFACE;
   680         windowSurface = EGL_NO_SURFACE;
   609     }
   681     }
   610 #endif
   682 #endif
   611 #endif
   683 #endif
   612     if (!context) {
   684     if (!context) {
   613         // Create a new EGL context and bind it to the widget surface.
   685         // Create a new EGL context and bind it to the widget surface.
   614         size = newSize;
   686         size = newSize;
   615         context = qt_vg_create_context(widget);
   687         context = qt_vg_create_context(widget, QInternal::Widget);
   616         if (!context)
   688         if (!context)
   617             return 0;
   689             return 0;
   618         // We want a direct to window rendering surface if possible.
   690         // We want a direct to window rendering surface if possible.
   619 #if defined(QVG_DIRECT_TO_WINDOW)
   691 #if defined(QVG_DIRECT_TO_WINDOW)
   620         surfaceProps.setValue(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
   692         surfaceProps.setValue(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
   627             surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT);
   699             surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT);
   628         }
   700         }
   629 #endif
   701 #endif
   630         EGLSurface surface = context->createSurface(widget, &surfaceProps);
   702         EGLSurface surface = context->createSurface(widget, &surfaceProps);
   631         if (surface == EGL_NO_SURFACE) {
   703         if (surface == EGL_NO_SURFACE) {
   632             qt_vg_destroy_context(context);
   704             qt_vg_destroy_context(context, QInternal::Widget);
   633             context = 0;
   705             context = 0;
   634             return 0;
   706             return 0;
   635         }
   707         }
   636         needToSwap = true;
   708         needToSwap = true;
   637 #if defined(QVG_DIRECT_TO_WINDOW)
   709 #if defined(QVG_DIRECT_TO_WINDOW)