Implement partial parallelisation of non-map mode viewport rendering

pull/451/head
Jonathan G Rennison 2 years ago
parent 07b752fe69
commit 7685c36f35

@ -33,6 +33,8 @@
#include "table/sprites.h"
#include "table/control_codes.h"
#include <atomic>
#include "safeguards.h"
byte _dirkeys; ///< 1 = left, 2 = up, 4 = right, 8 = down
@ -114,7 +116,7 @@ int8 _font_zoom_cfg; ///< Font zoom level in config.
* @ingroup dirty
*/
extern uint _dirty_block_colour;
extern std::atomic<uint> _dirty_block_colour;
static bool _whole_screen_dirty = false;
bool _gfx_draw_active = false;
@ -1052,18 +1054,18 @@ static BlitterMode GetBlitterMode(PaletteID pal)
* @param y Top coordinate of image in viewport, scaled by zoom
* @param sub If available, draw only specified part of the sprite
*/
void DrawSpriteViewport(const DrawPixelInfo *dpi, SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub)
void DrawSpriteViewport(const SpritePointerHolder &sprite_store, const DrawPixelInfo *dpi, SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub)
{
GfxBlitterCtx ctx(_cur_dpi);
GfxBlitterCtx ctx(dpi);
SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH);
if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) {
ctx.colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1;
GfxMainBlitterViewport(ctx, GetSprite(real_sprite, ST_NORMAL), x, y, BM_TRANSPARENT, sub, real_sprite);
ctx.colour_remap_ptr = sprite_store.GetRecolourSprite(GB(pal, 0, PALETTE_WIDTH)) + 1;
GfxMainBlitterViewport(ctx, sprite_store.GetSprite(real_sprite, ST_NORMAL), x, y, BM_TRANSPARENT, sub, real_sprite);
} else if (pal != PAL_NONE) {
if (HasBit(pal, PALETTE_TEXT_RECOLOUR)) {
ctx.SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH));
} else if (GB(pal, 0, PALETTE_WIDTH) != PAL_NONE) {
ctx.colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1;
ctx.colour_remap_ptr = sprite_store.GetRecolourSprite(GB(pal, 0, PALETTE_WIDTH)) + 1;
}
if (HasBit(pal, PALETTE_BRIGHTNESS_MODIFY)) {
int adjust = GB(pal, PALETTE_BRIGHTNESS_OFFSET, PALETTE_BRIGHTNESS_WIDTH);
@ -1071,9 +1073,22 @@ void DrawSpriteViewport(const DrawPixelInfo *dpi, SpriteID img, PaletteID pal, i
int sign_bit = 1 << (PALETTE_BRIGHTNESS_WIDTH - 1);
ctx.sprite_brightness_adjust = (adjust ^ sign_bit) - sign_bit;
}
GfxMainBlitterViewport(ctx, GetSprite(real_sprite, ST_NORMAL), x, y, GetBlitterMode(pal), sub, real_sprite);
GfxMainBlitterViewport(ctx, sprite_store.GetSprite(real_sprite, ST_NORMAL), x, y, GetBlitterMode(pal), sub, real_sprite);
} else {
GfxMainBlitterViewport(ctx, GetSprite(real_sprite, ST_NORMAL), x, y, BM_NORMAL, sub, real_sprite);
GfxMainBlitterViewport(ctx, sprite_store.GetSprite(real_sprite, ST_NORMAL), x, y, BM_NORMAL, sub, real_sprite);
}
}
void PrepareDrawSpriteViewportSpriteStore(SpritePointerHolder &sprite_store, SpriteID img, PaletteID pal)
{
SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH);
sprite_store.CacheSprite(real_sprite, ST_NORMAL);
if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) {
sprite_store.CacheSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR);
} else if (pal != PAL_NONE) {
if (!HasBit(pal, PALETTE_TEXT_RECOLOUR) && GB(pal, 0, PALETTE_WIDTH) != PAL_NONE) {
sprite_store.CacheSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR);
}
}
}
@ -1678,12 +1693,8 @@ static void DrawDirtyViewport(uint occlusion, int left, int top, int right, int
if (_game_mode == GM_MENU) {
RedrawScreenRect(left, top, right, bottom);
} else {
extern void ViewportDrawChk(Viewport *vp, int left, int top, int right, int bottom);
ViewportDrawChk(_dirty_viewport, left, top, right, bottom);
if (_dirty_viewport_disp_flags & (ND_SHADE_GREY | ND_SHADE_DIMMED)) {
GfxFillRect(left, top, right - 1, bottom - 1,
(_dirty_viewport_disp_flags & ND_SHADE_DIMMED) ? PALETTE_TO_TRANSPARENT : PALETTE_NEWSPAPER, FILLRECT_RECOLOUR);
}
extern void ViewportDrawChk(Viewport *vp, int left, int top, int right, int bottom, uint8 display_flags);
ViewportDrawChk(_dirty_viewport, left, top, right, bottom, _dirty_viewport_disp_flags);
VideoDriver::GetInstance()->MakeDirty(left, top, right - left, bottom - top);
}
}
@ -1743,7 +1754,7 @@ void DrawDirtyBlocks()
DrawOverlappedWindowFlags flags = DOWF_MARK_DIRTY;
if (unlikely(HasBit(_gfx_debug_flags, GDF_SHOW_WINDOW_DIRTY))) {
flags |= DOWF_SHOW_DEBUG;
_dirty_block_colour++;
_dirty_block_colour.fetch_add(1, std::memory_order_relaxed);
}
DrawOverlappedWindowWithClipping(w, w->left, w->top, w->left + w->width, w->top + w->height, flags);
w->flags &= ~(WF_DIRTY | WF_WIDGETS_DIRTY);
@ -1755,7 +1766,7 @@ void DrawDirtyBlocks()
DrawOverlappedWindowFlags flags = DOWF_MARK_DIRTY;
if (unlikely(HasBit(_gfx_debug_flags, GDF_SHOW_WIDGET_DIRTY))) {
flags |= DOWF_SHOW_DEBUG;
_dirty_block_colour++;
_dirty_block_colour.fetch_add(1, std::memory_order_relaxed);
}
DrawOverlappedWindowWithClipping(w, w->left + widget->pos_x, w->top + widget->pos_y, w->left + widget->pos_x + widget->current_x, w->top + widget->pos_y + widget->current_y, flags);
}
@ -1883,8 +1894,9 @@ void DrawDirtyBlocks()
RedrawScreenRect(r.left, r.top, r.right, r.bottom);
}
if (unlikely(HasBit(_gfx_debug_flags, GDF_SHOW_RECT_DIRTY))) {
ViewportDoDrawProcessAllPending();
for (const Rect &r : _dirty_blocks) {
GfxFillRect(r.left, r.top, r.right, r.bottom, _string_colourmap[++_dirty_block_colour & 0xF], FILLRECT_CHECKER);
GfxFillRect(r.left, r.top, r.right, r.bottom, _string_colourmap[(_dirty_block_colour.fetch_add(1, std::memory_order_relaxed) + 1) & 0xF], FILLRECT_CHECKER);
}
}
}
@ -1900,8 +1912,9 @@ void DrawDirtyBlocks()
}
_dirty_blocks.clear();
}
ViewportDoDrawProcessAllPending();
_gfx_draw_active = false;
++_dirty_block_colour;
_dirty_block_colour.fetch_add(1, std::memory_order_relaxed);
extern void ClearViewportCaches();
ClearViewportCaches();

