diff --git a/src/app/gfx/bitmap.cc b/src/app/gfx/bitmap.cc index d072537a..77ba011e 100644 --- a/src/app/gfx/bitmap.cc +++ b/src/app/gfx/bitmap.cc @@ -7,18 +7,13 @@ #include #include -#include -#include "app/core/platform/memory_tracker.h" -#include "app/core/platform/sdl_deleter.h" +#include "app/gfx/arena.h" #include "app/gfx/snes_palette.h" -#include "app/gfx/texture_pool.h" namespace yaze { namespace gfx { -using core::SDL_Surface_Deleter; - #if YAZE_LIB_PNG == 1 namespace png_internal { @@ -199,32 +194,6 @@ Uint32 GetSnesPixelFormat(int format) { 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, const std::vector &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) { - SDL_SaveBMP(surface_.get(), filename.data()); + SDL_SaveBMP(surface_, filename.data()); } 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_ = data; pixel_data_ = data_.data(); - surface_ = std::shared_ptr{ - AllocateSurface(width_, height_, depth_, GetSnesPixelFormat(format)), - SDL_Surface_Deleter{}}; + surface_ = Arena::Get().AllocateSurface(width_, height_, depth_, + GetSnesPixelFormat(format)); if (surface_ == nullptr) { SDL_Log("Bitmap::Create.SDL_CreateRGBSurfaceWithFormat failed: %s\n", SDL_GetError()); @@ -297,27 +265,19 @@ void Bitmap::Create(int width, int height, int depth, int format, } void Bitmap::Reformat(int format) { - surface_ = std::unique_ptr( - AllocateSurface(width_, height_, depth_, GetSnesPixelFormat(format)), - SDL_Surface_Deleter()); + surface_ = Arena::Get().AllocateSurface(width_, height_, depth_, + GetSnesPixelFormat(format)); surface_->pixels = pixel_data_; active_ = true; SetPalette(palette_); } void Bitmap::UpdateTexture(SDL_Renderer *renderer) { - auto converted_surface = std::unique_ptr( - SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0), - SDL_Surface_Deleter()); - if (converted_surface == nullptr) { - SDL_Log("SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError()); + if (!texture_) { + CreateTexture(renderer); + return; } - - 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()); + Arena::Get().UpdateTexture(texture_, surface_); } void Bitmap::CreateTexture(SDL_Renderer *renderer) { @@ -332,35 +292,16 @@ void Bitmap::CreateTexture(SDL_Renderer *renderer) { return; } - // If we already have a texture, don't create a new one - if (texture_) { - texture_in_use_ = true; - last_used_time_ = SDL_GetTicks64(); - 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", + // Get a texture from the Arena + texture_ = Arena::Get().AllocateTexture(renderer, width_, height_); + if (!texture_) { + SDL_Log("Bitmap::CreateTexture failed to allocate texture: %s\n", SDL_GetError()); return; } - // Create a shared_ptr with a custom deleter that returns the texture to the - // pool - texture_ = std::shared_ptr(raw_texture, [this](SDL_Texture *t) { - if (t) { - TexturePool::GetInstance().ReturnTexture(t, width_, height_, - SDL_PIXELFORMAT_RGB888); - } - }); - texture_in_use_ = true; last_used_time_ = SDL_GetTicks64(); - UpdateTextureData(); } @@ -369,33 +310,14 @@ void Bitmap::UpdateTextureData() { return; } - auto converted_surface = std::unique_ptr( - 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()); + Arena::Get().UpdateTexture(texture_, surface_); modified_ = false; } void Bitmap::CleanupUnusedTexture(uint64_t current_time, uint64_t timeout) { if (texture_ && !texture_in_use_ && (current_time - last_used_time_ > timeout)) { - // Release the texture back to the pool + Arena::Get().FreeTexture(texture_); texture_ = nullptr; } } @@ -415,7 +337,7 @@ void Bitmap::SetPalette(const SnesPalette &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) { auto pal_color = palette[i]; 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].a = pal_color.rgb().w; } - SDL_LockSurface(surface_.get()); + SDL_LockSurface(surface_); } void Bitmap::SetPaletteFromPaletteGroup(const SnesPalette &palette, int palette_id) { auto start_index = palette_id * 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) { auto pal_color = palette_[i]; 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; } } - SDL_LockSurface(surface_.get()); + SDL_LockSurface(surface_); } 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()); } - SDL_UnlockSurface(surface_.get()); + SDL_UnlockSurface(surface_); int i = 0; for (auto &each : colors) { 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; i++; } - SDL_LockSurface(surface_.get()); + SDL_LockSurface(surface_); } void Bitmap::SetPalette(const std::vector &palette) { - SDL_UnlockSurface(surface_.get()); + SDL_UnlockSurface(surface_); for (size_t i = 0; i < palette.size(); ++i) { surface_->format->palette->colors[i].r = palette[i].r; surface_->format->palette->colors[i].g = palette[i].g; surface_->format->palette->colors[i].b = palette[i].b; surface_->format->palette->colors[i].a = palette[i].a; } - SDL_LockSurface(surface_.get()); + SDL_LockSurface(surface_); } void Bitmap::WriteToPixel(int position, uint8_t value) { @@ -559,6 +481,10 @@ void Bitmap::Get16x16Tile(int tile_x, int tile_y, } void Bitmap::Cleanup() { + if (texture_) { + Arena::Get().FreeTexture(texture_); + texture_ = nullptr; + } active_ = false; width_ = 0; height_ = 0; @@ -568,11 +494,7 @@ void Bitmap::Cleanup() { } void Bitmap::Clear() { - active_ = false; - width_ = 0; - height_ = 0; - depth_ = 0; - data_size_ = 0; + Cleanup(); data_.clear(); pixel_data_ = nullptr; texture_pixels = nullptr; @@ -581,7 +503,7 @@ void Bitmap::Clear() { #if YAZE_LIB_PNG == 1 std::vector Bitmap::GetPngData() { std::vector png_data; - ConvertSurfaceToPng(surface_.get(), png_data); + ConvertSurfaceToPng(surface_, png_data); return png_data; } #endif diff --git a/src/app/gfx/bitmap.h b/src/app/gfx/bitmap.h index b5a1bfb6..23a540cc 100644 --- a/src/app/gfx/bitmap.h +++ b/src/app/gfx/bitmap.h @@ -65,7 +65,6 @@ void ConvertPngToSurface(const std::vector &png_data, */ class Bitmap { public: - // Constructors Bitmap() = default; /** @@ -111,12 +110,8 @@ class Bitmap { */ void SaveSurfaceToFile(std::string_view filename); - // Texture management /** * @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); @@ -157,7 +152,6 @@ class Bitmap { */ void SetPalette(const std::vector &palette); - // Pixel operations /** * @brief Write a value to a pixel at the given position */ @@ -199,8 +193,8 @@ class Bitmap { int size() const { return data_size_; } const uint8_t *data() const { return data_.data(); } std::vector &mutable_data() { return data_; } - SDL_Surface *surface() const { return surface_.get(); } - SDL_Texture *texture() const { return texture_.get(); } + SDL_Surface *surface() const { return surface_; } + SDL_Texture *texture() const { return texture_; } const std::vector &vector() const { return data_; } uint8_t at(int i) const { return data_[i]; } bool modified() const { return modified_; } @@ -210,9 +204,6 @@ class Bitmap { void set_modified(bool modified) { modified_ = modified; } #if YAZE_LIB_PNG == 1 - /** - * @brief Get the bitmap data as PNG - */ std::vector GetPngData(); #endif @@ -243,17 +234,16 @@ class Bitmap { // Data for the bitmap std::vector data_; - // Surface for the bitmap - std::shared_ptr surface_ = nullptr; + // Surface for the bitmap (managed by Arena) + SDL_Surface *surface_ = nullptr; - // Texture for the bitmap - std::shared_ptr texture_ = nullptr; + // Texture for the bitmap (managed by Arena) + SDL_Texture *texture_ = nullptr; }; // Type alias for a table of bitmaps using BitmapTable = std::unordered_map; -// Utility functions that operate on Bitmap objects /** * @brief Extract 8x8 tiles from a source bitmap */ @@ -266,17 +256,6 @@ std::vector ExtractTile8Bitmaps(const gfx::Bitmap &source_bmp, */ 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 yaze