Zoning: Cache expensive zoning overlay values

This commit is contained in:
Jonathan G Rennison
2018-01-22 17:49:53 +00:00
parent f8193578c1
commit 38fb8c1b84
6 changed files with 110 additions and 14 deletions

View File

@@ -36,6 +36,7 @@
#include "game/game.hpp" #include "game/game.hpp"
#include "goal_base.h" #include "goal_base.h"
#include "story_base.h" #include "story_base.h"
#include "zoning.h"
#include "table/strings.h" #include "table/strings.h"
@@ -119,6 +120,7 @@ void SetLocalCompany(CompanyID new_company)
/* ... and redraw the whole screen. */ /* ... and redraw the whole screen. */
MarkWholeScreenDirty(); MarkWholeScreenDirty();
InvalidateWindowClassesData(WC_SIGN_LIST, -1); InvalidateWindowClassesData(WC_SIGN_LIST, -1);
ClearZoningCaches();
} }
/** /**

View File

@@ -33,6 +33,7 @@
#include "viewport_func.h" #include "viewport_func.h"
#include "bridge_signal_map.h" #include "bridge_signal_map.h"
#include "command_func.h" #include "command_func.h"
#include "zoning.h"
#include "safeguards.h" #include "safeguards.h"
@@ -90,6 +91,8 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
FreeSignalPrograms(); FreeSignalPrograms();
FreeSignalDependencies(); FreeSignalDependencies();
ClearZoningCaches();
ResetPersistentNewGRFData(); ResetPersistentNewGRFData();
InitializeSound(); InitializeSound();

View File

@@ -69,6 +69,7 @@
#include "viewport_func.h" #include "viewport_func.h"
#include "thread/thread.h" #include "thread/thread.h"
#include "bridge_signal_map.h" #include "bridge_signal_map.h"
#include "zoning.h"
#include "linkgraph/linkgraphschedule.h" #include "linkgraph/linkgraphschedule.h"
#include "tracerestrict.h" #include "tracerestrict.h"
@@ -348,6 +349,8 @@ static void ShutdownGame()
FreeSignalPrograms(); FreeSignalPrograms();
FreeSignalDependencies(); FreeSignalDependencies();
ClearZoningCaches();
/* No NewGRFs were loaded when it was still bootstrapping. */ /* No NewGRFs were loaded when it was still bootstrapping. */
if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData(); if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData();

View File

@@ -29,6 +29,17 @@ enum ZoningEvaluationMode {
ZEM_TRACERESTRICT, ///< Check for restricted signals ZEM_TRACERESTRICT, ///< Check for restricted signals
}; };
/**
* Zoning evaluation modes
*/
enum ZoningModeMask {
ZMM_NOTHING = 0, ///< No zoning mask
ZMM_INNER, ///< Inner
ZMM_OUTER, ///< Outer
ZMM_ALL = ZMM_INNER | ZMM_OUTER,
};
DECLARE_ENUM_AS_BIT_SET(ZoningModeMask)
/** /**
* Global Zoning state structure * Global Zoning state structure
*/ */
@@ -47,12 +58,13 @@ void DrawTileZoning(const TileInfo *ti);
void ShowZoningToolbar(); void ShowZoningToolbar();
void ZoningMarkDirtyStationCoverageArea(const Station *st); void ZoningMarkDirtyStationCoverageArea(const Station *st, ZoningModeMask mask = ZMM_ALL);
inline void ZoningMarkDirtyStationCoverageArea(const Waypoint *st) { } // no-op inline void ZoningMarkDirtyStationCoverageArea(const Waypoint *st) { } // no-op
inline void ZoningStationWindowOpenClose(const Station *st) void ZoningStationWindowOpenClose(const Station *st);
{
if (_zoning.inner == ZEM_STA_CATCH_WIN || _zoning.outer == ZEM_STA_CATCH_WIN) ZoningMarkDirtyStationCoverageArea(st); void SetZoningMode(bool inner, ZoningEvaluationMode mode);
}
void ClearZoningCaches();
#endif /* ZONING_H */ #endif /* ZONING_H */

