diff --git a/data/benchmark.txt b/data/benchmark.txt new file mode 100644 index 0000000000..9b656114da --- /dev/null +++ b/data/benchmark.txt @@ -0,0 +1 @@ +france_iphone -1.65763 48.7958 4.41623 57.5269 diff --git a/iphone/Maps/Platform/IPhonePlatform.hpp b/iphone/Maps/Platform/IPhonePlatform.hpp index e82ad4b4fd..bdb486e5af 100644 --- a/iphone/Maps/Platform/IPhonePlatform.hpp +++ b/iphone/Maps/Platform/IPhonePlatform.hpp @@ -21,6 +21,7 @@ public: virtual bool DoPeriodicalUpdate() const; virtual double PeriodicalUpdateInterval() const; virtual vector GetFontNames() const; + virtual bool IsBenchmarking() const; private: string m_skinName; diff --git a/iphone/Maps/Platform/IPhonePlatform.mm b/iphone/Maps/Platform/IPhonePlatform.mm index 5b0b8c2c5a..94d513dcd9 100644 --- a/iphone/Maps/Platform/IPhonePlatform.mm +++ b/iphone/Maps/Platform/IPhonePlatform.mm @@ -189,6 +189,11 @@ vector IPhonePlatform::GetFontNames() const return res; } +bool IPhonePlatform::IsBenchmarking() const +{ + return false; +} + Platform & GetPlatform() { static IPhonePlatform platform; diff --git a/map/framework.hpp b/map/framework.hpp index 6034591ef3..af64047ab4 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -34,6 +34,7 @@ #include "../std/vector.hpp" #include "../std/shared_ptr.hpp" #include "../std/target_os.hpp" +#include "../std/fstream.hpp" #include "../base/start_mem_debug.hpp" @@ -96,6 +97,12 @@ class FrameWork model_t m_model; navigator_t m_navigator; shared_ptr m_windowHandle; + + bool m_isBenchmarking; + bool m_isBenchmarkInitialized; + vector > m_benchmarks; + unsigned m_currentBenchmark; + RenderQueue m_renderQueue; InformationDisplay m_informationDisplay; @@ -127,12 +134,7 @@ class FrameWork void SetMaxWorldRect() { -#ifdef PROFILER_DRAWING - // London - m_navigator.SetFromRect(m2::RectD(-0.423781, 60.0613, 0.210893, 60.5272)); -#else m_navigator.SetFromRect(m_model.GetWorldRect()); -#endif } threads::Mutex m_modelSyn; @@ -163,25 +165,51 @@ class FrameWork public: FrameWork(shared_ptr windowHandle, size_t bottomShift) : m_windowHandle(windowHandle), + m_isBenchmarking(GetPlatform().IsBenchmarking()), + m_isBenchmarkInitialized(false), + m_currentBenchmark(0), m_renderQueue(GetPlatform().SkinName(), GetPlatform().IsMultiSampled(), GetPlatform().DoPeriodicalUpdate(), - GetPlatform().PeriodicalUpdateInterval()), + GetPlatform().PeriodicalUpdateInterval(), + GetPlatform().IsBenchmarking()), m_isRedrawEnabled(true) { m_informationDisplay.setBottomShift(bottomShift); #ifdef DRAW_TOUCH_POINTS m_informationDisplay.enableDebugPoints(true); #endif - m_informationDisplay.enableCenter(true); + m_informationDisplay.enableCenter(false); + m_informationDisplay.enableGlobalRect(!m_isBenchmarking); m_informationDisplay.enableRuler(true); + #ifdef DEBUG m_informationDisplay.enableDebugInfo(true); #endif + + m_informationDisplay.enableBenchmarkInfo(m_isBenchmarking); + m_informationDisplay.setVisualScale(GetPlatform().VisualScale()); m_renderQueue.AddWindowHandle(m_windowHandle); } + void InitBenchmark() + { + ifstream fin(GetPlatform().WritablePathForFile("benchmark.txt").c_str()); + while (true) + { + string name; + double x0, y0, x1, y1; + fin >> name >> x0 >> y0 >> x1 >> y1; + if (!fin) + break; + m_navigator.SetFromRect(m2::RectD(x0, y0, x1, y1)); + m_renderQueue.AddBenchmarkCommand(boost::bind(&this_type::PaintImpl, this, _1, _2, _3, _4), m_navigator.Screen()); + m_benchmarks.push_back(make_pair(name, m2::RectD(x0, y0, x1, y1))); + } + Invalidate(); + } + void initializeGL(shared_ptr const & primaryContext, shared_ptr const & resourceManager) { @@ -244,6 +272,12 @@ public: m_navigator.OnSize(ptShift.x, ptShift.y, w, h); + if ((m_isBenchmarking) && (!m_isBenchmarkInitialized)) + { + m_isBenchmarkInitialized = true; + InitBenchmark(); + } + UpdateNow(); } @@ -321,18 +355,45 @@ public: DrawerYG * pDrawer = e->drawer().get(); m_informationDisplay.setScreen(m_navigator.Screen()); + m_informationDisplay.setDebugInfo(m_renderQueue.renderState().m_duration, GetCurrentScale()); m_informationDisplay.enableRuler(!IsEmptyModel()); m2::PointD const center = m_navigator.Screen().ClipRect().Center(); + + m_informationDisplay.setGlobalRect(m_navigator.Screen().GlobalRect()); m_informationDisplay.setCenter(m2::PointD(MercatorBounds::YToLat(center.y), MercatorBounds::XToLon(center.x))); { threads::MutexGuard guard(*m_renderQueue.renderState().m_mutex.get()); + if (m_isBenchmarking) + { + m2::PointD const center = m_renderQueue.renderState().m_actualScreen.ClipRect().Center(); + m_informationDisplay.setScreen(m_renderQueue.renderState().m_actualScreen); + m_informationDisplay.setCenter(m2::PointD(MercatorBounds::YToLat(center.y), MercatorBounds::XToLon(center.x))); + + if (m_benchmarks.empty()) + { + e->drawer()->screen()->beginFrame(); + e->drawer()->screen()->clear(); + m_informationDisplay.setDisplayRect(m2::RectI(0, 0, 100, 100)); + m_informationDisplay.enableRuler(false); + m_informationDisplay.doDraw(e->drawer().get()); + e->drawer()->screen()->endFrame(); + } + } + if (m_renderQueue.renderState().m_actualTarget.get() != 0) { + if (m_isBenchmarking + && !m_benchmarks.empty() + && m_informationDisplay.addBenchmarkInfo(m_benchmarks[m_currentBenchmark].first, + m_benchmarks[m_currentBenchmark].second, + m_renderQueue.renderState().m_duration)) + m_currentBenchmark++; + e->drawer()->screen()->beginFrame(); e->drawer()->screen()->clear(/*yg::Color(255, 0, 0, 255)*/); @@ -342,9 +403,13 @@ public: OGLCHECK(glPushMatrix()); OGLCHECK(glTranslatef(-ptShift.x, -ptShift.y, 0)); + ScreenBase currentScreen = m_navigator.Screen(); + if (m_isBenchmarking) + currentScreen = m_renderQueue.renderState().m_actualScreen; + pDrawer->screen()->blit(m_renderQueue.renderState().m_actualTarget, m_renderQueue.renderState().m_actualScreen, - m_navigator.Screen(), + currentScreen, yg::Color(0, 255, 0, 255), m2::RectI(0, 0, m_renderQueue.renderState().m_actualTarget->width(), diff --git a/map/information_display.cpp b/map/information_display.cpp index 6e65abe110..c105a77fb3 100644 --- a/map/information_display.cpp +++ b/map/information_display.cpp @@ -20,6 +20,8 @@ InformationDisplay::InformationDisplay() enableCenter(false); enableDebugInfo(false); enableMemoryWarning(false); + enableBenchmarkInfo(false); + enableGlobalRect(false); for (int i = 0; i < sizeof(m_DebugPts) / sizeof(m2::PointD); ++i) m_DebugPts[i] = m2::PointD(0, 0); @@ -287,10 +289,38 @@ void InformationDisplay::setCenter(m2::PointD const & pt) void InformationDisplay::drawCenter(DrawerYG * drawer) { + m_yOffset += 20; ostringstream out; out << "(" << m_centerPt.x << ", " << m_centerPt.y << ") Scale : " << m_currentScale; drawer->screen()->drawText( - m2::PointD(m_displayRect.minX(), m_displayRect.minY()) + m2::PointD(10, m_isDebugInfoEnabled ? 40 : 20), + m2::PointD(m_displayRect.minX() + 10, m_displayRect.minY() + m_yOffset), + 0, 10, + yg::Color(0, 0, 0, 0), + out.str().c_str(), + true, + yg::Color(255, 255, 255, 255), + yg::maxDepth, + true, + false); +} + +void InformationDisplay::enableGlobalRect(bool doEnable) +{ + m_isGlobalRectEnabled = doEnable; +} + +void InformationDisplay::setGlobalRect(m2::RectD const & r) +{ + m_globalRect = r; +} + +void InformationDisplay::drawGlobalRect(DrawerYG *pDrawer) +{ + m_yOffset += 20; + ostringstream out; + out << "(" << m_globalRect.minX() << ", " << m_globalRect.minY() << ", " << m_globalRect.maxX() << ", " << m_globalRect.maxY() << ") Scale : " << m_currentScale; + pDrawer->screen()->drawText( + m2::PointD(m_displayRect.minX() + 10, m_displayRect.minY() + m_yOffset), 0, 10, yg::Color(0, 0, 0, 0), out.str().c_str(), @@ -321,7 +351,11 @@ void InformationDisplay::drawDebugInfo(DrawerYG * drawer) else out << " FPS: " << 1.0 / m_frameDuration; - drawer->screen()->drawText(m2::PointD(m_displayRect.minX(), m_displayRect.minY()) + m2::PointD(10, 20), + m_yOffset += 20; + + m2::PointD pos = m2::PointD(m_displayRect.minX() + 10, m_displayRect.minY() + m_yOffset); + + drawer->screen()->drawText(pos, 0, 10, yg::Color(0, 0, 0, 0), out.str().c_str(), @@ -345,11 +379,8 @@ void InformationDisplay::memoryWarning() void InformationDisplay::drawMemoryWarning(DrawerYG * drawer) { - m2::PointD pos(m_displayRect.minX() + 10, m_displayRect.minY() + 20); - if (m_isDebugInfoEnabled) - pos += m2::PointD(0, 30); - if (m_isCenterEnabled) - pos += m2::PointD(0, 30); + m_yOffset += 20; + m2::PointD pos(m_displayRect.minX() + 10, m_displayRect.minY() + m_yOffset); ostringstream out; out << "MemoryWarning : " << m_lastMemoryWarning.ElapsedSeconds() << " sec. ago."; @@ -368,8 +399,71 @@ void InformationDisplay::drawMemoryWarning(DrawerYG * drawer) enableMemoryWarning(false); } +void InformationDisplay::enableBenchmarkInfo(bool doEnable) +{ + m_isBenchmarkInfoEnabled = doEnable; +} + +bool InformationDisplay::addBenchmarkInfo(string const & name, m2::RectD const & globalRect, double frameDuration) +{ + if (frameDuration == 0) + return false; + if ((m_benchmarkInfo.empty()) + ||(m_benchmarkInfo.back().m_duration != frameDuration)) + { + BenchmarkInfo info; + info.m_name = name; + info.m_duration = frameDuration; + info.m_rect = globalRect; + m_benchmarkInfo.push_back(info); + return true; + } + return false; +} + +void InformationDisplay::drawBenchmarkInfo(DrawerYG * pDrawer) +{ + m_yOffset += 20; + m2::PointD pos(m_displayRect.minX() + 10, m_displayRect.minY() + m_yOffset); + pDrawer->screen()->drawText(pos, + 0, 10, + yg::Color(0, 0, 0, 0), + "benchmark info :", + true, + yg::Color(255, 255, 255, 255), + yg::maxDepth, + true, + false); + + for (unsigned i = 0; i < m_benchmarkInfo.size(); ++i) + { + ostringstream out; + m2::RectD const & r = m_benchmarkInfo[i].m_rect; + out << " " << m_benchmarkInfo[i].m_name + << ", " << "rect: (" << r.minX() + << ", " << r.minY() + << ", " << r.maxX() + << ", " << r.maxY() + << "), duration : " << m_benchmarkInfo[i].m_duration; + m_yOffset += 20; + pos.y += 20; + pDrawer->screen()->drawText(pos, + 0, 10, + yg::Color(0, 0, 0, 0), + out.str().c_str(), + true, + yg::Color(255, 255, 255, 255), + yg::maxDepth, + true, + false + ); + } + +} + void InformationDisplay::doDraw(DrawerYG *drawer) { + m_yOffset = 0; if (m_isHeadingEnabled) drawHeading(drawer); if (m_isPositionEnabled) @@ -380,8 +474,12 @@ void InformationDisplay::doDraw(DrawerYG *drawer) drawRuler(drawer); if (m_isCenterEnabled) drawCenter(drawer); + if (m_isGlobalRectEnabled) + drawGlobalRect(drawer); if (m_isDebugInfoEnabled) drawDebugInfo(drawer); if (m_isMemoryWarningEnabled) drawMemoryWarning(drawer); + if (m_isBenchmarkInfoEnabled) + drawBenchmarkInfo(drawer); } diff --git a/map/information_display.hpp b/map/information_display.hpp index 868853d229..9f4451038c 100644 --- a/map/information_display.hpp +++ b/map/information_display.hpp @@ -15,6 +15,7 @@ private: ScreenBase m_screen; m2::RectI m_displayRect; + int m_yOffset; double m_headingOrientation; @@ -39,8 +40,23 @@ private: m2::PointD m_centerPt; int m_currentScale; + bool m_isGlobalRectEnabled; + m2::RectD m_globalRect; + bool m_isDebugInfoEnabled; double m_frameDuration; + + bool m_isBenchmarkInfoEnabled; + + struct BenchmarkInfo + { + string m_name; + m2::RectD m_rect; + double m_duration; + }; + + vector m_benchmarkInfo; + double m_bottomShift; double m_visualScale; @@ -77,6 +93,10 @@ public: void setCenter(m2::PointD const & latLongPt); void drawCenter(DrawerYG * pDrawer); + void enableGlobalRect(bool doEnable); + void setGlobalRect(m2::RectD const & r); + void drawGlobalRect(DrawerYG * pDrawer); + void enableDebugInfo(bool doEnable); void setDebugInfo(double frameDuration, int currentScale); void drawDebugInfo(DrawerYG * pDrawer); @@ -85,5 +105,9 @@ public: void memoryWarning(); void drawMemoryWarning(DrawerYG * pDrawer); + void enableBenchmarkInfo(bool doEnable); + bool addBenchmarkInfo(string const & name, m2::RectD const & globalRect, double frameDuration); + void drawBenchmarkInfo(DrawerYG * pDrawer); + void doDraw(DrawerYG * drawer); }; diff --git a/map/render_queue.cpp b/map/render_queue.cpp index 7799e1b9e2..48ca6ded98 100644 --- a/map/render_queue.cpp +++ b/map/render_queue.cpp @@ -5,15 +5,27 @@ #include "../yg/render_state.hpp" #include "../yg/rendercontext.hpp" -RenderQueue::RenderQueue(string const & skinName, bool isMultiSampled, bool doPeriodicalUpdate, double updateInterval) +RenderQueue::RenderQueue( + string const & skinName, + bool isMultiSampled, + bool doPeriodicalUpdate, + double updateInterval, + bool isBenchmarking) : 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); + m_routine = new RenderQueueRoutine( + m_renderState, + skinName, + isMultiSampled, + doPeriodicalUpdate, + updateInterval, + isBenchmarking); } void RenderQueue::initializeGL(shared_ptr const & primaryContext, @@ -37,6 +49,11 @@ void RenderQueue::AddCommand(RenderQueueRoutine::render_fn_t const & fn, ScreenB 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; diff --git a/map/render_queue.hpp b/map/render_queue.hpp index 27148a817a..f409c4bbb1 100644 --- a/map/render_queue.hpp +++ b/map/render_queue.hpp @@ -31,7 +31,11 @@ private: public: /// constructor. - RenderQueue(string const & skinName, bool isMultiSampled, bool doPeriodicalUpdate, double updateInterval); + RenderQueue(string const & skinName, + bool isMultiSampled, + bool doPeriodicalUpdate, + double updateInterval, + bool isBenchmarking); /// destructor. ~RenderQueue(); /// set the primary context. it starts the rendering thread. @@ -40,6 +44,7 @@ public: double ppmScale); /// 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(); diff --git a/map/render_queue_routine.cpp b/map/render_queue_routine.cpp index f40e42b9b3..470fd42bed 100644 --- a/map/render_queue_routine.cpp +++ b/map/render_queue_routine.cpp @@ -32,7 +32,8 @@ RenderQueueRoutine::RenderQueueRoutine(shared_ptr const & r string const & skinName, bool isMultiSampled, bool doPeriodicalUpdate, - double updateInterval) + double updateInterval, + bool isBenchmarking) { m_skinName = skinName; m_visualScale = 0; @@ -41,6 +42,7 @@ RenderQueueRoutine::RenderQueueRoutine(shared_ptr const & r m_isMultiSampled = isMultiSampled; m_doPeriodicalUpdate = doPeriodicalUpdate; m_updateInterval = updateInterval; + m_isBenchmarking = isBenchmarking; } void RenderQueueRoutine::Cancel() @@ -209,6 +211,17 @@ 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(); @@ -244,24 +257,28 @@ void RenderQueueRoutine::Do() { threads::ConditionGuard guard(m_hasRenderCommands); - while (m_renderCommands.empty()) - { - guard.Wait(); - if (IsCancelled()) - break; - } + if (m_isBenchmarking) + waitForRenderCommand(m_benchmarkRenderCommands, guard); + else + waitForRenderCommand(m_renderCommands, guard); if (IsCancelled()) break; /// Preparing render command for execution. - m_currentRenderCommand = m_renderCommands.front(); - m_renderCommands.erase(m_renderCommands.begin()); + if (m_isBenchmarking) + { + m_currentRenderCommand = m_benchmarkRenderCommands.front(); + m_benchmarkRenderCommands.erase(m_benchmarkRenderCommands.begin()); + } + else + { + m_currentRenderCommand = m_renderCommands.front(); + m_renderCommands.erase(m_renderCommands.begin()); + } processResize(m_currentRenderCommand->m_frameScreen); -// m_threadDrawer->screen()->setRenderTarget(m_renderState->m_backBufferLayers.front()); - m_currentRenderCommand->m_paintEvent = make_shared_ptr(new PaintEvent(m_threadDrawer)); /// this prevents the framework from flooding us with a bunch of RenderCommands with the same screen. @@ -349,8 +366,6 @@ void RenderQueueRoutine::Do() double duration = timer.ElapsedSeconds(); -// LOG(LINFO, ("FrameDuration: ", duration)); - if (!IsCancelled()) { /// We shouldn't update the actual target as it's already happened (through callback function) @@ -399,14 +414,30 @@ void RenderQueueRoutine::addCommand(render_fn_t const & fn, ScreenBase const & f /// pushing back new RenderCommand. m_renderCommands.push_back(make_shared_ptr(new RenderModelCommand(frameScreen, fn))); - /// 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))) + /// 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_isBenchmarking) + && (m_currentRenderCommand != 0) + && (!IsPanning(m_currentRenderCommand->m_frameScreen, frameScreen))) m_currentRenderCommand->m_paintEvent->setIsCancelled(true); 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) { diff --git a/map/render_queue_routine.hpp b/map/render_queue_routine.hpp index 574378f625..f46445213f 100644 --- a/map/render_queue_routine.hpp +++ b/map/render_queue_routine.hpp @@ -63,6 +63,7 @@ private: threads::Condition m_hasRenderCommands; shared_ptr m_currentRenderCommand; list > m_renderCommands; + list > m_benchmarkRenderCommands; shared_ptr m_renderState; shared_ptr m_fakeTarget; @@ -77,13 +78,18 @@ private: double m_updateInterval; double m_visualScale; string m_skinName; + bool m_isBenchmarking; + + void waitForRenderCommand(list > & cmdList, + threads::ConditionGuard & guard); public: RenderQueueRoutine(shared_ptr const & renderState, string const & skinName, bool isMultiSampled, bool doPeriodicalUpdate, - double updateInterval); + double updateInterval, + bool isBenchmarking); /// initialize GL rendering /// this function is called just before the thread starts. void initializeGL(shared_ptr const & renderContext, @@ -102,6 +108,8 @@ public: 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); }; diff --git a/platform/platform.hpp b/platform/platform.hpp index b31eb1d442..485cabda7e 100644 --- a/platform/platform.hpp +++ b/platform/platform.hpp @@ -70,6 +70,8 @@ public: virtual double PeriodicalUpdateInterval() const = 0; virtual vector GetFontNames() const = 0; + + virtual bool IsBenchmarking() const = 0; }; extern "C" Platform & GetPlatform(); diff --git a/platform/qtplatform.cpp b/platform/qtplatform.cpp index 86ddb0b206..6b9e8010a0 100644 --- a/platform/qtplatform.cpp +++ b/platform/qtplatform.cpp @@ -379,6 +379,11 @@ public: return res; } + + bool IsBenchmarking() const + { + return false; + } }; extern "C" Platform & GetPlatform()