Initial implementation of tile rendering.

This commit is contained in:
rachytski 2011-07-03 14:22:20 +03:00 committed by Alex Zolotarev
parent 722d22ad3a
commit 202ff73253
35 changed files with 809 additions and 907 deletions

View file

@ -24,7 +24,8 @@ SOURCES += \
runner.cpp \
timer.cpp \
internal/message.cpp \
exception.cpp
exception.cpp \
threaded_container.cpp
HEADERS += \
SRC_FIRST.hpp \
@ -66,4 +67,6 @@ HEADERS += \
buffer_vector.hpp \
array_adapters.hpp \
runner.hpp \
object_pool.hpp
mru_cache.hpp \
threaded_container.hpp \
threaded_list.hpp

View file

@ -31,6 +31,7 @@ SOURCES += \
buffer_vector_test.cpp \
assert_test.cpp \
timer_test.cpp \
object_pool_test.cpp\
mru_cache_test.cpp \
threaded_list_test.cpp
HEADERS +=

View file

@ -0,0 +1,31 @@
#include "../../base/SRC_FIRST.hpp"
#include "../../testing/testing.hpp"
#include "../mru_cache.hpp"
UNIT_TEST(MRUCache_Test)
{
my::MRUCache<int, int> m(4);
CHECK(m.HasElem(1) == false, ());
m.Add(1, 2, 1);
CHECK(m.HasElem(1) == true, ());
CHECK(m.Find(1, false) == 2, ());
m.Add(2, 4, 2);
CHECK(m.HasElem(2) == true, ());
CHECK(m.Find(2, false) == 4, ());
m.Touch(1);
m.Add(3, 9, 2);
CHECK(m.HasElem(3) == true, ());
CHECK(m.Find(3, false) == 9, ());
CHECK(m.HasElem(2) == false, ());
CHECK(m.HasElem(1) == true, ());
}

View file

