diff options
-rw-r--r-- | src/render/backend/platformsurfacefilter.cpp | 104 | ||||
-rw-r--r-- | src/render/backend/platformsurfacefilter_p.h | 34 | ||||
-rw-r--r-- | src/render/backend/renderer.cpp | 38 | ||||
-rw-r--r-- | src/render/backend/renderer_p.h | 15 | ||||
-rw-r--r-- | src/render/framegraph/qrendersurfaceselector.cpp | 49 | ||||
-rw-r--r-- | src/render/framegraph/qrendersurfaceselector_p.h | 2 | ||||
-rw-r--r-- | src/render/framegraph/rendersurfaceselector.cpp | 17 | ||||
-rw-r--r-- | src/render/framegraph/rendersurfaceselector_p.h | 6 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect.cpp | 41 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect_p.h | 8 | ||||
-rw-r--r-- | src/render/graphicshelpers/graphicscontext.cpp | 5 | ||||
-rw-r--r-- | src/render/graphicshelpers/graphicscontext_p.h | 1 |
12 files changed, 217 insertions, 103 deletions
diff --git a/src/render/backend/platformsurfacefilter.cpp b/src/render/backend/platformsurfacefilter.cpp index ac8e70fb5..d332133b3 100644 --- a/src/render/backend/platformsurfacefilter.cpp +++ b/src/render/backend/platformsurfacefilter.cpp @@ -51,11 +51,32 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Render { +QSemaphore PlatformSurfaceFilter::m_surfacesSemaphore(1); +QHash<QSurface *, bool> PlatformSurfaceFilter::m_surfacesValidity; + +// Surface protection +// The surface is accessible from multiple threads at 3 potential places +// 1) In here (the frontend) when we receive an event +// 2) In the RenderViewJobs +// 3) In the Renderer for the submission +// * We don't need any protection in 2) as we are just copying the pointer +// but not performing any access to the texture as all the information +// we need has been cached in the RenderSurfaceSelector element +// * This leaves us with case 1 and 3. It is important that if the surface +// is about to be destroyed that we let the time to the submission thread +// to complete whatever it is doing with a surface before we have the time +// to process the AboutToBeDestroyed event. For that we have lockSurface, releaseSurface +// on the PlatformSurfaceFilter. But that's not enough, you need to be sure that +// the surface is still valid. When locked, you can use isSurfaceValid to check +// if a surface is still accessible. +// A Surface is valid when it has been created and becomes invalid when AboutToBeDestroyed +// has been called +// SurfaceLocker is a convenience type to perform locking an surface validity check + PlatformSurfaceFilter::PlatformSurfaceFilter(QObject *parent) : QObject(parent) , m_obj(Q_NULLPTR) , m_surface(Q_NULLPTR) - , m_renderer(Q_NULLPTR) { qRegisterMetaType<QSurface *>("QSurface*"); } @@ -66,21 +87,6 @@ PlatformSurfaceFilter::~PlatformSurfaceFilter() m_obj->removeEventFilter(this); } -void PlatformSurfaceFilter::setWindow(QWindow *window) -{ - setSurface(window); -} - -void PlatformSurfaceFilter::setOffscreenSurface(QOffscreenSurface *offscreen) -{ - setSurface(offscreen); -} - -void PlatformSurfaceFilter::setRenderer(AbstractRenderer *renderer) -{ - m_renderer = renderer; -} - bool PlatformSurfaceFilter::eventFilter(QObject *obj, QEvent *e) { if (obj == m_obj && e->type() == QEvent::PlatformSurface) { @@ -88,13 +94,21 @@ bool PlatformSurfaceFilter::eventFilter(QObject *obj, QEvent *e) switch (ev->surfaceEventType()) { case QPlatformSurfaceEvent::SurfaceCreated: - setRendererSurface(m_surface); + // set validy to true + { + markSurfaceAsValid(); break; + } case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: - setSurface<QWindow>(Q_NULLPTR); - setRendererSurface(Q_NULLPTR); + // set validity to false + { + SurfaceLocker lock(); + // If we remove it, the call to isSurfaceValid will + // implicitely return false + PlatformSurfaceFilter::m_surfacesValidity.remove(m_surface); break; + } default: qCritical("Unknown surface type"); @@ -104,24 +118,50 @@ bool PlatformSurfaceFilter::eventFilter(QObject *obj, QEvent *e) if (obj == m_obj && e->type() == QEvent::Expose) { QExposeEvent *ev = static_cast<QExposeEvent *>(e); - m_renderer->setSurfaceExposed(!ev->region().isEmpty()); + Q_UNUSED(ev); + // We could use this to tell to ignore the RenderView + // at submission time since it's not exposed } return false; } -void PlatformSurfaceFilter::setRendererSurface(QSurface *surface) +void PlatformSurfaceFilter::lockSurface() +{ + PlatformSurfaceFilter::m_surfacesSemaphore.acquire(1); +} + +void PlatformSurfaceFilter::releaseSurface() +{ + PlatformSurfaceFilter::m_surfacesSemaphore.release(1); +} + +bool PlatformSurfaceFilter::isSurfaceValid(QSurface *surface) +{ + // Should be called only when the surface is locked + // with the semaphore + return m_surfacesValidity.value(surface, false); +} + +void PlatformSurfaceFilter::markSurfaceAsValid() +{ + SurfaceLocker lock(m_surface); + PlatformSurfaceFilter::m_surfacesValidity.insert(m_surface, true); +} + +SurfaceLocker::SurfaceLocker(QSurface *surface) + : m_surface(surface) +{ + PlatformSurfaceFilter::lockSurface(); +} + +SurfaceLocker::~SurfaceLocker() +{ + PlatformSurfaceFilter::releaseSurface(); +} + +bool SurfaceLocker::isSurfaceValid() const { - // Tell the renderer about the surface on which to render. This function - // is called in the context of the main thread and internally - // the renderer uses a private thread to submit OpenGL calls. The surface - // pointer within the renderer is protected by a mutex that is locked for - // the duration of a frame. In this way, the renderer can be sure to have - // a valid surface for the duration of the frame for which it is submitting - // draw calls. Only when the frame finishes and the mutex is unlocked does - // this call to Renderer::setSurface continue. Thereby blocking the main - // thread from destroying the platform surface before we are ready. -// if (m_renderer != Q_NULLPTR) -// m_renderer->setSurface(surface); + return PlatformSurfaceFilter::isSurfaceValid(m_surface); } } // namespace Render diff --git a/src/render/backend/platformsurfacefilter_p.h b/src/render/backend/platformsurfacefilter_p.h index be86085de..a33c64d72 100644 --- a/src/render/backend/platformsurfacefilter_p.h +++ b/src/render/backend/platformsurfacefilter_p.h @@ -53,6 +53,7 @@ #include <QtCore/qobject.h> #include <QtGui/qsurface.h> +#include <QSemaphore> QT_BEGIN_NAMESPACE @@ -72,15 +73,11 @@ public: explicit PlatformSurfaceFilter(QObject *parent = 0); ~PlatformSurfaceFilter(); - void setWindow(QWindow *window); - void setOffscreenSurface(QOffscreenSurface *offscreen); - - void setRenderer(AbstractRenderer *renderer); - bool eventFilter(QObject *obj, QEvent *e) Q_DECL_OVERRIDE; -private: - void setRendererSurface(QSurface *surface); + static void lockSurface(); + static void releaseSurface(); + static bool isSurfaceValid(QSurface *surface); template<class T> void setSurface(T *surface) @@ -94,13 +91,30 @@ private: m_surface = surface; m_obj = surface; - if (m_obj) + if (m_obj) { m_obj->installEventFilter(this); + markSurfaceAsValid(); + } } - +private: QObject *m_obj; QSurface *m_surface; - AbstractRenderer *m_renderer; + + static QSemaphore m_surfacesSemaphore; + static QHash<QSurface *, bool> m_surfacesValidity; + void markSurfaceAsValid(); +}; + +class SurfaceLocker +{ +public: + explicit SurfaceLocker(QSurface *surface); + ~SurfaceLocker(); + bool isSurfaceValid() const +; + +private: + QSurface *m_surface; }; } // namespace Render diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 1719cdd65..b1df0d5b1 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -78,6 +78,7 @@ #include <Qt3DRender/private/nodemanagers_p.h> #include <Qt3DRender/private/geometryrenderermanager_p.h> #include <Qt3DRender/private/openglvertexarrayobject_p.h> +#include <Qt3DRender/private/platformsurfacefilter_p.h> #include <Qt3DRender/qcameralens.h> #include <Qt3DCore/private/qeventfilterservice_p.h> @@ -467,7 +468,7 @@ void Renderer::render() void Renderer::doRender() { bool submissionSucceeded = false; - uint lastBoundFBOId = 0; + Renderer::ViewSubmissionResultData submissionData; if (isReadyToSubmit()) { // Lock the mutex to protect access to m_surface and check if we are still set @@ -485,7 +486,7 @@ void Renderer::doRender() clearDirtyBits(changesToUnset); // Render using current device state and renderer configuration - lastBoundFBOId = submitRenderViews(renderViews); + submissionData = submitRenderViews(renderViews); } // Delete all the RenderViews which will clear the allocators @@ -534,8 +535,11 @@ void Renderer::doRender() // as this allows us to gain a bit of time for the preparation of the // next frame // Finish up with last surface used in the list of RenderViews - if (submissionSucceeded) - m_graphicsContext->endDrawing(lastBoundFBOId == m_graphicsContext->defaultFBO()); + if (submissionSucceeded) { + SurfaceLocker surfaceLock(submissionData.surface); + // Finish up with last surface used in the list of RenderViews + m_graphicsContext->endDrawing(submissionData.lastBoundFBOId == m_graphicsContext->defaultFBO() && surfaceLock.isSurfaceValid()); + } } } @@ -599,7 +603,7 @@ bool Renderer::isReadyToSubmit() // Happens in RenderThread context when all RenderViewJobs are done // Returns the id of the last bound FBO -uint Renderer::submitRenderViews(const QVector<Render::RenderView *> &renderViews) +Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Render::RenderView *> &renderViews) { QElapsedTimer timer; quint64 queueElapsed = 0; @@ -626,6 +630,7 @@ uint Renderer::submitRenderViews(const QVector<Render::RenderView *> &renderView // If not, we have to free up the context from the previous surface // and make the context current on the new surface surface = renderView->surface(); + SurfaceLocker surfaceLock(surface); // TO DO: Make sure that the surface we are rendering too has not been unset @@ -633,13 +638,16 @@ uint Renderer::submitRenderViews(const QVector<Render::RenderView *> &renderView // TODO: Investigate if it's worth providing a fallback offscreen surface // to use when surface is null. Or if we should instead expose an // offscreensurface to Qt3D. - if (!surface) { + if (!surface || !surfaceLock.isSurfaceValid()) { m_lastFrameCorrect.store(0); continue; } - if (surface != previousSurface && previousSurface) - m_graphicsContext->endDrawing(lastBoundFBOId == m_graphicsContext->defaultFBO()); + if (surface != previousSurface && previousSurface) { + const bool swapBuffers = (lastBoundFBOId == m_graphicsContext->defaultFBO()) && PlatformSurfaceFilter::isSurfaceValid(previousSurface); + // We only call swap buffer if we are sure the previous surface is still valid + m_graphicsContext->endDrawing(swapBuffers); + } if (surface != previousSurface) { // If we can't make the context current on the surface, skip to the @@ -697,7 +705,9 @@ uint Renderer::submitRenderViews(const QVector<Render::RenderView *> &renderView frameElapsed = timer.elapsed(); } - if (surface) { + // Reset state and call doneCurrent if the surface + // is valid and was actually activated + if (surface && m_graphicsContext->hasValidGLHelper()) { // Reset state to the default state if the last stateset is not the // defaultRenderStateSet if (m_graphicsContext->currentStateSet() != m_defaultRenderStateSet) @@ -708,7 +718,13 @@ uint Renderer::submitRenderViews(const QVector<Render::RenderView *> &renderView qCDebug(Rendering) << Q_FUNC_INFO << "Submission of Queue in " << queueElapsed << "ms <=> " << queueElapsed / renderViewsCount << "ms per RenderView <=> Avg " << 1000.0f / (queueElapsed * 1.0f/ renderViewsCount * 1.0f) << " RenderView/s"; qCDebug(Rendering) << Q_FUNC_INFO << "Submission Completed in " << timer.elapsed() << "ms"; - return lastBoundFBOId; + // Stores the necessary information to safely perform + // the last swap buffer call + ViewSubmissionResultData resultData; + resultData.lastBoundFBOId = lastBoundFBOId; + resultData.surface = surface; + + return resultData; } void Renderer::markDirty(BackendNodeDirtySet changes, BackendNode *node) @@ -840,7 +856,7 @@ void Renderer::performDraw(GeometryRenderer *rGeometryRenderer, GLsizei primitiv rGeometryRenderer->unsetDirty(); } -void Renderer::performCompute(const RenderView *rv, RenderCommand *command) +void Renderer::performCompute(const RenderView *, RenderCommand *command) { Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command->m_shader); if (shader != Q_NULLPTR) { diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index 3afc84236..a52e75804 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -194,7 +194,20 @@ public: void enqueueRenderView(RenderView *renderView, int submitOrder); bool isReadyToSubmit(); - uint submitRenderViews(const QVector<Render::RenderView *> &renderViews); + + + struct ViewSubmissionResultData + { + ViewSubmissionResultData() + : lastBoundFBOId(0) + , surface(Q_NULLPTR) + {} + + uint lastBoundFBOId; + QSurface *surface; + }; + + ViewSubmissionResultData submitRenderViews(const QVector<Render::RenderView *> &renderViews); QMutex* mutex() { return &m_mutex; } diff --git a/src/render/framegraph/qrendersurfaceselector.cpp b/src/render/framegraph/qrendersurfaceselector.cpp index a0d7e3a47..8bd31ac12 100644 --- a/src/render/framegraph/qrendersurfaceselector.cpp +++ b/src/render/framegraph/qrendersurfaceselector.cpp @@ -86,6 +86,7 @@ namespace Qt3DRender { QRenderSurfaceSelectorPrivate::QRenderSurfaceSelectorPrivate() : Qt3DRender::QFrameGraphNodePrivate() , m_surface(Q_NULLPTR) + , m_surfaceEventFilter(new Qt3DRender::Render::PlatformSurfaceFilter()) { } @@ -143,6 +144,23 @@ void QRenderSurfaceSelector::setSurface(QSurface *surface) return; d->m_surface = surface; + // The platform surface filter only deals with QObject + // We assume therefore that our surface is actually a QObject underneath + if (d->m_surface) { + switch (d->m_surface->surfaceClass()) { + case QSurface::Window: + d->m_surfaceEventFilter->setSurface(static_cast<QWindow *>(d->m_surface)); + break; + case QSurface::Offscreen: + d->m_surfaceEventFilter->setSurface(static_cast<QOffscreenSurface *>(d->m_surface)); + break; + default: + break; + } + } else { + QWindow *nullWindow = Q_NULLPTR; + d->m_surfaceEventFilter->setSurface(nullWindow); + } emit surfaceChanged(surface); } @@ -177,6 +195,37 @@ void QRenderSurfaceSelector::setWindow(QWindow *window) return; d->m_surface = window; + d->m_surfaceEventFilter->setSurface(window); + + if (window) { + QObject::connect(window, &QWindow::widthChanged, [=] (int width) { + if (d->m_changeArbiter != Q_NULLPTR) { + Qt3DCore::QScenePropertyChangePtr change( + new Qt3DCore::QScenePropertyChange( + Qt3DCore::NodeUpdated, + Qt3DCore::QSceneChange::Node, + id())); + + change->setPropertyName("width"); + change->setValue(QVariant::fromValue(width)); + d->notifyObservers(change); + } + }); + QObject::connect(window, &QWindow::heightChanged, [=] (int height) { + if (d->m_changeArbiter != Q_NULLPTR) { + Qt3DCore::QScenePropertyChangePtr change( + new Qt3DCore::QScenePropertyChange( + Qt3DCore::NodeUpdated, + Qt3DCore::QSceneChange::Node, + id())); + + change->setPropertyName("height"); + change->setValue(QVariant::fromValue(height)); + d->notifyObservers(change); + } + }); + } + emit windowChanged(window); emit surfaceChanged(d->m_surface); } diff --git a/src/render/framegraph/qrendersurfaceselector_p.h b/src/render/framegraph/qrendersurfaceselector_p.h index 136ad0991..33e9eab96 100644 --- a/src/render/framegraph/qrendersurfaceselector_p.h +++ b/src/render/framegraph/qrendersurfaceselector_p.h @@ -52,6 +52,7 @@ // #include <Qt3DRender/private/qframegraphnode_p.h> +#include <Qt3DRender/private/platformsurfacefilter_p.h> #include <QtGui/qsurface.h> #include <QtGui/qwindow.h> @@ -69,6 +70,7 @@ public: QSurface *m_surface; QSize m_externalRenderTargetSize; + QScopedPointer<Qt3DRender::Render::PlatformSurfaceFilter> m_surfaceEventFilter; }; } // namespace Qt3DRender diff --git a/src/render/framegraph/rendersurfaceselector.cpp b/src/render/framegraph/rendersurfaceselector.cpp index 738e1f231..838b03c57 100644 --- a/src/render/framegraph/rendersurfaceselector.cpp +++ b/src/render/framegraph/rendersurfaceselector.cpp @@ -43,6 +43,7 @@ #include <Qt3DCore/qscenepropertychange.h> #include <QtGui/qwindow.h> +#include <QtGui/qscreen.h> #include <QtGui/qoffscreensurface.h> QT_BEGIN_NAMESPACE @@ -55,6 +56,9 @@ namespace Render { RenderSurfaceSelector::RenderSurfaceSelector() : FrameGraphNode(FrameGraphNode::Surface) , m_surface(Q_NULLPTR) + , m_width(0) + , m_height(0) + , m_devicePixelRatio(0.0f) { } @@ -64,6 +68,15 @@ void RenderSurfaceSelector::updateFromPeer(Qt3DCore::QNode *peer) m_surface = selector->surface(); setEnabled(selector->isEnabled()); setRenderTargetSize(selector->externalRenderTargetSize()); + if (m_surface) { + if (m_surface->surfaceClass() == QSurface::Window) { + QWindow *window = static_cast<QWindow *>(m_surface); + m_width = window->width(); + m_height = window->height(); + if (window->screen()) + m_devicePixelRatio = window->screen()->devicePixelRatio(); + } + } } void RenderSurfaceSelector::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -77,6 +90,10 @@ void RenderSurfaceSelector::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) setEnabled(propertyChange->value().toBool()); else if (propertyChange->propertyName() == QByteArrayLiteral("externalRenderTargetSize")) setRenderTargetSize(propertyChange->value().toSize()); + else if (propertyChange->propertyName() == QByteArrayLiteral("width")) + m_width = propertyChange->value().toInt(); + else if (propertyChange->propertyName() == QByteArrayLiteral("height")) + m_height = propertyChange->value().toInt(); markDirty(AbstractRenderer::AllDirty); } } diff --git a/src/render/framegraph/rendersurfaceselector_p.h b/src/render/framegraph/rendersurfaceselector_p.h index 114a52a31..8c84695a8 100644 --- a/src/render/framegraph/rendersurfaceselector_p.h +++ b/src/render/framegraph/rendersurfaceselector_p.h @@ -72,10 +72,16 @@ public: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; QSurface *surface() const { return m_surface; } + inline int width() const Q_DECL_NOEXCEPT { return m_width; } + inline int height() const Q_DECL_NOEXCEPT { return m_height; } + inline float devicePixelRatio() const Q_DECL_NOEXCEPT { return m_devicePixelRatio; } private: QSurface *m_surface; QSize m_renderTargetSize; + int m_width; + int m_height; + float m_devicePixelRatio; }; } // namespace Render diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 7ec2d45d8..0b8aca1c7 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -152,8 +152,6 @@ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type) : QAbstractAspectPrivate() , m_nodeManagers(new Render::NodeManagers()) , m_renderer(Q_NULLPTR) - , m_surfaceEventFilter(new Render::PlatformSurfaceFilter()) - , m_surface(Q_NULLPTR) , m_initialized(false) , m_framePreparationJob(new Render::FramePreparationJob(m_nodeManagers)) , m_cleanupJob(new Render::FrameCleanupJob(m_nodeManagers)) @@ -178,7 +176,6 @@ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type) // a targeted rendering API -> only OpenGL for now m_renderer = new Render::Renderer(type); m_renderer->setNodeManagers(m_nodeManagers); - m_surfaceEventFilter->setRenderer(m_renderer); } void QRenderAspectPrivate::registerBackendTypes() @@ -230,44 +227,6 @@ void QRenderAspectPrivate::registerBackendTypes() q->registerBackendType<QRenderState>(QBackendNodeMapperPtr(new Render::NodeFunctor<Render::RenderStateNode, Render::RenderStateManager>(m_renderer, m_nodeManagers->renderStateManager()))); } -void QRenderAspectPrivate::setSurface(QSurface *surface) -{ - if (m_surface == surface) - return; - - m_surface = surface; - - // If we have a new surface, install the platform surface event filter onto it - // so that we get informed when the underlying platform surface is about to be - // deleted and we can tell the renderer about it before it's too late. - if (m_surface) { - bool hasPlatformSurface = false; - switch (m_surface->surfaceClass()) { - case QSurface::Window: { - QWindow *window = static_cast<QWindow *>(m_surface); - m_surfaceEventFilter->setWindow(window); - hasPlatformSurface = (window->handle() != Q_NULLPTR); - m_devicePixelRatio = window->devicePixelRatio(); - break; - } - - case QSurface::Offscreen: { - QOffscreenSurface *offscreen = static_cast<QOffscreenSurface *>(m_surface); - m_surfaceEventFilter->setOffscreenSurface(offscreen); - hasPlatformSurface = (offscreen->handle() != Q_NULLPTR); - break; - } - } - - if (!m_surfaceSize.isValid()) - m_surfaceSize = surface->size(); - - // If the window/offscreen surface has a native surface, tell the renderer - // if (hasPlatformSurface) - // m_renderer->setSurface(surface); - } -} - QRenderAspect::QRenderAspect(QObject *parent) : QAbstractAspect(*new QRenderAspectPrivate(Threaded), parent) { diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h index 6bd84dc72..603a13a3e 100644 --- a/src/render/frontend/qrenderaspect_p.h +++ b/src/render/frontend/qrenderaspect_p.h @@ -80,7 +80,6 @@ public: Q_DECLARE_PUBLIC(QRenderAspect) void registerBackendTypes(); - void setSurface(QSurface *surface); void loadSceneParsers(); void renderInitialize(QOpenGLContext *context); void renderSynchronous(); @@ -91,13 +90,6 @@ public: Render::NodeManagers *m_nodeManagers; Render::AbstractRenderer *m_renderer; - // The filter has affinity with the main thread so we have to delete it there - // via QScopedPointerDeleteLater - QScopedPointer<Render::PlatformSurfaceFilter, QScopedPointerDeleteLater> m_surfaceEventFilter; - QSurface *m_surface; - QSize m_surfaceSize; - qreal m_devicePixelRatio; - bool m_initialized; Render::FramePreparationJobPtr m_framePreparationJob; Render::FrameCleanupJobPtr m_cleanupJob; diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index 30af526d4..6c0f69947 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -342,6 +342,11 @@ void GraphicsContext::activateGLHelper() } } +bool GraphicsContext::hasValidGLHelper() const +{ + return m_glHelper != Q_NULLPTR; +} + bool GraphicsContext::makeCurrent(QSurface *surface) { Q_ASSERT(m_gl); diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h index dbedd57e0..ca5f43c7a 100644 --- a/src/render/graphicshelpers/graphicscontext_p.h +++ b/src/render/graphicshelpers/graphicscontext_p.h @@ -123,6 +123,7 @@ public: bool makeCurrent(QSurface *surface); void doneCurrent(); void activateGLHelper(); + bool hasValidGLHelper() const; void activateShader(Shader* shader); QOpenGLShaderProgram *containsProgram(const ProgramDNA &dna); |