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:
@@ -7,18 +7,13 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
|
||||
#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<uint8_t> &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<SDL_Surface>{
|
||||
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<SDL_Surface, SDL_Surface_Deleter>(
|
||||
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_Surface, SDL_Surface_Deleter>(
|
||||
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<SDL_Texture>(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_Surface, SDL_Surface_Deleter>(
|
||||
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<SDL_Color> &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<uint8_t> Bitmap::GetPngData() {
|
||||
std::vector<uint8_t> png_data;
|
||||
ConvertSurfaceToPng(surface_.get(), png_data);
|
||||
ConvertSurfaceToPng(surface_, png_data);
|
||||
return png_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -65,7 +65,6 @@ void ConvertPngToSurface(const std::vector<uint8_t> &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<SDL_Color> &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<uint8_t> &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<uint8_t> &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<uint8_t> GetPngData();
|
||||
#endif
|
||||
|
||||
@@ -243,17 +234,16 @@ class Bitmap {
|
||||
// Data for the bitmap
|
||||
std::vector<uint8_t> data_;
|
||||
|
||||
// Surface for the bitmap
|
||||
std::shared_ptr<SDL_Surface> surface_ = nullptr;
|
||||
// Surface for the bitmap (managed by Arena)
|
||||
SDL_Surface *surface_ = nullptr;
|
||||
|
||||
// Texture for the bitmap
|
||||
std::shared_ptr<SDL_Texture> 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<int, gfx::Bitmap>;
|
||||
|
||||
// Utility functions that operate on Bitmap objects
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user