@ -1,7 +1,7 @@
#include "../../base/SRC_FIRST.hpp"
#include "../../testing/testing.hpp"
#include "../object_pool.hpp"
#include "../threaded_list.hpp"
#include "../thread.hpp"
#include "../../base/logging.hpp"
@ -9,19 +9,19 @@
struct ProcessorThread : public threads::IRoutine
{
ObjectPool<int> * m_p;
ThreadedList<int> * m_p;
int m_data;
list<int> * m_res;
int m_id;
ProcessorThread(ObjectPool<int> * p, list<int> * res, int id) : m_p(p), m_res(res), m_id(id)
ProcessorThread(ThreadedList<int> * p, list<int> * res, int id) : m_p(p), m_res(res), m_id(id)
{}
virtual void Do()
{
while (!m_p->IsCancelled())
{
int res = m_p->Reserve();
int res = m_p->Front(true);
m_res->push_back(res);
LOG(LINFO, (m_id, " thread got ", res));
threads::Sleep(10);
@ -30,13 +30,12 @@ struct ProcessorThread : public threads::IRoutine
}
};
UNIT_TEST(ObjectPool)
UNIT_TEST(ThreadedList)
{
list<int> l;
list<int> res;
ObjectPool<int> p;
p.Add(l);
ThreadedList<int> p;
threads::Thread t0;
t0.Create(new ProcessorThread(&p, &res, 0));
@ -47,14 +46,14 @@ UNIT_TEST(ObjectPool)
threads::Thread t2;
t2.Create(new ProcessorThread(&p, &res, 2));
p.Free(0);
threads::Sleep(200);
p.PushBack(0);
my::sleep(200);
p.Free(1);
threads::Sleep(200);
p.PushBack(1);
my::sleep(200);
p.Free(2);
threads::Sleep(200);
p.PushBack(2);
my::sleep(200);
TEST_EQUAL(res.front(), 0, ());
res.pop_front();

124
base/mru_cache.hpp Normal file
View file

@ -0,0 +1,124 @@
#pragma once
#include "../std/unordered_map.hpp"
#include "assert.hpp"
namespace my
{
template <typename TValue>
struct MRUCacheValueTraits
{
static void Evict(TValue & val){}
};
template <typename KeyT, typename ValueT, typename ValueTraitsT = MRUCacheValueTraits<ValueT> >
class MRUCache
{
public:
typedef MRUCache<KeyT, ValueT> this_type;
private:
MRUCache(this_type const & c);
this_type & operator= (this_type const &);
typedef list<KeyT> list_t;
struct MapEntry
{
ValueT m_value;
size_t m_weight;
typename list_t::iterator m_it;
};
typedef unordered_map<KeyT, MapEntry> map_t;
map_t m_map;
list_t m_list;
int m_curWeight;
int m_maxWeight;
public:
explicit MRUCache(size_t maxWeight)
: m_curWeight(0), m_maxWeight(maxWeight)
{}
bool HasElem(KeyT const & key)
{
return m_map.find(key) != m_map.end();
}
ValueT const & Find(KeyT const & key, bool DoTouch = true)
{
typename map_t::iterator it = m_map.find(key);
CHECK(it != m_map.end(), ());
if (DoTouch)
{
typename list_t::iterator listIt = it->second.m_it;
KeyT k = *listIt;
m_list.erase(listIt);
m_list.push_front(k);
it->second.m_it = m_list.begin();
}
return it->second.m_value;
}
void Touch(KeyT const & key)
{
if (!HasElem(key))
return;
typename map_t::iterator it = m_map.find(key);
CHECK(it != m_map.end(), ());
typename list_t::iterator listIt = it->second.m_it;
KeyT k = *listIt;
m_list.erase(listIt);
m_list.push_front(k);
it->second.m_it = m_list.begin();
}
void Remove(KeyT const & key)
{
typename map_t::iterator it = m_map.find(key);
if (it != m_map.end())
{
m_curWeight -= it->second.m_weight;
m_list.erase(it->second.m_it);
ValueTraitsT::Evict(it->second.m_value);
m_map.erase(it);
}
}
void Add(KeyT const & key, ValueT const & val, size_t weight)
{
if (HasElem(key))
Remove(key);
while (m_curWeight + weight > m_maxWeight)
{
if (m_list.empty())
return;
KeyT k = m_list.back();
m_list.pop_back();
m_curWeight -= m_map[k].m_weight;
ValueTraitsT::Evict(m_map[k].m_value);
m_map.erase(k);
}
m_list.push_front(key);
m_map[key].m_weight = weight;
m_map[key].m_value = val;
m_map[key].m_it = m_list.begin();
m_curWeight += weight;
}
void Clear()
{
for (typename map_t::iterator it = m_map.begin(); it != m_map.end(); ++it)
ValueTraitsT::Evict(it->second);
m_map.clear();
m_list.clear();
m_curWeight = 0;
}
};
}

View file

@ -1,91 +0,0 @@
#pragma once
#include "condition.hpp"
#include "../std/list.hpp"
/// multithreaded object pool.
/// implements condition waiting scheme, to save the CPU cycles.
template <typename T>
class ObjectPool
{
private:
list<T> m_List;
threads::Condition m_Cond;
bool m_IsCancelled;
public:
ObjectPool() : m_IsCancelled(false)
{}
void Add(list<T> const & l)
{
for (typename list<T>::const_iterator it = l.begin(); it != l.end(); ++it)
Free(*it);
}
size_t Size()
{
threads::ConditionGuard Guard(m_Cond);
return m_List.size();
}
void Add(T const & t)
{
Free(t);
}
void Clear()
{
threads::ConditionGuard Guard(m_Cond);
m_List.clear();
}
T const Reserve()
{
threads::ConditionGuard Guard(m_Cond);
while (m_List.empty())
{
if (m_IsCancelled)
break;
m_Cond.Wait();
}
if (m_IsCancelled)
return T();
T res = m_List.front();
m_List.pop_front();
return res;
}
/// cancel all waiting requests
void Cancel()
{
m_IsCancelled = true;
m_Cond.Signal(true);
}
bool IsCancelled() const
{
return m_IsCancelled;
}
void Free(T const & t)
{
threads::ConditionGuard Guard(m_Cond);
bool DoSignal = m_List.empty();
m_List.push_back(t);
if (DoSignal)
m_Cond.Signal(); //< this doesn't release the mutex associated with m_cond,
/// we should return as quickly as possible to minimize "waked threads" waiting time
}
};

View file

@ -0,0 +1,22 @@
#include "threaded_container.hpp"
ThreadedContainer::ThreadedContainer()
: m_WaitTime(0), m_IsCancelled(false)
{
}
void ThreadedContainer::Cancel()
{
m_IsCancelled = true;
m_Cond.Signal(true);
}
bool ThreadedContainer::IsCancelled() const
{
return m_IsCancelled;
}
double ThreadedContainer::WaitTime() const
{
return m_WaitTime;
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "condition.hpp"
#include "timer.hpp"
struct ThreadedContainer
{
protected:
my::Timer m_Timer;
double m_WaitTime;
threads::Condition m_Cond;
bool m_IsCancelled;
public:
ThreadedContainer();
void Cancel();
bool IsCancelled() const;
double WaitTime() const;
};

101
base/threaded_list.hpp Normal file
View file

@ -0,0 +1,101 @@
#pragma once
#include "condition.hpp"
#include "../std/list.hpp"
#include "threaded_container.hpp"
template <typename T>
class ThreadedList : public ThreadedContainer
{
private:
list<T> m_list;
public:
void PushBack(T const & t)
{
threads::ConditionGuard g(m_Cond);
bool doSignal = m_list.empty();
m_list.push_back(t);
if (doSignal)
m_Cond.Signal();
}
void PushFront(T const & t)
{
threads::ConditionGuard g(m_Cond);
bool doSignal = m_list.empty();
m_list.push_front(t);
if (doSignal)
m_Cond.Signal();
}
bool WaitNonEmpty()
{
double StartWaitTime = m_Timer.ElapsedSeconds();
while (m_list.empty())
{
if (IsCancelled())
break;
m_Cond.Wait();
}
m_WaitTime += m_Timer.ElapsedSeconds() - StartWaitTime;
if (IsCancelled())
return true;
return false;
}
T const Front(bool doPop)
{
threads::ConditionGuard g(m_Cond);
if (WaitNonEmpty())
return T();
T res = m_list.front();
if (doPop)
m_list.pop_front();
return res;
}
T const Back(bool doPop)
{
threads::ConditionGuard g(m_Cond);
if (WaitNonEmpty())
return T();
T res = m_list.back();
if (doPop)
m_list.pop_back();
return res;
}
size_t Size()
{
threads::ConditionGuard g(m_Cond);
return m_list.size();
}
void Clear()
{
threads::ConditionGuard g(m_Cond);
m_list.clear();
}
};

View file

@ -56,13 +56,11 @@ namespace fwork
ScreenBase const & convertor,
shared_ptr<PaintEvent> const & paintEvent,
int scaleLevel,
shared_ptr<yg::gl::RenderState> const & renderState,
yg::GlyphCache * glyphCache)
: m_rect(r),
m_convertor(convertor),
m_paintEvent(paintEvent),
m_zoom(scaleLevel),
m_renderState(renderState),
m_glyphCache(glyphCache)
#ifdef PROFILER_DRAWING
, m_drawCount(0)
@ -175,8 +173,6 @@ namespace fwork
sort(rules.begin(), rules.end(), less_depth());
m_renderState->m_isEmptyModelCurrent = false;
shared_ptr<di::DrawInfo> ptr(new di::DrawInfo(
f.GetPreferredDrawableName(languages::GetCurrentPriorities()),
f.GetRoadNumber(),
@ -271,19 +267,19 @@ namespace fwork
}
}
template <typename TModel>
/*template <typename TModel>
void FrameWork<TModel>::AddRedrawCommandSure()
{
m_renderQueue.AddCommand(bind(&this_type::PaintImpl, this, _1, _2, _3, _4), m_navigator.Screen());
}
template <typename TModel>
}*/
/* template <typename TModel>
void FrameWork<TModel>::AddRedrawCommand()
{
yg::gl::RenderState const state = m_renderQueue.CopyState();
if ((state.m_currentScreen != m_navigator.Screen()) && (m_isRedrawEnabled))
AddRedrawCommandSure();
}
}*/
template <typename TModel>
void FrameWork<TModel>::AddMap(string const & file)
@ -340,9 +336,6 @@ void FrameWork<TModel>::AddRedrawCommandSure()
m_isBenchmarkInitialized(false),
m_bgColor(0xEE, 0xEE, 0xDD, 0xFF),
m_renderQueue(GetPlatform().SkinName(),
GetPlatform().IsMultiSampled() && yg::gl::g_isMultisamplingSupported,
GetPlatform().DoPeriodicalUpdate(),
GetPlatform().PeriodicalUpdateInterval(),
GetPlatform().IsBenchmarking(),
GetPlatform().ScaleEtalonSize(),
m_bgColor),
@ -401,7 +394,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
template <typename TModel>
void FrameWork<TModel>::BenchmarkCommandFinished()
{
double duration = m_renderQueue.renderState().m_duration;
/* double duration = m_renderQueue.renderState().m_duration;
if (duration > m_maxDuration)
{
m_maxDuration = duration;
@ -418,13 +411,13 @@ void FrameWork<TModel>::AddRedrawCommandSure()
if (m_benchmarkResults.size() > 100)
SaveBenchmarkResults();
NextBenchmarkCommand();
// NextBenchmarkCommand();*/
}
template <typename TModel>
void FrameWork<TModel>::SaveBenchmarkResults()
{
string resultsPath;
/* string resultsPath;
Settings::Get("BenchmarkResults", resultsPath);
LOG(LINFO, (resultsPath));
ofstream fout(GetPlatform().WritablePathForFile(resultsPath).c_str(), ios::app);
@ -442,16 +435,17 @@ void FrameWork<TModel>::AddRedrawCommandSure()
<< m_benchmarkResults[i].m_time << endl;
}
m_benchmarkResults.clear();
m_benchmarkResults.clear();*/
}
template <typename TModel>
void FrameWork<TModel>::SendBenchmarkResults()
{
//ofstream fout(GetPlatform().WritablePathForFile("benchmarks/results.txt").c_str(), ios::app);
//fout << "[COMPLETED]";
//fout.close();
/// @todo send to server for adding to statistics graphics and delete results file
// ofstream fout(GetPlatform().WritablePathForFile("benchmarks/results.txt").c_str(), ios::app);
// fout << "[COMPLETED]";
// fout.close();
/// send to server for adding to statistics graphics
/// and delete results file
}
template <typename TModel>
@ -474,7 +468,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
fout << "START " << m_startTime << endl;
}
template <typename TModel>
/* template <typename TModel>
void FrameWork<TModel>::NextBenchmarkCommand()
{
if ((m_benchmarks[m_curBenchmark].m_provider->hasRect()) || (++m_curBenchmark < m_benchmarks.size()))
@ -491,7 +485,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
LOG(LINFO, ("Bechmarks took ", m_benchmarksTimer.ElapsedSeconds(), " seconds to complete"));
}
}
*/
struct PathAppender
{
string const & m_path;
@ -676,11 +670,11 @@ void FrameWork<TModel>::AddRedrawCommandSure()
m_curBenchmark = 0;
m_renderQueue.addRenderCommandFinishedFn(bind(&this_type::BenchmarkCommandFinished, this));
m_renderQueue.AddRenderCommandFinishedFn(bind(&this_type::BenchmarkCommandFinished, this));
m_benchmarksTimer.Reset();
MarkBenchmarkResultsStart();
NextBenchmarkCommand();
// NextBenchmarkCommand();
Invalidate();
}
@ -691,7 +685,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
shared_ptr<yg::ResourceManager> const & resourceManager)
{
m_resourceManager = resourceManager;
m_renderQueue.initializeGL(primaryContext, m_resourceManager, GetPlatform().VisualScale());
m_renderQueue.InitializeGL(primaryContext, m_resourceManager, GetPlatform().VisualScale());
}
template <typename TModel>
@ -749,7 +743,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
template <typename TModel>
void FrameWork<TModel>::UpdateNow()
{
AddRedrawCommand();
// AddRedrawCommand();
Invalidate();
}
@ -782,13 +776,9 @@ void FrameWork<TModel>::AddRedrawCommandSure()
if (w < 2) w = 2;
if (h < 2) h = 2;
m_renderQueue.OnSize(w, h);
m_informationDisplay.setDisplayRect(m2::RectI(m2::PointI(0, 0), m2::PointU(w, h)));
m2::PointU ptShift = m_renderQueue.renderState().coordSystemShift(true);
m_informationDisplay.setDisplayRect(m2::RectI(ptShift, ptShift + m2::PointU(w, h)));
m_navigator.OnSize(ptShift.x, ptShift.y, w, h);
m_navigator.OnSize(0, 0, w, h);
if ((m_isBenchmarking) && (!m_isBenchmarkInitialized))
{
@ -808,7 +798,8 @@ void FrameWork<TModel>::AddRedrawCommandSure()
void FrameWork<TModel>::SetRedrawEnabled(bool isRedrawEnabled)
{
m_isRedrawEnabled = isRedrawEnabled;
AddRedrawCommand();
Invalidate();
// AddRedrawCommand();
}
/// respond to device orientation changes
@ -823,8 +814,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
template <typename TModel>
double FrameWork<TModel>::GetCurrentScale() const
{
m2::PointD textureCenter(m_renderQueue.renderState().m_textureWidth / 2,
m_renderQueue.renderState().m_textureHeight / 2);
m2::PointD textureCenter(m_navigator.Screen().PixelRect().Center());
m2::RectD glbRect;
unsigned scaleEtalonSize = GetPlatform().ScaleEtalonSize();
@ -843,8 +833,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
m2::RectD const & selectRect,
int scaleLevel)
{
fwork::DrawProcessor doDraw(selectRect, screen, e, scaleLevel, m_renderQueue.renderStatePtr(), e->drawer()->screen()->glyphCache());
m_renderQueue.renderStatePtr()->m_isEmptyModelCurrent = true;
fwork::DrawProcessor doDraw(selectRect, screen, e, scaleLevel, e->drawer()->screen()->glyphCache());
try
{
@ -868,8 +857,8 @@ void FrameWork<TModel>::AddRedrawCommandSure()
}
catch (redraw_operation_cancelled const &)
{
m_renderQueue.renderStatePtr()->m_isEmptyModelCurrent = false;
m_renderQueue.renderStatePtr()->m_isEmptyModelActual = false;
// m_renderQueue.renderStatePtr()->m_isEmptyModelCurrent = false;
// m_renderQueue.renderStatePtr()->m_isEmptyModelActual = false;
}
if (m_navigator.Update(m_timer.ElapsedSeconds()))
@ -887,7 +876,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
m_informationDisplay.setScreen(m_navigator.Screen());
m_informationDisplay.setDebugInfo(m_renderQueue.renderState().m_duration, my::rounds(GetCurrentScale()));
// m_informationDisplay.setDebugInfo(m_renderQueue.renderState().m_duration, my::rounds(GetCurrentScale()));
m_informationDisplay.enableRuler(!IsEmptyModel());
@ -896,96 +885,69 @@ void FrameWork<TModel>::AddRedrawCommandSure()
m_informationDisplay.setGlobalRect(m_navigator.Screen().GlobalRect());
m_informationDisplay.setCenter(m2::PointD(MercatorBounds::XToLon(center.x), MercatorBounds::YToLat(center.y)));
/* if (m_isBenchmarking)
{
threads::MutexGuard guard(*m_renderQueue.renderState().m_mutex.get());
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::XToLon(center.x), MercatorBounds::YToLat(center.y)));
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::XToLon(center.x), MercatorBounds::YToLat(center.y)));
if (!m_isBenchmarkInitialized)
{
e->drawer()->screen()->beginFrame();
e->drawer()->screen()->clear(m_bgColor);
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_isBenchmarkInitialized)
{
e->drawer()->screen()->beginFrame();
e->drawer()->screen()->clear(m_bgColor);
m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(false);
OGLCHECK(glMatrixMode(GL_MODELVIEW));
OGLCHECK(glPushMatrix());
OGLCHECK(glTranslatef(-ptShift.x, -ptShift.y, 0));
ScreenBase currentScreen = m_navigator.Screen();
m_informationDisplay.enableEmptyModelMessage(m_renderQueue.renderStatePtr()->m_isEmptyModelActual);
if (m_isBenchmarking)
currentScreen = m_renderQueue.renderState().m_actualScreen;
pDrawer->screen()->blit(m_renderQueue.renderState().m_actualTarget,
m_renderQueue.renderState().m_actualScreen,
currentScreen);
/* m_tiler.seed(currentScreen, m_tileSize);
while (m_tiler.hasTile())
{
yg::Tiler::RectInfo ri = m_tiler.nextTile();
m_renderQueue.tileCache().lock();
if (m_renderQueue.tileCache().hasTile(ri))
{
yg::Tile tile = m_renderQueue.tileCache().getTile(ri);
m2::RectD pxRect;
currentScreen.GtoP(ri.m_rect, pxRect);
pDrawer->screen()->drawRectangle(pxRect, yg::Color(255, 0, 0, 64), yg::maxDepth - 1);
m_renderQueue.tileCache().unlock();
// pDrawer->screen()->blit(tile.m_renderTarget, tile.m_tileScreen, currentScreen);
}
else
{
m_renderQueue.tileCache().unlock();
// m_renderQueue.addTileRenderCmd();
m2::RectD pxRect;
currentScreen.GtoP(ri.m_rect, pxRect);
pDrawer->screen()->drawRectangle(pxRect, yg::Color(0, 0, 255, 192 - (ri.m_distance * 3 > 255 ? 255 : ri.m_distance * 3) / (255.0 / 192)), yg::maxDepth - 2);
}
}
*/
m_informationDisplay.doDraw(pDrawer);
/* m_renderQueue.renderState().m_actualInfoLayer->draw(
pDrawer->screen().get(),
m_renderQueue.renderState().m_actualScreen.PtoGMatrix() * currentScreen.GtoPMatrix());*/
m_locationState.DrawMyPosition(*pDrawer, m_navigator.Screen());
m_informationDisplay.setDisplayRect(m2::RectI(0, 0, 100, 100));
m_informationDisplay.enableRuler(false);
m_informationDisplay.doDraw(e->drawer().get());
e->drawer()->screen()->endFrame();
}
}*/
OGLCHECK(glPopMatrix());
e->drawer()->screen()->beginFrame();
e->drawer()->screen()->clear(m_bgColor);
ScreenBase currentScreen = m_navigator.Screen();
// m_informationDisplay.enableEmptyModelMessage(m_renderQueue.renderStatePtr()->m_isEmptyModelActual);
/* if (m_isBenchmarking)
currentScreen = m_renderQueue.renderState().m_actualScreen;*/
/* pDrawer->screen()->blit(m_renderQueue.renderState().m_actualTarget,
m_renderQueue.renderState().m_actualScreen,
currentScreen);*/
m_tiler.seed(currentScreen, m_tileSize);
while (m_tiler.hasTile())
{
yg::Tiler::RectInfo ri = m_tiler.nextTile();
m_renderQueue.TileCache().lock();
LOG(LINFO, ("Checking TileRect:", ri.m_rect));
if (m_renderQueue.TileCache().hasTile(ri))
{
yg::Tile tile = m_renderQueue.TileCache().getTile(ri);
m_renderQueue.TileCache().unlock();
pDrawer->screen()->blit(tile.m_renderTarget, tile.m_tileScreen, currentScreen, true);
}
else
{
e->drawer()->screen()->beginFrame();
e->drawer()->screen()->clear(m_bgColor);
e->drawer()->screen()->endFrame();
m_renderQueue.TileCache().unlock();
m_renderQueue.AddCommand(bind(&this_type::PaintImpl, this, _1, _2, _3, _4), ri, m_tiler.seqNum());
}
}
m_informationDisplay.doDraw(pDrawer);
/* m_renderQueue.renderState().m_actualInfoLayer->draw(
pDrawer->screen().get(),
m_renderQueue.renderState().m_actualScreen.PtoGMatrix() * currentScreen.GtoPMatrix());*/
m_locationState.DrawMyPosition(*pDrawer, m_navigator.Screen());
e->drawer()->screen()->endFrame();
}
template <typename TModel>
@ -1076,19 +1038,14 @@ void FrameWork<TModel>::AddRedrawCommandSure()
template <typename TModel>
void FrameWork<TModel>::Repaint()
{
m_renderQueue.SetRedrawAll();
AddRedrawCommandSure();
// AddRedrawCommandSure();
Invalidate();
}
template <typename TModel>
void FrameWork<TModel>::RepaintRect(m2::RectD const & rect)
{
threads::MutexGuard lock(*m_renderQueue.renderState().m_mutex.get());
m2::RectD pxRect(0, 0, m_renderQueue.renderState().m_surfaceWidth, m_renderQueue.renderState().m_surfaceHeight);
m2::RectD glbRect;
m_navigator.Screen().PtoG(pxRect, glbRect);
if (glbRect.Intersect(rect))
if (m_navigator.Screen().GlobalRect().IsIntersect(rect))
Repaint();
}
@ -1097,8 +1054,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
template <typename TModel>
void FrameWork<TModel>::StartDrag(DragEvent const & e)
{
m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(true);
m2::PointD pos = m_navigator.OrientPoint(e.Pos()) + ptShift;
m2::PointD pos = m_navigator.OrientPoint(e.Pos());
m_navigator.StartDrag(pos, m_timer.ElapsedSeconds());
#ifdef DRAW_TOUCH_POINTS
@ -1113,9 +1069,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
{
m_centeringMode = EDoNothing;
m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(true);
m2::PointD pos = m_navigator.OrientPoint(e.Pos()) + ptShift;
m2::PointD pos = m_navigator.OrientPoint(e.Pos());
m_navigator.DoDrag(pos, m_timer.ElapsedSeconds());
#ifdef DRAW_TOUCH_POINTS
@ -1128,9 +1082,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
template <typename TModel>
void FrameWork<TModel>::StopDrag(DragEvent const & e)
{
m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(true);
m2::PointD pos = m_navigator.OrientPoint(e.Pos()) + ptShift;
m2::PointD pos = m_navigator.OrientPoint(e.Pos());
m_navigator.StopDrag(pos, m_timer.ElapsedSeconds(), true);
@ -1156,7 +1108,7 @@ void FrameWork<TModel>::AddRedrawCommandSure()
void FrameWork<TModel>::ScaleToPoint(ScaleToPointEvent const & e)
{
m2::PointD const pt = (m_centeringMode == EDoNothing)
? m_navigator.OrientPoint(e.Pt()) + m_renderQueue.renderState().coordSystemShift(true)
? m_navigator.OrientPoint(e.Pt())
: m_navigator.Screen().PixelRect().Center();
m_navigator.ScaleToPoint(pt, e.ScaleFactor(), m_timer.ElapsedSeconds());
@ -1181,10 +1133,8 @@ void FrameWork<TModel>::AddRedrawCommandSure()
template <typename TModel>
void FrameWork<TModel>::StartScale(ScaleEvent const & e)
{
m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(true);
m2::PointD pt1 = m_navigator.OrientPoint(e.Pt1()) + ptShift;
m2::PointD pt2 = m_navigator.OrientPoint(e.Pt2()) + ptShift;
m2::PointD pt1 = m_navigator.OrientPoint(e.Pt1());
m2::PointD pt2 = m_navigator.OrientPoint(e.Pt2());
if ((m_locationState & location::State::EGps) && (m_centeringMode == ECenterOnly))
{
@ -1207,10 +1157,8 @@ void FrameWork<TModel>::AddRedrawCommandSure()
template <typename TModel>
void FrameWork<TModel>::DoScale(ScaleEvent const & e)
{
m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(true);
m2::PointD pt1 = m_navigator.OrientPoint(e.Pt1()) + ptShift;
m2::PointD pt2 = m_navigator.OrientPoint(e.Pt2()) + ptShift;
m2::PointD pt1 = m_navigator.OrientPoint(e.Pt1());
m2::PointD pt2 = m_navigator.OrientPoint(e.Pt2());
if ((m_locationState & location::State::EGps) && (m_centeringMode == ECenterOnly))
{
@ -1233,10 +1181,8 @@ void FrameWork<TModel>::AddRedrawCommandSure()
template <typename TModel>
void FrameWork<TModel>::StopScale(ScaleEvent const & e)
{
m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(true);
m2::PointD pt1 = m_navigator.OrientPoint(e.Pt1()) + ptShift;
m2::PointD pt2 = m_navigator.OrientPoint(e.Pt2()) + ptShift;
m2::PointD pt1 = m_navigator.OrientPoint(e.Pt1());
m2::PointD pt2 = m_navigator.OrientPoint(e.Pt2());
if ((m_locationState & location::State::EGps) && (m_centeringMode == ECenterOnly))
{

View file

@ -70,7 +70,6 @@ namespace fwork
vector<drule::Key> m_keys;
int m_zoom;
shared_ptr<yg::gl::RenderState> m_renderState;
yg::GlyphCache * m_glyphCache;
#ifdef PROFILER_DRAWING
@ -89,7 +88,6 @@ namespace fwork
ScreenBase const & convertor,
shared_ptr<PaintEvent> const & paintEvent,
int scaleLevel,
shared_ptr<yg::gl::RenderState> const & renderState,
yg::GlyphCache * glyphCache);
bool operator() (FeatureType const & f);
@ -174,7 +172,7 @@ class FrameWork
yg::Tiler m_tiler;
void BenchmarkCommandFinished();
void NextBenchmarkCommand();
// void NextBenchmarkCommand();
void SaveBenchmarkResults();
void SendBenchmarkResults();

View file

@ -7,114 +7,92 @@
RenderQueue::RenderQueue(
string const & skinName,
bool isMultiSampled,
bool doPeriodicalUpdate,
double updateInterval,
bool isBenchmarking,
unsigned scaleEtalonSize,
yg::Color const & bgColor
)
: m_renderState(new yg::gl::RenderState()),
m_tileCache(256 * 256 * 2, 10 * 1024 * 1024)
) : m_sequence(0), m_tileCache(39)
{
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,
bgColor);
m_tasksCount = 1; //< calculate from the CPU Cores Number
m_tasks = new Task[m_tasksCount];
for (unsigned i = 0; i < m_tasksCount; ++i)
m_tasks[i].m_routine = new RenderQueueRoutine(
skinName,
isBenchmarking,
scaleEtalonSize,
bgColor,
i,
this);
}
void RenderQueue::initializeGL(shared_ptr<yg::gl::RenderContext> const & primaryContext,
void RenderQueue::InitializeGL(shared_ptr<yg::gl::RenderContext> const & primaryContext,
shared_ptr<yg::ResourceManager> const & resourceManager,
double visualScale)
{
m_resourceManager = resourceManager;
m_routine->initializeGL(primaryContext->createShared(),
m_resourceManager);
m_routine->setVisualScale(visualScale);
m_renderQueueThread.Create(m_routine);
for (unsigned i = 0; i < m_tasksCount; ++i)
{
m_tasks[i].m_routine->initializeGL(primaryContext->createShared(),
m_resourceManager);
m_tasks[i].m_routine->setVisualScale(visualScale);
m_tasks[i].m_thread.Create(m_tasks[i].m_routine);
}
}
RenderQueue::~RenderQueue()
{
m_renderQueueThread.Cancel();
m_renderCommands.Cancel();
for (unsigned i = 0; i < m_tasksCount; ++i)
m_tasks[i].m_thread.Cancel();
}
void RenderQueue::AddCommand(RenderQueueRoutine::render_fn_t const & fn, ScreenBase const & frameScreen)
void RenderQueue::AddCommand(RenderQueueRoutine::render_fn_t const & fn, yg::Tiler::RectInfo const & rectInfo, size_t seqNum)
{
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;
m_sequence = seqNum;
m_renderCommands.PushBack(make_shared_ptr(new RenderQueueRoutine::Command(rectInfo, fn, seqNum)));
}
void RenderQueue::AddWindowHandle(shared_ptr<WindowHandle> const & windowHandle)
{
m_routine->addWindowHandle(windowHandle);
for (unsigned i = 0; i < m_tasksCount; ++i)
m_tasks[i].m_routine->addWindowHandle(windowHandle);
}
void RenderQueue::addRenderCommandFinishedFn(renderCommandFinishedFn fn)
void RenderQueue::AddRenderCommandFinishedFn(renderCommandFinishedFn fn)
{
m_routine->addRenderCommandFinishedFn(fn);
for (unsigned i = 0; i < m_tasksCount; ++i)
m_tasks[i].m_routine->addRenderCommandFinishedFn(fn);
}
void RenderQueue::OnSize(size_t w, size_t h)
void RenderQueue::MemoryWarning()
{
m_renderState->onSize(w, h);
for (unsigned i = 0; i < m_tasksCount; ++i)
m_tasks[i].m_routine->memoryWarning();
}
yg::gl::RenderState const RenderQueue::CopyState() const
void RenderQueue::EnterBackground()
{
yg::gl::RenderState state;
m_renderState->copyTo(state);
return state;
for (unsigned i = 0; i < m_tasksCount; ++i)
m_tasks[i].m_routine->enterBackground();
}
yg::gl::RenderState const & RenderQueue::renderState() const
void RenderQueue::EnterForeground()
{
return *m_renderState.get();
for (unsigned i = 0; i < m_tasksCount; ++i)
m_tasks[i].m_routine->enterForeground();
}
shared_ptr<yg::gl::RenderState> 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();
}
yg::TileCache & RenderQueue::tileCache()
yg::TileCache & RenderQueue::TileCache()
{
return m_tileCache;
}
size_t RenderQueue::CurrentSequence() const
{
return m_sequence;
}
ThreadedList<shared_ptr<RenderQueueRoutine::Command > > & RenderQueue::RenderCommands()
{
return m_renderCommands;
}

View file

@ -6,6 +6,7 @@
#include "render_queue_routine.hpp"
#include "../yg/tile_cache.hpp"
#include "../yg/tiler.hpp"
#include "../base/threaded_list.hpp"
namespace yg
{
@ -23,13 +24,23 @@ class RenderQueue
{
private:
/// single rendering task
struct Task
{
threads::Thread m_thread;
RenderQueueRoutine * m_routine;
};
Task * m_tasks;
size_t m_tasksCount;
size_t m_sequence;
friend class RenderQueueRoutine;
threads::Thread m_renderQueueThread;
shared_ptr<yg::gl::RenderState> m_renderState;
shared_ptr<yg::ResourceManager> m_resourceManager;
RenderQueueRoutine * m_routine;
ThreadedList<shared_ptr<RenderQueueRoutine::Command> > m_renderCommands;
yg::TileCache m_tileCache;
@ -39,50 +50,34 @@ public:
/// constructor.
RenderQueue(string const & skinName,
bool isMultiSampled,
bool doPeriodicalUpdate,
double updateInterval,
bool isBenchmarking,
unsigned scaleEtalonSize,
yg::Color const & bgColor);
/// destructor.
~RenderQueue();
/// set the primary context. it starts the rendering thread.
void initializeGL(shared_ptr<yg::gl::RenderContext> const & primaryContext,
void InitializeGL(shared_ptr<yg::gl::RenderContext> const & primaryContext,
shared_ptr<yg::ResourceManager> const & resourceManager,
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();
void AddCommand(RenderQueueRoutine::render_fn_t const & fn, yg::Tiler::RectInfo const & rectInfo, size_t seqNum);
/// set visual scale
void SetVisualScale(double visualScale);
/// add window handle to notify when rendering operation finishes
void AddWindowHandle(shared_ptr<WindowHandle> const & windowHandle);
void addRenderCommandFinishedFn(renderCommandFinishedFn fn);
/// process resize request
void OnSize(size_t w, size_t h);
/// copy primary render state
yg::gl::RenderState const CopyState() const;
shared_ptr<yg::gl::RenderState> const & renderStatePtr() const;
yg::gl::RenderState const & renderState() const;
/// add function, that will be called upon render command completion.
void AddRenderCommandFinishedFn(renderCommandFinishedFn fn);
/// free all possible memory caches.
void memoryWarning();
void MemoryWarning();
/// free all possible memory caches, opengl resources,
/// and make sure no opengl call will be made in background
void enterBackground();
void EnterBackground();
/// load all necessary memory caches and opengl resources.
void enterForeground();
void EnterForeground();
/// get tile cache.
yg::TileCache & tileCache();
/// add tiler rendering command.
void addTileRenderCmd(yg::Tiler::RectInfo const & ri);
yg::TileCache & TileCache();
/// number of the current tiler sequence to skip the old commands upon rendering.
size_t CurrentSequence() const;
/// common render commands queue for all rendering threads.
ThreadedList<shared_ptr<RenderQueueRoutine::Command> > & RenderCommands();
};

View file

@ -15,6 +15,7 @@
#include "../yg/skin.hpp"
#include "../yg/base_texture.hpp"
#include "../yg/info_layer.hpp"
#include "../yg/tile.hpp"
#include "../indexer/scales.hpp"
@ -22,29 +23,27 @@
#include "drawer_yg.hpp"
#include "window_handle.hpp"
#include "render_queue_routine.hpp"
#include "render_queue.hpp"
RenderQueueRoutine::RenderModelCommand::RenderModelCommand(ScreenBase const & frameScreen,
render_fn_t renderFn)
: m_frameScreen(frameScreen),
m_renderFn(renderFn)
RenderQueueRoutine::Command::Command(yg::Tiler::RectInfo const & rectInfo,
render_fn_t renderFn,
size_t seqNum)
: m_rectInfo(rectInfo),
m_renderFn(renderFn),
m_seqNum(seqNum)
{}
RenderQueueRoutine::RenderQueueRoutine(shared_ptr<yg::gl::RenderState> const & renderState,
string const & skinName,
bool isMultiSampled,
bool doPeriodicalUpdate,
double updateInterval,
RenderQueueRoutine::RenderQueueRoutine(string const & skinName,
bool isBenchmarking,
unsigned scaleEtalonSize,
yg::Color const & bgColor)
yg::Color const & bgColor,
size_t threadNum,
RenderQueue * renderQueue)
: m_threadNum(threadNum),
m_renderQueue(renderQueue)
{
m_skinName = skinName;
m_visualScale = 0;
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;
@ -53,160 +52,9 @@ RenderQueueRoutine::RenderQueueRoutine(shared_ptr<yg::gl::RenderState> const & r
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->setIsCancelled(true);
}
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<yg::gl::BaseTexture> 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<yg::gl::BaseTexture> 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<m2::RectI> & 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 = (newRect.SizeX() + 9) / 5;
int rectH = (newRect.SizeY() + 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));
*/
}
if (m_currentCommand != 0)
m_currentCommand->m_paintEvent->setIsCancelled(true);
}
void RenderQueueRoutine::setVisualScale(double visualScale)
@ -214,32 +62,26 @@ void RenderQueueRoutine::setVisualScale(double visualScale)
m_visualScale = visualScale;
}
void RenderQueueRoutine::waitForRenderCommand(list<shared_ptr<RenderModelCommand> > & 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());
unsigned tileWidth = m_resourceManager->tileTextureWidth();
unsigned tileHeight = m_resourceManager->tileTextureHeight();
shared_ptr<yg::gl::RenderBuffer> depthBuffer(new yg::gl::RenderBuffer(tileWidth, tileHeight, true));
m_frameBuffer->setDepthBuffer(depthBuffer);
DrawerYG::params_t params;
shared_ptr<yg::InfoLayer> infoLayer(new yg::InfoLayer());
params.m_resourceManager = m_resourceManager;
params.m_isMultiSampled = m_isMultiSampled;
params.m_frameBuffer = m_frameBuffer;
params.m_renderState = m_renderState;
params.m_doPeriodicalUpdate = m_doPeriodicalUpdate;
params.m_updateInterval = m_updateInterval;
params.m_glyphCacheID = m_resourceManager->renderThreadGlyphCacheID();
params.m_infoLayer = infoLayer;
params.m_glyphCacheID = m_resourceManager->renderThreadGlyphCacheID(m_threadNum);
params.m_useOverlay = true;
/* params.m_isDebugging = true;
params.m_drawPathes = false;
@ -247,187 +89,69 @@ void RenderQueueRoutine::Do()
params.m_drawTexts = false; */
m_threadDrawer = make_shared_ptr(new DrawerYG(m_skinName, params));
m_threadDrawer->onSize(tileWidth, tileHeight);
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));
CHECK(m_visualScale != 0, ("Set the VisualScale first!"));
CHECK(m_visualScale != 0, ("VisualScale is not set"));
m_threadDrawer->SetVisualScale(m_visualScale);
bool isPanning = false;
bool doRedrawAll = false;
bool fullRectRepaint = false;
/// update areas in pixel coordinates.
vector<m2::RectI> areas;
m2::RectI surfaceRect;
m2::RectI textureRect;
ScreenBase frameScreen;
frameScreen.OnSize(0, 0, tileWidth, tileHeight);
while (!IsCancelled())
{
{
threads::ConditionGuard guard(m_hasRenderCommands);
if (m_isBenchmarking)
waitForRenderCommand(m_benchmarkRenderCommands, guard);
else
waitForRenderCommand(m_renderCommands, guard);
threads::MutexGuard guard(m_mutex);
m_currentCommand = m_renderQueue->RenderCommands().Front(true);
if (IsCancelled())
break;
m_currentCommand->m_paintEvent = make_shared_ptr(new PaintEvent(m_threadDrawer));
/// Preparing render command for execution.
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());
}
/// commands from the previous sequence are ignored
if (m_currentCommand->m_seqNum < m_renderQueue->CurrentSequence())
continue;
m_currentRenderCommand->m_paintEvent = make_shared_ptr(new PaintEvent(m_threadDrawer));
bool hasTile = false;
/// 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_renderQueue->TileCache().lock();
hasTile = m_renderQueue->TileCache().hasTile(m_currentCommand->m_rectInfo);
m_renderQueue->TileCache().unlock();
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_renderState->m_currentInfoLayer->clear();
// m_renderState->m_actualInfoLayer->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);
m2::PointD offs(m_renderState->m_currentScreen.GtoP(prevScreen.PtoG(m2::PointD(0, 0))));
m_renderState->m_currentInfoLayer->offset(
offs,
redrawTextRect);
}
else
{
m_renderState->m_currentInfoLayer->clear();
// m_renderState->m_actualInfoLayer->clear();
}
}
if (hasTile)
continue;
}
if (IsCancelled())
break;
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.
shared_ptr<yg::gl::BaseTexture> tileTarget;
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());
tileTarget = m_resourceManager->renderTargets().Front(true);
if (IsCancelled())
break;
m_threadDrawer->beginFrame();
m_threadDrawer->screen()->setRenderTarget(tileTarget);
m_threadDrawer->screen()->enableClipRect(true);
m_threadDrawer->screen()->setClipRect(textureRect);
m_threadDrawer->clear(m_bgColor);
m_threadDrawer->beginFrame();
if ((isPanning) && (!doRedrawAll))
{
m_threadDrawer->screen()->blit(
m_renderState->m_actualTarget,
m_renderState->m_actualScreen,
m_renderState->m_currentScreen);
}
m_threadDrawer->clear(m_bgColor);
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);
frameScreen.SetFromRect(m_currentCommand->m_rectInfo.m_rect);
for (size_t i = 0; i < areas.size(); ++i)
{
if ((areas[i].SizeX() != 0) && (areas[i].SizeY() != 0))
{
frameScreen.PtoG(m2::Inflate<double>(m2::RectD(areas[i]), 30 * m_visualScale, 30 * m_visualScale), glbRect);
if ((glbRect.SizeX() == 0) || (glbRect.SizeY() == 0))
continue;
int scaleLevel = scales::GetScaleLevel(m_currentCommand->m_rectInfo.m_rect);
m_threadDrawer->screen()->setClipRect(areas[i]);
m_currentCommand->m_renderFn(
m_currentCommand->m_paintEvent,
frameScreen,
m_currentCommand->m_rectInfo.m_rect,
scaleLevel);
m_currentRenderCommand->m_renderFn(
m_currentRenderCommand->m_paintEvent,
m_currentRenderCommand->m_frameScreen,
glbRect,
scaleLevel);
}
}
/// rendering all collected texts
// m_infoLayer->draw(m_threadDrawer->screen().get(), math::Identity<double, 3>());
/// 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);
/// rendering all collected texts
m_renderState->m_currentInfoLayer->draw(m_threadDrawer->screen().get(), math::Identity<double, 3>());
m_threadDrawer->endFrame();
}
m_threadDrawer->endFrame();
double duration = timer.ElapsedSeconds();
@ -437,17 +161,23 @@ void RenderQueueRoutine::Do()
/// in the endFrame function
/// updateActualTarget();
m_currentRenderCommand.reset();
{
threads::MutexGuard guard(*m_renderState->m_mutex.get());
m_renderState->m_duration = duration;
threads::MutexGuard guard(m_mutex);
if (!m_currentCommand->m_paintEvent->isCancelled())
{
yg::Tile tile(tileTarget, frameScreen, m_currentCommand->m_rectInfo, duration);
m_renderQueue->TileCache().lock();
m_renderQueue->TileCache().addTile(m_currentCommand->m_rectInfo, yg::TileCache::Entry(tile, m_resourceManager));
m_renderQueue->TileCache().unlock();
}
m_currentCommand.reset();
}
invalidate();
callRenderCommandFinishedFns();
}
}
@ -469,49 +199,11 @@ void RenderQueueRoutine::invalidate()
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_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<yg::gl::RenderContext> const & renderContext,
shared_ptr<yg::ResourceManager> const & resourceManager)
{
m_renderContext = renderContext;
m_resourceManager = resourceManager;
m_threadRenderer.init(renderContext->createShared(), m_renderState);
}
void RenderQueueRoutine::memoryWarning()
@ -540,4 +232,3 @@ void RenderQueueRoutine::callRenderCommandFinishedFns()
for (list<renderCommandFinishedFn>::const_iterator it = m_renderCommandFinishedFns.begin(); it != m_renderCommandFinishedFns.end(); ++it)
(*it)();
}