@ -91,7 +91,9 @@ static const int DRAW_STRING_BUFFER = 2048;
void RedrawScreenRect(int left, int top, int right, int bottom);
Dimension GetSpriteSize(SpriteID sprid, Point *offset = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI);
void DrawSpriteViewport(const DrawPixelInfo *dpi, SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr);
struct SpritePointerHolder;
void DrawSpriteViewport(const SpritePointerHolder &sprite_store, const DrawPixelInfo *dpi, SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr);
void PrepareDrawSpriteViewportSpriteStore(SpritePointerHolder &sprite_store, SpriteID img, PaletteID pal);
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI);
std::unique_ptr<uint32[]> DrawSpriteToRgbaBuffer(SpriteID spriteId, ZoomLevel zoom = ZOOM_LVL_GUI);

@ -276,6 +276,8 @@ struct MainWindow : Window
{
this->DrawWidgets();
if (_game_mode == GM_MENU) {
ViewportDoDrawProcessAllPending();
static const SpriteID title_sprites[] = {SPR_OTTD_O, SPR_OTTD_P, SPR_OTTD_E, SPR_OTTD_N, SPR_OTTD_T, SPR_OTTD_T, SPR_OTTD_D};
uint letter_spacing = ScaleGUITrad(10);
int name_width = (lengthof(title_sprites) - 1) * letter_spacing;

@ -669,12 +669,15 @@ static void LargeWorldCallback(void *userdata, void *buf, uint y, uint pitch, ui
ScaleByZoom(left - wx - vp->left, vp->zoom) + vp->virtual_left,
ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top,
ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left,
ScaleByZoom((y + n) - vp->top, vp->zoom) + vp->virtual_top
ScaleByZoom((y + n) - vp->top, vp->zoom) + vp->virtual_top,
0
);
}
_cur_dpi = old_dpi;
ViewportDoDrawProcessAllPending();
/* Switch back to rendering to the screen */
_screen = old_screen;
_screen_disable_anim = old_disable_anim;

@ -12,6 +12,7 @@
#include "gfx_type.h"
#include "spriteloader/spriteloader.hpp"
#include "3rdparty/cpp-btree/btree_map.h"
/** Data structure describing a sprite. */
struct Sprite {
@ -72,4 +73,30 @@ void DupSprite(SpriteID old_spr, SpriteID new_spr);
uint32 GetSpriteMainColour(SpriteID sprite_id, PaletteID palette_id);
struct SpritePointerHolder {
private:
btree::btree_map<uint32, const void *> cache;
public:
inline const Sprite *GetSprite(SpriteID sprite, SpriteType type) const
{
return (const Sprite*)(this->cache.find(sprite | (type << 29))->second);
}
inline const byte *GetRecolourSprite(SpriteID sprite) const
{
return (const byte*)(this->cache.find(sprite | (ST_RECOLOUR << 29))->second);
}
void Clear()
{
this->cache.clear();
}
inline void CacheSprite(SpriteID sprite, SpriteType type)
{
this->cache[sprite | (type << 29)] = GetRawSprite(sprite, type);
}
};
#endif /* SPRITECACHE_H */

@ -126,19 +126,19 @@ void InitTextEffects()
_free_text_effect = 0;
}
void DrawTextEffects(DrawPixelInfo *dpi)
void DrawTextEffects(ViewportDrawerDynamic *vdd, DrawPixelInfo *dpi, bool load_transparent)
{
/* Don't draw the text effects when zoomed out a lot */
if (dpi->zoom > ZOOM_LVL_OUT_8X) return;
const int bottom_threshold = dpi->top + dpi->height;
const int top_threshold = dpi->top - ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM, dpi->zoom);
const bool show_loading = (_settings_client.gui.loading_indicators && !IsTransparencySet(TO_LOADING));
const bool show_loading = (_settings_client.gui.loading_indicators && !load_transparent);
for (TextEffect &te : _text_effects) {
if (te.string_id == INVALID_STRING_ID) continue;
if ((te.mode == TE_RISING || show_loading) && te.top > top_threshold && te.top < bottom_threshold) {
ViewportAddString(dpi, ZOOM_LVL_OUT_8X, &te, te.string_id, te.string_id - 1, STR_NULL, te.params_1, te.params_2);
ViewportAddString(vdd, dpi, ZOOM_LVL_OUT_8X, &te, te.string_id, te.string_id - 1, STR_NULL, te.params_1, te.params_2);
}
}
}

