From 425d6bc58416930763e9a74755ff64b6bc9771db Mon Sep 17 00:00:00 2001 From: ExMix Date: Wed, 8 Jul 2015 12:36:57 +0300 Subject: [drape] clean up drape_head code. Remove QtOGLContextFactory duplicate in qt application make rendering according qt widgets composition model --- drape/oglcontext.hpp | 1 + drape_frontend/backend_renderer.cpp | 1 + drape_frontend/frontend_renderer.cpp | 1 + drape_head/drape_head.pro | 4 - drape_head/drape_surface.cpp | 43 ++++----- drape_head/drape_surface.hpp | 19 ++-- drape_head/qtoglcontext.cpp | 49 ---------- drape_head/qtoglcontext.hpp | 22 ----- drape_head/qtoglcontextfactory.cpp | 31 ------ drape_head/qtoglcontextfactory.hpp | 21 ---- drape_head/testing_engine.cpp | 23 +---- drape_head/testing_engine.hpp | 15 +-- qt/draw_widget.cpp | 181 ++++++++++++++++++++++++++++------- qt/draw_widget.hpp | 46 +++++++-- qt/qtoglcontext.cpp | 85 ++++++++++++---- qt/qtoglcontext.hpp | 45 ++++++++- qt/qtoglcontextfactory.cpp | 19 ++-- qt/qtoglcontextfactory.hpp | 16 +++- 18 files changed, 350 insertions(+), 272 deletions(-) delete mode 100644 drape_head/qtoglcontext.cpp delete mode 100644 drape_head/qtoglcontext.hpp delete mode 100644 drape_head/qtoglcontextfactory.cpp delete mode 100644 drape_head/qtoglcontextfactory.hpp diff --git a/drape/oglcontext.hpp b/drape/oglcontext.hpp index ea28215670..bc33c9f462 100644 --- a/drape/oglcontext.hpp +++ b/drape/oglcontext.hpp @@ -9,6 +9,7 @@ public: virtual ~OGLContext() {} virtual void present() = 0; virtual void makeCurrent() = 0; + virtual void doneCurrent() {} virtual void setDefaultFramebuffer() = 0; /// @ param w, h - pixel size of render target (logical size * visual scale) virtual void resize(int /*w*/, int /*h*/) {} diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index 7d0da83c08..2a549ed95b 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -225,6 +225,7 @@ void BackendRenderer::ReleaseResources() m_routeBuilder.reset(); m_texMng->Release(); + m_contextFactory->getResourcesUploadContext()->doneCurrent(); } BackendRenderer::Routine::Routine(BackendRenderer & renderer) : m_renderer(renderer) {} diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 3d837219e1..56d488b848 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -837,6 +837,7 @@ void FrontendRenderer::ReleaseResources() m_routeRenderer.reset(); m_gpuProgramManager.reset(); + m_contextFactory->getDrawContext()->doneCurrent(); } void FrontendRenderer::AddUserEvent(UserEvent const & event) diff --git a/drape_head/drape_head.pro b/drape_head/drape_head.pro index 6f605377c9..925b12b1ef 100644 --- a/drape_head/drape_head.pro +++ b/drape_head/drape_head.pro @@ -29,15 +29,11 @@ macx-* { HEADERS += \ mainwindow.hpp \ - qtoglcontext.hpp \ - qtoglcontextfactory.hpp \ drape_surface.hpp \ testing_engine.hpp \ SOURCES += \ mainwindow.cpp \ main.cpp \ - qtoglcontext.cpp \ - qtoglcontextfactory.cpp \ drape_surface.cpp \ testing_engine.cpp \ diff --git a/drape_head/drape_surface.cpp b/drape_head/drape_surface.cpp index 8aeca78781..886f3b4eab 100644 --- a/drape_head/drape_surface.cpp +++ b/drape_head/drape_surface.cpp @@ -5,47 +5,44 @@ #include "base/logging.hpp" DrapeSurface::DrapeSurface() - : m_contextFactory(nullptr) { - setSurfaceType(QSurface::OpenGLSurface); - - QObject::connect(this, SIGNAL(heightChanged(int)), this, SLOT(sizeChanged(int))); - QObject::connect(this, SIGNAL(widthChanged(int)), this, SLOT(sizeChanged(int))); } DrapeSurface::~DrapeSurface() { + m_timer.stop(); + m_drapeEngine.reset(); } -void DrapeSurface::exposeEvent(QExposeEvent *e) +void DrapeSurface::initializeGL() { - Q_UNUSED(e); + CreateEngine(); + m_timer.setInterval(1000 / 30); + m_timer.setSingleShot(false); - if (isExposed()) - { - if (m_contextFactory == nullptr) - { - m_contextFactory = make_unique_dp(new QtOGLContextFactory(this), false); - CreateEngine(); - } - } + connect(&m_timer, SIGNAL(timeout()), SLOT(update())); + m_timer.start(); } -void DrapeSurface::CreateEngine() +void DrapeSurface::paintGL() { - float const pixelRatio = devicePixelRatio(); - m_drapeEngine = make_unique_dp(make_ref(m_contextFactory), - df::Viewport(0, 0, pixelRatio * width(), pixelRatio * height()), - pixelRatio); + m_drapeEngine->Draw(); } -void DrapeSurface::sizeChanged(int) +void DrapeSurface::resizeGL(int width, int height) { if (m_drapeEngine != nullptr) { float const vs = devicePixelRatio(); - int const w = width() * vs; - int const h = height() * vs; + int const w = width * vs; + int const h = height * vs; m_drapeEngine->Resize(w, h); } } + +void DrapeSurface::CreateEngine() +{ + float const pixelRatio = devicePixelRatio(); + m_drapeEngine = make_unique_dp(df::Viewport(0, 0, pixelRatio * width(), pixelRatio * height()), + pixelRatio); +} diff --git a/drape_head/drape_surface.hpp b/drape_head/drape_surface.hpp index 88d55b4e1e..fd2ceddb97 100644 --- a/drape_head/drape_surface.hpp +++ b/drape_head/drape_surface.hpp @@ -1,11 +1,11 @@ #pragma once -#include "drape_head/qtoglcontextfactory.hpp" #include "drape_head/testing_engine.hpp" -#include +#include +#include -class DrapeSurface : public QWindow +class DrapeSurface : public QOpenGLWindow { Q_OBJECT @@ -14,16 +14,13 @@ public: ~DrapeSurface(); protected: - void exposeEvent(QExposeEvent * e); + void initializeGL() override; + void paintGL() override; + void resizeGL(int w, int h) override; private: void CreateEngine(); - Q_SLOT void sizeChanged(int); - -private: - typedef drape_ptr TContextFactoryPtr; - typedef drape_ptr TEnginePrt; - TContextFactoryPtr m_contextFactory; - TEnginePrt m_drapeEngine; + drape_ptr m_drapeEngine; + QTimer m_timer; }; diff --git a/drape_head/qtoglcontext.cpp b/drape_head/qtoglcontext.cpp deleted file mode 100644 index 9d72f9dc12..0000000000 --- a/drape_head/qtoglcontext.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "drape_head/qtoglcontext.hpp" - -#include "base/assert.hpp" -#include "base/logging.hpp" - -#include "drape/glfunctions.hpp" - -QtOGLContext::QtOGLContext(QWindow * surface, QtOGLContext * contextToShareWith) -{ - m_isContextCreated = false; - m_surface = surface; - m_nativeContext = new QOpenGLContext(); - - if (contextToShareWith != NULL) - m_nativeContext->setShareContext(contextToShareWith->m_nativeContext); - - m_nativeContext->setFormat(m_surface->requestedFormat()); - ASSERT(m_surface->isExposed(), ()); - VERIFY(m_nativeContext->create(), ()); -} - -QtOGLContext::~QtOGLContext() -{ - delete m_nativeContext; -} - -void QtOGLContext::makeCurrent() -{ - ASSERT(m_nativeContext->isValid(), ()); - m_nativeContext->makeCurrent(m_surface); - -#ifdef DEBUG - LOG(LDEBUG, ("Current context : ", m_nativeContext)); - QList list = QOpenGLContextGroup::currentContextGroup()->shares(); - for (int i = 0; i < list.size(); ++i) - LOG(LDEBUG, ("Share context : ", list[i])); -#endif -} - -void QtOGLContext::present() -{ - m_nativeContext->makeCurrent(m_surface); - m_nativeContext->swapBuffers(m_surface); -} - -void QtOGLContext::setDefaultFramebuffer() -{ - GLFunctions::glBindFramebuffer(GL_FRAMEBUFFER, m_nativeContext->defaultFramebufferObject()); -} diff --git a/drape_head/qtoglcontext.hpp b/drape_head/qtoglcontext.hpp deleted file mode 100644 index 2bc7000de3..0000000000 --- a/drape_head/qtoglcontext.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "drape/oglcontext.hpp" - -#include -#include - -class QtOGLContext: public dp::OGLContext -{ -public: - QtOGLContext(QWindow * surface, QtOGLContext * contextToShareWith); - ~QtOGLContext(); - - virtual void present(); - virtual void makeCurrent(); - virtual void setDefaultFramebuffer(); - -private: - QOpenGLContext * m_nativeContext; - QWindow * m_surface; - bool m_isContextCreated; -}; diff --git a/drape_head/qtoglcontextfactory.cpp b/drape_head/qtoglcontextfactory.cpp deleted file mode 100644 index 28ce15cdae..0000000000 --- a/drape_head/qtoglcontextfactory.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "drape_head/qtoglcontextfactory.hpp" - -#include "base/assert.hpp" - -QtOGLContextFactory::QtOGLContextFactory(QWindow * surface) - : m_surface(surface) - , m_drawContext(NULL) - , m_uploadContext(NULL) -{} - -QtOGLContextFactory::~QtOGLContextFactory() -{ - delete m_drawContext; - delete m_uploadContext; -} - -dp::OGLContext * QtOGLContextFactory::getDrawContext() -{ - if (m_drawContext == NULL) - m_drawContext = new QtOGLContext(m_surface, m_uploadContext); - - return m_drawContext; -} - -dp::OGLContext * QtOGLContextFactory::getResourcesUploadContext() -{ - if (m_uploadContext == NULL) - m_uploadContext = new QtOGLContext(m_surface, m_drawContext); - - return m_uploadContext; -} diff --git a/drape_head/qtoglcontextfactory.hpp b/drape_head/qtoglcontextfactory.hpp deleted file mode 100644 index 0ce63d77d5..0000000000 --- a/drape_head/qtoglcontextfactory.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "drape/oglcontextfactory.hpp" -#include "drape_head/qtoglcontext.hpp" - -#include - -class QtOGLContextFactory : public dp::OGLContextFactory -{ -public: - QtOGLContextFactory(QWindow * surface); - ~QtOGLContextFactory(); - - virtual dp::OGLContext * getDrawContext(); - virtual dp::OGLContext * getResourcesUploadContext(); - -private: - QWindow * m_surface; - QtOGLContext * m_drawContext; - QtOGLContext * m_uploadContext; -}; diff --git a/drape_head/testing_engine.cpp b/drape_head/testing_engine.cpp index 79f51fae6f..68159b1842 100644 --- a/drape_head/testing_engine.cpp +++ b/drape_head/testing_engine.cpp @@ -326,13 +326,9 @@ private: TCreatorsMap m_creators; }; -TestingEngine::TestingEngine(ref_ptr oglcontextfactory, - Viewport const & viewport, - double vs) - : m_contextFactory(oglcontextfactory) - , m_viewport(viewport) +TestingEngine::TestingEngine(Viewport const & viewport, double vs) + : m_viewport(viewport) { - m_contextFactory->getDrawContext()->makeCurrent(); df::VisualParams::Init(vs, df::CalculateTileSize(viewport.GetWidth(), viewport.GetHeight())); GLFunctions::Init(); @@ -352,13 +348,10 @@ TestingEngine::TestingEngine(ref_ptr oglcontextfactory, ModelViewInit(); ProjectionInit(); - - m_timerId = startTimer(1000 / 30); } TestingEngine::~TestingEngine() { - killTimer(m_timerId); ClearScene(); m_textures->Release(); } @@ -379,9 +372,6 @@ void TestingEngine::Draw() ModelViewInit(); m_angle += 0.005; - dp::OGLContext * context = m_contextFactory->getDrawContext(); - context->setDefaultFramebuffer(); - m_viewport.Apply(); GLFunctions::glClearColor(0.65f, 0.65f, 0.65f, 1.0f); GLFunctions::glClear(); @@ -411,8 +401,6 @@ void TestingEngine::Draw() buckets[i]->Render(m_modelView); tree.EndOverlayPlacing(); } - - context->present(); } void TestingEngine::Resize(int w, int h) @@ -422,13 +410,6 @@ void TestingEngine::Resize(int w, int h) m_viewport.SetViewport(0, 0, w, h); ModelViewInit(); ProjectionInit(); - Draw(); -} - -void TestingEngine::timerEvent(QTimerEvent * e) -{ - if (e->timerId() == m_timerId) - Draw(); } void TestingEngine::DrawImpl() diff --git a/drape_head/testing_engine.hpp b/drape_head/testing_engine.hpp index fa06db5dd7..fb8c175dce 100644 --- a/drape_head/testing_engine.hpp +++ b/drape_head/testing_engine.hpp @@ -12,28 +12,18 @@ #include "std/map.hpp" -#include -#include - namespace df { -class TestingEngine : public QObject +class TestingEngine { public: - TestingEngine(ref_ptr oglcontextfactory, - Viewport const & viewport, - double vs); + TestingEngine(Viewport const & viewport, double vs); ~TestingEngine(); void Draw(); void Resize(int w, int h); -protected: - void timerEvent(QTimerEvent * e); - - int m_timerId; - private: void DrawImpl(); void DrawRects(); @@ -43,7 +33,6 @@ private: void ClearScene(); private: - ref_ptr m_contextFactory; drape_ptr m_batcher; drape_ptr m_programManager; drape_ptr m_textures; diff --git a/qt/draw_widget.cpp b/qt/draw_widget.cpp index a83adf994a..28a13ceaf4 100644 --- a/qt/draw_widget.cpp +++ b/qt/draw_widget.cpp @@ -1,6 +1,7 @@ #include "qt/draw_widget.hpp" #include "qt/slider_ctrl.hpp" +#include "qt/qtoglcontext.hpp" #include "drape_frontend/visual_params.hpp" @@ -19,6 +20,7 @@ #include #include +#include namespace qt { @@ -69,15 +71,14 @@ bool IsLocationEmulation(QMouseEvent * e) : m_contextFactory(nullptr), m_framework(new Framework()), m_ratio(1.0), + m_rendererThread(nullptr), + m_state(NotInitialized), m_pScale(nullptr), - m_emulatingLocation(false), - m_enableScaleUpdate(true) + m_enableScaleUpdate(true), + m_emulatingLocation(false) { setSurfaceType(QSurface::OpenGLSurface); - QObject::connect(this, SIGNAL(heightChanged(int)), this, SLOT(sizeChanged(int))); - QObject::connect(this, SIGNAL(widthChanged(int)), this, SLOT(sizeChanged(int))); - m_framework->SetUserMarkActivationListener([](unique_ptr mark) { }); @@ -103,6 +104,14 @@ bool IsLocationEmulation(QMouseEvent * e) void DrawWidget::PrepareShutdown() { + { + // Discard current and all future Swap requests + m_contextFactory->shutDown(); + frameSwappedSlot(NotInitialized); + } + + // Shutdown engine. FR have ogl context in this moment and can delete OGL resources + // PrepareToShutdown make FR::join and after this call we can bind OGL context to gui thread m_framework->PrepareToShutdown(); m_contextFactory.reset(); } @@ -188,22 +197,68 @@ bool IsLocationEmulation(QMouseEvent * e) m_framework->AddViewportListener(bind(&DrawWidget::OnViewportChanged, this, _1)); } - void DrawWidget::exposeEvent(QExposeEvent * e) + void DrawWidget::initializeGL() + { + Qt::ConnectionType swapType = Qt::QueuedConnection; + Qt::ConnectionType regType = Qt::BlockingQueuedConnection; + VERIFY(connect(this, SIGNAL(Swap()), SLOT(OnSwap()), swapType), ()); + VERIFY(connect(this, SIGNAL(RegRenderingThread(QThread *)), SLOT(OnRegRenderingThread(QThread *)), regType), ()); + VERIFY(connect(this, SIGNAL(frameSwapped()), SLOT(frameSwappedSlot())), ()); + + ASSERT(m_contextFactory == nullptr, ()); + m_ratio = devicePixelRatio(); + QOpenGLContext * ctx = context(); + QtOGLContextFactory::TRegisterThreadFn regFn = bind(&DrawWidget::CallRegisterThread, this, _1); + QtOGLContextFactory::TSwapFn swapFn = bind(&DrawWidget::CallSwap, this); + m_contextFactory = make_unique_dp(ctx, QThread::currentThread(), regFn, swapFn); + CreateEngine(); + LoadState(); + + emit EngineCreated(); + } + + void DrawWidget::resizeGL(int width, int height) { - Q_UNUSED(e); + float w = m_ratio * width; + float h = m_ratio * height; + m_framework->OnSize(w, h); + if (m_skin) + { + m_skin->Resize(w, h); + + gui::TWidgetsLayoutInfo layout; + m_skin->ForEach([&layout](gui::EWidget w, gui::Position const & pos) + { + layout[w] = pos.m_pixelPivot; + }); + m_framework->SetWidgetLayout(move(layout)); + } + } + + void DrawWidget::paintGL() { /*Must be empty*/ } + + void DrawWidget::exposeEvent(QExposeEvent * event) + { if (isExposed()) { - if (m_contextFactory == nullptr) + m_swapMutex.lock(); + bool needUnlock = true; + if (m_state == Render) { - m_ratio = devicePixelRatio(); - m_contextFactory = make_unique_dp(new QtOGLContextFactory(this)); - CreateEngine(); - LoadState(); + unique_lock waitContextLock(m_waitContextMutex); + m_state = WaitContext; + needUnlock = false; + m_swapMutex.unlock(); - emit EngineCreated(); + m_waitContextCond.wait(waitContextLock, [this](){ return m_state != WaitContext; }); } + + if (needUnlock) + m_swapMutex.unlock(); } + + TBase::exposeEvent(event); } void DrawWidget::mousePressEvent(QMouseEvent * e) @@ -284,6 +339,87 @@ bool IsLocationEmulation(QMouseEvent * e) m_emulatingLocation = false; } + void DrawWidget::CallSwap() + { + // Called on FR thread. In this point OGL context have already moved into GUI thread. + unique_lock lock(m_swapMutex); + if (m_state == NotInitialized) + { + // This can be in two cases if GUI thread in PrepareToShutDown + return; + } + + ASSERT(m_state != WaitSwap, ()); + if (m_state == WaitContext) + { + lock_guard waitContextLock(m_waitContextMutex); + m_state = Render; + m_waitContextCond.notify_one(); + } + + if (m_state == Render) + { + // We have to wait, while Qt on GUI thread finish composing widgets and make SwapBuffers + // After SwapBuffers Qt will call our SLOT(frameSwappedSlot) + m_state = WaitSwap; + emit Swap(); + m_swapCond.wait(lock, [this]() { return m_state != WaitSwap; }); + } + } + + void DrawWidget::CallRegisterThread(QThread * thread) + { + // Called on FR thread. SIGNAL(RegRenderingThread) and SLOT(OnRegRenderingThread) + // connected by through Qt::BlockingQueuedConnection and we don't need any synchronization + ASSERT(m_state == NotInitialized, ()); + emit RegRenderingThread(thread); + } + + void DrawWidget::OnSwap() + { + // Called on GUI thread. In this point FR thread must wait SwapBuffers signal + lock_guard lock(m_swapMutex); + if (m_state == WaitSwap) + { + context()->makeCurrent(this); + update(); + } + } + + void DrawWidget::OnRegRenderingThread(QThread * thread) + { + // Called on GUI thread. + // Here we register thread of FR, to return OGL context into it after SwapBuffers + // After this operation we can start rendering into back buffer on FR thread + lock_guard lock(m_swapMutex); + + ASSERT(m_state == NotInitialized, ()); + m_state = Render; + m_rendererThread = thread; + MoveContextToRenderThread(); + } + + void DrawWidget::frameSwappedSlot(RenderingState state) + { + // Qt call this slot on GUI thread after glSwapBuffers perfomed + // Here we move OGL context into FR thread and wake up FR + lock_guard lock(m_swapMutex); + + if (m_state == WaitSwap) + { + MoveContextToRenderThread(); + m_state = state; + m_swapCond.notify_all(); + } + } + + void DrawWidget::MoveContextToRenderThread() + { + QOpenGLContext * ctx = context(); + ctx->doneCurrent(); + ctx->moveToThread(m_rendererThread); + } + void DrawWidget::wheelEvent(QWheelEvent * e) { m_framework->Scale(exp(e->delta() / 360.0), m2::PointD(L2D(e->x()), L2D(e->y())), false); @@ -326,25 +462,6 @@ bool IsLocationEmulation(QMouseEvent * e) m_framework->SetMapStyle(mapStyle); } - void DrawWidget::sizeChanged(int) - { - float w = m_ratio * width(); - float h = m_ratio * height(); - m_framework->OnSize(w, h); - if (m_skin) - { - m_skin->Resize(w, h); - - gui::TWidgetsLayoutInfo layout; - m_skin->ForEach([&layout](gui::EWidget w, gui::Position const & pos) - { - layout[w] = pos.m_pixelPivot; - }); - - m_framework->SetWidgetLayout(move(layout)); - } - } - void DrawWidget::SubmitFakeLocationPoint(m2::PointD const & pt) { m_emulatingLocation = true; diff --git a/qt/draw_widget.hpp b/qt/draw_widget.hpp index 1cc6ecb999..3036c7d395 100644 --- a/qt/draw_widget.hpp +++ b/qt/draw_widget.hpp @@ -9,18 +9,20 @@ #include "drape_frontend/drape_engine.hpp" #include "std/unique_ptr.hpp" +#include "std/mutex.hpp" +#include "std/condition_variable.hpp" -#include +#include namespace qt { class QScaleSlider; - class DrawWidget : public QWindow + class DrawWidget : public QOpenGLWindow { - typedef QWindow TBase; + using TBase = QOpenGLWindow; - drape_ptr m_contextFactory; + drape_ptr m_contextFactory; unique_ptr m_framework; qreal m_ratio; @@ -67,9 +69,13 @@ namespace qt void CreateEngine(); protected: - /// @name Overriden from QWidget. + /// @name Overriden from QOpenGLWindow. //@{ - void exposeEvent(QExposeEvent * e) override; + void initializeGL() override; + void resizeGL(int width, int height) override; + void paintGL() override; + + void exposeEvent(QExposeEvent * event); void mousePressEvent(QMouseEvent * e) override; void mouseDoubleClickEvent(QMouseEvent * e) override; void mouseMoveEvent(QMouseEvent * e) override; @@ -79,7 +85,33 @@ namespace qt void keyReleaseEvent(QKeyEvent * e) override; //@} - Q_SLOT void sizeChanged(int); + private: + enum RenderingState + { + NotInitialized, + WaitContext, + WaitSwap, + Render, + }; + + void CallSwap(); + void CallRegisterThread(QThread * thread); + Q_SIGNAL void Swap(); + Q_SIGNAL void RegRenderingThread(QThread * thread); + Q_SLOT void OnSwap(); + Q_SLOT void OnRegRenderingThread(QThread * thread); + Q_SLOT void frameSwappedSlot(RenderingState state = Render); + + void MoveContextToRenderThread(); + QThread * m_rendererThread; + + mutex m_swapMutex; + condition_variable m_swapCond; + + mutex m_waitContextMutex; + condition_variable m_waitContextCond; + + RenderingState m_state; private: void SubmitFakeLocationPoint(m2::PointD const & pt); diff --git a/qt/qtoglcontext.cpp b/qt/qtoglcontext.cpp index 0ae989938e..a423e46756 100644 --- a/qt/qtoglcontext.cpp +++ b/qt/qtoglcontext.cpp @@ -5,45 +5,90 @@ #include "drape/glfunctions.hpp" -QtOGLContext::QtOGLContext(QWindow * surface, QtOGLContext * contextToShareWith) +QtRenderOGLContext::QtRenderOGLContext(QOpenGLContext * nativeContext, QThread * guiThread, + TRegisterThreadFn const & regFn, TSwapFn const & swapFn) + : m_surface(nativeContext->surface()) + , m_ctx(nativeContext) + , m_guiThread(guiThread) + , m_regFn(regFn) + , m_swapFn(swapFn) + , m_isRegistered(false) + , m_shutedDown(false) +{ +} + +void QtRenderOGLContext::present() +{ + if (m_shutedDown) + return; + + MoveContextOnGui(); + m_swapFn(); + + makeCurrent(); +} + +void QtRenderOGLContext::makeCurrent() +{ + if (!m_isRegistered) + { + m_regFn(QThread::currentThread()); + m_isRegistered = true; + } + + m_ctx->makeCurrent(m_surface); +} + +void QtRenderOGLContext::doneCurrent() +{ + MoveContextOnGui(); +} + +void QtRenderOGLContext::setDefaultFramebuffer() +{ + GLFunctions::glBindFramebuffer(GL_FRAMEBUFFER, m_ctx->defaultFramebufferObject()); +} + +void QtRenderOGLContext::shutDown() +{ + m_shutedDown = true; +} + +void QtRenderOGLContext::MoveContextOnGui() +{ + m_ctx->doneCurrent(); + m_ctx->moveToThread(m_guiThread); +} + +QtUploadOGLContext::QtUploadOGLContext(QSurface * surface, QOpenGLContext * contextToShareWith) { - m_isContextCreated = false; m_surface = surface; m_nativeContext = new QOpenGLContext(); - if (contextToShareWith != NULL) - m_nativeContext->setShareContext(contextToShareWith->m_nativeContext); + ASSERT(contextToShareWith != nullptr, ()); + m_nativeContext->setShareContext(contextToShareWith); - m_nativeContext->setFormat(m_surface->requestedFormat()); - ASSERT(m_surface->isExposed(), ()); + m_nativeContext->setFormat(contextToShareWith->format()); VERIFY(m_nativeContext->create(), ()); } -QtOGLContext::~QtOGLContext() +QtUploadOGLContext::~QtUploadOGLContext() { delete m_nativeContext; } -void QtOGLContext::makeCurrent() +void QtUploadOGLContext::makeCurrent() { ASSERT(m_nativeContext->isValid(), ()); m_nativeContext->makeCurrent(m_surface); - -#ifdef DEBUG - LOG(LDEBUG, ("Current context : ", m_nativeContext)); - QList list = QOpenGLContextGroup::currentContextGroup()->shares(); - for (int i = 0; i < list.size(); ++i) - LOG(LDEBUG, ("Share context : ", list[i])); -#endif } -void QtOGLContext::present() +void QtUploadOGLContext::present() { - m_nativeContext->makeCurrent(m_surface); - m_nativeContext->swapBuffers(m_surface); + ASSERT(false, ()); } -void QtOGLContext::setDefaultFramebuffer() +void QtUploadOGLContext::setDefaultFramebuffer() { - GLFunctions::glBindFramebuffer(GL_FRAMEBUFFER, 0); + ASSERT(false, ()); } diff --git a/qt/qtoglcontext.hpp b/qt/qtoglcontext.hpp index 2bc7000de3..feaaee10c6 100644 --- a/qt/qtoglcontext.hpp +++ b/qt/qtoglcontext.hpp @@ -2,14 +2,50 @@ #include "drape/oglcontext.hpp" +#include "std/function.hpp" +#include "std/atomic.hpp" + #include #include -class QtOGLContext: public dp::OGLContext +#include + +class QtRenderOGLContext : public dp::OGLContext +{ +public: + using TRegisterThreadFn = function; + using TSwapFn = function; + + QtRenderOGLContext(QOpenGLContext * nativeContext, QThread * guiThread, + TRegisterThreadFn const & regFn, TSwapFn const & swapFn); + + void present() override; + void makeCurrent() override; + void doneCurrent() override; + void setDefaultFramebuffer() override; + + void shutDown(); + + QOpenGLContext * getNativeContext() { return m_ctx; } + +private: + void MoveContextOnGui(); + +private: + QSurface * m_surface; + QOpenGLContext * m_ctx; + QThread * m_guiThread; + TRegisterThreadFn m_regFn; + TSwapFn m_swapFn; + bool m_isRegistered; + atomic m_shutedDown; +}; + +class QtUploadOGLContext: public dp::OGLContext { public: - QtOGLContext(QWindow * surface, QtOGLContext * contextToShareWith); - ~QtOGLContext(); + QtUploadOGLContext(QSurface * surface, QOpenGLContext * contextToShareWith); + ~QtUploadOGLContext(); virtual void present(); virtual void makeCurrent(); @@ -17,6 +53,5 @@ public: private: QOpenGLContext * m_nativeContext; - QWindow * m_surface; - bool m_isContextCreated; + QSurface * m_surface; }; diff --git a/qt/qtoglcontextfactory.cpp b/qt/qtoglcontextfactory.cpp index 71b9da7a79..d40caed765 100644 --- a/qt/qtoglcontextfactory.cpp +++ b/qt/qtoglcontextfactory.cpp @@ -2,30 +2,33 @@ #include "base/assert.hpp" -QtOGLContextFactory::QtOGLContextFactory(QWindow * surface) - : m_surface(surface) - , m_drawContext(nullptr) +QtOGLContextFactory::QtOGLContextFactory(QOpenGLContext * renderContext, QThread * thread, + TRegisterThreadFn const & regFn, TSwapFn const & swapFn) + : m_drawContext(new QtRenderOGLContext(renderContext, thread, regFn, swapFn)) , m_uploadContext(nullptr) -{} +{ + m_uploadThreadSurface = new QOffscreenSurface(renderContext->screen()); + m_uploadThreadSurface->create(); +} QtOGLContextFactory::~QtOGLContextFactory() { delete m_drawContext; delete m_uploadContext; + + m_uploadThreadSurface->destroy(); + delete m_uploadThreadSurface; } dp::OGLContext * QtOGLContextFactory::getDrawContext() { - if (m_drawContext == nullptr) - m_drawContext = new QtOGLContext(m_surface, m_uploadContext); - return m_drawContext; } dp::OGLContext * QtOGLContextFactory::getResourcesUploadContext() { if (m_uploadContext == nullptr) - m_uploadContext = new QtOGLContext(m_surface, m_drawContext); + m_uploadContext = new QtUploadOGLContext(m_uploadThreadSurface, m_drawContext->getNativeContext()); return m_uploadContext; } diff --git a/qt/qtoglcontextfactory.hpp b/qt/qtoglcontextfactory.hpp index 0c75929cef..ea9c4936cd 100644 --- a/qt/qtoglcontextfactory.hpp +++ b/qt/qtoglcontextfactory.hpp @@ -3,14 +3,20 @@ #include "drape/oglcontextfactory.hpp" #include "qt/qtoglcontext.hpp" -#include +#include class QtOGLContextFactory : public dp::OGLContextFactory { public: - QtOGLContextFactory(QWindow * surface); + using TRegisterThreadFn = QtRenderOGLContext::TRegisterThreadFn; + using TSwapFn = QtRenderOGLContext::TSwapFn; + + QtOGLContextFactory(QOpenGLContext * renderContext, QThread * thread, + TRegisterThreadFn const & regFn, TSwapFn const & swapFn); ~QtOGLContextFactory(); + void shutDown() { m_drawContext->shutDown(); } + virtual dp::OGLContext * getDrawContext(); virtual dp::OGLContext * getResourcesUploadContext(); @@ -19,7 +25,7 @@ protected: virtual bool isUploadContextCreated() const { return m_uploadContext != nullptr; } private: - QWindow * m_surface; - QtOGLContext * m_drawContext; - QtOGLContext * m_uploadContext; + QtRenderOGLContext * m_drawContext; + QtUploadOGLContext * m_uploadContext; + QOffscreenSurface * m_uploadThreadSurface; }; -- cgit v1.2.3