View file

@ -9,6 +9,8 @@
#include "../std/function.hpp"
#include "../yg/thread_renderer.hpp"
#include "../yg/color.hpp"
#include "../yg/tile_cache.hpp"
#include "../yg/tiler.hpp"
class DrawerYG;
@ -19,11 +21,13 @@ namespace threads
class PaintEvent;
class WindowHandle;
class RenderQueue;
namespace yg
{
class ResourceManager;
namespace gl
{
class RenderContext;
@ -43,74 +47,59 @@ public:
typedef function<void(shared_ptr<PaintEvent>, ScreenBase const &, m2::RectD const &, int)> render_fn_t;
typedef function<void()> renderCommandFinishedFn;
private:
threads::CommandsQueue m_threadRendererQueue;
yg::gl::ThreadRenderer m_threadRenderer;
struct RenderModelCommand
/// Single tile rendering command
struct Command
{
ScreenBase m_frameScreen;
yg::Tiler::RectInfo m_rectInfo;
shared_ptr<PaintEvent> m_paintEvent;
render_fn_t m_renderFn;
RenderModelCommand(ScreenBase const & frameScreen,
render_fn_t renderFn);
size_t m_seqNum;
Command(yg::Tiler::RectInfo const & rectInfo,
render_fn_t renderFn,
size_t seqNum); //< paintEvent is set later after construction
};
private:
shared_ptr<yg::gl::RenderContext> m_renderContext;
shared_ptr<yg::gl::FrameBuffer> m_frameBuffer;
shared_ptr<DrawerYG> m_threadDrawer;
shared_ptr<yg::gl::Screen> m_auxScreen;
threads::Condition m_hasRenderCommands;
shared_ptr<RenderModelCommand> m_currentRenderCommand;
list<shared_ptr<RenderModelCommand> > m_renderCommands;
list<shared_ptr<RenderModelCommand> > m_benchmarkRenderCommands;
shared_ptr<yg::gl::RenderState> m_renderState;
threads::Mutex m_mutex;
shared_ptr<Command> m_currentCommand;
shared_ptr<yg::ResourceManager> m_resourceManager;
/// A list of window handles to notify about ending rendering operations.
list<shared_ptr<WindowHandle> > 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<shared_ptr<RenderModelCommand> > & cmdList,
threads::ConditionGuard & guard);
size_t m_threadNum;
list<renderCommandFinishedFn> m_renderCommandFinishedFns;
RenderQueue * m_renderQueue;
void callRenderCommandFinishedFns();
public:
RenderQueueRoutine(shared_ptr<yg::gl::RenderState> const & renderState,
string const & skinName,
bool isMultiSampled,
bool doPeriodicalUpdate,
double updateInterval,
RenderQueueRoutine(string const & skinName,
bool isBenchmarking,
unsigned scaleEtalonSize,
yg::Color const & bgColor);
yg::Color const & bgColor,
size_t threadNum,
RenderQueue * renderQueue);
/// initialize GL rendering
/// this function is called just before the thread starts.
void initializeGL(shared_ptr<yg::gl::RenderContext> const & renderContext,
shared_ptr<yg::ResourceManager> 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<m2::RectI> & areas);
/// Thread procedure
void Do();
/// invalidate all connected window handles
@ -118,9 +107,9 @@ public:
/// add monitoring window
void addWindowHandle(shared_ptr<WindowHandle> window);
/// add model rendering command to rendering queue
void addCommand(render_fn_t const & fn, ScreenBase const & frameScreen);
void addCommand(render_fn_t const & fn, yg::Tiler::RectInfo const & rectInfo, size_t seqNumber);
/// add benchmark rendering command
void addBenchmarkCommand(render_fn_t const & fn, ScreenBase const & frameScreen);
// void addBenchmarkCommand(render_fn_t const & fn, m2::RectD const & globalRect);
/// set the resolution scale factor to the main thread drawer;
void setVisualScale(double visualScale);
/// free all available memory

View file

@ -56,7 +56,6 @@ namespace qt
"fonts_whitelist.txt",
"fonts_blacklist.txt",
2 * 1024 * 1024,
500 * 1024,
yg::Rt8Bpp,
!yg::gl::g_isBufferObjectsSupported,
!pl.IsMultiSampled()));

