summaryrefslogtreecommitdiffstats
path: root/src/openvg/qwindowsurface_vgegl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvg/qwindowsurface_vgegl.cpp')
-rw-r--r--src/openvg/qwindowsurface_vgegl.cpp124
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;
}