View File

@@ -26,10 +26,14 @@
#include "tracerestrict.h" #include "tracerestrict.h"
#include "window_func.h" #include "window_func.h"
#include "zoning.h" #include "zoning.h"
#include "3rdparty/cpp-btree/btree_set.h"
Zoning _zoning; Zoning _zoning;
static const SpriteID ZONING_INVALID_SPRITE_ID = UINT_MAX; static const SpriteID ZONING_INVALID_SPRITE_ID = UINT_MAX;
static btree::btree_set<uint32> _zoning_cache_inner;
static btree::btree_set<uint32> _zoning_cache_outer;
/** /**
* Draw the zoning sprites. * Draw the zoning sprites.
* *
@@ -338,6 +342,40 @@ SpriteID TileZoningSpriteEvaluation(TileIndex tile, Owner owner, ZoningEvaluatio
} }
} }
inline SpriteID TileZoningSpriteEvaluationCached(TileIndex tile, Owner owner, ZoningEvaluationMode ev_mode, bool is_inner)
{
if (ev_mode >= ZEM_STA_CATCH && ev_mode <= ZEM_IND_UNSER) {
// cacheable
btree::btree_set<uint32> &cache = is_inner ? _zoning_cache_inner : _zoning_cache_outer;
auto iter = cache.lower_bound(tile << 3);
if (iter != cache.end() && *iter >> 3 == tile) {
switch (*iter & 7) {
case 0: return ZONING_INVALID_SPRITE_ID;
case 1: return SPR_ZONING_INNER_HIGHLIGHT_RED;
case 2: return SPR_ZONING_INNER_HIGHLIGHT_ORANGE;
case 3: return SPR_ZONING_INNER_HIGHLIGHT_BLACK;
case 4: return SPR_ZONING_INNER_HIGHLIGHT_LIGHT_BLUE;
default: NOT_REACHED();
}
} else {
SpriteID s = TileZoningSpriteEvaluation(tile, owner, ev_mode);
uint val = tile << 3;
switch (s) {
case ZONING_INVALID_SPRITE_ID: val |= 0; break;
case SPR_ZONING_INNER_HIGHLIGHT_RED: val |= 1; break;
case SPR_ZONING_INNER_HIGHLIGHT_ORANGE: val |= 2; break;
case SPR_ZONING_INNER_HIGHLIGHT_BLACK: val |= 3; break;
case SPR_ZONING_INNER_HIGHLIGHT_LIGHT_BLUE: val |= 4; break;
default: NOT_REACHED();
}
cache.insert(iter, val);
return s;
}
} else {
return TileZoningSpriteEvaluation(tile, owner, ev_mode);
}
}
/** /**
* Draw the the zoning on the tile. * Draw the the zoning on the tile.
* *
@@ -351,11 +389,11 @@ void DrawTileZoning(const TileInfo *ti)
} }
if (_zoning.outer != ZEM_NOTHING) { if (_zoning.outer != ZEM_NOTHING) {
DrawZoningSprites(SPR_SELECT_TILE, TileZoningSpriteEvaluation(ti->tile, _local_company, _zoning.outer), ti); DrawZoningSprites(SPR_SELECT_TILE, TileZoningSpriteEvaluationCached(ti->tile, _local_company, _zoning.outer, false), ti);
} }
if (_zoning.inner != ZEM_NOTHING) { if (_zoning.inner != ZEM_NOTHING) {
DrawZoningSprites(SPR_ZONING_INNER_HIGHLIGHT_BASE, TileZoningSpriteEvaluation(ti->tile, _local_company, _zoning.inner), ti); DrawZoningSprites(SPR_ZONING_INNER_HIGHLIGHT_BASE, TileZoningSpriteEvaluationCached(ti->tile, _local_company, _zoning.inner, true), ti);
} }
} }
@@ -376,18 +414,57 @@ static uint GetZoningModeDependantStationCoverageRadius(const Station *st, Zonin
* @param const Station *st * @param const Station *st
* The station to use * The station to use
*/ */
void ZoningMarkDirtyStationCoverageArea(const Station *st) void ZoningMarkDirtyStationCoverageArea(const Station *st, ZoningModeMask mask)
{ {
if (st->rect.IsEmpty()) return; if (st->rect.IsEmpty()) return;
uint radius = max<uint>(GetZoningModeDependantStationCoverageRadius(st, _zoning.outer), GetZoningModeDependantStationCoverageRadius(st, _zoning.inner)); uint outer_radius = mask & ZMM_OUTER ? GetZoningModeDependantStationCoverageRadius(st, _zoning.outer) : 0;
uint inner_radius = mask & ZMM_INNER ? GetZoningModeDependantStationCoverageRadius(st, _zoning.inner) : 0;
uint radius = max<uint>(outer_radius, inner_radius);
if (radius > 0) { if (radius > 0) {
Rect rect = st->GetCatchmentRectUsingRadius(radius); Rect rect = st->GetCatchmentRectUsingRadius(radius);
for (int x = rect.left; x <= rect.right; x++) {
for (int y = rect.top; y <= rect.bottom; y++) { for (int y = rect.top; y <= rect.bottom; y++) {
for (int x = rect.left; x <= rect.right; x++) {
MarkTileDirtyByTile(TileXY(x, y)); MarkTileDirtyByTile(TileXY(x, y));
} }
} }
auto invalidate_cache_rect = [&](btree::btree_set<uint32> &cache) {
for (int y = rect.top; y <= rect.bottom; y++) {
auto iter = cache.lower_bound(TileXY(rect.left, y) << 3);
auto end_iter = iter;
uint end = TileXY(rect.right, y) << 3;
while (end_iter != cache.end() && *end_iter < end) ++end_iter;
cache.erase(iter, end_iter);
}
};
if (outer_radius) invalidate_cache_rect(_zoning_cache_outer);
if (inner_radius) invalidate_cache_rect(_zoning_cache_inner);
} }
} }
void ZoningStationWindowOpenClose(const Station *st)
{
ZoningModeMask mask = ZMM_NOTHING;
if (_zoning.inner == ZEM_STA_CATCH_WIN) mask |= ZMM_INNER;
if (_zoning.outer == ZEM_STA_CATCH_WIN) mask |= ZMM_OUTER;
if (mask != ZMM_NOTHING) ZoningMarkDirtyStationCoverageArea(st, mask);
}
void ClearZoningCaches()
{
_zoning_cache_inner.clear();
_zoning_cache_outer.clear();
}
void SetZoningMode(bool inner, ZoningEvaluationMode mode)
{
ZoningEvaluationMode &current_mode = inner ? _zoning.inner : _zoning.outer;
btree::btree_set<uint32> &cache = inner ? _zoning_cache_inner : _zoning_cache_outer;
if (current_mode == mode) return;
current_mode = mode;
cache.clear();
MarkWholeScreenDirty();
}

View File

@@ -103,15 +103,14 @@ struct ZoningWindow : public Window {
{ {
switch(widget) { switch(widget) {
case ZTW_OUTER_DROPDOWN: case ZTW_OUTER_DROPDOWN:
_zoning.outer = DropDownIndexToZoningEvaluationMode(index); SetZoningMode(false, DropDownIndexToZoningEvaluationMode(index));
break; break;
case ZTW_INNER_DROPDOWN: case ZTW_INNER_DROPDOWN:
_zoning.inner = DropDownIndexToZoningEvaluationMode(index); SetZoningMode(true, DropDownIndexToZoningEvaluationMode(index));
break; break;
} }
this->InvalidateData(); this->InvalidateData();
MarkWholeScreenDirty();
} }
virtual void SetStringParameters(int widget) const virtual void SetStringParameters(int widget) const