View file

@ -60,7 +60,6 @@ void GLDrawWidget::initializeGL()
"fonts_whitelist.txt",
"fonts_blacklist.txt",
2 * 1024 * 1024,
500 * 1024,
yg::Rt8Bpp,
!yg::gl::g_isBufferObjectsSupported,
!GetPlatform().IsMultiSampled()));

View file

@ -8,6 +8,7 @@
#include <functional>
using std::greater;
using std::less;
using std::greater;
using std::equal_to;
#ifdef DEBUG_NEW

View file

@ -40,14 +40,20 @@ namespace yg
void Blitter::blit(shared_ptr<BaseTexture> const & srcSurface,
ScreenBase const & from,
ScreenBase const & to,
bool isSubPixel,
yg::Color const & color,
m2::RectI const & srcRect,
m2::RectU const & texRect)
{
m2::PointF pt = to.GtoP(from.PtoG(m2::PointF(srcRect.minX(), srcRect.minY())));
pt.x = pt.x - my::rounds(pt.x);
pt.y = pt.y - my::rounds(pt.y);
if (!isSubPixel)
{
pt.x = pt.x - my::rounds(pt.x);
pt.y = pt.y - my::rounds(pt.y);
}
else
pt = m2::PointF(0, 0);
m2::PointF pts[4] =
{
@ -70,11 +76,13 @@ namespace yg
void Blitter::blit(shared_ptr<BaseTexture> const & srcSurface,
ScreenBase const & from,
ScreenBase const & to)
ScreenBase const & to,
bool isSubPixel)
{
blit(srcSurface,
from,
to,
isSubPixel,
yg::Color(),
m2::RectI(0, 0, srcSurface->width(), srcSurface->height()),
m2::RectU(0, 0, srcSurface->width(), srcSurface->height()));
@ -168,7 +176,7 @@ namespace yg
yg::Color const & color,
bool hasColor)
{
m_blitStorage = resourceManager()->blitStorages().Reserve();
m_blitStorage = resourceManager()->blitStorages().Front(true);
AuxVertex * pointsData = (AuxVertex*)m_blitStorage.m_vertices->lock();
@ -203,7 +211,7 @@ namespace yg
/// This call is necessary to avoid parasite blitting in updateActualTarget() on IPhone.
OGLCHECK(glFinish());
resourceManager()->blitStorages().Free(m_blitStorage);
resourceManager()->blitStorages().PushBack(m_blitStorage);
m_blitStorage = yg::gl::Storage();
}
}

