From c0d4ab69d06c8cbefddafdb4b8bed13fbe9b7c3f Mon Sep 17 00:00:00 2001 From: frosch Date: Sat, 3 May 2025 18:35:50 +0200 Subject: [PATCH] Codechange: Add a container to index data by zoom level. --- src/blitter/32bpp_anim.cpp | 4 ++-- src/blitter/32bpp_optimized.cpp | 29 ++++++++++++++++------------- src/blitter/32bpp_optimized.hpp | 2 +- src/blitter/32bpp_simple.cpp | 2 +- src/blitter/32bpp_sse2.cpp | 2 +- src/blitter/32bpp_sse2.hpp | 2 +- src/blitter/40bpp_anim.cpp | 4 ++-- src/blitter/8bpp_optimized.cpp | 2 +- src/blitter/8bpp_optimized.hpp | 2 +- src/blitter/8bpp_simple.cpp | 2 +- src/blitter/null.cpp | 2 +- src/spritecache.cpp | 8 ++++---- src/spriteloader/spriteloader.hpp | 18 ++++++++++++++++-- src/video/opengl.cpp | 16 ++++++++++------ 14 files changed, 58 insertions(+), 37 deletions(-) diff --git a/src/blitter/32bpp_anim.cpp b/src/blitter/32bpp_anim.cpp index 6635d34d0f..68275f001a 100644 --- a/src/blitter/32bpp_anim.cpp +++ b/src/blitter/32bpp_anim.cpp @@ -25,8 +25,8 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel { const SpriteData *src = (const SpriteData *)bp->sprite; - const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]); - const uint16_t *src_n = (const uint16_t *)(src->data + src->offset[zoom][1]); + const Colour *src_px = reinterpret_cast(src->data + src->offset[0][zoom]); + const uint16_t *src_n = reinterpret_cast(src->data + src->offset[1][zoom]); for (uint i = bp->skip_top; i != 0; i--) { src_px = (const Colour *)((const uint8_t *)src_px + *(const uint32_t *)src_px); diff --git a/src/blitter/32bpp_optimized.cpp b/src/blitter/32bpp_optimized.cpp index d4446375e5..3a0c592c68 100644 --- a/src/blitter/32bpp_optimized.cpp +++ b/src/blitter/32bpp_optimized.cpp @@ -32,11 +32,11 @@ inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomL /* src_px : each line begins with uint32_t n = 'number of bytes in this line', * then n times is the Colour struct for this line */ - const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]); + const Colour *src_px = reinterpret_cast(src->data + src->offset[0][zoom]); /* src_n : each line begins with uint32_t n = 'number of bytes in this line', * then interleaved stream of 'm' and 'n' channels. 'm' is remap, * 'n' is number of bytes with the same alpha channel class */ - const uint16_t *src_n = (const uint16_t *)(src->data + src->offset[zoom][1]); + const uint16_t *src_n = reinterpret_cast(src->data + src->offset[1][zoom]); /* skip upper lines in src_px and src_n */ for (uint i = bp->skip_top; i != 0; i--) { @@ -291,7 +291,7 @@ Sprite *Blitter_32bppOptimized::EncodeInternal(SpriteType sprite_type, const Spr /* streams of pixels (a, r, g, b channels) * * stored in separated stream so data are always aligned on 4B boundary */ - std::array, ZOOM_LVL_END> dst_px_orig; + SpriteCollMap> dst_px_orig; /* interleaved stream of 'm' channel and 'n' channel * 'n' is number of following pixels with the same alpha channel class @@ -299,10 +299,10 @@ Sprite *Blitter_32bppOptimized::EncodeInternal(SpriteType sprite_type, const Spr * * it has to be stored in one stream so fewer registers are used - * x86 has problems with register allocation even with this solution */ - std::array, ZOOM_LVL_END> dst_n_orig; + SpriteCollMap> dst_n_orig; /* lengths of streams */ - uint32_t lengths[ZOOM_LVL_END][2]; + SpriteCollMap lengths[2]; ZoomLevel zoom_min; ZoomLevel zoom_max; @@ -406,18 +406,18 @@ Sprite *Blitter_32bppOptimized::EncodeInternal(SpriteType sprite_type, const Spr dst_n_ln = (uint32_t *)dst_n; } - lengths[z][0] = reinterpret_cast(dst_px_ln) - reinterpret_cast(dst_px_orig[z].get()); // all are aligned to 4B boundary - lengths[z][1] = reinterpret_cast(dst_n_ln) - reinterpret_cast(dst_n_orig[z].get()); + lengths[0][z] = reinterpret_cast(dst_px_ln) - reinterpret_cast(dst_px_orig[z].get()); // all are aligned to 4B boundary + lengths[1][z] = reinterpret_cast(dst_n_ln) - reinterpret_cast(dst_n_orig[z].get()); } uint len = 0; // total length of data for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { - len += lengths[z][0] + lengths[z][1]; + len += lengths[0][z] + lengths[1][z]; } Sprite *dest_sprite = allocator.Allocate(sizeof(*dest_sprite) + sizeof(SpriteData) + len); - const auto &root_sprite = sprite[ZOOM_LVL_MIN]; + const auto &root_sprite = sprite.Root(); dest_sprite->height = root_sprite.height; dest_sprite->width = root_sprite.width; dest_sprite->x_offs = root_sprite.x_offs; @@ -426,12 +426,15 @@ Sprite *Blitter_32bppOptimized::EncodeInternal(SpriteType sprite_type, const Spr SpriteData *dst = (SpriteData *)dest_sprite->data; memset(dst, 0, sizeof(*dst)); + uint32_t offset = 0; for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { - dst->offset[z][0] = z == zoom_min ? 0 : lengths[z - 1][1] + dst->offset[z - 1][1]; - dst->offset[z][1] = lengths[z][0] + dst->offset[z][0]; + dst->offset[0][z] = offset; + offset += lengths[0][z]; + dst->offset[1][z] = offset; + offset += lengths[1][z]; - memcpy(dst->data + dst->offset[z][0], dst_px_orig[z].get(), lengths[z][0]); - memcpy(dst->data + dst->offset[z][1], dst_n_orig[z].get(), lengths[z][1]); + memcpy(dst->data + dst->offset[0][z], dst_px_orig[z].get(), lengths[0][z]); + memcpy(dst->data + dst->offset[1][z], dst_n_orig[z].get(), lengths[1][z]); } return dest_sprite; diff --git a/src/blitter/32bpp_optimized.hpp b/src/blitter/32bpp_optimized.hpp index 6c50ff1c34..c1a8a37cd2 100644 --- a/src/blitter/32bpp_optimized.hpp +++ b/src/blitter/32bpp_optimized.hpp @@ -17,7 +17,7 @@ class Blitter_32bppOptimized : public Blitter_32bppSimple { public: /** Data stored about a (single) sprite. */ struct SpriteData { - uint32_t offset[ZOOM_LVL_END][2]; ///< Offsets (from .data) to streams for different zoom levels, and the normal and remap image information. + SpriteCollMap offset[2]; ///< Offsets (from .data) to streams for different zoom levels, and the normal and remap image information. uint8_t data[]; ///< Data, all zoomlevels. }; diff --git a/src/blitter/32bpp_simple.cpp b/src/blitter/32bpp_simple.cpp index 4a3861a8b2..d3fe2f98ca 100644 --- a/src/blitter/32bpp_simple.cpp +++ b/src/blitter/32bpp_simple.cpp @@ -117,7 +117,7 @@ void Blitter_32bppSimple::DrawColourMappingRect(void *dst, int width, int height Sprite *Blitter_32bppSimple::Encode(SpriteType, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) { - const auto &root_sprite = sprite[ZOOM_LVL_MIN]; + const auto &root_sprite = sprite.Root(); Blitter_32bppSimple::Pixel *dst; Sprite *dest_sprite = allocator.Allocate(sizeof(*dest_sprite) + static_cast(root_sprite.height) * static_cast(root_sprite.width) * sizeof(*dst)); diff --git a/src/blitter/32bpp_sse2.cpp b/src/blitter/32bpp_sse2.cpp index fec59bc1f9..3cf7279eea 100644 --- a/src/blitter/32bpp_sse2.cpp +++ b/src/blitter/32bpp_sse2.cpp @@ -52,7 +52,7 @@ Sprite *Blitter_32bppSSE_Base::Encode(SpriteType sprite_type, const SpriteLoader } Sprite *dst_sprite = allocator.Allocate(sizeof(Sprite) + sizeof(SpriteData) + all_sprites_size); - const auto &root_sprite = sprite[ZOOM_LVL_MIN]; + const auto &root_sprite = sprite.Root(); dst_sprite->height = root_sprite.height; dst_sprite->width = root_sprite.width; dst_sprite->x_offs = root_sprite.x_offs; diff --git a/src/blitter/32bpp_sse2.hpp b/src/blitter/32bpp_sse2.hpp index 0efc8bf9a5..383ef41c39 100644 --- a/src/blitter/32bpp_sse2.hpp +++ b/src/blitter/32bpp_sse2.hpp @@ -73,7 +73,7 @@ public: }; struct SpriteData { SpriteFlags flags{}; - std::array infos{}; + SpriteCollMap infos{}; uint8_t data[]; ///< Data, all zoomlevels. }; diff --git a/src/blitter/40bpp_anim.cpp b/src/blitter/40bpp_anim.cpp index b2a48b7a2c..1af0158c61 100644 --- a/src/blitter/40bpp_anim.cpp +++ b/src/blitter/40bpp_anim.cpp @@ -96,11 +96,11 @@ inline void Blitter_40bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel /* src_px : each line begins with uint32_t n = 'number of bytes in this line', * then n times is the Colour struct for this line */ - const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]); + const Colour *src_px = reinterpret_cast(src->data + src->offset[0][zoom]); /* src_n : each line begins with uint32_t n = 'number of bytes in this line', * then interleaved stream of 'm' and 'n' channels. 'm' is remap, * 'n' is number of bytes with the same alpha channel class */ - const uint16_t *src_n = (const uint16_t *)(src->data + src->offset[zoom][1]); + const uint16_t *src_n = reinterpret_cast(src->data + src->offset[1][zoom]); /* skip upper lines in src_px and src_n */ for (uint i = bp->skip_top; i != 0; i--) { diff --git a/src/blitter/8bpp_optimized.cpp b/src/blitter/8bpp_optimized.cpp index a670b8a4bf..c4a1b223ac 100644 --- a/src/blitter/8bpp_optimized.cpp +++ b/src/blitter/8bpp_optimized.cpp @@ -221,7 +221,7 @@ Sprite *Blitter_8bppOptimized::Encode(SpriteType sprite_type, const SpriteLoader /* Allocate the exact amount of memory we need */ Sprite *dest_sprite = allocator.Allocate(sizeof(*dest_sprite) + size); - const auto &root_sprite = sprite[ZOOM_LVL_MIN]; + const auto &root_sprite = sprite.Root(); dest_sprite->height = root_sprite.height; dest_sprite->width = root_sprite.width; dest_sprite->x_offs = root_sprite.x_offs; diff --git a/src/blitter/8bpp_optimized.hpp b/src/blitter/8bpp_optimized.hpp index 5ca0cb676b..240b6dbdd9 100644 --- a/src/blitter/8bpp_optimized.hpp +++ b/src/blitter/8bpp_optimized.hpp @@ -18,7 +18,7 @@ class Blitter_8bppOptimized final : public Blitter_8bppBase { public: /** Data stored about a (single) sprite. */ struct SpriteData { - uint32_t offset[ZOOM_LVL_END]; ///< Offsets (from .data) to streams for different zoom levels. + SpriteCollMap offset; ///< Offsets (from .data) to streams for different zoom levels. uint8_t data[]; ///< Data, all zoomlevels. }; diff --git a/src/blitter/8bpp_simple.cpp b/src/blitter/8bpp_simple.cpp index e54fe9d376..54cb9ee404 100644 --- a/src/blitter/8bpp_simple.cpp +++ b/src/blitter/8bpp_simple.cpp @@ -63,7 +63,7 @@ void Blitter_8bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoom Sprite *Blitter_8bppSimple::Encode(SpriteType, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) { - const auto &root_sprite = sprite[ZOOM_LVL_MIN]; + const auto &root_sprite = sprite.Root(); Sprite *dest_sprite; dest_sprite = allocator.Allocate(sizeof(*dest_sprite) + static_cast(root_sprite.height) * static_cast(root_sprite.width)); diff --git a/src/blitter/null.cpp b/src/blitter/null.cpp index 5b3922ea04..41b8a719b1 100644 --- a/src/blitter/null.cpp +++ b/src/blitter/null.cpp @@ -20,7 +20,7 @@ Sprite *Blitter_Null::Encode(SpriteType, const SpriteLoader::SpriteCollection &s Sprite *dest_sprite; dest_sprite = allocator.Allocate(sizeof(*dest_sprite)); - const auto &root_sprite = sprite[ZOOM_LVL_MIN]; + const auto &root_sprite = sprite.Root(); dest_sprite->height = root_sprite.height; dest_sprite->width = root_sprite.width; dest_sprite->x_offs = root_sprite.x_offs; diff --git a/src/spritecache.cpp b/src/spritecache.cpp index 4d82164b87..d272ccf2eb 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -250,7 +250,7 @@ static bool ResizeSpriteIn(SpriteLoader::SpriteCollection &sprite, ZoomLevel src static void ResizeSpriteOut(SpriteLoader::SpriteCollection &sprite, ZoomLevel zoom) { - const auto &root_sprite = sprite[ZOOM_LVL_MIN]; + const auto &root_sprite = sprite.Root(); const auto &src_sprite = sprite[zoom - 1]; auto &dest_sprite = sprite[zoom]; @@ -417,7 +417,7 @@ static bool ResizeSprites(SpriteLoader::SpriteCollection &sprite, ZoomLevels spr } } - /* Upscale to desired sprite_min_zoom if provided sprite only had zoomed in versions. */ + /* Replace sprites with higher resolution than the desired maximum source resolution with scaled up sprites, if not already done. */ if (first_avail < _settings_client.gui.sprite_zoom_min) { for (ZoomLevel zoom = std::min(ZOOM_LVL_NORMAL, _settings_client.gui.sprite_zoom_min); zoom > ZOOM_LVL_MIN; --zoom) { ResizeSpriteIn(sprite, zoom, zoom - 1); @@ -522,7 +522,7 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty * Ugly: yes. Other solution: no. Blame the original author or * something ;) The image should really have been a data-stream * (so type = 0xFF basically). */ - const auto &root_sprite = sprite[ZOOM_LVL_MIN]; + const auto &root_sprite = sprite.Root(); uint num = root_sprite.width * root_sprite.height; Sprite *s = allocator.Allocate(sizeof(*s) + num); @@ -1080,4 +1080,4 @@ void GfxClearFontSpriteCache() } } -/* static */ ReusableBuffer SpriteLoader::Sprite::buffer[ZOOM_LVL_END]; +/* static */ SpriteCollMap> SpriteLoader::Sprite::buffer; diff --git a/src/spriteloader/spriteloader.hpp b/src/spriteloader/spriteloader.hpp index b57910538f..2803f37869 100644 --- a/src/spriteloader/spriteloader.hpp +++ b/src/spriteloader/spriteloader.hpp @@ -26,6 +26,20 @@ enum class SpriteComponent : uint8_t { }; using SpriteComponents = EnumBitSet; +/** + * Map zoom level to data. + */ +template +class SpriteCollMap { + std::array data; +public: + inline constexpr T &operator[](const ZoomLevel &zoom) { return this->data[zoom]; } + inline constexpr const T &operator[](const ZoomLevel &zoom) const { return this->data[zoom]; } + + T &Root() { return this->data[ZOOM_LVL_MIN]; } + const T &Root() const { return this->data[ZOOM_LVL_MIN]; } +}; + /** Interface for the loader of our sprites. */ class SpriteLoader { public: @@ -60,13 +74,13 @@ public: void AllocateData(ZoomLevel zoom, size_t size) { this->data = Sprite::buffer[zoom].ZeroAllocate(size); } private: /** Allocated memory to pass sprite data around */ - static ReusableBuffer buffer[ZOOM_LVL_END]; + static SpriteCollMap> buffer; }; /** * Type defining a collection of sprites, one for each zoom level. */ - using SpriteCollection = std::array; + using SpriteCollection = SpriteCollMap; /** * Load a sprite from the disk and return a sprite struct which is the same for all loaders. diff --git a/src/video/opengl.cpp b/src/video/opengl.cpp index a0238a77f4..8acfa5e7a0 100644 --- a/src/video/opengl.cpp +++ b/src/video/opengl.cpp @@ -1397,9 +1397,14 @@ void OpenGLBackend::RenderOglSprite(OpenGLSprite *gl_sprite, PaletteID pal, int * Create an OpenGL sprite with a palette remap part. * @param sprite The sprite to create the OpenGL sprite for */ -OpenGLSprite::OpenGLSprite(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite) : - dim(sprite[ZOOM_LVL_MIN].width, sprite[ZOOM_LVL_MIN].height), x_offs(sprite[ZOOM_LVL_MIN].x_offs), y_offs(sprite[ZOOM_LVL_MIN].y_offs) +OpenGLSprite::OpenGLSprite(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite) { + const auto &root_sprite = sprite.Root(); + this->dim.width = root_sprite.width; + this->dim.height = root_sprite.height; + this->x_offs = root_sprite.x_offs; + this->y_offs = root_sprite.y_offs; + int levels = sprite_type == SpriteType::Font ? 1 : ZOOM_LVL_END; assert(levels > 0); (void)_glGetError(); @@ -1408,7 +1413,6 @@ OpenGLSprite::OpenGLSprite(SpriteType sprite_type, const SpriteLoader::SpriteCol _glActiveTexture(GL_TEXTURE0); _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - const auto &root_sprite = sprite[ZOOM_LVL_MIN]; for (int t = TEX_RGBA; t < NUM_TEX; t++) { /* Sprite component present? */ if (t == TEX_RGBA && root_sprite.colours == SpriteComponent::Palette) continue; @@ -1436,9 +1440,9 @@ OpenGLSprite::OpenGLSprite(SpriteType sprite_type, const SpriteLoader::SpriteCol } /* Upload texture data. */ - for (int i = 0; i < (sprite_type == SpriteType::Font ? 1 : ZOOM_LVL_END); i++) { - const auto &src_sprite = sprite[i]; - this->Update(src_sprite.width, src_sprite.height, i, src_sprite.data); + for (ZoomLevel zoom = ZOOM_LVL_MIN; zoom <= (sprite_type == SpriteType::Font ? ZOOM_LVL_MIN : ZOOM_LVL_MAX); ++zoom) { + const auto &src_sprite = sprite[zoom]; + this->Update(src_sprite.width, src_sprite.height, zoom, src_sprite.data); } assert(_glGetError() == GL_NO_ERROR);