diff --git a/map/benchmark_tiling_render_policy_mt.cpp b/map/benchmark_tiling_render_policy_mt.cpp index b2c5793b9d..c1f09827ac 100644 --- a/map/benchmark_tiling_render_policy_mt.cpp +++ b/map/benchmark_tiling_render_policy_mt.cpp @@ -13,11 +13,6 @@ void BenchmarkTilingRenderPolicyMT::Initialize(shared_ptr TilingRenderPolicyMT::Initialize(renderContext, resourceManager); } -void BenchmarkTilingRenderPolicyMT::OnSize(int w, int h) -{ - TilingRenderPolicyMT::OnSize(w, h); -} - void BenchmarkTilingRenderPolicyMT::DrawFrame(shared_ptr const & e, ScreenBase const & s) { diff --git a/map/benchmark_tiling_render_policy_mt.hpp b/map/benchmark_tiling_render_policy_mt.hpp index c037473626..396c72dc33 100644 --- a/map/benchmark_tiling_render_policy_mt.hpp +++ b/map/benchmark_tiling_render_policy_mt.hpp @@ -13,6 +13,4 @@ public: shared_ptr const & resourceManager); void DrawFrame(shared_ptr const & e, ScreenBase const & s); - - void OnSize(int w, int h); }; diff --git a/map/events.hpp b/map/events.hpp index 16f0cdd3b7..cb9d9bf99e 100644 --- a/map/events.hpp +++ b/map/events.hpp @@ -48,11 +48,12 @@ class PaintEvent : public Event DrawerYG * m_drawer; core::CommandsQueue::Environment const * m_env; + bool m_isCancelled; public: PaintEvent(DrawerYG * drawer, core::CommandsQueue::Environment const * env = 0) - : m_drawer(drawer), m_env(env) + : m_drawer(drawer), m_env(env), m_isCancelled(false) {} DrawerYG * drawer() const @@ -60,9 +61,18 @@ public: return m_drawer; } + void Cancel() + { + ASSERT(m_env == 0, ()); + m_isCancelled = true; + } + bool isCancelled() const { - return (m_env && m_env->IsCancelled()); + if (m_env) + return m_env->IsCancelled(); + else + return m_isCancelled; } }; diff --git a/map/framework.cpp b/map/framework.cpp index e342e86a5d..3b319d3e4b 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -26,6 +26,7 @@ #include "../std/fstream.hpp" #include "render_policy_st.hpp" +#include "render_policy_mt.hpp" #include "tiling_render_policy_st.hpp" #include "tiling_render_policy_mt.hpp" @@ -86,7 +87,8 @@ Framework::Framework(shared_ptr windowHandle, // on Android policy is created in AndroidFramework #ifndef OMIM_OS_ANDROID // SetRenderPolicy(make_shared_ptr(new RenderPolicyST(windowHandle, bind(&this_type::DrawModel, this, _1, _2, _3, _4, _5)))); - SetRenderPolicy(make_shared_ptr(new TilingRenderPolicyMT(windowHandle, bind(&this_type::DrawModel, this, _1, _2, _3, _4, _5)))); +// SetRenderPolicy(make_shared_ptr(new TilingRenderPolicyMT(windowHandle, bind(&this_type::DrawModel, this, _1, _2, _3, _4, _5)))); + SetRenderPolicy(make_shared_ptr(new RenderPolicyMT(windowHandle, bind(&this_type::DrawModel, this, _1, _2, _3, _4, _5)))); #endif m_informationDisplay.setBottomShift(bottomShift); #ifdef DRAW_TOUCH_POINTS @@ -252,9 +254,13 @@ void Framework::OnSize(int w, int h) m_informationDisplay.setDisplayRect(m2::RectI(m2::PointI(0, 0), m2::PointU(w, h))); - m_navigator.OnSize(0, 0, w, h); + m2::RectI const & viewPort = m_renderPolicy->OnSize(w, h); - m_renderPolicy->OnSize(w, h); + m_navigator.OnSize( + viewPort.minX(), + viewPort.minY(), + viewPort.SizeX(), + viewPort.SizeY()); } template @@ -298,7 +304,8 @@ void Framework::DrawModel(shared_ptr const & e, try { //threads::MutexGuard lock(m_modelSyn); - m_model.ForEachFeature_TileDrawing(selectRect, doDraw, scaleLevel); +// m_model.ForEachFeature_TileDrawing(selectRect, doDraw, scaleLevel); + m_model.ForEachFeature(selectRect, doDraw, scaleLevel); } catch (redraw_operation_cancelled const &) { @@ -436,13 +443,13 @@ template void Framework::StartDrag(DragEvent const & e) { m2::PointD pos = m_navigator.OrientPoint(e.Pos()); - m_navigator.StartDrag(pos, m_timer.ElapsedSeconds()); #ifdef DRAW_TOUCH_POINTS m_informationDisplay.setDebugPoint(0, pos); #endif - Invalidate(); + m_navigator.StartDrag(pos, m_timer.ElapsedSeconds()); + m_renderPolicy->StartDrag(pos, m_timer.ElapsedSeconds()); } template @@ -451,13 +458,14 @@ void Framework::DoDrag(DragEvent const & e) m_centeringMode = EDoNothing; m2::PointD pos = m_navigator.OrientPoint(e.Pos()); - m_navigator.DoDrag(pos, m_timer.ElapsedSeconds()); #ifdef DRAW_TOUCH_POINTS m_informationDisplay.setDebugPoint(0, pos); #endif - Invalidate(); + m_navigator.DoDrag(pos, m_timer.ElapsedSeconds()); + + m_renderPolicy->DoDrag(pos, m_timer.ElapsedSeconds()); } template @@ -471,14 +479,14 @@ void Framework::StopDrag(DragEvent const & e) m_informationDisplay.setDebugPoint(0, m2::PointD(0, 0)); #endif - Invalidate(); + m_renderPolicy->StopDrag(pos, m_timer.ElapsedSeconds()); } template void Framework::Move(double azDir, double factor) { m_navigator.Move(azDir, factor); - //m_tiler.seed(m_navigator.Screen(), m_tileSize); + Invalidate(); } //@} @@ -526,14 +534,13 @@ void Framework::StartScale(ScaleEvent const & e) pt2 += ptDiff; } - m_navigator.StartScale(pt1, pt2, m_timer.ElapsedSeconds()); - #ifdef DRAW_TOUCH_POINTS m_informationDisplay.setDebugPoint(0, pt1); m_informationDisplay.setDebugPoint(1, pt2); #endif - Invalidate(); + m_navigator.StartScale(pt1, pt2, m_timer.ElapsedSeconds()); + m_renderPolicy->StartScale(pt1, pt2, m_timer.ElapsedSeconds()); } template @@ -550,14 +557,13 @@ void Framework::DoScale(ScaleEvent const & e) pt2 += ptDiff; } - m_navigator.DoScale(pt1, pt2, m_timer.ElapsedSeconds()); - #ifdef DRAW_TOUCH_POINTS m_informationDisplay.setDebugPoint(0, pt1); m_informationDisplay.setDebugPoint(1, pt2); #endif - Invalidate(); + m_navigator.DoScale(pt1, pt2, m_timer.ElapsedSeconds()); + m_renderPolicy->DoScale(pt1, pt2, m_timer.ElapsedSeconds()); } template @@ -574,14 +580,13 @@ void Framework::StopScale(ScaleEvent const & e) pt2 += ptDiff; } - m_navigator.StopScale(pt1, pt2, m_timer.ElapsedSeconds()); - #ifdef DRAW_TOUCH_POINTS m_informationDisplay.setDebugPoint(0, m2::PointD(0, 0)); m_informationDisplay.setDebugPoint(0, m2::PointD(0, 0)); #endif - Invalidate(); + m_navigator.StopScale(pt1, pt2, m_timer.ElapsedSeconds()); + m_renderPolicy->StopScale(pt1, pt2, m_timer.ElapsedSeconds()); } template diff --git a/map/map.pro b/map/map.pro index 31e81a749a..e6a27563db 100644 --- a/map/map.pro +++ b/map/map.pro @@ -34,7 +34,10 @@ HEADERS += \ tiler.hpp \ tile.hpp \ tile_cache.hpp \ - screen_coverage.hpp + screen_coverage.hpp \ + render_policy_mt.hpp \ + render_queue.hpp \ + render_queue_routine.hpp SOURCES += \ feature_vec_model.cpp \ @@ -58,7 +61,10 @@ SOURCES += \ tiler.cpp \ tile_cache.cpp \ tile.cpp \ - screen_coverage.cpp + screen_coverage.cpp \ + render_policy_mt.cpp \ + render_queue_routine.cpp \ + render_queue.cpp !iphone*:!bada*:!android* { HEADERS += qgl_render_context.hpp diff --git a/map/navigator.cpp b/map/navigator.cpp index a648a5e1ed..4ebd1c6eaf 100644 --- a/map/navigator.cpp +++ b/map/navigator.cpp @@ -403,17 +403,19 @@ EOrientation Navigator::Orientation() const m2::PointD const Navigator::OrientPoint(m2::PointD const & pt) const { + m2::PointD ptShift(m_Screen.PixelRect().minX(), m_Screen.PixelRect().minY()); + switch (m_orientation) { case EOrientation90: - return m2::PointD(m_Screen.GetWidth() - pt.y, pt.x); + return m2::PointD(m_Screen.GetWidth() - pt.y, pt.x) + ptShift; case EOrientation180: - return m2::PointD(m_Screen.GetWidth() - pt.x, m_Screen.GetHeight() - pt.y); + return m2::PointD(m_Screen.GetWidth() - pt.x, m_Screen.GetHeight() - pt.y) + ptShift; case EOrientation270: - return m2::PointD(pt.y, m_Screen.GetHeight() - pt.x); + return m2::PointD(pt.y, m_Screen.GetHeight() - pt.x) + ptShift; case EOrientation0: - return pt; + return pt + ptShift; }; - return m2::PointD(0, 0); + return ptShift; } diff --git a/map/render_policy.cpp b/map/render_policy.cpp index 094d607372..d5f66a0c34 100644 --- a/map/render_policy.cpp +++ b/map/render_policy.cpp @@ -1,6 +1,7 @@ #include "../base/SRC_FIRST.hpp" #include "render_policy.hpp" +#include "window_handle.hpp" RenderPolicy::RenderPolicy(shared_ptr const & windowHandle, TRenderFn const & renderFn) : m_bgColor(0xEE, 0xEE, 0xDD, 0xFF), @@ -33,3 +34,38 @@ void RenderPolicy::Initialize(shared_ptr const &, { m_resourceManager = resourceManager; } + +m2::RectI const RenderPolicy::OnSize(int w, int h) +{ + return m2::RectI(0, 0, w, h); +} + +void RenderPolicy::StartDrag(m2::PointD const & pt, double timeInSec) +{ + m_windowHandle->invalidate(); +} + +void RenderPolicy::DoDrag(m2::PointD const & pt, double timeInSec) +{ + m_windowHandle->invalidate(); +} + +void RenderPolicy::StopDrag(m2::PointD const & pt, double timeInSec) +{ + m_windowHandle->invalidate(); +} + +void RenderPolicy::StartScale(m2::PointD const & pt1, m2::PointD const & pt2, double timeInSec) +{ + m_windowHandle->invalidate(); +} + +void RenderPolicy::DoScale(m2::PointD const & pt1, m2::PointD const & pt2, double timeInSec) +{ + m_windowHandle->invalidate(); +} + +void RenderPolicy::StopScale(m2::PointD const & pt1, m2::PointD const & pt2, double timeInSec) +{ + m_windowHandle->invalidate(); +} diff --git a/map/render_policy.hpp b/map/render_policy.hpp index b2fca30f88..27169c2846 100644 --- a/map/render_policy.hpp +++ b/map/render_policy.hpp @@ -50,8 +50,19 @@ public: /// drawing single frame virtual void DrawFrame(shared_ptr const & paintEvent, ScreenBase const & currentScreen) = 0; /// processing resize request - virtual void OnSize(int w, int h) = 0; + virtual m2::RectI const OnSize(int w, int h); /// initialize render policy virtual void Initialize(shared_ptr const & primaryContext, shared_ptr const & resourceManager) = 0; + + /// reacting on navigation actions + /// @{ + virtual void StartDrag(m2::PointD const & pt, double timeInSec); + virtual void DoDrag(m2::PointD const & pt, double timeInSec); + virtual void StopDrag(m2::PointD const & pt, double timeInSec); + + virtual void StartScale(m2::PointD const & pt1, m2::PointD const & pt2, double timeInSec); + virtual void DoScale(m2::PointD const & pt1, m2::PointD const & pt2, double timeInSec); + virtual void StopScale(m2::PointD const & pt1, m2::PointD const & pt2, double timeInSec); + /// @} }; diff --git a/map/render_policy_mt.cpp b/map/render_policy_mt.cpp new file mode 100644 index 0000000000..8d18caaa4e --- /dev/null +++ b/map/render_policy_mt.cpp @@ -0,0 +1,96 @@ +#include "../base/SRC_FIRST.hpp" + +#include "render_policy_mt.hpp" +#include "events.hpp" +#include "drawer_yg.hpp" +#include "../yg/render_state.hpp" + +#include "../geometry/transformations.hpp" + +#include "../base/mutex.hpp" + +#include "../platform/platform.hpp" + +RenderPolicyMT::RenderPolicyMT(shared_ptr const & wh, + RenderPolicy::TRenderFn const & renderFn) + : RenderPolicy(wh, renderFn), + m_renderQueue(GetPlatform().SkinName(), + false, + true, + 0.1, + false, + GetPlatform().ScaleEtalonSize(), + GetPlatform().VisualScale(), + bgColor()), + m_DoAddCommand(true) +{ + m_renderQueue.AddWindowHandle(wh); +} + +void RenderPolicyMT::Initialize(shared_ptr const & rc, + shared_ptr const & rm) +{ + m_renderQueue.initializeGL(rc, rm); + RenderPolicy::Initialize(rc, rm); +} + +m2::RectI const RenderPolicyMT::OnSize(int w, int h) +{ + m_renderQueue.OnSize(w, h); + + m2::PointU pt = m_renderQueue.renderState().coordSystemShift(); + + return m2::RectI(pt.x, pt.y, pt.x + w, pt.y + h); +} + +void RenderPolicyMT::DrawFrame(shared_ptr const & e, + ScreenBase const & s) +{ + if (m_DoAddCommand && (s != m_renderQueue.renderState().m_actualScreen)) + m_renderQueue.AddCommand(renderFn(), s); + + DrawerYG * pDrawer = e->drawer(); + + threads::MutexGuard g(*m_renderQueue.renderState().m_mutex.get()); + + e->drawer()->screen()->clear(bgColor()); + + if (m_renderQueue.renderState().m_actualTarget.get() != 0) + { + m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(false); + +// OGLCHECK(glMatrixMode(GL_MODELVIEW)); +// OGLCHECK(glPushMatrix()); +// OGLCHECK(glTranslatef(-ptShift.x, -ptShift.y, 0)); + + math::Matrix m = m_renderQueue.renderState().m_actualScreen.PtoGMatrix() * s.GtoPMatrix(); + m = math::Shift(m, -ptShift); + + pDrawer->screen()->blit(m_renderQueue.renderState().m_actualTarget, + m); + } +} + +void RenderPolicyMT::StartDrag(m2::PointD const & pt, double timeInSec) +{ + m_DoAddCommand = false; + RenderPolicy::StartDrag(pt, timeInSec); +} + +void RenderPolicyMT::StopDrag(m2::PointD const & pt, double timeInSec) +{ + m_DoAddCommand = true; + RenderPolicy::StopDrag(pt, timeInSec); +} + +void RenderPolicyMT::StartScale(m2::PointD const & pt1, m2::PointD const & pt2, double timeInSec) +{ + m_DoAddCommand = false; + RenderPolicy::StartScale(pt1, pt2, timeInSec); +} + +void RenderPolicyMT::StopScale(m2::PointD const & pt1, m2::PointD const & pt2, double timeInSec) +{ + m_DoAddCommand = true; + RenderPolicy::StartScale(pt1, pt2, timeInSec); +} diff --git a/map/render_policy_mt.hpp b/map/render_policy_mt.hpp new file mode 100644 index 0000000000..eb993c88d9 --- /dev/null +++ b/map/render_policy_mt.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "render_policy.hpp" +#include "render_queue.hpp" +#include "../geometry/point2d.hpp" + +class WindowHandle; + +class RenderPolicyMT : public RenderPolicy +{ +private: + + RenderQueue m_renderQueue; + bool m_DoAddCommand; + +public: + RenderPolicyMT(shared_ptr const & wh, + RenderPolicy::TRenderFn const & renderFn); + + void Initialize(shared_ptr const & rc, + shared_ptr const & rm); + + void DrawFrame(shared_ptr const & paintEvent, + ScreenBase const & screenBase); + + m2::RectI const OnSize(int w, int h); + + void StartDrag(m2::PointD const & pt, double timeInSec); + void StopDrag(m2::PointD const & pt, double timeInSec); + + void StartScale(m2::PointD const & pt1, m2::PointD const & pt2, double timeInSec); + void StopScale(m2::PointD const & pt1, m2::PointD const & pt2, double timeInSec); +}; diff --git a/map/render_policy_st.cpp b/map/render_policy_st.cpp index 9d3448deea..1c5f979676 100644 --- a/map/render_policy_st.cpp +++ b/map/render_policy_st.cpp @@ -43,7 +43,3 @@ void RenderPolicyST::DrawFrame(shared_ptr const & e, infoLayer->draw(e->drawer()->screen().get(), math::Identity()); e->drawer()->screen()->resetInfoLayer(); } - -void RenderPolicyST::OnSize(int w, int h) -{ -} diff --git a/map/render_policy_st.hpp b/map/render_policy_st.hpp index 50b8d00604..87a2fbc122 100644 --- a/map/render_policy_st.hpp +++ b/map/render_policy_st.hpp @@ -16,6 +16,4 @@ public: void DrawFrame(shared_ptr const & paintEvent, ScreenBase const & screenBase); - - void OnSize(int w, int h); }; diff --git a/map/render_queue.cpp b/map/render_queue.cpp new file mode 100644 index 0000000000..267def05f0 --- /dev/null +++ b/map/render_queue.cpp @@ -0,0 +1,109 @@ +#include "../base/SRC_FIRST.hpp" + +#include "render_queue.hpp" + +#include "../yg/render_state.hpp" +#include "../yg/rendercontext.hpp" + +RenderQueue::RenderQueue( + string const & skinName, + bool isMultiSampled, + bool doPeriodicalUpdate, + double updateInterval, + bool isBenchmarking, + unsigned scaleEtalonSize, + double visualScale, + yg::Color const & bgColor + ) + : m_renderState(new yg::gl::RenderState()) +{ + m_renderState->m_surfaceWidth = 100; + m_renderState->m_surfaceHeight = 100; + m_renderState->m_textureWidth = 256; + m_renderState->m_textureHeight = 256; + m_renderState->m_duration = 0; + + m_routine = new RenderQueueRoutine( + m_renderState, + skinName, + isMultiSampled, + doPeriodicalUpdate, + updateInterval, + isBenchmarking, + scaleEtalonSize, + visualScale, + bgColor); +} + +void RenderQueue::initializeGL(shared_ptr const & primaryContext, + shared_ptr const & resourceManager) +{ + m_resourceManager = resourceManager; + m_routine->initializeGL(primaryContext->createShared(), + m_resourceManager); + m_renderQueueThread.Create(m_routine); +} + +RenderQueue::~RenderQueue() +{ + m_renderQueueThread.Cancel(); +} + +void RenderQueue::AddCommand(RenderQueueRoutine::render_fn_t const & fn, ScreenBase const & frameScreen) +{ + m_routine->addCommand(fn, frameScreen); +} + +void RenderQueue::AddBenchmarkCommand(RenderQueueRoutine::render_fn_t const & fn, ScreenBase const & frameScreen) +{ + m_routine->addBenchmarkCommand(fn, frameScreen); +} + +void RenderQueue::SetRedrawAll() +{ + m_renderState->m_doRepaintAll = true; +} + +void RenderQueue::AddWindowHandle(shared_ptr const & windowHandle) +{ + m_routine->addWindowHandle(windowHandle); +} + +void RenderQueue::OnSize(size_t w, size_t h) +{ + m_renderState->onSize(w, h); +} + +yg::gl::RenderState const RenderQueue::CopyState() const +{ + yg::gl::RenderState state; + m_renderState->copyTo(state); + return state; +} + +yg::gl::RenderState const & RenderQueue::renderState() const +{ + return *m_renderState.get(); +} + +shared_ptr const & RenderQueue::renderStatePtr() const +{ + return m_renderState; +} + +void RenderQueue::memoryWarning() +{ + m_routine->memoryWarning(); +} + +void RenderQueue::enterBackground() +{ + m_routine->enterBackground(); +} + +void RenderQueue::enterForeground() +{ + m_routine->enterForeground(); +} + + diff --git a/map/render_queue.hpp b/map/render_queue.hpp new file mode 100644 index 0000000000..ec7b205dbd --- /dev/null +++ b/map/render_queue.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include "../base/thread.hpp" +#include "../geometry/screenbase.hpp" +#include "../std/shared_ptr.hpp" +#include "render_queue_routine.hpp" + +namespace yg +{ + class ResourceManager; + namespace gl + { + class RenderState; + class RenderContext; + } +} + +class WindowHandle; + +class RenderQueue +{ +private: + + friend class RenderQueueRoutine; + + threads::Thread m_renderQueueThread; + + shared_ptr m_renderState; + shared_ptr m_resourceManager; + RenderQueueRoutine * m_routine; + +public: + /// constructor. + RenderQueue(string const & skinName, + bool isMultiSampled, + bool doPeriodicalUpdate, + double updateInterval, + bool isBenchmarking, + unsigned scaleEtalonSize, + double visualScale, + yg::Color const & bgColor); + /// destructor. + ~RenderQueue(); + /// set the primary context. it starts the rendering thread. + void initializeGL(shared_ptr const & primaryContext, + shared_ptr const & resourceManager); + /// add command to the commands queue. + void AddCommand(RenderQueueRoutine::render_fn_t const & fn, ScreenBase const & frameScreen); + void AddBenchmarkCommand(RenderQueueRoutine::render_fn_t const & fn, ScreenBase const & frameScreen); + + void SetRedrawAll(); + + void SetVisualScale(double visualScale); + + /// add window handle to notify when rendering operation finishes + void AddWindowHandle(shared_ptr const & windowHandle); + /// process resize request + void OnSize(size_t w, size_t h); + /// copy primary render state + yg::gl::RenderState const CopyState() const; + + shared_ptr const & renderStatePtr() const; + + yg::gl::RenderState const & renderState() const; + + /// free all possible memory caches + void memoryWarning(); + /// free all possible memory caches, opengl resources, + /// and make sure no opengl call will be made in background + void enterBackground(); + /// load all necessary memory caches and opengl resources. + void enterForeground(); +}; diff --git a/map/render_queue_routine.cpp b/map/render_queue_routine.cpp new file mode 100644 index 0000000000..caebb4e29d --- /dev/null +++ b/map/render_queue_routine.cpp @@ -0,0 +1,514 @@ +#include "../base/SRC_FIRST.hpp" +#include "../base/mutex.hpp" +#include "../base/timer.hpp" +#include "../base/logging.hpp" + +#include "../std/bind.hpp" + +#include "../yg/internal/opengl.hpp" +#include "../yg/render_state.hpp" +#include "../yg/rendercontext.hpp" +#include "../yg/framebuffer.hpp" +#include "../yg/renderbuffer.hpp" +#include "../yg/texture.hpp" +#include "../yg/resource_manager.hpp" +#include "../yg/screen.hpp" +#include "../yg/pen_info.hpp" +#include "../yg/skin.hpp" + +#include "../indexer/scales.hpp" + +#include "events.hpp" +#include "drawer_yg.hpp" +#include "window_handle.hpp" +#include "render_queue_routine.hpp" +RenderQueueRoutine::RenderModelCommand::RenderModelCommand(ScreenBase const & frameScreen, + render_fn_t renderFn) + : m_frameScreen(frameScreen), + m_renderFn(renderFn) +{} + +RenderQueueRoutine::RenderQueueRoutine(shared_ptr const & renderState, + string const & skinName, + bool isMultiSampled, + bool doPeriodicalUpdate, + double updateInterval, + bool isBenchmarking, + unsigned scaleEtalonSize, + double visualScale, + yg::Color const & bgColor) +{ + m_skinName = skinName; + m_visualScale = visualScale; + m_renderState = renderState; + m_renderState->addInvalidateFn(bind(&RenderQueueRoutine::invalidate, this)); + m_isMultiSampled = isMultiSampled; + m_doPeriodicalUpdate = doPeriodicalUpdate; + m_updateInterval = updateInterval; + m_isBenchmarking = isBenchmarking; + m_scaleEtalonSize = scaleEtalonSize; + m_bgColor = bgColor; +} + +void RenderQueueRoutine::Cancel() +{ + IRoutine::Cancel(); + /// Waking up the sleeping thread... + m_hasRenderCommands.Signal(); + /// ...Or cancelling the current rendering command in progress. + if (m_currentRenderCommand != 0) + m_currentRenderCommand->m_paintEvent->Cancel(); +} + +void RenderQueueRoutine::processResize(ScreenBase const & frameScreen) +{ + if (m_renderState->m_isResized) + { + size_t texW = m_renderState->m_textureWidth; + size_t texH = m_renderState->m_textureHeight; + + m_renderState->m_depthBuffer.reset(); + + if (!m_isMultiSampled) + { + m_renderState->m_depthBuffer = make_shared_ptr(new yg::gl::RenderBuffer(texW, texH, true)); + m_threadDrawer->screen()->frameBuffer()->setDepthBuffer(m_renderState->m_depthBuffer); + } + + m_threadDrawer->onSize(texW, texH); + m_threadDrawer->screen()->frameBuffer()->onSize(texW, texH); + + shared_ptr oldActualTarget = m_renderState->m_actualTarget; + + m_renderState->m_actualTarget.reset(); + m_renderState->m_actualTarget = m_resourceManager->createRenderTarget(texW, texH); + + m_auxScreen->onSize(texW, texH); + m_auxScreen->setRenderTarget(m_renderState->m_actualTarget); + m_auxScreen->beginFrame(); + m_auxScreen->clear(m_bgColor); + + if (oldActualTarget != 0) + { + m_auxScreen->blit(oldActualTarget, + m_renderState->m_actualScreen, + frameScreen); + oldActualTarget.reset(); + } + m_auxScreen->endFrame(); + + for (size_t i = 0; i < m_renderState->m_backBufferLayers.size(); ++i) + { + shared_ptr oldBackBuffer = m_renderState->m_backBufferLayers[i]; + m_renderState->m_backBufferLayers[i].reset(); + m_renderState->m_backBufferLayers[i] = m_resourceManager->createRenderTarget(texW, texH); + m_auxScreen->setRenderTarget(m_renderState->m_backBufferLayers[i]); + m_auxScreen->beginFrame(); + m_auxScreen->clear(m_bgColor); + + if (oldBackBuffer != 0) + { + m_auxScreen->blit(oldBackBuffer, + m_renderState->m_actualScreen, + frameScreen); + oldBackBuffer.reset(); + } + m_auxScreen->endFrame(); + + m_renderState->m_actualScreen = frameScreen; + } + + m_renderState->m_isResized = false; + } +} + +void RenderQueueRoutine::getUpdateAreas( + ScreenBase const & oldScreen, + m2::RectI const & oldRect, + ScreenBase const & newScreen, + m2::RectI const & newRect, + vector & areas) +{ + areas.clear(); + + if (IsPanning(oldScreen, newScreen)) + { + m2::RectD o(newScreen.GtoP(oldScreen.PtoG(m2::PointD(oldRect.minX(), oldRect.minY()))), + newScreen.GtoP(oldScreen.PtoG(m2::PointD(oldRect.maxX(), oldRect.maxY())))); + m2::RectD n(newRect); + + /// checking two corner cases + if (o.IsRectInside(n)) + return; + if (!o.IsIntersect(n)) + { + areas.push_back(m2::RectI(n)); + return; + } + + double leftBarMinX = 0; + double leftBarMaxX = 0; + double rightBarMinX = n.maxX(); + double rightBarMaxX = n.maxX(); + double topBarMinY = 0; + double topBarMaxY = 0; + double bottomBarMinY = n.maxY(); + double bottomBarMaxY = n.maxY(); + + if (o.minX() > n.minX()) + leftBarMaxX = ceil(o.minX()); + if (o.maxX() < n.maxX()) + rightBarMinX = floor(o.maxX()); + if (o.minY() > n.minY()) + topBarMaxY = ceil(o.minY()); + if (o.maxY() < n.maxY()) + bottomBarMinY = floor(o.maxY()); + + if (leftBarMinX != leftBarMaxX) + areas.push_back(m2::RectI(leftBarMinX, topBarMinY, leftBarMaxX, bottomBarMinY)); + if (topBarMinY != topBarMaxY) + areas.push_back(m2::RectI(leftBarMaxX, topBarMinY, rightBarMaxX, topBarMaxY)); + if (rightBarMinX != rightBarMaxX) + areas.push_back(m2::RectI(rightBarMinX, topBarMaxY, rightBarMaxX, bottomBarMaxY)); + if (bottomBarMinY != bottomBarMaxY) + areas.push_back(m2::RectI(leftBarMinX, bottomBarMinY, rightBarMinX, bottomBarMaxY)); + } + else + { + areas.push_back(newRect); + +/* int rectW = (w + 9) / 5; + int rectH = (h + 9) / 5; + m2::RectI r( 2 * rectW, 2 * rectH, 3 * rectW, 3 * rectH); + areas.push_back(r); + areas.push_back(m2::Offset(r, -rectW, 0)); + areas.push_back(m2::Offset(r, -rectW, -rectH)); + areas.push_back(m2::Offset(r, 0, -rectH)); + areas.push_back(m2::Offset(r, rectW, -rectH)); + areas.push_back(m2::Offset(r, rectW, 0)); + areas.push_back(m2::Offset(r, rectW, rectH)); + areas.push_back(m2::Offset(r, 0, rectH)); + areas.push_back(m2::Offset(r, -rectW, rectH)); + areas.push_back(m2::Offset(r, -2 * rectW, rectH)); + areas.push_back(m2::Offset(r, -2 * rectW, 0)); + areas.push_back(m2::Offset(r, -2 * rectW, -rectH)); + areas.push_back(m2::Offset(r, -2 * rectW, -2*rectH)); + areas.push_back(m2::Offset(r, -rectW, -2*rectH)); + areas.push_back(m2::Offset(r, 0, -2*rectH)); + areas.push_back(m2::Offset(r, rectW, -2*rectH)); + areas.push_back(m2::Offset(r, 2 * rectW, -2*rectH)); + areas.push_back(m2::Offset(r, 2 * rectW, -rectH)); + areas.push_back(m2::Offset(r, 2 * rectW, 0)); + areas.push_back(m2::Offset(r, 2 * rectW, rectH)); + areas.push_back(m2::Offset(r, 2 * rectW, 2*rectH)); + areas.push_back(m2::Offset(r, rectW, 2*rectH)); + areas.push_back(m2::Offset(r, 0, 2*rectH)); + areas.push_back(m2::Offset(r, -rectW, 2*rectH)); + areas.push_back(m2::Offset(r, -2*rectW, 2*rectH)); +*/ + } +} + +void RenderQueueRoutine::setVisualScale(double visualScale) +{ + m_visualScale = visualScale; +} + +void RenderQueueRoutine::waitForRenderCommand(list > & cmdList, + threads::ConditionGuard & guard) +{ + while (cmdList.empty()) + { + guard.Wait(); + if (IsCancelled()) + break; + } +} + +void RenderQueueRoutine::Do() +{ + m_renderContext->makeCurrent(); + + m_frameBuffer = make_shared_ptr(new yg::gl::FrameBuffer()); + + DrawerYG::params_t params; + + params.m_resourceManager = m_resourceManager; + params.m_frameBuffer = m_frameBuffer; + params.m_renderState = m_renderState; + params.m_doPeriodicalUpdate = m_doPeriodicalUpdate; + params.m_updateInterval = m_updateInterval; + params.m_skinName = m_skinName; + params.m_visualScale = m_visualScale; + params.m_threadID = 0; + params.m_glyphCacheID = m_resourceManager->renderThreadGlyphCacheID(0); + params.m_useOverlay = true; +/* params.m_isDebugging = true; + params.m_drawPathes = false; + params.m_drawAreas = false; + params.m_drawTexts = false;*/ + + m_threadDrawer = make_shared_ptr(new DrawerYG(params)); + + yg::gl::Screen::Params auxParams; + auxParams.m_frameBuffer = make_shared_ptr(new yg::gl::FrameBuffer()); + auxParams.m_resourceManager = m_resourceManager; + + m_auxScreen = make_shared_ptr(new yg::gl::Screen(auxParams)); + + bool isPanning = false; + bool doRedrawAll = false; + bool fullRectRepaint = false; + /// update areas in pixel coordinates. + vector areas; + + m2::RectI surfaceRect; + m2::RectI textureRect; + + shared_ptr infoLayer(new yg::InfoLayer()); + m_threadDrawer->screen()->setInfoLayer(infoLayer); + + while (!IsCancelled()) + { + { + threads::ConditionGuard guard(m_hasRenderCommands); + + waitForRenderCommand(m_renderCommands, guard); + + if (IsCancelled()) + break; + + m_currentRenderCommand = m_renderCommands.front(); + m_renderCommands.erase(m_renderCommands.begin()); + + m_currentRenderCommand->m_paintEvent = make_shared_ptr(new PaintEvent(m_threadDrawer.get())); + + /// this prevents the framework from flooding us with a bunch of RenderCommands with the same screen. + { + threads::MutexGuard guard(*m_renderState->m_mutex.get()); + + m_renderState->m_currentScreen = m_currentRenderCommand->m_frameScreen; + + m2::RectI prevRect(0, 0, 0, 0); + ScreenBase prevScreen = m_renderState->m_actualScreen; + + if (m_renderState->m_actualTarget != 0) + prevRect = m2::RectI(0, 0, + m_renderState->m_actualTarget->width(), + m_renderState->m_actualTarget->height()); + + processResize(m_currentRenderCommand->m_frameScreen); + + /// saving parameters, which might be changed from the GUI thread for later use. + surfaceRect = m2::RectI(0, 0, m_renderState->m_surfaceWidth, m_renderState->m_surfaceHeight); + textureRect = m2::RectI(0, 0, m_renderState->m_textureWidth, m_renderState->m_textureHeight); + + m2::RectI curRect = textureRect; + + doRedrawAll = m_renderState->m_doRepaintAll; + + fullRectRepaint = false; + + if (m_renderState->m_doRepaintAll) + { + areas.clear(); + areas.push_back(curRect); + fullRectRepaint = true; + m_threadDrawer->screen()->infoLayer()->clear(); + m_renderState->m_doRepaintAll = false; + } + else + { + getUpdateAreas(prevScreen, + prevRect, + m_currentRenderCommand->m_frameScreen, + curRect, + areas); + if ((areas.size() == 1) && (areas[0] == curRect)) + fullRectRepaint = true; + } + + isPanning = IsPanning(prevScreen, m_renderState->m_currentScreen); + + if (isPanning) + { + m2::RectD oldRect = m2::RectD(m_renderState->m_currentScreen.GtoP(prevScreen.PtoG(m2::PointD(prevRect.minX(), prevRect.minY()))), + m_renderState->m_currentScreen.GtoP(prevScreen.PtoG(m2::PointD(prevRect.maxX(), prevRect.maxY())))); + m2::RectD redrawTextRect(curRect); + + if (!redrawTextRect.Intersect(oldRect)) + redrawTextRect = m2::RectD(0, 0, 0, 0); + + shared_ptr infoLayer(new yg::InfoLayer()); + infoLayer->merge(*m_threadDrawer->screen()->infoLayer().get(), + prevScreen.PtoGMatrix() * m_renderState->m_currentScreen.GtoPMatrix()); + + m_threadDrawer->screen()->setInfoLayer(infoLayer); + } + else + m_threadDrawer->screen()->infoLayer()->clear(); + } + } + + my::Timer timer; + + /// At this point renderQueue->mutex is released to allow + /// main thread to add new rendering tasks and blit already + /// rendered model while the current command is actually rendering. + + if (m_currentRenderCommand != 0) + { + /// this fixes some strange issue with multisampled framebuffer. + /// setRenderTarget should be made here. + m_threadDrawer->screen()->setRenderTarget(m_renderState->m_backBufferLayers.front()); + + m_threadDrawer->beginFrame(); + + m_threadDrawer->screen()->enableClipRect(true); + m_threadDrawer->screen()->setClipRect(textureRect); + m_threadDrawer->clear(m_bgColor); + + if ((isPanning) && (!doRedrawAll)) + { + m_threadDrawer->screen()->blit( + m_renderState->m_actualTarget, + m_renderState->m_actualScreen, + m_renderState->m_currentScreen); + } + + //m_threadDrawer->screen()->setNeedTextRedraw(isPanning); + + ScreenBase const & frameScreen = m_currentRenderCommand->m_frameScreen; + m2::RectD glbRect; + frameScreen.PtoG(m2::RectD(textureRect.Center() - m2::PointD(m_scaleEtalonSize / 2, m_scaleEtalonSize / 2), + textureRect.Center() + m2::PointD(m_scaleEtalonSize / 2, m_scaleEtalonSize / 2)), + glbRect); +// frameScreen.PtoG(m2::RectD(surfaceRect), glbRect); + int scaleLevel = scales::GetScaleLevel(glbRect); + + for (size_t i = 0; i < areas.size(); ++i) + { + if ((areas[i].SizeX() != 0) && (areas[i].SizeY() != 0)) + { + frameScreen.PtoG(m2::Inflate(m2::RectD(areas[i]), 30 * m_visualScale, 30 * m_visualScale), glbRect); + if ((glbRect.SizeX() == 0) || (glbRect.SizeY() == 0)) + continue; + + m_threadDrawer->screen()->setClipRect(areas[i]); + + m_currentRenderCommand->m_renderFn( + m_currentRenderCommand->m_paintEvent, + m_currentRenderCommand->m_frameScreen, + glbRect, + glbRect, + scaleLevel); + } + } + + /// if something were actually drawn, or (exclusive or) we are repainting the whole rect + if ((!m_renderState->m_isEmptyModelCurrent) || (fullRectRepaint)) + m_renderState->m_isEmptyModelActual = m_renderState->m_isEmptyModelCurrent; + + /// setting the "whole texture" clip rect to render texts opened by panning. + m_threadDrawer->screen()->setClipRect(textureRect); + + m_threadDrawer->screen()->infoLayer()->draw(m_threadDrawer->screen().get(), math::Identity()); + + m_threadDrawer->endFrame(); + } + + double duration = timer.ElapsedSeconds(); + + if (!IsCancelled()) + { + /// We shouldn't update the actual target as it's already happened (through callback function) + /// in the endFrame function + /// updateActualTarget(); + + m_currentRenderCommand.reset(); + + { + threads::MutexGuard guard(*m_renderState->m_mutex.get()); + m_renderState->m_duration = duration; + } + + invalidate(); + } + + } + + // By VNG: We can't destroy render context in drawing thread. + // Notify render context instead. + m_renderContext->endThreadDrawing(); +} + +void RenderQueueRoutine::addWindowHandle(shared_ptr window) +{ + m_windowHandles.push_back(window); +} + +void RenderQueueRoutine::invalidate() +{ + for_each(m_windowHandles.begin(), + m_windowHandles.end(), + bind(&WindowHandle::invalidate, _1)); +} + +void RenderQueueRoutine::addCommand(render_fn_t const & fn, ScreenBase const & frameScreen) +{ + /// Command queue modification is syncronized by mutex + threads::ConditionGuard guard(m_hasRenderCommands); + + bool needToSignal = m_renderCommands.empty(); + + /// Clearing a list of commands. + m_renderCommands.clear(); + + /// pushing back new RenderCommand. + m_renderCommands.push_back(make_shared_ptr(new RenderModelCommand(frameScreen, fn))); + + /// if we are in benchmarking mode, we shouldn't cancel any render command + /// else, if we are not panning, we should cancel the render command in progress to start a new one + if ((m_currentRenderCommand != 0) + && (!IsPanning(m_currentRenderCommand->m_frameScreen, frameScreen))) + m_currentRenderCommand->m_paintEvent->Cancel(); + + if (needToSignal) + guard.Signal(); +} + +void RenderQueueRoutine::addBenchmarkCommand(render_fn_t const & fn, ScreenBase const & frameScreen) +{ + /// Command queue modification is syncronized by mutex + threads::ConditionGuard guard(m_hasRenderCommands); + + bool needToSignal = m_renderCommands.empty(); + + m_benchmarkRenderCommands.push_back(make_shared_ptr(new RenderModelCommand(frameScreen, fn))); + + if (needToSignal) + guard.Signal(); +} + +void RenderQueueRoutine::initializeGL(shared_ptr const & renderContext, + shared_ptr const & resourceManager) +{ + m_renderContext = renderContext; + m_resourceManager = resourceManager; +} + +void RenderQueueRoutine::memoryWarning() +{ + m_threadDrawer->screen()->memoryWarning(); +} + +void RenderQueueRoutine::enterBackground() +{ + m_threadDrawer->screen()->enterBackground(); +} + +void RenderQueueRoutine::enterForeground() +{ + m_threadDrawer->screen()->enterForeground(); +} + diff --git a/map/render_queue_routine.hpp b/map/render_queue_routine.hpp new file mode 100644 index 0000000000..39b1c8c246 --- /dev/null +++ b/map/render_queue_routine.hpp @@ -0,0 +1,124 @@ +#pragma once + +#include "../base/thread.hpp" +#include "../base/condition.hpp" +#include "../base/commands_queue.hpp" +#include "../geometry/rect2d.hpp" +#include "../geometry/screenbase.hpp" +#include "../std/list.hpp" +#include "../std/function.hpp" +#include "../yg/color.hpp" + +class DrawerYG; + +namespace threads +{ + class Condition; +} + +class PaintEvent; +class WindowHandle; + +namespace yg +{ + class ResourceManager; + + namespace gl + { + class RenderContext; + class FrameBuffer; + class RenderBuffer; + class BaseTexture; + class RenderState; + class RenderState; + class Screen; + } +} + +class RenderQueueRoutine : public threads::IRoutine +{ +public: + + typedef function, ScreenBase const &, m2::RectD const &, m2::RectD const &, int)> render_fn_t; + +private: + + struct RenderModelCommand + { + ScreenBase m_frameScreen; + shared_ptr m_paintEvent; + render_fn_t m_renderFn; + RenderModelCommand(ScreenBase const & frameScreen, + render_fn_t renderFn); + }; + + shared_ptr m_renderContext; + shared_ptr m_frameBuffer; + shared_ptr m_threadDrawer; + shared_ptr m_auxScreen; + + threads::Condition m_hasRenderCommands; + shared_ptr m_currentRenderCommand; + list > m_renderCommands; + list > m_benchmarkRenderCommands; + + shared_ptr m_renderState; + + shared_ptr m_resourceManager; + + /// A list of window handles to notify about ending rendering operations. + list > m_windowHandles; + + bool m_isMultiSampled; + bool m_doPeriodicalUpdate; + double m_updateInterval; + double m_visualScale; + string m_skinName; + bool m_isBenchmarking; + unsigned m_scaleEtalonSize; + yg::Color m_bgColor; + + void waitForRenderCommand(list > & cmdList, + threads::ConditionGuard & guard); + +public: + RenderQueueRoutine(shared_ptr const & renderState, + string const & skinName, + bool isMultiSampled, + bool doPeriodicalUpdate, + double updateInterval, + bool isBenchmarking, + unsigned scaleEtalonSize, + double visualScale, + yg::Color const & bgColor); + /// initialize GL rendering + /// this function is called just before the thread starts. + void initializeGL(shared_ptr const & renderContext, + shared_ptr const & resourceManager); + /// This function should always be called from the main thread. + void Cancel(); + /// Check, whether the resize command is queued, and resize accordingly. + void processResize(ScreenBase const & frameScreen); + /// Get update areas for the current render state + void getUpdateAreas(ScreenBase const & oldScreen, m2::RectI const & oldRect, + ScreenBase const & newScreen, m2::RectI const & newRect, + vector & areas); + /// Thread procedure + void Do(); + /// invalidate all connected window handles + void invalidate(); + /// add monitoring window + void addWindowHandle(shared_ptr window); + /// add model rendering command to rendering queue + void addCommand(render_fn_t const & fn, ScreenBase const & frameScreen); + /// add benchmark rendering command + void addBenchmarkCommand(render_fn_t const & fn, ScreenBase const & frameScreen); + /// set the resolution scale factor to the main thread drawer; + void setVisualScale(double visualScale); + /// free all available memory + void memoryWarning(); + /// free all easily recreatable opengl resources and make sure that no opengl call will be made. + void enterBackground(); + /// recreate all necessary opengl resources and prepare to run in foreground. + void enterForeground(); +}; diff --git a/map/screen_coverage.cpp b/map/screen_coverage.cpp index 38de2dba1e..31f0a93094 100644 --- a/map/screen_coverage.cpp +++ b/map/screen_coverage.cpp @@ -92,7 +92,7 @@ void ScreenCoverage::Merge(Tiler::RectInfo const & ri) } -void ScreenCoverage::Remove(Tile const * tile) +void ScreenCoverage::Remove(Tile const *) { } diff --git a/map/tiling_render_policy_mt.cpp b/map/tiling_render_policy_mt.cpp index a14124d4c3..76e208c355 100644 --- a/map/tiling_render_policy_mt.cpp +++ b/map/tiling_render_policy_mt.cpp @@ -19,7 +19,7 @@ TilingRenderPolicyMT::TilingRenderPolicyMT(shared_ptr const & wind m_tileRenderer(GetPlatform().SkinName(), GetPlatform().ScaleEtalonSize(), GetPlatform().MaxTilesCount(), - GetPlatform().CpuCores(), + 1, //GetPlatform().CpuCores(), bgColor(), renderFn), m_coverageGenerator(GetPlatform().TileSize(), @@ -37,10 +37,6 @@ void TilingRenderPolicyMT::Initialize(shared_ptr const & m_coverageGenerator.Initialize(); } -void TilingRenderPolicyMT::OnSize(int /*w*/, int /*h*/) -{ -} - void TilingRenderPolicyMT::DrawFrame(shared_ptr const & e, ScreenBase const & currentScreen) { DrawerYG * pDrawer = e->drawer(); diff --git a/map/tiling_render_policy_mt.hpp b/map/tiling_render_policy_mt.hpp index edef1bf89e..d6a84908d0 100644 --- a/map/tiling_render_policy_mt.hpp +++ b/map/tiling_render_policy_mt.hpp @@ -43,7 +43,5 @@ public: void Initialize(shared_ptr const & renderContext, shared_ptr const & resourceManager); - void OnSize(int w, int h); - void DrawFrame(shared_ptr const & ev, ScreenBase const & currentScreen); }; diff --git a/map/tiling_render_policy_st.cpp b/map/tiling_render_policy_st.cpp index 510b6643ab..369189ec60 100644 --- a/map/tiling_render_policy_st.cpp +++ b/map/tiling_render_policy_st.cpp @@ -52,9 +52,6 @@ void TilingRenderPolicyST::Initialize(shared_ptr const & m_tileScreen.OnSize(renderRect); } -void TilingRenderPolicyST::OnSize(int /*w*/, int /*h*/) -{} - void TilingRenderPolicyST::DrawFrame(shared_ptr const & e, ScreenBase const & currentScreen) { DrawerYG * pDrawer = e->drawer(); diff --git a/map/tiling_render_policy_st.hpp b/map/tiling_render_policy_st.hpp index d313b8dbc7..211158aea4 100644 --- a/map/tiling_render_policy_st.hpp +++ b/map/tiling_render_policy_st.hpp @@ -34,6 +34,4 @@ public: shared_ptr const & resourceManager); void DrawFrame(shared_ptr const & paintEvent, ScreenBase const & screenBase); - - void OnSize(int w, int h); }; diff --git a/yg/blitter.cpp b/yg/blitter.cpp index 7ebca5b31e..a29d35507c 100644 --- a/yg/blitter.cpp +++ b/yg/blitter.cpp @@ -45,7 +45,34 @@ namespace yg m2::RectI const & srcRect, m2::RectU const & texRect) { - m2::PointF pt = to.GtoP(from.PtoG(m2::PointF(srcRect.minX(), srcRect.minY()))); + blit(srcSurface, + from.PtoGMatrix() * to.GtoPMatrix(), + isSubPixel, + color, + srcRect, + texRect); + } + + void Blitter::blit(shared_ptr const & srcSurface, + math::Matrix const & m, + bool isSubPixel) + { + blit(srcSurface, + m, + isSubPixel, + yg::Color(), + m2::RectI(0, 0, srcSurface->width(), srcSurface->height()), + m2::RectU(0, 0, srcSurface->width(), srcSurface->height())); + } + + void Blitter::blit(shared_ptr const & srcSurface, + math::Matrix const & m, + bool isSubPixel, + yg::Color const & color, + m2::RectI const & srcRect, + m2::RectU const & texRect) + { + m2::PointF pt = m2::PointF(m2::PointD(srcRect.minX(), srcRect.minY()) * m); if (!isSubPixel) { @@ -57,10 +84,10 @@ namespace yg m2::PointF pts[4] = { - to.GtoP(from.PtoG(m2::PointF(srcRect.minX(), srcRect.minY()))) + pt, - to.GtoP(from.PtoG(m2::PointF(srcRect.maxX(), srcRect.minY()))) + pt, - to.GtoP(from.PtoG(m2::PointF(srcRect.maxX(), srcRect.maxY()))) + pt, - to.GtoP(from.PtoG(m2::PointF(srcRect.minX(), srcRect.maxY()))) + pt + m2::PointF(m2::PointD(srcRect.minX(), srcRect.minY()) * m) + pt, + m2::PointF(m2::PointD(srcRect.maxX(), srcRect.minY()) * m) + pt, + m2::PointF(m2::PointD(srcRect.maxX(), srcRect.maxY()) * m) + pt, + m2::PointF(m2::PointD(srcRect.minX(), srcRect.maxY()) * m) + pt }; m2::PointF texPts[4] = diff --git a/yg/blitter.hpp b/yg/blitter.hpp index 06f39aba7f..f10f40039b 100644 --- a/yg/blitter.hpp +++ b/yg/blitter.hpp @@ -55,6 +55,17 @@ namespace yg ScreenBase const & to, bool isSubPixel = false); + void blit(shared_ptr const & srcSurface, + math::Matrix const & m, + bool isSubPixel = false); + + void blit(shared_ptr const & srcSurface, + math::Matrix const & m, + bool isSubPixel, + yg::Color const & color, + m2::RectI const & srcRect, + m2::RectU const & texRect); + void immDrawSolidRect(m2::RectF const & rect, yg::Color const & color); diff --git a/yg/geometry_batcher.hpp b/yg/geometry_batcher.hpp index e1535f516b..6738013a22 100644 --- a/yg/geometry_batcher.hpp +++ b/yg/geometry_batcher.hpp @@ -5,7 +5,7 @@ #include "indexbuffer.hpp" #include "renderbuffer.hpp" #include "framebuffer.hpp" -#include "geometry_renderer.hpp" +#include "render_state_updater.hpp" #include "storage.hpp" #include "skin_page.hpp" @@ -30,7 +30,7 @@ namespace yg namespace gl { - class GeometryBatcher : public GeometryRenderer + class GeometryBatcher : public RenderStateUpdater { public: @@ -38,7 +38,7 @@ namespace yg private: - typedef GeometryRenderer base_t; + typedef RenderStateUpdater base_t; shared_ptr m_skin; diff --git a/yg/glyph_cache.cpp b/yg/glyph_cache.cpp index d6a35915ab..9044e29c5a 100644 --- a/yg/glyph_cache.cpp +++ b/yg/glyph_cache.cpp @@ -300,12 +300,12 @@ namespace yg strings::UniString GlyphCache::log2vis(strings::UniString const & str) { // FriBidiEnv e; -/* size_t const count = str.size(); + size_t const count = str.size(); strings::UniString res(count); FriBidiParType dir = FRIBIDI_PAR_LTR; // requested base direction fribidi_log2vis(&str[0], count, &dir, &res[0], 0, 0, 0); - return res;*/ - return str; + return res; +// return str; } } diff --git a/yg/render_state_updater.cpp b/yg/render_state_updater.cpp new file mode 100644 index 0000000000..2e69445acd --- /dev/null +++ b/yg/render_state_updater.cpp @@ -0,0 +1,119 @@ +#include "../base/SRC_FIRST.hpp" + +#include "render_state_updater.hpp" +#include "render_state.hpp" +#include "framebuffer.hpp" +#include "base_texture.hpp" + +#include "internal/opengl.hpp" + +#include "../base/logging.hpp" + +namespace yg +{ + namespace gl + { + RenderStateUpdater::Params::Params() + : m_doPeriodicalUpdate(false), m_updateInterval(0.0) + {} + + RenderStateUpdater::RenderStateUpdater(Params const & params) + : base_t(params), + m_renderState(params.m_renderState), + m_doPeriodicalUpdate(params.m_doPeriodicalUpdate), + m_updateInterval(params.m_updateInterval) + { + } + + shared_ptr const & RenderStateUpdater::renderState() const + { + return m_renderState; + } + + void RenderStateUpdater::drawGeometry(shared_ptr const & texture, + shared_ptr const & vertices, + shared_ptr const & indices, + size_t indicesCount) + { + base_t::drawGeometry(texture, vertices, indices, indicesCount); + m_indicesCount += indicesCount; + if (m_doPeriodicalUpdate + && m_renderState + && (m_indicesCount > 20000) + && (m_updateTimer.ElapsedSeconds() > m_updateInterval)) + { + updateActualTarget(); + m_indicesCount %= 20000; + m_updateTimer.Reset(); + } + } + + void RenderStateUpdater::updateActualTarget() + { + /// Carefully synchronizing the access to the m_renderState to minimize wait time. + OGLCHECK(glFinish()); + + { + threads::MutexGuard guard(*m_renderState->m_mutex.get()); + swap(m_renderState->m_actualTarget, m_renderState->m_backBufferLayers.front()); + m_renderState->m_actualScreen = m_renderState->m_currentScreen; + } + + /// blitting will be performed through + /// non-multisampled framebuffer for the sake of speed + + frameBuffer()->setRenderTarget(m_renderState->m_backBufferLayers.front()); + frameBuffer()->makeCurrent(); + + OGLCHECK(glFinish()); + + OGLCHECK(glDisable(GL_SCISSOR_TEST)); + + OGLCHECK(glClearColor(192 / 255.0, 192 / 255.0, 192 / 255.0, 1.0)); + OGLCHECK(glClear(GL_COLOR_BUFFER_BIT)); + + shared_ptr actualTarget = m_renderState->m_actualTarget; + + immDrawTexturedRect( + m2::RectF(0, 0, actualTarget->width(), actualTarget->height()), + m2::RectF(0, 0, 1, 1), + actualTarget + ); + + if (clipRectEnabled()) + OGLCHECK(glEnable(GL_SCISSOR_TEST)); + + OGLCHECK(glFinish()); + + m_renderState->invalidate(); + } + + void RenderStateUpdater::beginFrame() + { + base_t::beginFrame(); + m_indicesCount = 0; + m_updateTimer.Reset(); + } + + void RenderStateUpdater::setClipRect(m2::RectI const & rect) + { + if ((m_renderState) && (m_indicesCount)) + { + updateActualTarget(); + m_indicesCount = 0; + m_updateTimer.Reset(); + } + + base_t::setClipRect(rect); + } + + void RenderStateUpdater::endFrame() + { + if (m_renderState) + updateActualTarget(); + m_indicesCount = 0; + m_updateTimer.Reset(); + base_t::endFrame(); + } + } +} diff --git a/yg/render_state_updater.hpp b/yg/render_state_updater.hpp new file mode 100644 index 0000000000..b261c50140 --- /dev/null +++ b/yg/render_state_updater.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "../std/shared_ptr.hpp" +#include "../geometry/screenbase.hpp" +#include "../base/timer.hpp" + +#include "geometry_renderer.hpp" + +namespace yg +{ + namespace gl + { + class RenderState; + + class RenderStateUpdater : public GeometryRenderer + { + private: + + typedef GeometryRenderer base_t; + + shared_ptr m_renderState; + + int m_indicesCount; + bool m_doPeriodicalUpdate; + double m_updateInterval; + my::Timer m_updateTimer; + + public: + + struct Params : base_t::Params + { + bool m_doPeriodicalUpdate; + double m_updateInterval; + shared_ptr m_renderState; + Params(); + }; + + RenderStateUpdater(Params const & params); + + shared_ptr const & renderState() const; + + void drawGeometry(shared_ptr const & texture, + shared_ptr const & vertices, + shared_ptr const & indices, + size_t indicesCount); + + void beginFrame(); + void endFrame(); + void setClipRect(m2::RectI const & rect); + virtual void updateActualTarget(); + }; + } +} diff --git a/yg/yg.pro b/yg/yg.pro index 7b09f02a6f..0501e8a932 100644 --- a/yg/yg.pro +++ b/yg/yg.pro @@ -55,7 +55,8 @@ SOURCES += \ info_layer.cpp \ overlay_element.cpp \ symbol_element.cpp \ - overlay_renderer.cpp + overlay_renderer.cpp \ + render_state_updater.cpp HEADERS += \ internal/opengl.hpp \ @@ -103,7 +104,8 @@ HEADERS += \ info_layer.hpp \ overlay_element.hpp \ symbol_element.hpp \ - overlay_renderer.hpp + overlay_renderer.hpp \ + render_state_updater.hpp win32 { HEADERS += internal/opengl_win32.hpp