View file

@ -45,13 +45,15 @@ namespace yg
void blit(shared_ptr<BaseTexture> const & srcSurface,
ScreenBase const & from,
ScreenBase const & to,
bool isSubPixel,
yg::Color const & color,
m2::RectI const & srcRect,
m2::RectU const & texRect);
void blit(shared_ptr<BaseTexture> const & srcSurface,
ScreenBase const & from,
ScreenBase const & to);
ScreenBase const & to,
bool isSubPixel = false);
void immDrawSolidRect(m2::RectF const & rect,
yg::Color const & color);

View file

@ -76,7 +76,7 @@ namespace yg
{
if (!m_hasStorage)
{
m_storage = usage != SkinPage::EStaticUsage ? resourceManager->storages().Reserve() : resourceManager->smallStorages().Reserve();
m_storage = usage != SkinPage::EStaticUsage ? resourceManager->storages().Front(true) : resourceManager->smallStorages().Front(true);
m_maxVertices = m_storage.m_vertices->size() / sizeof(Vertex);
m_maxIndices = m_storage.m_indices->size() / sizeof(unsigned short);
@ -220,9 +220,9 @@ namespace yg
renderedData = true;
if (skinPage->usage() != SkinPage::EStaticUsage)
resourceManager()->storages().Free(pipeline.m_storage);
resourceManager()->storages().PushBack(pipeline.m_storage);
else
resourceManager()->smallStorages().Free(pipeline.m_storage);
resourceManager()->smallStorages().PushBack(pipeline.m_storage);
pipeline.m_hasStorage = false;
pipeline.m_storage = Storage();

View file

@ -23,7 +23,8 @@ namespace yg
: TextRenderer(p),
m_useOverlay(p.m_useOverlay),
m_drawTexts(p.m_drawTexts),
m_drawSymbols(p.m_drawSymbols)
m_drawSymbols(p.m_drawSymbols),
m_infoLayer(p.m_infoLayer)
{
}
@ -45,10 +46,10 @@ namespace yg
SymbolElement se(params);
if (!renderState().get() || !m_useOverlay)
if (!m_infoLayer.get() || !m_useOverlay)
se.draw(this, math::Identity<double, 3>());
else
renderState()->m_currentInfoLayer->addSymbol(se);
m_infoLayer->addSymbol(se);
}
void OverlayRenderer::drawCircle(m2::PointD const & pt,
@ -88,10 +89,10 @@ namespace yg
StraightTextElement ste(params);
if (!renderState().get() || !m_useOverlay)
if (!m_infoLayer.get() || !m_useOverlay)
ste.draw(this, math::Identity<double, 3>());
else
renderState()->m_currentInfoLayer->addStraightText(ste);
m_infoLayer->addStraightText(ste);
}
bool OverlayRenderer::drawPathText(
@ -117,10 +118,10 @@ namespace yg
PathTextElement pte(params);
if (!renderState().get() || !m_useOverlay)
if (!m_infoLayer.get() || !m_useOverlay)
pte.draw(this, math::Identity<double, 3>());
else
renderState()->m_currentInfoLayer->addPathText(pte);
m_infoLayer->addPathText(pte);
return true;
}

View file

@ -1,6 +1,8 @@
#pragma once
#include "text_renderer.hpp"
#include "../std/shared_ptr.hpp"
#include "info_layer.hpp"
namespace yg
{
@ -13,6 +15,7 @@ namespace yg
bool m_useOverlay;
bool m_drawTexts;
bool m_drawSymbols;
shared_ptr<yg::InfoLayer> m_infoLayer;
public:
@ -21,6 +24,7 @@ namespace yg
bool m_useOverlay;
bool m_drawTexts;
bool m_drawSymbols;
shared_ptr<yg::InfoLayer> m_infoLayer;
Params();
};

View file

@ -47,52 +47,7 @@ namespace yg
}
void RenderStateUpdater::updateActualTarget()
{
/// Carefully synchronizing the access to the m_renderState to minimize wait time.
OGLCHECK(glFinish());
updateFrameBuffer();
{
threads::MutexGuard guard(*m_renderState->m_mutex.get());
swap(m_renderState->m_actualTarget, m_renderState->m_backBufferLayers.front());
// swap(m_renderState->m_actualInfoLayer, m_renderState->m_currentInfoLayer);
m_renderState->m_actualScreen = m_renderState->m_currentScreen;
}
/// copying info layer
// *m_renderState->m_currentInfoLayer.get() = *m_renderState->m_actualInfoLayer.get();
/// 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<BaseTexture> 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());
if (isMultiSampled())
multiSampledFrameBuffer()->makeCurrent();
m_renderState->invalidate();
}
{}
void RenderStateUpdater::beginFrame()
{

View file

@ -24,14 +24,15 @@ namespace yg
size_t blitVBSize, size_t blitIBSize, size_t blitStoragesCount,
size_t dynamicTexWidth, size_t dynamicTexHeight, size_t dynamicTexCount,
size_t fontTexWidth, size_t fontTexHeight, size_t fontTexCount,
size_t tileTexWidth, size_t tileTexHeight, size_t tileTexCount,
char const * blocksFile, char const * whiteListFile, char const * blackListFile,
size_t primaryGlyphCacheSize,
size_t secondaryGlyphCacheSize,
size_t glyphCacheSize,
RtFormat fmt,
bool useVA,
bool fillSkinAlpha)
: m_dynamicTextureWidth(dynamicTexWidth), m_dynamicTextureHeight(dynamicTexHeight),
m_fontTextureWidth(fontTexWidth), m_fontTextureHeight(fontTexHeight),
m_tileTextureWidth(tileTexWidth), m_tileTextureHeight(tileTexHeight),
m_vbSize(vbSize), m_ibSize(ibSize),
m_smallVBSize(smallVBSize), m_smallIBSize(smallIBSize),
m_blitVBSize(blitVBSize), m_blitIBSize(blitIBSize),
@ -40,9 +41,9 @@ namespace yg
m_fillSkinAlpha(fillSkinAlpha)
{
/// primary cache is for rendering, so it's big
m_glyphCaches.push_back(GlyphCache(GlyphCache::Params(blocksFile, whiteListFile, blackListFile, primaryGlyphCacheSize)));
/// secondary caches is for glyph metrics only, so they are small
m_glyphCaches.push_back(GlyphCache(GlyphCache::Params(blocksFile, whiteListFile, blackListFile, secondaryGlyphCacheSize)));
m_glyphCaches.push_back(GlyphCache(GlyphCache::Params(blocksFile, whiteListFile, blackListFile, glyphCacheSize / 3)));
m_glyphCaches.push_back(GlyphCache(GlyphCache::Params(blocksFile, whiteListFile, blackListFile, glyphCacheSize / 3)));
m_glyphCaches.push_back(GlyphCache(GlyphCache::Params(blocksFile, whiteListFile, blackListFile, glyphCacheSize / 3)));
if (useVA)
{
@ -50,24 +51,24 @@ namespace yg
}
for (size_t i = 0; i < storagesCount; ++i)
m_storages.Add(gl::Storage(vbSize, ibSize, m_useVA));
m_storages.PushBack(gl::Storage(vbSize, ibSize, m_useVA));
LOG(LINFO, ("allocating ", (vbSize + ibSize) * storagesCount, " bytes for main storage"));
for (size_t i = 0; i < smallStoragesCount; ++i)
m_smallStorages.Add(gl::Storage(smallVBSize, smallIBSize, m_useVA));
m_smallStorages.PushBack(gl::Storage(smallVBSize, smallIBSize, m_useVA));
LOG(LINFO, ("allocating ", (smallVBSize + smallIBSize) * smallStoragesCount, " bytes for small storage"));
for (size_t i = 0; i < blitStoragesCount; ++i)
m_blitStorages.Add(gl::Storage(blitVBSize, blitIBSize, m_useVA));
m_blitStorages.PushBack(gl::Storage(blitVBSize, blitIBSize, m_useVA));
LOG(LINFO, ("allocating ", (blitVBSize + blitIBSize) * blitStoragesCount, " bytes for blit storage"));
for (size_t i = 0; i < dynamicTexCount; ++i)
{
shared_ptr<gl::BaseTexture> t(new TDynamicTexture(dynamicTexWidth, dynamicTexHeight));
m_dynamicTextures.Add(t);
m_dynamicTextures.PushBack(t);
#ifdef DEBUG
static_cast<TDynamicTexture*>(t.get())->randomize();
#endif
@ -78,13 +79,21 @@ namespace yg
for (size_t i = 0; i < fontTexCount; ++i)
{
shared_ptr<gl::BaseTexture> t(new TDynamicTexture(fontTexWidth, fontTexHeight));
m_fontTextures.Add(t);
m_fontTextures.PushBack(t);
#ifdef DEBUG
static_cast<TDynamicTexture*>(t.get())->randomize();
#endif
}
LOG(LINFO, ("allocating ", fontTexWidth * fontTexHeight * sizeof(TDynamicTexture::pixel_t), " bytes for font textures"));
for (size_t i = 0; i < tileTexCount; ++i)
{
shared_ptr<gl::BaseTexture> t(new TStaticTexture(tileTexWidth, tileTexHeight));
m_renderTargets.PushBack(t);
}
LOG(LINFO, ("allocating ", tileTexWidth * tileTexHeight * sizeof(TStaticTexture::pixel_t), " bytes for tiles"));
}
shared_ptr<gl::BaseTexture> const & ResourceManager::getTexture(string const & fileName)
@ -144,6 +153,15 @@ namespace yg
return m_fontTextureHeight;
}
size_t ResourceManager::tileTextureWidth() const
{
return m_tileTextureWidth;
}
size_t ResourceManager::tileTextureHeight() const
{
return m_tileTextureHeight;
}
GlyphCache * ResourceManager::glyphCache(int glyphCacheID)
{
@ -184,16 +202,16 @@ namespace yg
threads::MutexGuard guard(m_mutex);
for (size_t i = 0; i < m_storagesCount; ++i)
m_storages.Add(gl::Storage(m_vbSize, m_ibSize, m_useVA));
m_storages.PushBack(gl::Storage(m_vbSize, m_ibSize, m_useVA));
for (size_t i = 0; i < m_smallStoragesCount; ++i)
m_smallStorages.Add(gl::Storage(m_smallVBSize, m_smallIBSize, m_useVA));
m_smallStorages.PushBack(gl::Storage(m_smallVBSize, m_smallIBSize, m_useVA));
for (size_t i = 0; i < m_blitStoragesCount; ++i)
m_blitStorages.Add(gl::Storage(m_blitVBSize, m_blitIBSize, m_useVA));
m_blitStorages.PushBack(gl::Storage(m_blitVBSize, m_blitIBSize, m_useVA));
for (size_t i = 0; i < m_dynamicTexturesCount; ++i)
m_dynamicTextures.Add(shared_ptr<gl::BaseTexture>(new TDynamicTexture(m_dynamicTextureWidth, m_dynamicTextureHeight)));
m_dynamicTextures.PushBack(shared_ptr<gl::BaseTexture>(new TDynamicTexture(m_dynamicTextureWidth, m_dynamicTextureHeight)));
for (size_t i = 0; i < m_fontTexturesCount; ++i)
m_fontTextures.Add(shared_ptr<gl::BaseTexture>(new TDynamicTexture(m_fontTextureWidth, m_fontTextureHeight)));
m_fontTextures.PushBack(shared_ptr<gl::BaseTexture>(new TDynamicTexture(m_fontTextureWidth, m_fontTextureHeight)));
}
shared_ptr<yg::gl::BaseTexture> ResourceManager::createRenderTarget(unsigned w, unsigned h)
@ -214,39 +232,43 @@ namespace yg
return m_fillSkinAlpha;
}
int ResourceManager::renderThreadGlyphCacheID() const
int ResourceManager::renderThreadGlyphCacheID(int threadNum) const
{
return 0;
return 1 + threadNum;
}
int ResourceManager::guiThreadGlyphCacheID() const
{
return 1;
return 0;
}
ObjectPool<gl::Storage> & ResourceManager::storages()
ThreadedList<gl::Storage> & ResourceManager::storages()
{
return m_storages;
}
ObjectPool<gl::Storage> & ResourceManager::smallStorages()
ThreadedList<gl::Storage> & ResourceManager::smallStorages()
{
return m_smallStorages;
}
ObjectPool<gl::Storage> & ResourceManager::blitStorages()
ThreadedList<gl::Storage> & ResourceManager::blitStorages()
{
return m_blitStorages;
}
ObjectPool<shared_ptr<gl::BaseTexture> > & ResourceManager::dynamicTextures()
ThreadedList<shared_ptr<gl::BaseTexture> > & ResourceManager::dynamicTextures()
{
return m_dynamicTextures;
}
ObjectPool<shared_ptr<gl::BaseTexture> > & ResourceManager::fontTextures()
ThreadedList<shared_ptr<gl::BaseTexture> > & ResourceManager::fontTextures()
{
return m_fontTextures;
}
ThreadedList<shared_ptr<gl::BaseTexture> > & ResourceManager::renderTargets()
{
return m_renderTargets;
}
}

