summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/egl/qegl.cpp83
-rw-r--r--src/gui/egl/qegl_p.h9
-rw-r--r--src/openvg/qpixmapdata_vg.cpp5
-rw-r--r--src/openvg/qvg_p.h9
-rw-r--r--src/openvg/qwindowsurface_vgegl.cpp123
5 files changed, 118 insertions, 111 deletions
diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp
index 222524e..a405bbb 100644
--- a/src/gui/egl/qegl.cpp
+++ b/src/gui/egl/qegl.cpp
@@ -47,21 +47,33 @@
QT_BEGIN_NAMESPACE
+// Current GL and VG contexts. These are used to determine if
+// we can avoid an eglMakeCurrent() after a call to lazyDoneCurrent().
+// If a background thread modifies the value, the worst that will
+// happen is a redundant eglMakeCurrent() in the foreground thread.
+static QEglContext * volatile currentGLContext = 0;
+static QEglContext * volatile currentVGContext = 0;
+
QEglContext::QEglContext()
: apiType(QEgl::OpenGL)
, dpy(EGL_NO_DISPLAY)
, ctx(EGL_NO_CONTEXT)
, surf(EGL_NO_SURFACE)
, cfg(0)
+ , currentSurface(EGL_NO_SURFACE)
, share(false)
, current(false)
- , reserved(0)
{
}
QEglContext::~QEglContext()
{
destroy();
+
+ if (currentGLContext == this)
+ currentGLContext = 0;
+ if (currentVGContext == this)
+ currentVGContext = 0;
}
bool QEglContext::isValid() const
@@ -210,6 +222,19 @@ void QEglContext::destroySurface()
}
}
+// Destroy an EGL surface object. If it was current on this context
+// then call doneCurrent() for it first.
+void QEglContext::destroySurface(EGLSurface surface)
+{
+ if (surface != EGL_NO_SURFACE) {
+ if (surface == currentSurface)
+ doneCurrent();
+ eglDestroySurface(dpy, surface);
+ if (surf == surface)
+ surf = EGL_NO_SURFACE;
+ }
+}
+
// Destroy the context. Note: this does not destroy the surface.
void QEglContext::destroy()
{
@@ -224,14 +249,28 @@ void QEglContext::destroy()
bool QEglContext::makeCurrent()
{
+ return makeCurrent(surf);
+}
+
+bool QEglContext::makeCurrent(EGLSurface surface)
+{
if (ctx == EGL_NO_CONTEXT) {
qWarning() << "QEglContext::makeCurrent(): Cannot make invalid context current";
return false;
}
+ // If lazyDoneCurrent() was called on the surface, then we may be able
+ // to assume that it is still current within the thread.
+ if (surface == currentSurface && currentContext(apiType) == this) {
+ current = true;
+ return true;
+ }
+
current = true;
+ currentSurface = surface;
+ setCurrentContext(apiType, this);
- bool ok = eglMakeCurrent(dpy, surf, surf, ctx);
+ bool ok = eglMakeCurrent(dpy, surface, surface, ctx);
if (!ok)
qWarning() << "QEglContext::makeCurrent():" << errorString(eglGetError());
return ok;
@@ -245,6 +284,8 @@ bool QEglContext::doneCurrent()
return false;
current = false;
+ currentSurface = EGL_NO_SURFACE;
+ setCurrentContext(apiType, 0);
// We need to select the correct API before calling eglMakeCurrent()
// with EGL_NO_CONTEXT because threads can have both OpenGL and OpenVG
@@ -264,6 +305,17 @@ bool QEglContext::doneCurrent()
return ok;
}
+// Act as though doneCurrent() was called, but keep the context
+// and the surface active for the moment. This allows makeCurrent()
+// to skip a call to eglMakeCurrent() if we are using the same
+// surface as the last set of painting operations. We leave the
+// currentContext() pointer as-is for now.
+bool QEglContext::lazyDoneCurrent()
+{
+ current = false;
+ return true;
+}
+
bool QEglContext::swapBuffers()
{
if(ctx == EGL_NO_CONTEXT)
@@ -275,6 +327,17 @@ bool QEglContext::swapBuffers()
return ok;
}
+bool QEglContext::swapBuffers(EGLSurface surface)
+{
+ if(ctx == EGL_NO_CONTEXT)
+ return false;
+
+ bool ok = eglSwapBuffers(dpy, surface);
+ if (!ok)
+ qWarning() << "QEglContext::swapBuffers():" << errorString(eglGetError());
+ return ok;
+}
+
// Wait for native rendering operations to complete before starting
// to use OpenGL/OpenVG operations.
void QEglContext::waitNative()
@@ -411,4 +474,20 @@ bool QEglContext::hasExtension(const char* extensionName)
return extensions().contains(QLatin1String(extensionName));
}
+QEglContext *QEglContext::currentContext(QEgl::API api)
+{
+ if (api == QEgl::OpenGL)
+ return currentGLContext;
+ else
+ return currentVGContext;
+}
+
+void QEglContext::setCurrentContext(QEgl::API api, QEglContext *context)
+{
+ if (api == QEgl::OpenGL)
+ currentGLContext = context;
+ else
+ currentVGContext = context;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h
index 366bd9e..3903cd0 100644
--- a/src/gui/egl/qegl_p.h
+++ b/src/gui/egl/qegl_p.h
@@ -92,12 +92,16 @@ public:
bool createSurface(QPaintDevice *device, const QEglProperties *properties = 0);
bool recreateSurface(QPaintDevice *device);
void destroySurface();
+ void destroySurface(EGLSurface surface);
void destroy();
bool makeCurrent();
+ bool makeCurrent(EGLSurface surface);
bool doneCurrent();
+ bool lazyDoneCurrent();
bool swapBuffers();
+ bool swapBuffers(EGLSurface surface);
void waitNative();
void waitClient();
@@ -131,11 +135,14 @@ private:
EGLContext ctx;
EGLSurface surf;
EGLConfig cfg;
+ EGLSurface currentSurface;
bool share;
bool current;
- void *reserved; // For extension data in future versions.
static EGLDisplay getDisplay(QPaintDevice *device);
+
+ static QEglContext *currentContext(QEgl::API api);
+ static void setCurrentContext(QEgl::API api, QEglContext *context);
};
QT_END_NAMESPACE
diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp
index 38a89e6..2003f3b 100644
--- a/src/openvg/qpixmapdata_vg.cpp
+++ b/src/openvg/qpixmapdata_vg.cpp
@@ -82,12 +82,11 @@ QVGPixmapData::~QVGPixmapData()
// We don't currently have a widget surface active, but we
// need a surface to make the context current. So use the
// shared pbuffer surface instead.
- qt_vg_make_current(context, qt_vg_shared_surface());
+ context->makeCurrent(qt_vg_shared_surface());
vgDestroyImage(vgImage);
if (vgImageOpacity != VG_INVALID_HANDLE)
vgDestroyImage(vgImageOpacity);
- qt_vg_done_current(context);
- context->setSurface(EGL_NO_SURFACE);
+ context->lazyDoneCurrent();
}
#else
vgDestroyImage(vgImage);
diff --git a/src/openvg/qvg_p.h b/src/openvg/qvg_p.h
index 764e98f..04e2bab 100644
--- a/src/openvg/qvg_p.h
+++ b/src/openvg/qvg_p.h
@@ -81,15 +81,6 @@ Q_OPENVG_EXPORT void qt_vg_destroy_context(QEglContext *context);
// destroy VGImage objects when there is no other surface available.
Q_OPENVG_EXPORT EGLSurface qt_vg_shared_surface(void);
-// Make a context current with a specific surface.
-Q_OPENVG_EXPORT void qt_vg_make_current(QEglContext *context, EGLSurface surface);
-
-// Make a context uncurrent.
-Q_OPENVG_EXPORT void qt_vg_done_current(QEglContext *context, bool force = false);
-
-// Destroy a surface that was previously associated with a context.
-Q_OPENVG_EXPORT void qt_vg_destroy_surface(QEglContext *context, EGLSurface surface);
-
// Convert the configuration format in a context to a VG or QImage format.
Q_OPENVG_EXPORT VGImageFormat qt_vg_config_to_vg_format(QEglContext *context);
Q_OPENVG_EXPORT QImage::Format qt_vg_config_to_image_format(QEglContext *context);
diff --git a/src/openvg/qwindowsurface_vgegl.cpp b/src/openvg/qwindowsurface_vgegl.cpp
index 06759d4..cb3f7fc 100644
--- a/src/openvg/qwindowsurface_vgegl.cpp
+++ b/src/openvg/qwindowsurface_vgegl.cpp
@@ -125,7 +125,6 @@ public:
int refCount;
QVGPaintEngine *engine;
EGLSurface surface;
- EGLSurface lastSurface;
};
QVGSharedContext::QVGSharedContext()
@@ -133,7 +132,6 @@ QVGSharedContext::QVGSharedContext()
, refCount(0)
, engine(0)
, surface(EGL_NO_SURFACE)
- , lastSurface(EGL_NO_SURFACE)
{
}
@@ -144,12 +142,12 @@ QVGSharedContext::~QVGSharedContext()
++refCount;
if (context)
- qt_vg_make_current(context, qt_vg_shared_surface());
+ context->makeCurrent(qt_vg_shared_surface());
delete engine;
if (context)
- qt_vg_done_current(context, true);
- if (surface != EGL_NO_SURFACE)
- qt_vg_destroy_surface(context, surface);
+ context->doneCurrent();
+ if (context && surface != EGL_NO_SURFACE)
+ context->destroySurface(surface);
delete context;
}
@@ -265,12 +263,12 @@ void qt_vg_destroy_context(QEglContext *context)
// This is not the shared context. Shouldn't happen!
delete context;
} else if (--(shared->refCount) <= 0) {
- qt_vg_make_current(shared->context, qt_vg_shared_surface());
+ shared->context->makeCurrent(qt_vg_shared_surface());
delete shared->engine;
shared->engine = 0;
- qt_vg_done_current(shared->context, true);
+ shared->context->doneCurrent();
if (shared->surface != EGL_NO_SURFACE) {
- qt_vg_destroy_surface(shared->context, shared->surface);
+ eglDestroySurface(shared->context->display(), shared->surface);
shared->surface = EGL_NO_SURFACE;
}
delete shared->context;
@@ -303,50 +301,6 @@ EGLSurface qt_vg_shared_surface(void)
return shared->surface;
}
-void qt_vg_make_current(QEglContext *context, EGLSurface surface)
-{
- // Bail out if the context and surface are already current.
- if (context->isCurrent() && context->surface() == surface)
- return;
-
- // Are we setting the surface to the same as the last elided doneCurrent()?
- QVGSharedContext *shared = sharedContext();
- if (context->isCurrent() && shared->lastSurface == surface) {
- shared->lastSurface = EGL_NO_SURFACE;
- context->setSurface(surface);
- return;
- }
-
- // Switch to the new context and surface.
- shared->lastSurface = EGL_NO_SURFACE;
- context->setSurface(surface);
- context->makeCurrent();
-}
-
-void qt_vg_done_current(QEglContext *context, bool force)
-{
- QVGSharedContext *shared = sharedContext();
- if (force) {
- context->doneCurrent();
- shared->lastSurface = EGL_NO_SURFACE;
- } else {
- // Keep the context current for now just in case we immediately
- // reuse the same surface for the next frame.
- shared->lastSurface = context->surface();
- }
-}
-
-void qt_vg_destroy_surface(QEglContext *context, EGLSurface surface)
-{
- QVGSharedContext *shared = sharedContext();
- if (shared->lastSurface == surface) {
- shared->lastSurface = EGL_NO_SURFACE;
- context->doneCurrent();
- }
- context->setSurface(surface);
- context->destroySurface();
-}
-
#else
QEglContext *qt_vg_create_context(QPaintDevice *device)
@@ -364,24 +318,6 @@ EGLSurface qt_vg_shared_surface(void)
return EGL_NO_SURFACE;
}
-void qt_vg_make_current(QEglContext *context, EGLSurface surface)
-{
- context->setSurface(surface);
- context->makeCurrent();
-}
-
-void qt_vg_done_current(QEglContext *context, bool force)
-{
- Q_UNUSED(force);
- context->doneCurrent();
-}
-
-void qt_vg_destroy_surface(QEglContext *context, EGLSurface surface)
-{
- context->setSurface(surface);
- context->destroySurface();
-}
-
#endif
QVGEGLWindowSurfacePrivate::QVGEGLWindowSurfacePrivate(QWindowSurface *win)
@@ -470,13 +406,13 @@ QVGEGLWindowSurfaceVGImage::~QVGEGLWindowSurfaceVGImage()
// We need a current context to be able to destroy the image.
// We use the shared surface because the native window handle
// associated with "windowSurface" may have been destroyed already.
- qt_vg_make_current(context, qt_vg_shared_surface());
- qt_vg_destroy_surface(context, backBufferSurface);
+ context->makeCurrent(qt_vg_shared_surface());
+ context->destroySurface(backBufferSurface);
vgDestroyImage(backBuffer);
- qt_vg_done_current(context, true);
+ context->doneCurrent();
}
if (windowSurface != EGL_NO_SURFACE)
- qt_vg_destroy_surface(context, windowSurface);
+ context->destroySurface(windowSurface);
qt_vg_destroy_context(context);
}
}
@@ -489,7 +425,7 @@ QEglContext *QVGEGLWindowSurfaceVGImage::ensureContext(QWidget *widget)
// the back buffer. Keep the same context and paint engine.
size = newSize;
if (isPaintingActive)
- qt_vg_done_current(context, true);
+ context->doneCurrent();
isPaintingActive = false;
recreateBackBuffer = true;
}
@@ -512,7 +448,7 @@ void QVGEGLWindowSurfaceVGImage::beginPaint(QWidget *widget)
// Create a VGImage object to act as the back buffer
// for this window. We have to create the VGImage with a
// current context, so activate the main surface for the window.
- qt_vg_make_current(context, mainSurface());
+ context->makeCurrent(mainSurface());
recreateBackBuffer = false;
if (backBufferSurface != EGL_NO_SURFACE) {
eglDestroySurface(context->display(), backBufferSurface);
@@ -538,9 +474,9 @@ void QVGEGLWindowSurfaceVGImage::beginPaint(QWidget *widget)
}
}
if (backBufferSurface != EGL_NO_SURFACE)
- qt_vg_make_current(context, backBufferSurface);
+ context->makeCurrent(backBufferSurface);
else
- qt_vg_make_current(context, mainSurface());
+ context->makeCurrent(mainSurface());
isPaintingActive = true;
}
}
@@ -555,9 +491,8 @@ void QVGEGLWindowSurfaceVGImage::endPaint
if (backBufferSurface != EGL_NO_SURFACE) {
if (isPaintingActive)
vgFlush();
- qt_vg_done_current(context);
+ context->lazyDoneCurrent();
}
- context->setSurface(EGL_NO_SURFACE);
isPaintingActive = false;
}
}
@@ -592,7 +527,7 @@ void QVGEGLWindowSurfaceQImage::endPaint
if (backBufferSurface != EGL_NO_SURFACE) {
if (isPaintingActive)
vgFlush();
- qt_vg_make_current(context, mainSurface());
+ context->makeCurrent(mainSurface());
QRegion rgn = region.intersected
(QRect(0, 0, image->width(), image->height()));
if (rgn.numRects() == 1) {
@@ -602,9 +537,8 @@ void QVGEGLWindowSurfaceQImage::endPaint
for (int index = 0; index < rects.size(); ++index)
copySubImage(image, backBuffer, rects[index]);
}
- qt_vg_done_current(context);
+ context->lazyDoneCurrent();
}
- context->setSurface(EGL_NO_SURFACE);
isPaintingActive = false;
}
}
@@ -625,7 +559,7 @@ QVGEGLWindowSurfaceDirect::~QVGEGLWindowSurfaceDirect()
destroyPaintEngine();
if (context) {
if (windowSurface != EGL_NO_SURFACE)
- qt_vg_destroy_surface(context, windowSurface);
+ context->destroySurface(windowSurface);
qt_vg_destroy_context(context);
}
}
@@ -642,9 +576,8 @@ QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget)
// We can keep the same context and paint engine.
size = newSize;
if (isPaintingActive)
- qt_vg_done_current(context, true);
- context->setSurface(windowSurface);
- context->destroySurface();
+ context->doneCurrent();
+ context->destroySurface(windowSurface);
#if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT)
if (isPremultipliedContext(context)) {
surfaceProps.setValue
@@ -667,8 +600,7 @@ QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget)
// in the new context.
qt_vg_destroy_paint_engine(engine);
engine = 0;
- context->setSurface(windowSurface);
- context->destroySurface();
+ context->destroySurface(windowSurface);
qt_vg_destroy_context(context);
context = 0;
windowSurface = EGL_NO_SURFACE;
@@ -730,7 +662,7 @@ void QVGEGLWindowSurfaceDirect::beginPaint(QWidget *widget)
{
QEglContext *context = ensureContext(widget);
if (context) {
- qt_vg_make_current(context, windowSurface);
+ context->makeCurrent(windowSurface);
isPaintingActive = true;
}
}
@@ -744,14 +676,13 @@ void QVGEGLWindowSurfaceDirect::endPaint
if (context) {
if (needToSwap) {
if (!isPaintingActive)
- qt_vg_make_current(context, windowSurface);
- context->swapBuffers();
- qt_vg_done_current(context);
+ context->makeCurrent(windowSurface);
+ context->swapBuffers(windowSurface);
+ context->lazyDoneCurrent();
} else if (isPaintingActive) {
vgFlush();
- qt_vg_done_current(context);
+ context->lazyDoneCurrent();
}
- context->setSurface(EGL_NO_SURFACE);
isPaintingActive = false;
}
}