implemented cancellation of unnecessary commands. fixed corresponding deadlock, when the starvation on primaryStorages has been occurring.

This commit is contained in:
rachytski 2012-01-04 18:52:51 +04:00 committed by Alex Zolotarev
parent b9fe677fff
commit 99a00dda73
20 changed files with 222 additions and 69 deletions

View file

@ -6,9 +6,8 @@
FenceManager::FenceManager(int conditionPoolSize)
: m_currentFence(0)
{
m_conditionPool.resize(conditionPoolSize);
for (unsigned i = 0; i < m_conditionPool.size(); ++i)
m_conditionPool[i] = new threads::Condition();
for (unsigned i = 0; i < conditionPoolSize; ++i)
m_conditionPool.push_back(new threads::Condition());
}
FenceManager::~FenceManager()
@ -21,10 +20,8 @@ FenceManager::~FenceManager()
delete it->second;
}
for (unsigned i = 0; i < m_conditionPool.size(); ++i)
{
delete m_conditionPool[i];
}
for (list<threads::Condition*>::iterator it = m_conditionPool.begin(); it != m_conditionPool.end(); ++it)
delete *it;
}
int FenceManager::insertFence()
@ -34,8 +31,8 @@ int FenceManager::insertFence()
if (m_conditionPool.empty())
return -1;
threads::Condition * cond = m_conditionPool.back();
m_conditionPool.pop_back();
threads::Condition * cond = m_conditionPool.front();
m_conditionPool.pop_front();
int id = m_currentFence++;
@ -52,20 +49,20 @@ void FenceManager::signalFence(int id)
if (it == m_activeFences.end())
{
LOG(LWARNING, ("fence with id", id, "has been already signalled or hasn't been installed yet"));
LOG(LINFO, ("fence with id", id, "has been already signalled or hasn't been installed yet"));
return;
}
threads::Condition * cond = it->second;
/// signalling to all waiting fences
cond->Signal(true);
/// erasing fence from active fences
m_activeFences.erase(it);
/// returning condition to the pool
m_conditionPool.push_back(cond);
/// signalling to all waiting fences
cond->Signal(true);
}
void FenceManager::joinFence(int id)
@ -78,7 +75,7 @@ void FenceManager::joinFence(int id)
if (it == m_activeFences.end())
{
LOG(LWARNING, ("fence with id", id, "has been already reached in the past or hasn't been installed yet"));
LOG(LINFO, ("fence with id", id, "has been already reached in the past or hasn't been installed yet"));
return;
}

View file

