macOS: Update NSOpenGLContext drawable on beginning of frame if needed

If the size or DPR of the window we're drawing to with QOpenGLContext
changes we need to call [NSOpenGLContext update] to recreate the backing
texture.

We were doing this in QCocoaGLContext::makeCurrent(), based on the
assumption that clients would always call makeCurrent() before drawing,
which is a documented requirement of QOpenGLContext:

  "To be able to support certain platforms, QOpenGLContext requires
  that you call makeCurrent() again before starting rendering a new
  frame, after calling swapBuffers()."

However RHI doesn't follow this rule, and skips makeCurrent() from
QRhiGles2::ensureContext() if the context is already current.

This was causing issues when moving a window between screens with
different device-pixel-ratios, as we were correctly rendering to
the window with the updated DPR, but we had not resized the target
texture to match.

Changing QRhiGles2::ensureContext() might be an option, but nowadays
we have QPlatformOpenGLContext::beginFrame(), which is guaranteed
to be called (by RHI, not by generic QOpenGLContext clients).

To cater for RHI we now call [NSOpenGLContext update] also from
the beginFrame callback.

Fixes: QTBUG-114873
Pick-to: 6.5
Change-Id: I9461135109fb1473ef9965f72f52beeb41b03680
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
(cherry picked from commit 48c176e1b891428af504087b117a72bcaa806930)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Tor Arne Vestbø 2024-10-28 16:05:10 +01:00 committed by Qt Cherry-pick Bot
parent 945c8bf54d
commit 1696091c5b
2 changed files with 20 additions and 0 deletions

View File

@ -29,6 +29,7 @@ public:
void initialize() override;
bool makeCurrent(QPlatformSurface *surface) override;
void beginFrame() override;
void swapBuffers(QPlatformSurface *surface) override;
void doneCurrent() override;

View File

@ -332,6 +332,25 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
return true;
}
void QCocoaGLContext::beginFrame()
{
QMacAutoReleasePool pool;
Q_ASSERT(context() && context()->surface());
auto *surface = context()->surface()->surfaceHandle();
Q_ASSERT(surface);
qCDebug(lcQpaOpenGLContext) << "Beginning frame for" << this
<< "in" << QThread::currentThread() << "for" << surface;
Q_ASSERT(surface->surface()->supportsOpenGL());
if (surface->surface()->surfaceClass() == QSurface::Window) {
if (m_needsUpdate.fetchAndStoreRelaxed(false))
update();
}
}
/*!
Sets the drawable object of the NSOpenGLContext, which is the
frame buffer that is the target of OpenGL drawing operations.