diff options
Diffstat (limited to 'src/openvg/qwindowsurface_vgegl.cpp')
-rw-r--r-- | src/openvg/qwindowsurface_vgegl.cpp | 124 |
1 files changed, 103 insertions, 21 deletions
diff --git a/src/openvg/qwindowsurface_vgegl.cpp b/src/openvg/qwindowsurface_vgegl.cpp index 62871cf..1571083 100644 --- a/src/openvg/qwindowsurface_vgegl.cpp +++ b/src/openvg/qwindowsurface_vgegl.cpp @@ -111,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) { } @@ -154,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) @@ -166,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 @@ -278,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; @@ -291,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); } } @@ -338,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; } @@ -434,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); } } @@ -453,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; @@ -548,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); } } @@ -587,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; } @@ -596,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. @@ -613,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; } |