Utilize EGL_KHR_surfaceless_context in QOffscreenSurface when available
Use it also in the context initialization code which also relied on pbuffers until now. This is safe to do since QOffscreenSurface is deliberately kept minimal: we only support it for rendering to FBOs or uploading textures, it is quite useless for any rendering type of operation. Therefore simply not creating a surface when the extension is available is viable and should not break anything. While we should have done this a long time ago, the real inspiration now is to avoid crashes with some bad EGL implementations. Mesa in particular tends to crash in its interal configuration handling when trying to create a pbuffer surface with more exotic attributes, for example with multisampling enabled. Just getting rid of those properties is not an option since the resulting pbuffer would not be compatible with the existing context. Therefore our only option is to avoid the pbuffer altogether. There's a so-far-ignored patch for Mesa http://patchwork.freedesktop.org/patch/38100/ which tries to solve some of this but it turns out it is not sufficient to avoid problems with the multisampled case. So to avoid more headache, we just stop using pbuffers there. [ChangeLog][QtGui] QOffscreenSurface is now relying on EGL_KHR_surfaceless_context when available, and avoids creating a pbuffer surface when the extension is present. Change-Id: Id18742768b8e66c8d92ce65a9bf64b0296e14db7 Reviewed-by: Sean Harmer <sean.harmer@kdab.com>bb10
parent
5382312e5c
commit
d800180f82
|
|
@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE
|
|||
QOffscreenSurface is intended to be used with QOpenGLContext to allow rendering with OpenGL in
|
||||
an arbitrary thread without the need to create a QWindow.
|
||||
|
||||
Even though the surface is renderable, the surface's pixels are not accessible.
|
||||
Even though the surface is typically renderable, the surface's pixels are not accessible.
|
||||
QOffscreenSurface should only be used to create OpenGL resources such as textures
|
||||
or framebuffer objects.
|
||||
|
||||
|
|
@ -77,6 +77,11 @@ QT_BEGIN_NAMESPACE
|
|||
created}. Passing the format returned from QWindow::requestedFormat() to setFormat()
|
||||
may result in an incompatible offscreen surface since the underlying windowing system
|
||||
interface may offer a different set of configurations for window and pbuffer surfaces.
|
||||
|
||||
\note Some platforms may utilize a surfaceless context extension (for example
|
||||
EGL_KHR_surfaceless_context) when available. In this case there will be no underlying
|
||||
native surface. For the use cases of QOffscreenSurface (rendering to FBOs, texture
|
||||
upload) this is not a problem.
|
||||
*/
|
||||
class Q_GUI_EXPORT QOffscreenSurfacePrivate : public QObjectPrivate
|
||||
{
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@ QEGLPbuffer::QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffs
|
|||
, m_display(display)
|
||||
, m_pbuffer(EGL_NO_SURFACE)
|
||||
{
|
||||
if (q_hasEglExtension(display, "EGL_KHR_surfaceless_context"))
|
||||
return;
|
||||
|
||||
EGLConfig config = q_configFromGLFormat(m_display, m_format, false, EGL_PBUFFER_BIT);
|
||||
|
||||
if (config) {
|
||||
|
|
@ -74,7 +77,8 @@ QEGLPbuffer::QEGLPbuffer(EGLDisplay display, const QSurfaceFormat &format, QOffs
|
|||
|
||||
QEGLPbuffer::~QEGLPbuffer()
|
||||
{
|
||||
eglDestroySurface(m_display, m_pbuffer);
|
||||
if (m_pbuffer != EGL_NO_SURFACE)
|
||||
eglDestroySurface(m_display, m_pbuffer);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -278,7 +278,13 @@ void QEGLPlatformContext::updateFormatFromGL()
|
|||
EGLSurface prevSurfaceDraw = eglGetCurrentSurface(EGL_DRAW);
|
||||
EGLSurface prevSurfaceRead = eglGetCurrentSurface(EGL_READ);
|
||||
|
||||
EGLSurface tempSurface = createTemporaryOffscreenSurface();
|
||||
// Rely on the surfaceless extension, if available. This is beneficial since we can
|
||||
// avoid creating an extra pbuffer surface which is apparently troublesome with some
|
||||
// drivers (Mesa) when certain attributes are present (multisampling).
|
||||
EGLSurface tempSurface = EGL_NO_SURFACE;
|
||||
if (!q_hasEglExtension(m_eglDisplay, "EGL_KHR_surfaceless_context"))
|
||||
tempSurface = createTemporaryOffscreenSurface();
|
||||
|
||||
if (eglMakeCurrent(m_eglDisplay, tempSurface, tempSurface, m_eglContext)) {
|
||||
if (m_format.renderableType() == QSurfaceFormat::OpenGL
|
||||
|| m_format.renderableType() == QSurfaceFormat::OpenGLES) {
|
||||
|
|
@ -316,8 +322,11 @@ void QEGLPlatformContext::updateFormatFromGL()
|
|||
}
|
||||
}
|
||||
eglMakeCurrent(prevDisplay, prevSurfaceDraw, prevSurfaceRead, prevContext);
|
||||
} else {
|
||||
qWarning("QEGLPlatformContext: Failed to make temporary surface current, format not updated");
|
||||
}
|
||||
destroyTemporaryOffscreenSurface(tempSurface);
|
||||
if (tempSurface != EGL_NO_SURFACE)
|
||||
destroyTemporaryOffscreenSurface(tempSurface);
|
||||
#endif // QT_NO_OPENGL
|
||||
}
|
||||
|
||||
|
|
@ -354,7 +363,8 @@ bool QEGLPlatformContext::makeCurrent(QPlatformSurface *surface)
|
|||
: surface->format().swapInterval();
|
||||
if (requestedSwapInterval >= 0 && m_swapInterval != requestedSwapInterval) {
|
||||
m_swapInterval = requestedSwapInterval;
|
||||
eglSwapInterval(eglDisplay(), m_swapInterval);
|
||||
if (eglSurface != EGL_NO_SURFACE) // skip if using surfaceless context
|
||||
eglSwapInterval(eglDisplay(), m_swapInterval);
|
||||
}
|
||||
} else {
|
||||
qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError());
|
||||
|
|
@ -383,9 +393,11 @@ void QEGLPlatformContext::swapBuffers(QPlatformSurface *surface)
|
|||
{
|
||||
eglBindAPI(m_api);
|
||||
EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface);
|
||||
bool ok = eglSwapBuffers(m_eglDisplay, eglSurface);
|
||||
if (!ok)
|
||||
qWarning("QEGLPlatformContext: eglSwapBuffers failed: %x", eglGetError());
|
||||
if (eglSurface != EGL_NO_SURFACE) { // skip if using surfaceless context
|
||||
bool ok = eglSwapBuffers(m_eglDisplay, eglSurface);
|
||||
if (!ok)
|
||||
qWarning("QEGLPlatformContext: eglSwapBuffers failed: %x", eglGetError());
|
||||
}
|
||||
}
|
||||
|
||||
void (*QEGLPlatformContext::getProcAddress(const QByteArray &procName)) ()
|
||||
|
|
|
|||
Loading…
Reference in New Issue