View file

@ -6,7 +6,7 @@
#include "../std/list.hpp"
#include "../base/mutex.hpp"
#include "../base/object_pool.hpp"
#include "../base/threaded_list.hpp"
#include "storage.hpp"
#include "glyph_cache.hpp"
@ -42,12 +42,17 @@ namespace yg
size_t m_dynamicTextureWidth;
size_t m_dynamicTextureHeight;
ObjectPool<shared_ptr<gl::BaseTexture> > m_dynamicTextures;
ThreadedList<shared_ptr<gl::BaseTexture> > m_dynamicTextures;
size_t m_fontTextureWidth;
size_t m_fontTextureHeight;
ObjectPool<shared_ptr<gl::BaseTexture> > m_fontTextures;
ThreadedList<shared_ptr<gl::BaseTexture> > m_fontTextures;
size_t m_tileTextureWidth;
size_t m_tileTextureHeight;
ThreadedList<shared_ptr<gl::BaseTexture> > m_renderTargets;
size_t m_vbSize;
size_t m_ibSize;
@ -58,9 +63,9 @@ namespace yg
size_t m_blitVBSize;
size_t m_blitIBSize;
ObjectPool<gl::Storage> m_storages;
ObjectPool<gl::Storage> m_smallStorages;
ObjectPool<gl::Storage> m_blitStorages;
ThreadedList<gl::Storage> m_storages;
ThreadedList<gl::Storage> m_smallStorages;
ThreadedList<gl::Storage> m_blitStorages;
vector<GlyphCache> m_glyphCaches;
@ -82,20 +87,21 @@ namespace yg
size_t blitVBSize, size_t blitIBSize, size_t blitStoragesCount,
size_t texWidth, size_t texHeight, size_t texCount,
size_t fontTexWidth, size_t fontTexHeight, size_t fontTexCount,
size_t tileTexWidth, size_t tileTexHeight, size_t tileTexCount,
char const * blocksFile, char const * whileListFile, char const * blackListFile,
size_t primaryGlyphCacheSize,
size_t secondaryGlyphCacheSize,
size_t glyphCacheSize,
RtFormat fmt,
bool useVA,
bool fillSkinAlpha);
shared_ptr<gl::BaseTexture> const & getTexture(string const & fileName);
ObjectPool<gl::Storage> & storages();
ObjectPool<gl::Storage> & smallStorages();
ObjectPool<gl::Storage> & blitStorages();
ObjectPool<shared_ptr<gl::BaseTexture> > & dynamicTextures();
ObjectPool<shared_ptr<gl::BaseTexture> > & fontTextures();
ThreadedList<gl::Storage> & storages();
ThreadedList<gl::Storage> & smallStorages();
ThreadedList<gl::Storage> & blitStorages();
ThreadedList<shared_ptr<gl::BaseTexture> > & dynamicTextures();
ThreadedList<shared_ptr<gl::BaseTexture> > & fontTextures();
ThreadedList<shared_ptr<gl::BaseTexture> > & renderTargets();
size_t dynamicTextureWidth() const;
size_t dynamicTextureHeight() const;
@ -103,11 +109,14 @@ namespace yg
size_t fontTextureWidth() const;
size_t fontTextureHeight() const;
size_t tileTextureWidth() const;
size_t tileTextureHeight() const;
shared_ptr<GlyphInfo> const getGlyphInfo(GlyphKey const & key);
GlyphMetrics const getGlyphMetrics(GlyphKey const & key);
GlyphCache * glyphCache(int glyphCacheID = 0);
int renderThreadGlyphCacheID() const;
int renderThreadGlyphCacheID(int threadNum) const;
int guiThreadGlyphCacheID() const;
void addFonts(vector<string> const & fontNames);