@ -14,6 +14,8 @@
#include "gfx_type.h"
#include "strings_type.h"
struct ViewportDrawerDynamic;
/**
* Text effect modes.
*/
@ -29,7 +31,7 @@ typedef size_t TextEffectID;
void MoveAllTextEffects(uint delta_ms);
TextEffectID AddTextEffect(StringID msg, int x, int y, uint8 duration, TextEffectMode mode);
void InitTextEffects();
void DrawTextEffects(DrawPixelInfo *dpi);
void DrawTextEffects(ViewportDrawerDynamic *vdd, DrawPixelInfo *dpi, bool load_transparent);
void UpdateTextEffect(TextEffectID effect_id, StringID msg);
void RemoveTextEffect(TextEffectID effect_id);
void UpdateAllTextEffectVirtCoords();

File diff suppressed because it is too large Load Diff

@ -18,6 +18,7 @@
#include "vehicle_base.h"
struct TileInfo;
struct ViewportDrawerDynamic;
static const int TILE_HEIGHT_STEP = 50; ///< One Z unit tile height difference is displayed as 50m.
@ -69,7 +70,7 @@ void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub = null
void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0);
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent = false, int bb_offset_x = 0, int bb_offset_y = 0, int bb_offset_z = 0, const SubSprite *sub = nullptr);
void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent = false, const SubSprite *sub = nullptr, bool scale = true, bool relative = true);
void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, uint64 params_1, uint64 params_2 = 0, Colours colour = INVALID_COLOUR);
void ViewportAddString(ViewportDrawerDynamic *vdd, const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, uint64 params_1, uint64 params_2 = 0, Colours colour = INVALID_COLOUR);
void StartSpriteCombine();
@ -87,7 +88,8 @@ void SetRedErrorSquare(TileIndex tile);
void SetTileSelectSize(int w, int h);
void SetTileSelectBigSize(int ox, int oy, int sx, int sy);
void ViewportDoDraw(Viewport *vp, int left, int top, int right, int bottom);
void ViewportDoDraw(Viewport *vp, int left, int top, int right, int bottom, uint8 display_flags);
void ViewportDoDrawProcessAllPending();
bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant = false);
bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant = false);

