Let QPlatformBackingStore handle its own QOpenGLContext
The resources allocated by QPlatformBackingStore are owned by the class, and should be allocated in a context the class also owns. This removes the asymmetry of having to pass in a context to composeAndFlush, while having to make the same context current before destroying the platform backingstore. The context owned by QPlatformBackingStore is shared with the associated window though a new QWindowPrivate::shareContext() API. The result is that on e.g. iOS, the backingstore does not need to tie the resource allocation of QPlatformBackingStore to the global share context, but can instead tie them to the per-window context, and hence clean them up after each window is closed. Task-number: QTBUG-56653 Change-Id: Ic1bcae50dafeeafaa8d16a7febd83b840ec6367a Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io> Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
parent
aeee3be166
commit
8e70241dcc
@ -45,6 +45,7 @@
|
|||||||
#ifndef QT_NO_OPENGL
|
#ifndef QT_NO_OPENGL
|
||||||
#include <qpa/qplatformopenglcontext.h>
|
#include <qpa/qplatformopenglcontext.h>
|
||||||
#include "qopenglcontext.h"
|
#include "qopenglcontext.h"
|
||||||
|
#include "qopenglcontext_p.h"
|
||||||
#endif
|
#endif
|
||||||
#include "qscreen.h"
|
#include "qscreen.h"
|
||||||
|
|
||||||
@ -2633,6 +2634,11 @@ QWindow *QWindowPrivate::topLevelWindow() const
|
|||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QOpenGLContext *QWindowPrivate::shareContext() const
|
||||||
|
{
|
||||||
|
return qt_gl_global_share_context();
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Creates a local representation of a window created by another process or by
|
Creates a local representation of a window created by another process or by
|
||||||
using native libraries below Qt.
|
using native libraries below Qt.
|
||||||
|
@ -130,6 +130,8 @@ public:
|
|||||||
|
|
||||||
QWindow *topLevelWindow() const;
|
QWindow *topLevelWindow() const;
|
||||||
|
|
||||||
|
virtual QOpenGLContext *shareContext() const;
|
||||||
|
|
||||||
virtual QWindow *eventReceiver() { Q_Q(QWindow); return q; }
|
virtual QWindow *eventReceiver() { Q_Q(QWindow); return q; }
|
||||||
|
|
||||||
virtual void setVisible(bool visible);
|
virtual void setVisible(bool visible);
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include <QtGui/QOpenGLFunctions>
|
#include <QtGui/QOpenGLFunctions>
|
||||||
#ifndef QT_NO_OPENGL
|
#ifndef QT_NO_OPENGL
|
||||||
#include <QtGui/qopengltextureblitter.h>
|
#include <QtGui/qopengltextureblitter.h>
|
||||||
|
#include <QtGui/qoffscreensurface.h>
|
||||||
#endif
|
#endif
|
||||||
#include <qpa/qplatformgraphicsbuffer.h>
|
#include <qpa/qplatformgraphicsbuffer.h>
|
||||||
#include <qpa/qplatformgraphicsbufferhelper.h>
|
#include <qpa/qplatformgraphicsbufferhelper.h>
|
||||||
@ -95,14 +96,15 @@ public:
|
|||||||
~QPlatformBackingStorePrivate()
|
~QPlatformBackingStorePrivate()
|
||||||
{
|
{
|
||||||
#ifndef QT_NO_OPENGL
|
#ifndef QT_NO_OPENGL
|
||||||
QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
if (context) {
|
||||||
if (ctx) {
|
QOffscreenSurface offscreenSurface;
|
||||||
|
offscreenSurface.setFormat(context->format());
|
||||||
|
offscreenSurface.create();
|
||||||
|
context->makeCurrent(&offscreenSurface);
|
||||||
if (textureId)
|
if (textureId)
|
||||||
ctx->functions()->glDeleteTextures(1, &textureId);
|
context->functions()->glDeleteTextures(1, &textureId);
|
||||||
if (blitter)
|
if (blitter)
|
||||||
blitter->destroy();
|
blitter->destroy();
|
||||||
} else if (textureId || blitter) {
|
|
||||||
qWarning("No context current during QPlatformBackingStore destruction, OpenGL resources not released");
|
|
||||||
}
|
}
|
||||||
delete blitter;
|
delete blitter;
|
||||||
#endif
|
#endif
|
||||||
@ -110,6 +112,7 @@ public:
|
|||||||
QWindow *window;
|
QWindow *window;
|
||||||
QBackingStore *backingStore;
|
QBackingStore *backingStore;
|
||||||
#ifndef QT_NO_OPENGL
|
#ifndef QT_NO_OPENGL
|
||||||
|
QScopedPointer<QOpenGLContext> context;
|
||||||
mutable GLuint textureId;
|
mutable GLuint textureId;
|
||||||
mutable QSize textureSize;
|
mutable QSize textureSize;
|
||||||
mutable bool needsSwizzle;
|
mutable bool needsSwizzle;
|
||||||
@ -316,20 +319,31 @@ static void blitTextureForWidget(const QPlatformTextureList *textures, int idx,
|
|||||||
|
|
||||||
void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion,
|
void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion,
|
||||||
const QPoint &offset,
|
const QPoint &offset,
|
||||||
QPlatformTextureList *textures, QOpenGLContext *context,
|
QPlatformTextureList *textures,
|
||||||
bool translucentBackground)
|
bool translucentBackground)
|
||||||
{
|
{
|
||||||
if (!qt_window_private(window)->receivedExpose)
|
if (!qt_window_private(window)->receivedExpose)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!context->makeCurrent(window)) {
|
if (!d_ptr->context) {
|
||||||
|
d_ptr->context.reset(new QOpenGLContext);
|
||||||
|
d_ptr->context->setFormat(d_ptr->window->requestedFormat());
|
||||||
|
d_ptr->context->setScreen(d_ptr->window->screen());
|
||||||
|
d_ptr->context->setShareContext(qt_window_private(d_ptr->window)->shareContext());
|
||||||
|
if (!d_ptr->context->create()) {
|
||||||
|
qWarning("composeAndFlush: QOpenGLContext creation failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d_ptr->context->makeCurrent(window)) {
|
||||||
qWarning("composeAndFlush: makeCurrent() failed");
|
qWarning("composeAndFlush: makeCurrent() failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWindowPrivate::get(window)->lastComposeTime.start();
|
QWindowPrivate::get(window)->lastComposeTime.start();
|
||||||
|
|
||||||
QOpenGLFunctions *funcs = context->functions();
|
QOpenGLFunctions *funcs = d_ptr->context->functions();
|
||||||
funcs->glViewport(0, 0, window->width() * window->devicePixelRatio(), window->height() * window->devicePixelRatio());
|
funcs->glViewport(0, 0, window->width() * window->devicePixelRatio(), window->height() * window->devicePixelRatio());
|
||||||
funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1);
|
funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1);
|
||||||
funcs->glClear(GL_COLOR_BUFFER_BIT);
|
funcs->glClear(GL_COLOR_BUFFER_BIT);
|
||||||
@ -435,7 +449,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i
|
|||||||
funcs->glDisable(GL_BLEND);
|
funcs->glDisable(GL_BLEND);
|
||||||
d_ptr->blitter->release();
|
d_ptr->blitter->release();
|
||||||
|
|
||||||
context->swapBuffers(window);
|
d_ptr->context->swapBuffers(window);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/*!
|
/*!
|
||||||
|
@ -120,7 +120,7 @@ public:
|
|||||||
virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) = 0;
|
virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) = 0;
|
||||||
#ifndef QT_NO_OPENGL
|
#ifndef QT_NO_OPENGL
|
||||||
virtual void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
virtual void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
||||||
QPlatformTextureList *textures, QOpenGLContext *context,
|
QPlatformTextureList *textures,
|
||||||
bool translucentBackground);
|
bool translucentBackground);
|
||||||
#endif
|
#endif
|
||||||
virtual QImage toImage() const;
|
virtual QImage toImage() const;
|
||||||
|
@ -202,14 +202,13 @@ void QOpenGLCompositorBackingStore::flush(QWindow *window, const QRegion ®ion
|
|||||||
}
|
}
|
||||||
|
|
||||||
void QOpenGLCompositorBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
void QOpenGLCompositorBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
||||||
QPlatformTextureList *textures, QOpenGLContext *context,
|
QPlatformTextureList *textures,
|
||||||
bool translucentBackground)
|
bool translucentBackground)
|
||||||
{
|
{
|
||||||
// QOpenGLWidget/QQuickWidget content provided as textures. The raster content goes on top.
|
// QOpenGLWidget/QQuickWidget content provided as textures. The raster content goes on top.
|
||||||
|
|
||||||
Q_UNUSED(region);
|
Q_UNUSED(region);
|
||||||
Q_UNUSED(offset);
|
Q_UNUSED(offset);
|
||||||
Q_UNUSED(context);
|
|
||||||
Q_UNUSED(translucentBackground);
|
Q_UNUSED(translucentBackground);
|
||||||
|
|
||||||
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
|
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
|
||||||
@ -218,7 +217,7 @@ void QOpenGLCompositorBackingStore::composeAndFlush(QWindow *window, const QRegi
|
|||||||
|
|
||||||
// The compositor's context and the context to which QOpenGLWidget/QQuickWidget
|
// The compositor's context and the context to which QOpenGLWidget/QQuickWidget
|
||||||
// textures belong are not the same. They share resources, though.
|
// textures belong are not the same. They share resources, though.
|
||||||
Q_ASSERT(context->shareGroup() == dstCtx->shareGroup());
|
Q_ASSERT(qt_window_private(window)->shareContext()->shareGroup() == dstCtx->shareGroup());
|
||||||
|
|
||||||
QWindow *dstWin = compositor->targetWindow();
|
QWindow *dstWin = compositor->targetWindow();
|
||||||
if (!dstWin)
|
if (!dstWin)
|
||||||
|
@ -75,7 +75,7 @@ public:
|
|||||||
|
|
||||||
QImage toImage() const Q_DECL_OVERRIDE;
|
QImage toImage() const Q_DECL_OVERRIDE;
|
||||||
void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
||||||
QPlatformTextureList *textures, QOpenGLContext *context,
|
QPlatformTextureList *textures,
|
||||||
bool translucentBackground) Q_DECL_OVERRIDE;
|
bool translucentBackground) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
const QPlatformTextureList *textures() const { return m_textures; }
|
const QPlatformTextureList *textures() const { return m_textures; }
|
||||||
|
@ -55,9 +55,6 @@ public:
|
|||||||
~QIOSBackingStore();
|
~QIOSBackingStore();
|
||||||
|
|
||||||
void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE;
|
void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private:
|
|
||||||
QOpenGLContext *m_context;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -55,7 +55,6 @@ QT_BEGIN_NAMESPACE
|
|||||||
*/
|
*/
|
||||||
QIOSBackingStore::QIOSBackingStore(QWindow *window)
|
QIOSBackingStore::QIOSBackingStore(QWindow *window)
|
||||||
: QRasterBackingStore(window)
|
: QRasterBackingStore(window)
|
||||||
, m_context(new QOpenGLContext)
|
|
||||||
{
|
{
|
||||||
// We use the surface both for raster operations and for GL drawing (when
|
// We use the surface both for raster operations and for GL drawing (when
|
||||||
// we blit the raster image), so the type needs to cover both use cases.
|
// we blit the raster image), so the type needs to cover both use cases.
|
||||||
@ -64,22 +63,10 @@ QIOSBackingStore::QIOSBackingStore(QWindow *window)
|
|||||||
|
|
||||||
Q_ASSERT_X(window->surfaceType() != QSurface::OpenGLSurface, "QIOSBackingStore",
|
Q_ASSERT_X(window->surfaceType() != QSurface::OpenGLSurface, "QIOSBackingStore",
|
||||||
"QBackingStore on iOS can only be used with raster-enabled surfaces.");
|
"QBackingStore on iOS can only be used with raster-enabled surfaces.");
|
||||||
|
|
||||||
m_context->setFormat(window->requestedFormat());
|
|
||||||
m_context->setScreen(window->screen());
|
|
||||||
Q_ASSERT(QOpenGLContext::globalShareContext());
|
|
||||||
m_context->setShareContext(QOpenGLContext::globalShareContext());
|
|
||||||
m_context->create();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QIOSBackingStore::~QIOSBackingStore()
|
QIOSBackingStore::~QIOSBackingStore()
|
||||||
{
|
{
|
||||||
// We're using composeAndFlush from QPlatformBackingStore, which
|
|
||||||
// need to clean up any textures in its destructor, so make the
|
|
||||||
// context current and keep it alive until QPlatformBackingStore
|
|
||||||
// has cleaned up everything.
|
|
||||||
m_context->makeCurrent(window());
|
|
||||||
m_context->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset)
|
void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset)
|
||||||
@ -98,7 +85,7 @@ void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin
|
|||||||
}
|
}
|
||||||
|
|
||||||
static QPlatformTextureList emptyTextureList;
|
static QPlatformTextureList emptyTextureList;
|
||||||
composeAndFlush(window, region, offset, &emptyTextureList, m_context, false);
|
composeAndFlush(window, region, offset, &emptyTextureList, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -600,10 +600,10 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin
|
|||||||
|
|
||||||
#ifndef QT_NO_OPENGL
|
#ifndef QT_NO_OPENGL
|
||||||
void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
||||||
QPlatformTextureList *textures, QOpenGLContext *context,
|
QPlatformTextureList *textures,
|
||||||
bool translucentBackground)
|
bool translucentBackground)
|
||||||
{
|
{
|
||||||
QPlatformBackingStore::composeAndFlush(window, region, offset, textures, context, translucentBackground);
|
QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground);
|
||||||
|
|
||||||
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
|
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
|
||||||
if (platformWindow->needsSync()) {
|
if (platformWindow->needsSync()) {
|
||||||
|
@ -61,7 +61,7 @@ public:
|
|||||||
void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) override;
|
void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) override;
|
||||||
#ifndef QT_NO_OPENGL
|
#ifndef QT_NO_OPENGL
|
||||||
void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
||||||
QPlatformTextureList *textures, QOpenGLContext *context,
|
QPlatformTextureList *textures,
|
||||||
bool translucentBackground) override;
|
bool translucentBackground) override;
|
||||||
#endif
|
#endif
|
||||||
QImage toImage() const override;
|
QImage toImage() const override;
|
||||||
|
@ -1876,39 +1876,15 @@ static void deleteBackingStore(QWidgetPrivate *d)
|
|||||||
{
|
{
|
||||||
QTLWExtra *topData = d->topData();
|
QTLWExtra *topData = d->topData();
|
||||||
|
|
||||||
// The context must be current when destroying the backing store as it may attempt to
|
|
||||||
// release resources like textures and shader programs. The window may not be suitable
|
|
||||||
// anymore as there will often not be a platform window underneath at this stage. Fall
|
|
||||||
// back to a QOffscreenSurface in this case.
|
|
||||||
QScopedPointer<QOffscreenSurface> tempSurface;
|
|
||||||
#ifndef QT_NO_OPENGL
|
|
||||||
if (d->textureChildSeen && topData->shareContext) {
|
|
||||||
if (topData->window->handle()) {
|
|
||||||
topData->shareContext->makeCurrent(topData->window);
|
|
||||||
} else {
|
|
||||||
tempSurface.reset(new QOffscreenSurface);
|
|
||||||
tempSurface->setFormat(topData->shareContext->format());
|
|
||||||
tempSurface->create();
|
|
||||||
topData->shareContext->makeCurrent(tempSurface.data());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
delete topData->backingStore;
|
delete topData->backingStore;
|
||||||
topData->backingStore = 0;
|
topData->backingStore = 0;
|
||||||
|
|
||||||
#ifndef QT_NO_OPENGL
|
|
||||||
if (d->textureChildSeen && topData->shareContext)
|
|
||||||
topData->shareContext->doneCurrent();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWidgetPrivate::deleteTLSysExtra()
|
void QWidgetPrivate::deleteTLSysExtra()
|
||||||
{
|
{
|
||||||
if (extra && extra->topextra) {
|
if (extra && extra->topextra) {
|
||||||
//the qplatformbackingstore may hold a reference to the window, so the backingstore
|
//the qplatformbackingstore may hold a reference to the window, so the backingstore
|
||||||
//needs to be deleted first. If the backingstore holds GL resources, we need to
|
//needs to be deleted first.
|
||||||
// make the context current here. This is taken care of by deleteBackingStore().
|
|
||||||
|
|
||||||
extra->topextra->backingStoreTracker.destroy();
|
extra->topextra->backingStoreTracker.destroy();
|
||||||
deleteBackingStore(this);
|
deleteBackingStore(this);
|
||||||
|
@ -143,10 +143,8 @@ void QWidgetBackingStore::qt_flush(QWidget *widget, const QRegion ®ion, QBack
|
|||||||
// WA_TranslucentBackground. Therefore the compositor needs to know whether the app intends
|
// WA_TranslucentBackground. Therefore the compositor needs to know whether the app intends
|
||||||
// to rely on translucency, in order to decide if it should clear to transparent or opaque.
|
// to rely on translucency, in order to decide if it should clear to transparent or opaque.
|
||||||
const bool translucentBackground = widget->testAttribute(Qt::WA_TranslucentBackground);
|
const bool translucentBackground = widget->testAttribute(Qt::WA_TranslucentBackground);
|
||||||
// Use the tlw's context, not widget's. The difference is important with native child
|
backingStore->handle()->composeAndFlush(widget->windowHandle(), effectiveRegion, offset,
|
||||||
// widgets where tlw != widget.
|
widgetTextures, translucentBackground);
|
||||||
backingStore->handle()->composeAndFlush(widget->windowHandle(), effectiveRegion, offset, widgetTextures,
|
|
||||||
tlw->d_func()->shareContext(), translucentBackground);
|
|
||||||
widget->window()->d_func()->sendComposeStatus(widget->window(), true);
|
widget->window()->d_func()->sendComposeStatus(widget->window(), true);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
@ -96,6 +96,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
QRectF closestAcceptableGeometry(const QRectF &rect) const Q_DECL_OVERRIDE;
|
QRectF closestAcceptableGeometry(const QRectF &rect) const Q_DECL_OVERRIDE;
|
||||||
|
QOpenGLContext *shareContext() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const
|
QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const
|
||||||
@ -127,6 +128,13 @@ QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QOpenGLContext *QWidgetWindowPrivate::shareContext() const
|
||||||
|
{
|
||||||
|
Q_Q(const QWidgetWindow);
|
||||||
|
const QWidgetPrivate *widgetPrivate = QWidgetPrivate::get(q->widget());
|
||||||
|
return widgetPrivate->shareContext();
|
||||||
|
}
|
||||||
|
|
||||||
QWidgetWindow::QWidgetWindow(QWidget *widget)
|
QWidgetWindow::QWidgetWindow(QWidget *widget)
|
||||||
: QWindow(*new QWidgetWindowPrivate(), 0)
|
: QWindow(*new QWidgetWindowPrivate(), 0)
|
||||||
, m_widget(widget)
|
, m_widget(widget)
|
||||||
|
Loading…
Reference in New Issue
Block a user