Change how dirty screen, window and viewport areas are tracked for later redrawing
Track dirty viewport areas seperately form general screen redraws. Maintain a dirty block grid per viewport, with a smaller block size. Use even smaller block size in viewport map mode. Use a rectangle array for general screen redraws instead of a block grid. Add a dirty bit to windows and widgets, to simplify the common case of repainting a whole window or widget, without catching neighbouring windows or viewports.
This commit is contained in:
@@ -258,7 +258,7 @@ struct ViewportDrawer {
|
||||
Point foundation_offset[FOUNDATION_PART_END]; ///< Pixel offset for ground sprites on the foundations.
|
||||
};
|
||||
|
||||
static void MarkViewportDirty(const ViewPort * const vp, int left, int top, int right, int bottom);
|
||||
static void MarkViewportDirty(ViewPort * const vp, int left, int top, int right, int bottom);
|
||||
static void MarkRouteStepDirty(RouteStepsMap::const_iterator cit);
|
||||
static void MarkRouteStepDirty(const TileIndex tile, uint order_nr);
|
||||
|
||||
@@ -372,6 +372,8 @@ void InitializeWindowViewport(Window *w, int x, int y,
|
||||
|
||||
vp->map_type = VPMT_BEGIN;
|
||||
|
||||
UpdateViewportSizeZoom(vp);
|
||||
|
||||
Point pt;
|
||||
|
||||
if (follow_flags & 0x80000000) {
|
||||
@@ -575,6 +577,15 @@ static void DoSetViewportPosition(const Window *w, const int left, const int top
|
||||
}
|
||||
}
|
||||
|
||||
inline void UpdateViewportDirtyBlockLeftMargin(ViewPort *vp)
|
||||
{
|
||||
if (vp->zoom >= ZOOM_LVL_DRAW_MAP) {
|
||||
vp->dirty_block_left_margin = 0;
|
||||
} else {
|
||||
vp->dirty_block_left_margin = UnScaleByZoomLower((-vp->virtual_left) & 127, vp->zoom);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetViewportPosition(Window *w, int x, int y, bool force_update_overlay)
|
||||
{
|
||||
ViewPort *vp = w->viewport;
|
||||
@@ -585,6 +596,7 @@ static void SetViewportPosition(Window *w, int x, int y, bool force_update_overl
|
||||
|
||||
vp->virtual_left = x;
|
||||
vp->virtual_top = y;
|
||||
UpdateViewportDirtyBlockLeftMargin(vp);
|
||||
|
||||
if (force_update_overlay || IsViewportOverlayOutsideCachedRegion(w)) RebuildViewportOverlay(w, true);
|
||||
|
||||
@@ -1479,8 +1491,8 @@ static void ViewportAddLandscape()
|
||||
* - Right column is column of upper_right (rounded up) and one column to the right.
|
||||
* Note: Integer-division does not round down for negative numbers, so ensure rounding with another increment/decrement.
|
||||
*/
|
||||
int left_column = (upper_left.y - upper_left.x) / (int)TILE_SIZE - 2;
|
||||
int right_column = (upper_right.y - upper_right.x) / (int)TILE_SIZE + 2;
|
||||
int left_column = DivTowardsNegativeInf(upper_left.y - upper_left.x, (int)TILE_SIZE) - 1;
|
||||
int right_column = DivTowardsPositiveInf(upper_right.y - upper_right.x, (int)TILE_SIZE) + 1;
|
||||
|
||||
int potential_bridge_height = ZOOM_LVL_BASE * TILE_HEIGHT * _settings_game.construction.max_bridge_height;
|
||||
|
||||
@@ -1488,7 +1500,7 @@ static void ViewportAddLandscape()
|
||||
* The first row that could possibly be visible is the row above upper_left (if it is at height 0).
|
||||
* Due to integer-division not rounding down for negative numbers, we need another decrement.
|
||||
*/
|
||||
int row = (upper_left.x + upper_left.y) / (int)TILE_SIZE - 2;
|
||||
int row = DivTowardsNegativeInf(upper_left.y + upper_left.x, (int)TILE_SIZE) - 1;
|
||||
bool last_row = false;
|
||||
for (; !last_row; row++) {
|
||||
last_row = true;
|
||||
@@ -3003,8 +3015,8 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom
|
||||
_vd.dpi.pitch = old_dpi->pitch;
|
||||
_vd.last_child = nullptr;
|
||||
|
||||
int x = UnScaleByZoom(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left;
|
||||
int y = UnScaleByZoom(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top;
|
||||
int x = UnScaleByZoomLower(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left;
|
||||
int y = UnScaleByZoomLower(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top;
|
||||
|
||||
_vd.dpi.dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top);
|
||||
|
||||
@@ -3098,7 +3110,7 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom
|
||||
* Make sure we don't draw a too big area at a time.
|
||||
* If we do, the sprite sorter will run into major performance problems and the sprite memory may overflow.
|
||||
*/
|
||||
static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
|
||||
void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom)
|
||||
{
|
||||
if ((vp->zoom < ZOOM_LVL_DRAW_MAP) && ((int64)ScaleByZoom(bottom - top, vp->zoom) * (int64)ScaleByZoom(right - left, vp->zoom) > (int64)(1000000 * ZOOM_LVL_BASE * ZOOM_LVL_BASE))) {
|
||||
if ((bottom - top) > (right - left)) {
|
||||
@@ -3120,7 +3132,7 @@ static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, in
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom)
|
||||
static inline void ViewportDraw(ViewPort *vp, int left, int top, int right, int bottom)
|
||||
{
|
||||
if (right <= vp->left || bottom <= vp->top) return;
|
||||
|
||||
@@ -3134,6 +3146,8 @@ static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right
|
||||
if (top < vp->top) top = vp->top;
|
||||
if (bottom > vp->top + vp->height) bottom = vp->top + vp->height;
|
||||
|
||||
vp->is_drawn = true;
|
||||
|
||||
ViewportDrawChk(vp, left, top, right, bottom);
|
||||
}
|
||||
|
||||
@@ -3230,6 +3244,15 @@ void UpdateViewportPosition(Window *w)
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateViewportSizeZoom(ViewPort *vp)
|
||||
{
|
||||
vp->dirty_blocks_per_column = CeilDiv(vp->height, vp->GetDirtyBlockHeight());
|
||||
vp->dirty_blocks_per_row = CeilDiv(vp->width, vp->GetDirtyBlockWidth());
|
||||
uint size = vp->dirty_blocks_per_row * vp->dirty_blocks_per_column;
|
||||
vp->dirty_blocks.assign(size, false);
|
||||
UpdateViewportDirtyBlockLeftMargin(vp);
|
||||
}
|
||||
|
||||
void UpdateActiveScrollingViewport(Window *w)
|
||||
{
|
||||
if (w && (!_settings_client.gui.show_scrolling_viewport_on_map || w->viewport->zoom >= ZOOM_LVL_DRAW_MAP)) w = nullptr;
|
||||
@@ -3283,7 +3306,7 @@ void UpdateActiveScrollingViewport(Window *w)
|
||||
* @param bottom Bottom edge of area to repaint
|
||||
* @ingroup dirty
|
||||
*/
|
||||
static void MarkViewportDirty(const ViewPort * const vp, int left, int top, int right, int bottom)
|
||||
static void MarkViewportDirty(ViewPort * const vp, int left, int top, int right, int bottom)
|
||||
{
|
||||
/* Rounding wrt. zoom-out level */
|
||||
right += (1 << vp->zoom) - 1;
|
||||
@@ -3305,12 +3328,21 @@ static void MarkViewportDirty(const ViewPort * const vp, int left, int top, int
|
||||
|
||||
if (top >= vp->virtual_height) return;
|
||||
|
||||
SetDirtyBlocks(
|
||||
UnScaleByZoomLower(left, vp->zoom) + vp->left,
|
||||
UnScaleByZoomLower(top, vp->zoom) + vp->top,
|
||||
UnScaleByZoom(right, vp->zoom) + vp->left + 1,
|
||||
UnScaleByZoom(bottom, vp->zoom) + vp->top + 1
|
||||
);
|
||||
uint x = max<int>(0, UnScaleByZoomLower(left, vp->zoom) - vp->dirty_block_left_margin) >> vp->GetDirtyBlockWidthShift();
|
||||
uint y = UnScaleByZoomLower(top, vp->zoom) >> vp->GetDirtyBlockHeightShift();
|
||||
uint w = (max<int>(0, UnScaleByZoomLower(right, vp->zoom) - 1 - vp->dirty_block_left_margin) >> vp->GetDirtyBlockWidthShift()) + 1 - x;
|
||||
uint h = ((UnScaleByZoom(bottom, vp->zoom) - 1) >> vp->GetDirtyBlockHeightShift()) + 1 - y;
|
||||
|
||||
uint column_skip = vp->dirty_blocks_per_column - h;
|
||||
uint pos = (x * vp->dirty_blocks_per_column) + y;
|
||||
for (uint i = 0; i < w; i++) {
|
||||
for (uint j = 0; j < h; j++) {
|
||||
vp->dirty_blocks[pos] = true;
|
||||
pos++;
|
||||
}
|
||||
pos += column_skip;
|
||||
}
|
||||
vp->is_dirty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3324,7 +3356,7 @@ static void MarkViewportDirty(const ViewPort * const vp, int left, int top, int
|
||||
*/
|
||||
void MarkAllViewportsDirty(int left, int top, int right, int bottom, const ZoomLevel mark_dirty_if_zoomlevel_is_below)
|
||||
{
|
||||
for (const ViewPort * const vp : _viewport_window_cache) {
|
||||
for (ViewPort * const vp : _viewport_window_cache) {
|
||||
if (vp->zoom >= mark_dirty_if_zoomlevel_is_below) continue;
|
||||
MarkViewportDirty(vp, left, top, right, bottom);
|
||||
}
|
||||
@@ -3341,7 +3373,7 @@ static void MarkRouteStepDirty(const TileIndex tile, uint order_nr)
|
||||
assert(tile != INVALID_TILE);
|
||||
const Point pt = RemapCoords2(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2);
|
||||
const int char_height = GetCharacterHeight(FS_SMALL) + 1;
|
||||
for (const ViewPort * const vp : _viewport_window_cache) {
|
||||
for (ViewPort * const vp : _viewport_window_cache) {
|
||||
const int half_width = ScaleByZoom((_vp_route_step_width / 2) + 1, vp->zoom);
|
||||
const int height = ScaleByZoom(_vp_route_step_height_top + char_height * order_nr + _vp_route_step_height_bottom, vp->zoom);
|
||||
MarkViewportDirty(vp, pt.x - half_width, pt.y - height, pt.x + half_width, pt.y);
|
||||
@@ -3370,7 +3402,7 @@ void MarkAllViewportMapsDirty(int left, int top, int right, int bottom)
|
||||
{
|
||||
Window *w;
|
||||
FOR_ALL_WINDOWS_FROM_BACK(w) {
|
||||
const ViewPort *vp = w->viewport;
|
||||
ViewPort *vp = w->viewport;
|
||||
if (vp != nullptr && vp->zoom >= ZOOM_LVL_DRAW_MAP) {
|
||||
assert(vp->width != 0);
|
||||
MarkViewportDirty(vp, left, top, right, bottom);
|
||||
|
Reference in New Issue
Block a user