diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/egl/qegl.cpp | 83 | ||||
-rw-r--r-- | src/gui/egl/qegl_p.h | 9 | ||||
-rw-r--r-- | src/openvg/qpixmapdata_vg.cpp | 5 | ||||
-rw-r--r-- | src/openvg/qvg_p.h | 9 | ||||
-rw-r--r-- | src/openvg/qwindowsurface_vgegl.cpp | 123 |
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; } } |