Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorExMix <rahuba.youri@mapswithme.com>2015-07-08 12:36:57 +0300
committerr.kuznetsov <r.kuznetsov@corp.mail.ru>2015-11-30 16:09:31 +0300
commit425d6bc58416930763e9a74755ff64b6bc9771db (patch)
tree946a9d2067390bc749fb352b5c7e6ef69b096056
parent4e8d7d40e78f1fa7ca55b7b107ecab6e19d978e0 (diff)
[drape] clean up drape_head code. Remove QtOGLContextFactory duplicate
in qt application make rendering according qt widgets composition model
-rw-r--r--drape/oglcontext.hpp1
-rw-r--r--drape_frontend/backend_renderer.cpp1
-rwxr-xr-xdrape_frontend/frontend_renderer.cpp1
-rw-r--r--drape_head/drape_head.pro4
-rw-r--r--drape_head/drape_surface.cpp43
-rw-r--r--drape_head/drape_surface.hpp19
-rw-r--r--drape_head/qtoglcontext.cpp49
-rw-r--r--drape_head/qtoglcontext.hpp22
-rw-r--r--drape_head/qtoglcontextfactory.cpp31
-rw-r--r--drape_head/qtoglcontextfactory.hpp21
-rw-r--r--drape_head/testing_engine.cpp23
-rw-r--r--drape_head/testing_engine.hpp15
-rw-r--r--qt/draw_widget.cpp181
-rw-r--r--qt/draw_widget.hpp46
-rw-r--r--qt/qtoglcontext.cpp85
-rw-r--r--qt/qtoglcontext.hpp45
-rw-r--r--qt/qtoglcontextfactory.cpp19
-rw-r--r--qt/qtoglcontextfactory.hpp16
18 files changed, 350 insertions, 272 deletions
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<dp::ThreadSafeFactory>(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<df::TestingEngine>(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::TestingEngine>(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 <QtGui/QWindow>
+#include <QtGui/QOpenGLWindow>
+#include <QtCore/QTimer>
-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<dp::OGLContextFactory> TContextFactoryPtr;
- typedef drape_ptr<df::TestingEngine> TEnginePrt;
- TContextFactoryPtr m_contextFactory;
- TEnginePrt m_drapeEngine;
+ drape_ptr<df::TestingEngine> 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<QOpenGLContext *> 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 <QtGui/QWindow>
-#include <QtGui/QOpenGLContext>
-
-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 <QtGui/QWindow>
-
-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<dp::OGLContextFactory> 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<dp::OGLContextFactory> 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 <QObject>
-#include <QEvent>
-
namespace df
{
-class TestingEngine : public QObject
+class TestingEngine
{
public:
- TestingEngine(ref_ptr<dp::OGLContextFactory> 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<dp::OGLContextFactory> m_contextFactory;
drape_ptr<dp::Batcher> m_batcher;
drape_ptr<dp::GpuProgramManager> m_programManager;
drape_ptr<dp::TextureManager> 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 <QtCore/QLocale>
#include <QtCore/QDateTime>
+#include <QtCore/QThread>
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<UserMarkCopy> 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<QtOGLContextFactory>(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<dp::ThreadSafeFactory>(new QtOGLContextFactory(this));
- CreateEngine();
- LoadState();
+ unique_lock<mutex> 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<mutex> 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<mutex> 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<mutex> 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<mutex> 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<mutex> 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 <QtGui/QWindow>
+#include <QtGui/QOpenGLWindow>
namespace qt
{
class QScaleSlider;
- class DrawWidget : public QWindow
+ class DrawWidget : public QOpenGLWindow
{
- typedef QWindow TBase;
+ using TBase = QOpenGLWindow;
- drape_ptr<dp::OGLContextFactory> m_contextFactory;
+ drape_ptr<QtOGLContextFactory> m_contextFactory;
unique_ptr<Framework> 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<QOpenGLContext *> 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 <QtGui/QWindow>
#include <QtGui/QOpenGLContext>
-class QtOGLContext: public dp::OGLContext
+#include <QtCore/QThread>
+
+class QtRenderOGLContext : public dp::OGLContext
+{
+public:
+ using TRegisterThreadFn = function<void (QThread * thread)>;
+ using TSwapFn = function<void ()>;
+
+ 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<bool> 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 <QtGui/QWindow>
+#include <QtGui/QOffscreenSurface>
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;
};