@ -2147,16 +2147,10 @@ void NWidgetViewport::Draw(const Window *w)
if (this->disp_flags & ND_NO_TRANSPARENCY) {
TransparencyOptionBits to_backup = _transparency_opt;
_transparency_opt &= (1 << TO_SIGNS) | (1 << TO_LOADING); // Disable all transparency, except textual stuff
w->DrawViewport();
w->DrawViewport(this->disp_flags);
_transparency_opt = to_backup;
} else {
w->DrawViewport();
}
/* Optionally shade the viewport. */
if (this->disp_flags & (ND_SHADE_GREY | ND_SHADE_DIMMED)) {
GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1,
(this->disp_flags & ND_SHADE_DIMMED) ? PALETTE_TO_TRANSPARENT : PALETTE_NEWSPAPER, FILLRECT_RECOLOUR);
w->DrawViewport(this->disp_flags);
}
}

@ -948,8 +948,8 @@ void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom, D
dp->zoom = ZOOM_LVL_NORMAL;
w->OnPaint();
if (unlikely(flags & DOWF_SHOW_DEBUG)) {
extern void ViewportDrawDirtyBlocks();
ViewportDrawDirtyBlocks();
extern void ViewportDrawDirtyBlocks(const DrawPixelInfo *dpi, bool increment_colour);
ViewportDrawDirtyBlocks(_cur_dpi, false);
}
if (flags & DOWF_MARK_DIRTY) {
VideoDriver::GetInstance()->MakeDirty(left, top, right - left, bottom - top);
@ -3295,6 +3295,7 @@ void UpdateWindows()
/* Update viewport only if window is not shaded. */
if (w->viewport != nullptr && !w->IsShaded()) UpdateViewportPosition(w);
}
ViewportDoDrawProcessAllPending();
NetworkDrawChatMessage();
/* Redraw mouse cursor in case it was hidden */
DrawMouseCursor();

@ -576,7 +576,7 @@ public:
void SetWidgetDirty(byte widget_index);
void DrawWidgets() const;
void DrawViewport() const;
void DrawViewport(uint8 display_flags) const;
void DrawSortButtonState(int widget, SortButtonState state) const;
static int SortButtonWidth();

Loading…
Cancel
Save