@ -4,14 +4,14 @@
#include "../base/mutex.hpp"
#include "../std/map.hpp"
#include "../std/vector.hpp"
#include "../std/list.hpp"
class FenceManager
{
private:
threads::Mutex m_mutex;
vector<threads::Condition *> m_conditionPool;
list<threads::Condition *> m_conditionPool;
map<int, threads::Condition *> m_activeFences;
int m_currentFence;

View file

@ -75,10 +75,20 @@ public:
{
double StartWaitTime = m_Timer.ElapsedSeconds();
bool doFirstWait = true;
while ((m_isEmpty = m_list.empty()))
{
if (IsCancelled())
break;
if (doFirstWait)
{
doFirstWait = false;
if (!m_resName.empty())
LOG(LINFO, ("consumer is waiting for", m_resName));
}
m_Cond.Wait();
}

View file

@ -77,22 +77,33 @@ void QueuedRenderPolicy::RenderQueuedCommands(int pipelineNum)
list<yg::gl::Packet>::iterator it;
yg::gl::Packet::EType bucketType = m_Pipelines[pipelineNum].m_Type;
for (it = m_Pipelines[pipelineNum].m_FrameBucket.begin();
it != m_Pipelines[pipelineNum].m_FrameBucket.end();
++it)
{
if (it->m_state)
{
it->m_state->m_isDebugging = m_IsDebugging;
it->m_state->apply(curState.get());
curState = it->m_state;
}
if (it->m_command)
{
it->m_command->setIsDebugging(m_IsDebugging);
it->m_command->perform();
}
if (bucketType == yg::gl::Packet::ECancelPoint)
{
if (it->m_command)
it->m_command->cancel();
}
else
{
ASSERT(bucketType == yg::gl::Packet::ECheckPoint, ());
if (it->m_state)
{
it->m_state->m_isDebugging = m_IsDebugging;
it->m_state->apply(curState.get());
curState = it->m_state;
}
if (it->m_command)
it->m_command->perform();
}
}
/// should clear to release resources, refered from the stored commands.
@ -111,7 +122,7 @@ void QueuedRenderPolicy::PacketsPipeline::FillFrameBucket(list<yg::gl::Packet> &
{
m_FrameBucket.clear();
/// searching for "group boundary" markers
/// searching for "delimiter" markers
list<yg::gl::Packet>::iterator first = renderQueue.begin();
list<yg::gl::Packet>::iterator last = renderQueue.begin();
@ -121,7 +132,8 @@ void QueuedRenderPolicy::PacketsPipeline::FillFrameBucket(list<yg::gl::Packet> &
while ((packetsLeft != 0) && (last != renderQueue.end()))
{
yg::gl::Packet p = *last;
if (p.m_groupBoundary)
if ((p.m_type == yg::gl::Packet::ECheckPoint)
|| (p.m_type == yg::gl::Packet::ECancelPoint))
{
/// found frame boundary, copying
copy(first, ++last, back_inserter(m_FrameBucket));
@ -129,6 +141,9 @@ void QueuedRenderPolicy::PacketsPipeline::FillFrameBucket(list<yg::gl::Packet> &
renderQueue.erase(first, last);
first = renderQueue.begin();
last = renderQueue.begin();
m_Type = p.m_type;
if (m_Type == yg::gl::Packet::ECancelPoint)
break;
}
else
++last;
@ -137,12 +152,28 @@ void QueuedRenderPolicy::PacketsPipeline::FillFrameBucket(list<yg::gl::Packet> &
}
}
void QueuedRenderPolicy::CopyQueuedCommands(list<yg::gl::Packet> &l, list<yg::gl::Packet> &r)
{
swap(l, r);
}
void QueuedRenderPolicy::DismissQueuedCommands(int pipelineNum)
{
while (!m_Pipelines[pipelineNum].m_Queue.Empty())
if (m_IsDebugging)
LOG(LINFO, ("cancelling packetsQueue for pipeline", pipelineNum));
m_Pipelines[pipelineNum].m_Queue.cancel();
list<yg::gl::Packet> l;
m_Pipelines[pipelineNum].m_Queue.ProcessList(bind(&QueuedRenderPolicy::CopyQueuedCommands, this, _1, ref(l)));
for (list<yg::gl::Packet>::iterator it = l.begin(); it != l.end(); ++it)
{
yg::gl::Packet p = m_Pipelines[pipelineNum].m_Queue.Back(true);
if (p.m_groupBoundary)
yg::gl::Packet p = *it;
if ((p.m_type == yg::gl::Packet::ECheckPoint)
|| (p.m_type == yg::gl::Packet::ECancelPoint))
{
if (p.m_command)
p.m_command->perform();

View file

@ -15,6 +15,7 @@ private:
{
yg::gl::PacketsQueue m_Queue; //< all enqueued commands
list<yg::gl::Packet> m_FrameBucket; //< list of commands to execute on current frame
yg::gl::Packet::EType m_Type;
void FillFrameBucket(list<yg::gl::Packet> & QueueData);
};
@ -29,6 +30,8 @@ private:
protected:
void CopyQueuedCommands(list<yg::gl::Packet> & l, list<yg::gl::Packet> & r);
void RenderQueuedCommands(int pipelineNum);
void DismissQueuedCommands(int pipelineNum);

View file

@ -443,6 +443,10 @@ void RenderQueueRoutine::Do()
glbRect,
scaleLevel);
/// all unprocessed commands should be cancelled
if (m_currentRenderCommand->m_paintEvent->isCancelled() && m_glQueue)
m_glQueue->insertCancelPoint();
if (!m_renderState->m_isEmptyModelCurrent)
cumulativeEmptyModelCurrent = m_renderState->m_isEmptyModelCurrent;
@ -519,6 +523,11 @@ void RenderQueueRoutine::Invalidate::perform()
bind(&WindowHandle::invalidate, _1));
}
void RenderQueueRoutine::Invalidate::cancel()
{
perform();
}
void RenderQueueRoutine::invalidate()
{
for_each(m_windowHandles.begin(),
@ -529,7 +538,7 @@ void RenderQueueRoutine::invalidate()
{
shared_ptr<Invalidate> command(new Invalidate());
command->m_windowHandles = m_windowHandles;
m_glQueue->PushBack(yg::gl::Packet(command, true));
m_glQueue->processPacket(yg::gl::Packet(command, yg::gl::Packet::ECheckPoint));
}
}

View file

@ -57,6 +57,7 @@ private:
{
list<shared_ptr<WindowHandle> > m_windowHandles;
void perform();
void cancel();
};
shared_ptr<yg::gl::RenderContext> m_renderContext;

View file

@ -28,7 +28,8 @@ TileRenderer::TileRenderer(
m_renderFn(renderFn),
m_skinName(skinName),
m_bgColor(bgColor),
m_sequenceID(0)
m_sequenceID(0),
m_isExiting(false)
{
m_resourceManager = rm;
m_primaryContext = primaryRC;
@ -74,7 +75,7 @@ TileRenderer::TileRenderer(
TileRenderer::~TileRenderer()
{
LOG(LINFO, ("deleting tile renderer"));
m_isExiting = true;
m_queue.Cancel();
}
@ -175,17 +176,35 @@ void TileRenderer::DrawTile(core::CommandsQueue::Environment const & env,
if (!env.isCancelled())
drawer->screen()->resetInfoLayer();
yg::gl::PacketsQueue * glQueue = threadData.m_drawerParams.m_renderQueue;
if (!env.isCancelled())
{
yg::gl::PacketsQueue * glQueue = threadData.m_drawerParams.m_renderQueue;
if (glQueue)
{
glQueue->insertCheckPoint();
glQueue->completeCommands();
}
}
else
{
if (!m_isExiting)
{
if (glQueue)
{
glQueue->insertCancelPoint();
glQueue->completeCommands();
}
}
}
double duration = timer.ElapsedSeconds();
if (env.isCancelled())
m_resourceManager->renderTargetTextures()->Free(tileTarget);
{
if (!m_isExiting)
m_resourceManager->renderTargetTextures()->Free(tileTarget);
}
else
AddTile(rectInfo, Tile(tileTarget, tileInfoLayer, frameScreen, rectInfo, duration));
}

View file

@ -53,6 +53,7 @@ protected:
string m_skinName;
yg::Color m_bgColor;
int m_sequenceID;
bool m_isExiting;
void InitializeThreadGL(core::CommandsQueue::Environment const & env);
void FinalizeThreadGL(core::CommandsQueue::Environment const & env);

View file

@ -42,7 +42,7 @@ TilingRenderPolicyST::TilingRenderPolicyST(VideoTimer * videoTimer,
sizeof(yg::gl::Vertex),
10000 * sizeof(unsigned short),
sizeof(unsigned short),
4,
12,
true,
false,
2,
@ -188,12 +188,12 @@ TilingRenderPolicyST::~TilingRenderPolicyST()
LOG(LINFO, ("deleting TilingRenderPolicyST"));
base_t::DismissQueuedCommands(0);
base_t::DismissQueuedCommands(1);
LOG(LINFO, ("reseting coverageGenerator"));
m_coverageGenerator.reset();
base_t::DismissQueuedCommands(1);
base_t::DismissQueuedCommands(0);
LOG(LINFO, ("reseting tileRenderer"));
m_tileRenderer.reset();

View file

@ -25,7 +25,7 @@ namespace yg
base_t::beginFrame();
m_areasCount = 0;
m_trianglesCount = 0;
};
}
void AreaRenderer::endFrame()
{

View file

@ -110,6 +110,11 @@ namespace yg
m_storagePool->Free(m_storage);
}
void GeometryBatcher::FreeStorage::cancel()
{
perform();
}
void GeometryBatcher::freeStorage(int pipelineID)
{
GeometryPipeline & pipeline = m_pipelines[pipelineID];
@ -329,6 +334,11 @@ namespace yg
m_texturePool->Free(m_texture);
}
void GeometryBatcher::FreeTexture::cancel()
{
perform();
}
void GeometryBatcher::freeTexture(int pipelineID)
{
if (!m_skin->getPage(pipelineID)->hasTexture())
@ -371,6 +381,11 @@ namespace yg
m_storage.m_indices->unlock();
}
void GeometryBatcher::UnlockStorage::cancel()
{
perform();
}
void GeometryBatcher::unlockPipeline(int pipelineID)
{
GeometryPipeline & pipeline = m_pipelines[pipelineID];
@ -390,6 +405,11 @@ namespace yg
m_storage.m_indices->discard();
}
void GeometryBatcher::DiscardStorage::cancel()
{
perform();
}
void GeometryBatcher::discardPipeline(int pipelineID)
{
GeometryPipeline & pipeline = m_pipelines[pipelineID];

View file

@ -90,6 +90,7 @@ namespace yg
Storage m_storage;
void perform();
void cancel();
};
struct FreeTexture : public Command
@ -98,6 +99,7 @@ namespace yg
shared_ptr<BaseTexture> m_texture;
void perform();
void cancel();
};
struct UnlockStorage : public Command
@ -105,6 +107,7 @@ namespace yg
Storage m_storage;
void perform();
void cancel();
};
struct DiscardStorage : public Command
@ -112,6 +115,7 @@ namespace yg
Storage m_storage;
void perform();
void cancel();
};
public:

View file

@ -1,4 +1,5 @@
#include "packets_queue.hpp"
#include "../base/logging.hpp"
namespace yg
{
@ -28,37 +29,52 @@ namespace yg
Command::~Command()
{}
void Command::cancel()
{
if ((m_isDebugging) && (!m_name.empty()))
LOG(LINFO, ("cancelling", m_name, "command"));
}
void Command::perform()
{
if ((m_isDebugging) && (!m_name.empty()))
LOG(LINFO, ("performing", m_name, "command"));
}
Packet::Packet()
: m_groupBoundary(true)
{}
Packet::Packet(bool groupBoundary)
: m_groupBoundary(groupBoundary)
Packet::Packet(EType type)
: m_type(type)
{}
Packet::Packet(shared_ptr<Command> const & command,
bool groupBoundary)
Packet::Packet(shared_ptr<Command> const & command, EType type)
: m_command(command),
m_groupBoundary(groupBoundary)
m_type(type)
{}
Packet::Packet(shared_ptr<BaseState> const & state,
shared_ptr<Command> const & command,
bool groupBoundary)
EType type)
: m_state(state),
m_command(command),
m_groupBoundary(groupBoundary)
m_type(type)
{
if (m_state && m_command)
m_state->m_isDebugging = m_command->isDebugging();
}
PacketsQueue::PacketsQueue() : m_fenceManager(10)
PacketsQueue::PacketsQueue() : m_fenceManager(5)
{}
void PacketsQueue::markFrameBoundary()
void PacketsQueue::insertCheckPoint()
{
PushBack(Packet(true));
processPacket(Packet(Packet::ECheckPoint));
}
void PacketsQueue::insertCancelPoint()
{
processPacket(Packet(Packet::ECancelPoint));
}
struct SignalFence : public Command
@ -74,12 +90,17 @@ namespace yg
{
m_fenceManager->signalFence(m_id);
}
void cancel()
{
perform();
}
};
int PacketsQueue::insertFence()
{
int id = m_fenceManager.insertFence();
PushBack(Packet(make_shared_ptr(new SignalFence(id, &m_fenceManager)), true));
processPacket(Packet(make_shared_ptr(new SignalFence(id, &m_fenceManager)), Packet::ECheckPoint));
return id;
}
@ -92,5 +113,21 @@ namespace yg
{
joinFence(insertFence());
}
void PacketsQueue::cancel()
{
Cancel();
}
void PacketsQueue::processPacket(Packet const & packet)
{
if (IsCancelled())
{
if (packet.m_command)
packet.m_command->cancel();
}
else
PushBack(packet);
}
}
}

View file

@ -23,7 +23,10 @@ namespace yg
struct Command
{
private:
bool m_isDebugging;
string m_name;
public:
bool isDebugging() const;
@ -32,27 +35,36 @@ namespace yg
Command();
virtual ~Command();
virtual void perform() = 0;
virtual void perform();
virtual void cancel();
friend class Renderer;
};
struct Packet
{
shared_ptr<BaseState> m_state;
shared_ptr<Command> m_command;
bool m_groupBoundary;
enum EType
{
ECommand,
ECheckPoint,
ECancelPoint
};
explicit Packet();
shared_ptr<BaseState> m_state;
shared_ptr<Command> m_command;
EType m_type;
Packet();
/// empty packet act as a frame delimiter
explicit Packet(bool groupBoundary);
explicit Packet(EType type);
/// non-opengl command, without any state
explicit Packet(shared_ptr<Command> const & command,
bool groupBoundary);
Packet(shared_ptr<Command> const & command,
EType type);
/// opengl command with state
explicit Packet(shared_ptr<BaseState> const & state,
shared_ptr<Command> const & command,
bool groupBoundary);
Packet(shared_ptr<BaseState> const & state,
shared_ptr<Command> const & command,
EType type);
};
class PacketsQueue : public ThreadedList<Packet>
@ -65,7 +77,11 @@ namespace yg
PacketsQueue();
void markFrameBoundary();
void processPacket(Packet const & packet);
void cancel();
void insertCheckPoint();
void insertCancelPoint();
int insertFence();
void joinFence(int id);

View file

@ -345,7 +345,7 @@ namespace yg
return m_isDebugging;
}
void Renderer::processCommand(shared_ptr<Command> const & command)
void Renderer::processCommand(shared_ptr<Command> const & command, Packet::EType type)
{
// command->m_isDebugging = false;
command->m_isDebugging = renderQueue();
@ -354,7 +354,7 @@ namespace yg
{
shared_ptr<BaseState> state = createState();
getState(state.get());
m_renderQueue->PushBack(Packet(state, command, false));
m_renderQueue->processPacket(Packet(state, command, type));
}
else
command->perform();
@ -368,7 +368,7 @@ namespace yg
void Renderer::markFrameBoundary()
{
if (m_renderQueue)
m_renderQueue->PushBack(Packet(true));
m_renderQueue->processPacket(Packet(Packet::ECheckPoint));
}
}
}

View file

@ -120,7 +120,7 @@ namespace yg
virtual void getState(BaseState * state);
void processCommand(shared_ptr<Command> const & command);
void processCommand(shared_ptr<Command> const & command, Packet::EType type = Packet::ECommand);
PacketsQueue * renderQueue();
/// insert empty packet into glQueue to mark the frame boundary

View file

@ -361,6 +361,10 @@ namespace yg
static_cast<gl::ManagedTexture*>(m_texture.get())->unlock();
}
void SkinPage::UploadData::cancel()
{
perform();
}
void SkinPage::uploadData(yg::gl::PacketsQueue * glQueue)
{
@ -371,7 +375,7 @@ namespace yg
shared_ptr<UploadData> cmd(new UploadData(m_uploadQueue, m_texture));
if (glQueue)
glQueue->PushBack(yg::gl::Packet(cmd, false));
glQueue->processPacket(yg::gl::Packet(cmd, yg::gl::Packet::ECommand));
else
cmd->perform();

View file

@ -107,6 +107,7 @@ namespace yg
shared_ptr<yg::gl::BaseTexture> const & texture);
void perform();
void cancel();
};
void clearColorHandles();

View file

@ -55,7 +55,7 @@ namespace yg
m_cachePage->uploadData(m_glQueue);
if (m_glQueue)
m_glQueue->PushBack(yg::gl::Packet(make_shared_ptr(new yg::gl::Renderer::FinishCommand()), false));
m_glQueue->processPacket(yg::gl::Packet(make_shared_ptr(new yg::gl::Renderer::FinishCommand()), yg::gl::Packet::ECommand));
/// waiting for upload to complete
if (m_glQueue)