Refactor Bitmap class to utilize Arena for surface and texture management

Replace custom surface and texture allocation methods with Arena's allocation, improving memory management. Update related methods to work with raw pointers instead of smart pointers, enhancing performance and reducing overhead. Clean up unused code and comments for better clarity.
This commit is contained in:
scawful
2025-04-30 18:00:44 -04:00
parent d92f9b7b04
commit 4f8d765c48
2 changed files with 36 additions and 135 deletions

View File

@@ -7,18 +7,13 @@
#include <cstdint> #include <cstdint>
#include <future> #include <future>
#include <memory>
#include "app/core/platform/memory_tracker.h" #include "app/gfx/arena.h"
#include "app/core/platform/sdl_deleter.h"
#include "app/gfx/snes_palette.h" #include "app/gfx/snes_palette.h"
#include "app/gfx/texture_pool.h"
namespace yaze { namespace yaze {
namespace gfx { namespace gfx {
using core::SDL_Surface_Deleter;
#if YAZE_LIB_PNG == 1 #if YAZE_LIB_PNG == 1
namespace png_internal { namespace png_internal {
@@ -199,32 +194,6 @@ Uint32 GetSnesPixelFormat(int format) {
return SDL_PIXELFORMAT_INDEX8; return SDL_PIXELFORMAT_INDEX8;
} }
// Custom allocator for SDL_Surface
SDL_Surface *AllocateSurface(int width, int height, int depth, Uint32 format) {
SDL_Surface *surface =
SDL_CreateRGBSurfaceWithFormat(0, width, height, depth, format);
if (surface) {
core::MemoryTracker::GetInstance().TrackAllocation(
surface, width * height * (depth / 8), "SDL_Surface");
}
return surface;
}
// Custom allocator for SDL_Texture
SDL_Texture *AllocateTexture(SDL_Renderer *renderer, Uint32 format, int access,
int width, int height) {
SDL_Texture *texture =
SDL_CreateTexture(renderer, format, access, width, height);
if (texture) {
// Estimate size (this is approximate)
size_t estimated_size = width * height * 4; // Assume 4 bytes per pixel
core::MemoryTracker::GetInstance().TrackAllocation(texture, estimated_size,
"SDL_Texture");
}
return texture;
}
// Bitmap class implementation
Bitmap::Bitmap(int width, int height, int depth, Bitmap::Bitmap(int width, int height, int depth,
const std::vector<uint8_t> &data) const std::vector<uint8_t> &data)
: width_(width), height_(height), depth_(depth), data_(data) { : width_(width), height_(height), depth_(depth), data_(data) {
@@ -243,7 +212,7 @@ Bitmap::Bitmap(int width, int height, int depth,
} }
void Bitmap::SaveSurfaceToFile(std::string_view filename) { void Bitmap::SaveSurfaceToFile(std::string_view filename) {
SDL_SaveBMP(surface_.get(), filename.data()); SDL_SaveBMP(surface_, filename.data());
} }
void Bitmap::Initialize(int width, int height, int depth, void Bitmap::Initialize(int width, int height, int depth,
@@ -283,9 +252,8 @@ void Bitmap::Create(int width, int height, int depth, int format,
data_.reserve(data_size_); data_.reserve(data_size_);
data_ = data; data_ = data;
pixel_data_ = data_.data(); pixel_data_ = data_.data();
surface_ = std::shared_ptr<SDL_Surface>{ surface_ = Arena::Get().AllocateSurface(width_, height_, depth_,
AllocateSurface(width_, height_, depth_, GetSnesPixelFormat(format)), GetSnesPixelFormat(format));
SDL_Surface_Deleter{}};
if (surface_ == nullptr) { if (surface_ == nullptr) {
SDL_Log("Bitmap::Create.SDL_CreateRGBSurfaceWithFormat failed: %s\n", SDL_Log("Bitmap::Create.SDL_CreateRGBSurfaceWithFormat failed: %s\n",
SDL_GetError()); SDL_GetError());
@@ -297,27 +265,19 @@ void Bitmap::Create(int width, int height, int depth, int format,
} }
void Bitmap::Reformat(int format) { void Bitmap::Reformat(int format) {
surface_ = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>( surface_ = Arena::Get().AllocateSurface(width_, height_, depth_,
AllocateSurface(width_, height_, depth_, GetSnesPixelFormat(format)), GetSnesPixelFormat(format));
SDL_Surface_Deleter());
surface_->pixels = pixel_data_; surface_->pixels = pixel_data_;
active_ = true; active_ = true;
SetPalette(palette_); SetPalette(palette_);
} }
void Bitmap::UpdateTexture(SDL_Renderer *renderer) { void Bitmap::UpdateTexture(SDL_Renderer *renderer) {
auto converted_surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>( if (!texture_) {
SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0), CreateTexture(renderer);
SDL_Surface_Deleter()); return;
if (converted_surface == nullptr) {
SDL_Log("SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError());
} }
Arena::Get().UpdateTexture(texture_, surface_);
SDL_LockTexture(texture_.get(), nullptr, (void **)&texture_pixels,
&converted_surface->pitch);
memcpy(texture_pixels, converted_surface->pixels,
converted_surface->h * converted_surface->pitch);
SDL_UnlockTexture(texture_.get());
} }
void Bitmap::CreateTexture(SDL_Renderer *renderer) { void Bitmap::CreateTexture(SDL_Renderer *renderer) {
@@ -332,35 +292,16 @@ void Bitmap::CreateTexture(SDL_Renderer *renderer) {
return; return;
} }
// If we already have a texture, don't create a new one // Get a texture from the Arena
if (texture_) { texture_ = Arena::Get().AllocateTexture(renderer, width_, height_);
texture_in_use_ = true; if (!texture_) {
last_used_time_ = SDL_GetTicks64(); SDL_Log("Bitmap::CreateTexture failed to allocate texture: %s\n",
return;
}
// Get a texture from the pool
SDL_Texture *raw_texture = TexturePool::GetInstance().GetTexture(
renderer, width_, height_, SDL_PIXELFORMAT_RGB888);
if (!raw_texture) {
SDL_Log("Bitmap::CreateTexture failed to get texture from pool: %s\n",
SDL_GetError()); SDL_GetError());
return; return;
} }
// Create a shared_ptr with a custom deleter that returns the texture to the
// pool
texture_ = std::shared_ptr<SDL_Texture>(raw_texture, [this](SDL_Texture *t) {
if (t) {
TexturePool::GetInstance().ReturnTexture(t, width_, height_,
SDL_PIXELFORMAT_RGB888);
}
});
texture_in_use_ = true; texture_in_use_ = true;
last_used_time_ = SDL_GetTicks64(); last_used_time_ = SDL_GetTicks64();
UpdateTextureData(); UpdateTextureData();
} }
@@ -369,33 +310,14 @@ void Bitmap::UpdateTextureData() {
return; return;
} }
auto converted_surface = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>( Arena::Get().UpdateTexture(texture_, surface_);
SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0),
SDL_Surface_Deleter());
if (converted_surface == nullptr) {
SDL_Log("SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError());
return;
}
void *pixels;
int pitch;
if (SDL_LockTexture(texture_.get(), nullptr, &pixels, &pitch) != 0) {
SDL_Log("SDL_LockTexture failed: %s\n", SDL_GetError());
return;
}
memcpy(pixels, converted_surface->pixels,
converted_surface->h * converted_surface->pitch);
SDL_UnlockTexture(texture_.get());
modified_ = false; modified_ = false;
} }
void Bitmap::CleanupUnusedTexture(uint64_t current_time, uint64_t timeout) { void Bitmap::CleanupUnusedTexture(uint64_t current_time, uint64_t timeout) {
if (texture_ && !texture_in_use_ && if (texture_ && !texture_in_use_ &&
(current_time - last_used_time_ > timeout)) { (current_time - last_used_time_ > timeout)) {
// Release the texture back to the pool Arena::Get().FreeTexture(texture_);
texture_ = nullptr; texture_ = nullptr;
} }
} }
@@ -415,7 +337,7 @@ void Bitmap::SetPalette(const SnesPalette &palette) {
throw std::runtime_error("Failed to get SDL palette"); throw std::runtime_error("Failed to get SDL palette");
} }
SDL_UnlockSurface(surface_.get()); SDL_UnlockSurface(surface_);
for (size_t i = 0; i < palette.size(); ++i) { for (size_t i = 0; i < palette.size(); ++i) {
auto pal_color = palette[i]; auto pal_color = palette[i];
sdl_palette->colors[i].r = pal_color.rgb().x; sdl_palette->colors[i].r = pal_color.rgb().x;
@@ -423,14 +345,14 @@ void Bitmap::SetPalette(const SnesPalette &palette) {
sdl_palette->colors[i].b = pal_color.rgb().z; sdl_palette->colors[i].b = pal_color.rgb().z;
sdl_palette->colors[i].a = pal_color.rgb().w; sdl_palette->colors[i].a = pal_color.rgb().w;
} }
SDL_LockSurface(surface_.get()); SDL_LockSurface(surface_);
} }
void Bitmap::SetPaletteFromPaletteGroup(const SnesPalette &palette, void Bitmap::SetPaletteFromPaletteGroup(const SnesPalette &palette,
int palette_id) { int palette_id) {
auto start_index = palette_id * 8; auto start_index = palette_id * 8;
palette_ = palette.sub_palette(start_index, start_index + 8); palette_ = palette.sub_palette(start_index, start_index + 8);
SDL_UnlockSurface(surface_.get()); SDL_UnlockSurface(surface_);
for (size_t i = 0; i < palette_.size(); ++i) { for (size_t i = 0; i < palette_.size(); ++i) {
auto pal_color = palette_[i]; auto pal_color = palette_[i];
if (pal_color.is_transparent()) { if (pal_color.is_transparent()) {
@@ -445,7 +367,7 @@ void Bitmap::SetPaletteFromPaletteGroup(const SnesPalette &palette,
surface_->format->palette->colors[i].a = pal_color.rgb().w; surface_->format->palette->colors[i].a = pal_color.rgb().w;
} }
} }
SDL_LockSurface(surface_.get()); SDL_LockSurface(surface_);
} }
void Bitmap::SetPaletteWithTransparent(const SnesPalette &palette, size_t index, void Bitmap::SetPaletteWithTransparent(const SnesPalette &palette, size_t index,
@@ -475,7 +397,7 @@ void Bitmap::SetPaletteWithTransparent(const SnesPalette &palette, size_t index,
colors.push_back(pal_color.rgb()); colors.push_back(pal_color.rgb());
} }
SDL_UnlockSurface(surface_.get()); SDL_UnlockSurface(surface_);
int i = 0; int i = 0;
for (auto &each : colors) { for (auto &each : colors) {
surface_->format->palette->colors[i].r = each.x; surface_->format->palette->colors[i].r = each.x;
@@ -484,18 +406,18 @@ void Bitmap::SetPaletteWithTransparent(const SnesPalette &palette, size_t index,
surface_->format->palette->colors[i].a = each.w; surface_->format->palette->colors[i].a = each.w;
i++; i++;
} }
SDL_LockSurface(surface_.get()); SDL_LockSurface(surface_);
} }
void Bitmap::SetPalette(const std::vector<SDL_Color> &palette) { void Bitmap::SetPalette(const std::vector<SDL_Color> &palette) {
SDL_UnlockSurface(surface_.get()); SDL_UnlockSurface(surface_);
for (size_t i = 0; i < palette.size(); ++i) { for (size_t i = 0; i < palette.size(); ++i) {
surface_->format->palette->colors[i].r = palette[i].r; surface_->format->palette->colors[i].r = palette[i].r;
surface_->format->palette->colors[i].g = palette[i].g; surface_->format->palette->colors[i].g = palette[i].g;
surface_->format->palette->colors[i].b = palette[i].b; surface_->format->palette->colors[i].b = palette[i].b;
surface_->format->palette->colors[i].a = palette[i].a; surface_->format->palette->colors[i].a = palette[i].a;
} }
SDL_LockSurface(surface_.get()); SDL_LockSurface(surface_);
} }
void Bitmap::WriteToPixel(int position, uint8_t value) { void Bitmap::WriteToPixel(int position, uint8_t value) {
@@ -559,6 +481,10 @@ void Bitmap::Get16x16Tile(int tile_x, int tile_y,
} }
void Bitmap::Cleanup() { void Bitmap::Cleanup() {
if (texture_) {
Arena::Get().FreeTexture(texture_);
texture_ = nullptr;
}
active_ = false; active_ = false;
width_ = 0; width_ = 0;
height_ = 0; height_ = 0;
@@ -568,11 +494,7 @@ void Bitmap::Cleanup() {
} }
void Bitmap::Clear() { void Bitmap::Clear() {
active_ = false; Cleanup();
width_ = 0;
height_ = 0;
depth_ = 0;
data_size_ = 0;
data_.clear(); data_.clear();
pixel_data_ = nullptr; pixel_data_ = nullptr;
texture_pixels = nullptr; texture_pixels = nullptr;
@@ -581,7 +503,7 @@ void Bitmap::Clear() {
#if YAZE_LIB_PNG == 1 #if YAZE_LIB_PNG == 1
std::vector<uint8_t> Bitmap::GetPngData() { std::vector<uint8_t> Bitmap::GetPngData() {
std::vector<uint8_t> png_data; std::vector<uint8_t> png_data;
ConvertSurfaceToPng(surface_.get(), png_data); ConvertSurfaceToPng(surface_, png_data);
return png_data; return png_data;
} }
#endif #endif

View File

@@ -65,7 +65,6 @@ void ConvertPngToSurface(const std::vector<uint8_t> &png_data,
*/ */
class Bitmap { class Bitmap {
public: public:
// Constructors
Bitmap() = default; Bitmap() = default;
/** /**
@@ -111,12 +110,8 @@ class Bitmap {
*/ */
void SaveSurfaceToFile(std::string_view filename); void SaveSurfaceToFile(std::string_view filename);
// Texture management
/** /**
* @brief Creates the underlying SDL_Texture to be displayed. * @brief Creates the underlying SDL_Texture to be displayed.
*
* Converts the surface from a RGB to ARGB format.
* Uses SDL_TEXTUREACCESS_STREAMING to allow for live updates.
*/ */
void CreateTexture(SDL_Renderer *renderer); void CreateTexture(SDL_Renderer *renderer);
@@ -157,7 +152,6 @@ class Bitmap {
*/ */
void SetPalette(const std::vector<SDL_Color> &palette); void SetPalette(const std::vector<SDL_Color> &palette);
// Pixel operations
/** /**
* @brief Write a value to a pixel at the given position * @brief Write a value to a pixel at the given position
*/ */
@@ -199,8 +193,8 @@ class Bitmap {
int size() const { return data_size_; } int size() const { return data_size_; }
const uint8_t *data() const { return data_.data(); } const uint8_t *data() const { return data_.data(); }
std::vector<uint8_t> &mutable_data() { return data_; } std::vector<uint8_t> &mutable_data() { return data_; }
SDL_Surface *surface() const { return surface_.get(); } SDL_Surface *surface() const { return surface_; }
SDL_Texture *texture() const { return texture_.get(); } SDL_Texture *texture() const { return texture_; }
const std::vector<uint8_t> &vector() const { return data_; } const std::vector<uint8_t> &vector() const { return data_; }
uint8_t at(int i) const { return data_[i]; } uint8_t at(int i) const { return data_[i]; }
bool modified() const { return modified_; } bool modified() const { return modified_; }
@@ -210,9 +204,6 @@ class Bitmap {
void set_modified(bool modified) { modified_ = modified; } void set_modified(bool modified) { modified_ = modified; }
#if YAZE_LIB_PNG == 1 #if YAZE_LIB_PNG == 1
/**
* @brief Get the bitmap data as PNG
*/
std::vector<uint8_t> GetPngData(); std::vector<uint8_t> GetPngData();
#endif #endif
@@ -243,17 +234,16 @@ class Bitmap {
// Data for the bitmap // Data for the bitmap
std::vector<uint8_t> data_; std::vector<uint8_t> data_;
// Surface for the bitmap // Surface for the bitmap (managed by Arena)
std::shared_ptr<SDL_Surface> surface_ = nullptr; SDL_Surface *surface_ = nullptr;
// Texture for the bitmap // Texture for the bitmap (managed by Arena)
std::shared_ptr<SDL_Texture> texture_ = nullptr; SDL_Texture *texture_ = nullptr;
}; };
// Type alias for a table of bitmaps // Type alias for a table of bitmaps
using BitmapTable = std::unordered_map<int, gfx::Bitmap>; using BitmapTable = std::unordered_map<int, gfx::Bitmap>;
// Utility functions that operate on Bitmap objects
/** /**
* @brief Extract 8x8 tiles from a source bitmap * @brief Extract 8x8 tiles from a source bitmap
*/ */
@@ -266,17 +256,6 @@ std::vector<gfx::Bitmap> ExtractTile8Bitmaps(const gfx::Bitmap &source_bmp,
*/ */
Uint32 GetSnesPixelFormat(int format); Uint32 GetSnesPixelFormat(int format);
/**
* @brief Allocate an SDL surface with the given dimensions and format
*/
SDL_Surface *AllocateSurface(int width, int height, int depth, Uint32 format);
/**
* @brief Allocate an SDL texture with the given dimensions and format
*/
SDL_Texture *AllocateTexture(SDL_Renderer *renderer, Uint32 format, int access,
int width, int height);
} // namespace gfx } // namespace gfx
} // namespace yaze } // namespace yaze