Optimise HierarchicalPathfinder::Update by speeding up the chunk dirtiness check.

By adding a custom function in Grid, the code gets vectorised on both
gcc and clang, resulting in much faster code and faster update times,
sometimes substantially (on giant maps or when few chunks must be
updated).

Reviewed By: mimo
Differential Revision: https://code.wildfiregames.com/D73
This was SVN commit r20630.
This commit is contained in:
wraitii 2017-12-10 08:59:43 +00:00
parent 1933461009
commit f7aa7ac79e
6 changed files with 31 additions and 23 deletions

View File

@ -21,9 +21,11 @@
#include <vector>
#include "maths/Vector2D.h"
#include "simulation2/helpers/Grid.h"
#include "simulation2/helpers/Player.h"
template<typename T>
class Grid;
/**
* Describes an outline of a territory, where the latter are understood to mean the largest sets of mutually connected tiles
* ('connected' as in the mathematical sense from graph theory) that are either all reachable or all unreachable from a root

View File

@ -18,9 +18,10 @@
#include "lib/ogl.h"
#include "maths/Matrix3D.h"
#include "simulation2/helpers/Grid.h"
class CSimulation2;
template<typename T>
class Grid;
/**
* Maintains the territory boundary texture, used for

View File

@ -20,10 +20,12 @@
#include "simulation2/system/Interface.h"
#include "simulation2/helpers/Grid.h"
#include "simulation2/helpers/Player.h"
#include "simulation2/components/ICmpPosition.h"
template<typename T>
class Grid;
class ICmpTerritoryManager : public IComponent
{
public:

View File

@ -102,6 +102,22 @@ public:
return m_W == 0 && m_H == 0;
}
bool any_set_in_square(int i0, int j0, int i1, int j1) const
{
#if GRID_BOUNDS_DEBUG
ENSURE(i0 >= 0 && j0 >= 0 && i1 < m_W && j1 < m_H);
#endif
for (int j = j0; j < j1; ++j)
{
int sum = 0;
for (int i = i0; i < i1; ++i)
sum += m_Data[j*m_W + i];
if (sum > 0)
return true;
}
return false;
}
void reset()
{
if (m_Data)

View File

@ -411,10 +411,16 @@ void HierarchicalPathfinder::Update(Grid<NavcellData>* grid, const Grid<u8>& dir
for (int cj = 0; cj < m_ChunksH; ++cj)
{
int j0 = cj * CHUNK_SIZE;
int j1 = std::min(j0 + CHUNK_SIZE, (int)dirtinessGrid.m_H);
for (int ci = 0; ci < m_ChunksW; ++ci)
{
if (!IsChunkDirty(ci, cj, dirtinessGrid))
// Skip chunks where no navcells are dirty.
int i0 = ci * CHUNK_SIZE;
int i1 = std::min(i0 + CHUNK_SIZE, (int)dirtinessGrid.m_W);
if (!dirtinessGrid.any_set_in_square(i0, j0, i1, j1))
continue;
for (const std::pair<std::string, pass_class_t>& passClassMask : m_PassClassMasks)
{
pass_class_t passClass = passClassMask.second;
@ -448,23 +454,6 @@ void HierarchicalPathfinder::Update(Grid<NavcellData>* grid, const Grid<u8>& dir
}
}
bool HierarchicalPathfinder::IsChunkDirty(int ci, int cj, const Grid<u8>& dirtinessGrid) const
{
int i0 = ci * CHUNK_SIZE;
int j0 = cj * CHUNK_SIZE;
int i1 = std::min(i0 + CHUNK_SIZE, (int)dirtinessGrid.m_W);
int j1 = std::min(j0 + CHUNK_SIZE, (int)dirtinessGrid.m_H);
for (int j = j0; j < j1; ++j)
{
for (int i = i0; i < i1; ++i)
{
if (dirtinessGrid.get(i, j))
return true;
}
}
return false;
}
/**
* Find edges between regions in this chunk and the adjacent below/left chunks.
*/

View File

@ -86,8 +86,6 @@ public:
void Update(Grid<NavcellData>* grid, const Grid<u8>& dirtinessGrid);
bool IsChunkDirty(int ci, int cj, const Grid<u8>& dirtinessGrid) const;
RegionID Get(u16 i, u16 j, pass_class_t passClass);
/**