View file

@ -750,10 +750,10 @@ namespace yg
switch (m_usage)
{
case EDynamicUsage:
m_resourceManager->dynamicTextures().Free(m_texture);
m_resourceManager->dynamicTextures().PushBack(m_texture);
break;
case EFontsUsage:
m_resourceManager->fontTextures().Free(m_texture);
m_resourceManager->fontTextures().PushBack(m_texture);
break;
default:
LOG(LINFO, ("freeTexture call for with invalid usage param"));
@ -768,10 +768,10 @@ namespace yg
switch (m_usage)
{
case EDynamicUsage:
m_texture = m_resourceManager->dynamicTextures().Reserve();
m_texture = m_resourceManager->dynamicTextures().Front(true);
break;
case EFontsUsage:
m_texture = m_resourceManager->fontTextures().Reserve();
m_texture = m_resourceManager->fontTextures().Front(true);
break;
default:
LOG(LINFO, ("freeTexture call for with invalid usage param"));

View file

@ -28,6 +28,20 @@ namespace yg
template <typename Traits>
class Texture<Traits, false> : public BaseTexture
{
public:
typedef Traits traits_t;
typedef typename Traits::pixel_t pixel_t;
typedef typename Traits::const_pixel_t const_pixel_t;
typedef typename Traits::view_t view_t;
typedef typename Traits::const_view_t const_view_t;
typedef typename Traits::image_t image_t;
static const int maxChannelVal = Traits::maxChannelVal;
static const int channelScaleFactor = Traits::channelScaleFactor;
static const int gl_pixel_data_type = Traits::gl_pixel_data_type;
static const int gl_pixel_format_type = Traits::gl_pixel_format_type;
private:
void upload(void * data)

View file

@ -3,16 +3,30 @@
#include "../geometry/screenbase.hpp"
#include "../std/shared_ptr.hpp"
#include "base_texture.hpp"
#include "renderbuffer.hpp"
#include "resource_manager.hpp"
#include "tiler.hpp"
namespace yg
{
struct Tile
{
shared_ptr<gl::RenderBuffer> m_depthBuffer; //< taken from resource manager
shared_ptr<gl::BaseTexture> m_renderTarget; //< taken from resource manager
ScreenBase m_tileScreen;
ScreenBase m_tileScreen; //< cached to calculate it once, cause tile blitting
//< is performed on GUI thread.
Tiler::RectInfo m_rectInfo; //< taken from tiler
double m_duration;
Tile()
{}
Tile(shared_ptr<gl::BaseTexture> const & renderTarget,
ScreenBase const & tileScreen,
Tiler::RectInfo const & rectInfo,
double duration)
: m_renderTarget(renderTarget),
m_tileScreen(tileScreen),
m_rectInfo(rectInfo),
m_duration(duration)
{}
};
}

View file

@ -1,20 +1,23 @@
#include "tile_cache.hpp"
#include "../std/cmath.hpp"
namespace yg
{
TileCache::TileCache(size_t tileMemSize, size_t memSize)
: m_cache(log(memSize / static_cast<double>(tileMemSize)) / log(2.0))
TileCache::Entry::Entry()
{}
TileCache::Entry::Entry(Tile const & tile, shared_ptr<yg::ResourceManager> const & rm)
: m_tile(tile), m_rm(rm)
{}
TileCache::TileCache(size_t maxCacheSize)
: m_cache(maxCacheSize)
{
}
void TileCache::addTile(Tiler::RectInfo const & key, Tile const & value)
void TileCache::addTile(Tiler::RectInfo const & key, Entry const & entry)
{
bool found;
Tile & cachedVal = m_cache.Find(key.toUInt64Cell(), found);
cachedVal = value;
m_cache.Add(key.toUInt64Cell(), entry, 1);
}
void TileCache::lock()
@ -29,12 +32,11 @@ namespace yg
bool TileCache::hasTile(Tiler::RectInfo const & key)
{
return m_cache.HasKey(key.toUInt64Cell());
return m_cache.HasElem(key.toUInt64Cell());
}
Tile const & TileCache::getTile(Tiler::RectInfo const & key)
{
bool found;
return m_cache.Find(key.toUInt64Cell(), found);
return m_cache.Find(key.toUInt64Cell()).m_tile;
}
}

View file

@ -2,27 +2,48 @@
#include "tile.hpp"
#include "tiler.hpp"
#include "../base/cache.hpp"
#include "../base/mru_cache.hpp"
#include "../base/mutex.hpp"
namespace yg
{
class ResourceManager;
class TileCache
{
public:
struct Entry
{
Tile m_tile;
shared_ptr<yg::ResourceManager> m_rm;
Entry();
Entry(Tile const & tile, shared_ptr<yg::ResourceManager> const & rm);
};
struct EntryValueTraits
{
static void Evict(Entry & val)
{
if (val.m_rm)
val.m_rm->renderTargets().PushBack(val.m_tile.m_renderTarget);
}
};
private:
my::Cache<uint64_t, Tile> m_cache;
my::MRUCache<uint64_t, Entry, EntryValueTraits> m_cache;
threads::Mutex m_mutex;
public:
TileCache(size_t tileMemSize, size_t memSize);
TileCache(size_t maxCacheSize);
/// lock for multithreaded access
void lock();
/// unlock for multithreaded access
void unlock();
/// add tile to cache
void addTile(Tiler::RectInfo const & key, Tile const & value);
void addTile(Tiler::RectInfo const & key, Entry const & entry);
/// check, whether we have some tile in the cache
bool hasTile(Tiler::RectInfo const & key);
/// get tile from the cache

View file

@ -2,6 +2,7 @@
#include "tiler.hpp"
#include "../indexer/mercator.hpp"
#include "../indexer/scales.hpp"
#include "../base/logging.hpp"
namespace yg
{
@ -22,7 +23,7 @@ namespace yg
}
Tiler::RectInfo::RectInfo()
: m_scale(0), m_x(0), m_y(0), m_coverage(0), m_distance(0)
: m_scale(0), m_x(0), m_y(0), m_distance(0), m_coverage(0)
{}
Tiler::RectInfo::RectInfo(int scale, int x, int y, m2::RectD const & globRect)
@ -55,18 +56,30 @@ namespace yg
bool operator<(Tiler::RectInfo const & l, Tiler::RectInfo const & r)
{
if (l.m_coverage != r.m_coverage)
return l.m_coverage < r.m_coverage;
return l.m_coverage > r.m_coverage;
return l.m_distance < r.m_distance;
}
bool operator>(Tiler::RectInfo const & l, Tiler::RectInfo const & r)
{
if (l.m_coverage != r.m_coverage)
return l.m_coverage < r.m_coverage;
return l.m_distance > r.m_distance;
}
void Tiler::seed(ScreenBase const & screen, int scaleEtalonSize)
{
if (screen != m_screen)
++m_seqNum;
m2::RectD glbRect;
m2::PointD pxCenter = screen.PixelRect().Center();
screen.PtoG(m2::RectD(pxCenter - m2::PointD(scaleEtalonSize / 2, scaleEtalonSize / 2),
pxCenter + m2::PointD(scaleEtalonSize / 2, scaleEtalonSize / 2)),
glbRect);
glbRect);
m_scale = scales::GetScaleLevel(glbRect);
m_screen = screen;
@ -80,11 +93,26 @@ namespace yg
int minTileY = floor(screenRect.minY() / rectSizeY);
int maxTileY = ceil(screenRect.maxY() / rectSizeY);
unsigned rectCount = 0;
/// clearing previous coverage
while (!m_coverage.empty())
m_coverage.pop();
for (int tileY = minTileY; tileY < maxTileY; ++tileY)
for (int tileX = minTileX; tileX < maxTileX; ++tileX)
{
m_coverage.push(RectInfo(m_scale, tileX, tileY, screenRect));
++rectCount;
}
LOG(LINFO, ("Tiler coverage contains ", rectCount, " rectangles"));
}
Tiler::Tiler() : m_seqNum(0)
{}
bool Tiler::hasTile()
{
return !m_coverage.empty();
@ -96,4 +124,9 @@ namespace yg
m_coverage.pop();
return r;
}
size_t Tiler::seqNum() const
{
return m_seqNum;
}
}

View file

@ -3,6 +3,7 @@
#include "../geometry/screenbase.hpp"
#include "../geometry/rect2d.hpp"
#include "../std/queue.hpp"
#include "../std/functional.hpp"
namespace yg
{
@ -35,11 +36,14 @@ namespace yg
ScreenBase m_screen;
int m_scale;
size_t m_seqNum;
priority_queue<RectInfo> m_coverage;
priority_queue<RectInfo, vector<RectInfo>, greater<RectInfo> > m_coverage;
public:
Tiler();
/// seed tiler with new screenBase.
/// if there are an existing tile sequence it is
/// reorganized to reflect screen changes.
@ -49,7 +53,10 @@ namespace yg
bool hasTile();
/// pop tile from the sequence and return it
RectInfo const nextTile();
size_t seqNum() const;
};
bool operator <(Tiler::RectInfo const & l, Tiler::RectInfo const & r);
bool operator >(Tiler::RectInfo const & l, Tiler::RectInfo const & r);
}

View file

@ -8,6 +8,6 @@
UNIT_TEST(SkinLoaderTest_Main)
{
GL_TEST_START;
shared_ptr<yg::ResourceManager> rm(new yg::ResourceManager(1000, 1000, 2, 1000, 1000, 2, 1000, 1000, 2, 128, 128, 15, 256, 256, 5, "", "", "", 2 * 1024 * 1024, 500 * 1024, yg::Rt8Bpp, false, false));
shared_ptr<yg::ResourceManager> rm(new yg::ResourceManager(1000, 1000, 2, 1000, 1000, 2, 1000, 1000, 2, 128, 128, 15, 256, 256, 5, 256, 256, 40, "", "", "", 2 * 1024 * 1024, yg::Rt8Bpp, false, false));
/*yg::Skin * skin = */loadSkin(rm, "basic.skn", 2, 2);
};

View file

@ -10,7 +10,7 @@ UNIT_TEST(SkinTest_Main)
{
GL_TEST_START;
shared_ptr<yg::ResourceManager> rm(new yg::ResourceManager(100, 100, 1, 100, 100, 1, 100, 100, 1, 128, 128, 15, 256, 256, 5, "", "", "", 2 * 1024 * 1024, 500 * 1024, yg::Rt8Bpp, false, false));
shared_ptr<yg::ResourceManager> rm(new yg::ResourceManager(100, 100, 1, 100, 100, 1, 100, 100, 1, 128, 128, 15, 256, 256, 5, 256, 256, 40, "", "", "", 2 * 1024 * 1024, yg::Rt8Bpp, false, false));
yg::Skin * skin = loadSkin(rm, "test.skn", 2, 2);
double p0 [] = {1, 1};