From 39b0a6f152d70eff50fde978c074a6a0860e6394 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 12 Sep 2019 16:09:36 +0200 Subject: [PATCH] rhi: gl: Pick up context loss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...and change the return value of makeThreadLocalNativeContextCurrent() to a bool since we expect this to mirror QOpenGLContext::makeCurrent(). Change-Id: I339507152e461fe28fcf7fe777165e6d0072f055 Reviewed-by: Christian Strømme --- src/gui/rhi/qrhi.cpp | 43 +++++++++++++++++++++++++++++++----- src/gui/rhi/qrhi_p.h | 2 +- src/gui/rhi/qrhi_p_p.h | 2 +- src/gui/rhi/qrhid3d11.cpp | 5 +++-- src/gui/rhi/qrhid3d11_p_p.h | 2 +- src/gui/rhi/qrhigles2.cpp | 29 +++++++++++++++--------- src/gui/rhi/qrhigles2_p_p.h | 3 ++- src/gui/rhi/qrhimetal.mm | 5 +++-- src/gui/rhi/qrhimetal_p_p.h | 2 +- src/gui/rhi/qrhinull.cpp | 5 +++-- src/gui/rhi/qrhinull_p_p.h | 2 +- src/gui/rhi/qrhivulkan.cpp | 5 +++-- src/gui/rhi/qrhivulkan_p_p.h | 2 +- 13 files changed, 76 insertions(+), 31 deletions(-) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 585dc8a8fae..858be0159b3 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -468,7 +468,7 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") \value FrameOpDeviceLost The graphics device was lost. This can be recoverable by attempting to repeat the operation (such as, beginFrame()) after releasing and reinitializing all objects backed by native graphics - resources. + resources. See isDeviceLost(). */ /*! @@ -5022,10 +5022,17 @@ const QRhiNativeHandles *QRhi::nativeHandles() has to ensure external OpenGL code provided by the application can still run like it did before with direct usage of OpenGL, as long as the QRhi is using the OpenGL backend. + + \return false when failed, similarly to QOpenGLContext::makeCurrent(). When + the operation failed, isDeviceLost() can be called to determine if there + was a loss of context situation. Such a check is equivalent to checking via + QOpenGLContext::isValid(). + + \sa QOpenGLContext::makeCurrent(), QOpenGLContext::isValid() */ -void QRhi::makeThreadLocalNativeContextCurrent() +bool QRhi::makeThreadLocalNativeContextCurrent() { - d->makeThreadLocalNativeContextCurrent(); + return d->makeThreadLocalNativeContextCurrent(); } /*! @@ -5092,6 +5099,12 @@ void QRhi::releaseCachedResources() reinitialized then. However, applications and libraries working directly with QRhi are expected to be prepared to check and handle device loss situations themselves. + + \note With OpenGL, applications may need to opt-in to context reset + notifications by setting QSurfaceFormat::ResetNotification on the + QOpenGLContext. This is typically done by enabling the flag in + QRhiGles2InitParams::format. Keep in mind however that some systems may + generate context resets situations even when this flag is not set. */ bool QRhi::isDeviceLost() const { @@ -5259,7 +5272,17 @@ QRhiSwapChain *QRhi::newSwapChain() \endlist - \sa endFrame(), beginOffscreenFrame() + \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult + value on failure. Some of these should be treated as soft, "try again + later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned, + the swapchain is to be resized or updated by calling + QRhiSwapChain::buildOrResize(). The application should then attempt to + generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is + lost but this may also be recoverable by releasing all resources, including + the QRhi itself, and then recreating all resources. See isDeviceLost() for + further discussion. + + \sa endFrame(), beginOffscreenFrame(), isDeviceLost() */ QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags) { @@ -5284,7 +5307,17 @@ QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags f Passing QRhi::SkipPresent skips queuing the Present command or calling swapBuffers. - \sa beginFrame() + \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult + value on failure. Some of these should be treated as soft, "try again + later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned, + the swapchain is to be resized or updated by calling + QRhiSwapChain::buildOrResize(). The application should then attempt to + generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is + lost but this may also be recoverable by releasing all resources, including + the QRhi itself, and then recreating all resources. See isDeviceLost() for + further discussion. + + \sa beginFrame(), isDeviceLost() */ QRhi::FrameOpResult QRhi::endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags) { diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 6f0b8e0b04b..c73f03cf72f 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -1414,7 +1414,7 @@ public: int resourceLimit(ResourceLimit limit) const; const QRhiNativeHandles *nativeHandles(); - void makeThreadLocalNativeContextCurrent(); + bool makeThreadLocalNativeContextCurrent(); QRhiProfiler *profiler(); diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h index 7c0b000c339..63f27b6de42 100644 --- a/src/gui/rhi/qrhi_p_p.h +++ b/src/gui/rhi/qrhi_p_p.h @@ -156,7 +156,7 @@ public: virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0; virtual const QRhiNativeHandles *nativeHandles() = 0; virtual void sendVMemStatsToProfiler() = 0; - virtual void makeThreadLocalNativeContextCurrent() = 0; + virtual bool makeThreadLocalNativeContextCurrent() = 0; virtual void releaseCachedResources() = 0; virtual bool isDeviceLost() const = 0; diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 0977a3042de..1d2f3cfa806 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -502,9 +502,10 @@ void QRhiD3D11::sendVMemStatsToProfiler() // nothing to do here } -void QRhiD3D11::makeThreadLocalNativeContextCurrent() +bool QRhiD3D11::makeThreadLocalNativeContextCurrent() { - // nothing to do here + // not applicable + return false; } void QRhiD3D11::releaseCachedResources() diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index da7fe84b1a1..cf4808510ca 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -631,7 +631,7 @@ public: int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; - void makeThreadLocalNativeContextCurrent() override; + bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; bool isDeviceLost() const override; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index d408490b344..2d51d892e32 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -371,7 +371,12 @@ bool QRhiGles2::ensureContext(QSurface *surface) const return true; if (!ctx->makeCurrent(surface)) { - qWarning("QRhiGles2: Failed to make context current. Expect bad things to happen."); + if (ctx->isValid()) { + qWarning("QRhiGles2: Failed to make context current. Expect bad things to happen."); + } else { + qWarning("QRhiGles2: Context is lost."); + contextLost = true; + } return false; } @@ -491,6 +496,8 @@ bool QRhiGles2::create(QRhi::Flags flags) nativeHandlesStruct.context = ctx; + contextLost = false; + return true; } @@ -753,12 +760,12 @@ void QRhiGles2::sendVMemStatsToProfiler() // nothing to do here } -void QRhiGles2::makeThreadLocalNativeContextCurrent() +bool QRhiGles2::makeThreadLocalNativeContextCurrent() { if (inFrame && !ofr.active) - ensureContext(currentSwapChain->surface); + return ensureContext(currentSwapChain->surface); else - ensureContext(); + return ensureContext(); } void QRhiGles2::releaseCachedResources() @@ -774,7 +781,7 @@ void QRhiGles2::releaseCachedResources() bool QRhiGles2::isDeviceLost() const { - return false; + return contextLost; } QRhiRenderBuffer *QRhiGles2::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, @@ -1161,7 +1168,7 @@ QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain); if (!ensureContext(swapChainD->surface)) - return QRhi::FrameOpError; + return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError; currentSwapChain = swapChainD; @@ -1184,7 +1191,7 @@ QRhi::FrameOpResult QRhiGles2::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame addBoundaryCommand(&swapChainD->cb, QGles2CommandBuffer::Command::EndFrame); if (!ensureContext(swapChainD->surface)) - return QRhi::FrameOpError; + return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError; executeCommandBuffer(&swapChainD->cb); @@ -1208,7 +1215,7 @@ QRhi::FrameOpResult QRhiGles2::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi: { Q_UNUSED(flags); if (!ensureContext()) - return QRhi::FrameOpError; + return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError; ofr.active = true; @@ -1230,7 +1237,7 @@ QRhi::FrameOpResult QRhiGles2::endOffscreenFrame(QRhi::EndFrameFlags flags) addBoundaryCommand(&ofr.cbWrapper, QGles2CommandBuffer::Command::EndFrame); if (!ensureContext()) - return QRhi::FrameOpError; + return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError; executeCommandBuffer(&ofr.cbWrapper); @@ -1244,14 +1251,14 @@ QRhi::FrameOpResult QRhiGles2::finish() Q_ASSERT(!currentSwapChain); Q_ASSERT(ofr.cbWrapper.recordingPass == QGles2CommandBuffer::NoPass); if (!ensureContext()) - return QRhi::FrameOpError; + return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError; executeCommandBuffer(&ofr.cbWrapper); ofr.cbWrapper.resetCommands(); } else { Q_ASSERT(currentSwapChain); Q_ASSERT(currentSwapChain->cb.recordingPass == QGles2CommandBuffer::NoPass); if (!ensureContext(currentSwapChain->surface)) - return QRhi::FrameOpError; + return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError; executeCommandBuffer(¤tSwapChain->cb); currentSwapChain->cb.resetCommands(); } diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index 3664e7162b9..e7bcb626b6d 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -664,7 +664,7 @@ public: int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; - void makeThreadLocalNativeContextCurrent() override; + bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; bool isDeviceLost() const override; @@ -770,6 +770,7 @@ public: QVector supportedCompressedFormats; mutable QVector supportedSampleCountList; QRhiGles2NativeHandles nativeHandlesStruct; + mutable bool contextLost = false; struct DeferredReleaseEntry { enum Type { diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 2d85c86bf00..0b1ab72c2cc 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -583,9 +583,10 @@ void QRhiMetal::sendVMemStatsToProfiler() // nothing to do here } -void QRhiMetal::makeThreadLocalNativeContextCurrent() +bool QRhiMetal::makeThreadLocalNativeContextCurrent() { - // nothing to do here + // not applicable + return false; } void QRhiMetal::releaseCachedResources() diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 633e9b8de42..a08f56072a0 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -416,7 +416,7 @@ public: int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; - void makeThreadLocalNativeContextCurrent() override; + bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; bool isDeviceLost() const override; diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index b58d9f5c560..60d620813bb 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -169,9 +169,10 @@ void QRhiNull::sendVMemStatsToProfiler() // nothing to do here } -void QRhiNull::makeThreadLocalNativeContextCurrent() +bool QRhiNull::makeThreadLocalNativeContextCurrent() { - // nothing to do here + // not applicable + return false; } void QRhiNull::releaseCachedResources() diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h index d6dbdbdc753..ee301d247bb 100644 --- a/src/gui/rhi/qrhinull_p_p.h +++ b/src/gui/rhi/qrhinull_p_p.h @@ -282,7 +282,7 @@ public: int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; - void makeThreadLocalNativeContextCurrent() override; + bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; bool isDeviceLost() const override; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 64fea37292e..444c91dd751 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -3767,9 +3767,10 @@ void QRhiVulkan::sendVMemStatsToProfiler() quint32(stats.total.usedBytes), quint32(stats.total.unusedBytes))); } -void QRhiVulkan::makeThreadLocalNativeContextCurrent() +bool QRhiVulkan::makeThreadLocalNativeContextCurrent() { - // nothing to do here + // not applicable + return false; } void QRhiVulkan::releaseCachedResources() diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index a53b3b88fba..a390bc3707c 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -711,7 +711,7 @@ public: int resourceLimit(QRhi::ResourceLimit limit) const override; const QRhiNativeHandles *nativeHandles() override; void sendVMemStatsToProfiler() override; - void makeThreadLocalNativeContextCurrent() override; + bool makeThreadLocalNativeContextCurrent() override; void releaseCachedResources() override; bool isDeviceLost() const override;