20 static Arena instance;
36 uint32_t gen = bitmap ? bitmap->
generation() : 0;
47 const auto& command = *it;
48 bool processed =
false;
51 if (command.bitmap && command.bitmap->generation() != command.generation) {
52 LOG_DEBUG(
"Arena",
"Skipping stale texture command (gen %u != %u)",
53 command.generation, command.bitmap->generation());
58 switch (command.type) {
60 if (command.bitmap && command.bitmap->surface() &&
61 command.bitmap->surface()->format && command.bitmap->is_active() &&
62 command.bitmap->width() > 0 && command.bitmap->height() > 0) {
65 command.bitmap->width(), command.bitmap->height());
67 command.bitmap->set_texture(texture);
72 LOG_ERROR(
"Arena",
"Exception during single texture creation");
78 if (command.bitmap && command.bitmap->texture() &&
79 command.bitmap->surface() && command.bitmap->surface()->format &&
80 command.bitmap->is_active()) {
86 LOG_ERROR(
"Arena",
"Exception during single texture update");
92 if (command.bitmap && command.bitmap->texture()) {
95 command.bitmap->set_texture(
nullptr);
98 LOG_ERROR(
"Arena",
"Exception during single texture destruction");
114 if (!active_renderer) {
125 constexpr size_t kMaxTexturesPerFrame = 8;
126 size_t processed = 0;
130 processed < kMaxTexturesPerFrame) {
131 const auto& command = *it;
132 bool should_remove =
true;
135 if (command.bitmap && command.bitmap->generation() != command.generation) {
136 LOG_DEBUG(
"Arena",
"Skipping stale texture command (gen %u != %u)",
137 command.generation, command.bitmap->generation());
146 switch (command.type) {
151 if (command.bitmap && command.bitmap->surface() &&
152 command.bitmap->is_active() && command.bitmap->width() > 0 &&
153 command.bitmap->height() > 0) {
156 auto* surf = command.bitmap->surface();
158 bool has_palette = palette !=
nullptr;
159 int color_count = has_palette ? palette->ncolors : 0;
163 "Arena::ProcessTextureQueue (CREATE)", surf);
165 "Arena::ProcessTextureQueue", has_palette, color_count);
171 "Creating texture from surface WITHOUT palette - "
172 "colors will be incorrect!");
174 "Arena::ProcessTextureQueue", 0,
false,
"Surface has NO palette");
175 }
else if (color_count < 90) {
177 "Creating texture with only %d palette colors (expected "
181 "Arena::ProcessTextureQueue", 0,
false,
182 absl::StrFormat(
"Low color count: %d", color_count));
187 "Arena::ProcessTextureQueue", 0,
true,
"Calling CreateTexture...");
190 command.bitmap->width(), command.bitmap->height());
194 "Arena::ProcessTextureQueue", 0,
true,
"CreateTexture SUCCESS");
196 command.bitmap->set_texture(texture);
201 "Arena::ProcessTextureQueue", 0,
false,
"CreateTexture returned NULL");
202 should_remove =
false;
205 LOG_ERROR(
"Arena",
"Exception during texture creation");
207 "Arena::ProcessTextureQueue", 0,
false,
"EXCEPTION during texture creation");
208 should_remove =
true;
215 if (command.bitmap && command.bitmap->texture() &&
216 command.bitmap->surface() && command.bitmap->surface()->format &&
217 command.bitmap->is_active()) {
223 LOG_ERROR(
"Arena",
"Exception during texture update");
229 if (command.bitmap && command.bitmap->texture()) {
232 command.bitmap->set_texture(
nullptr);
235 LOG_ERROR(
"Arena",
"Exception during texture destruction");
256 if (std::get<0>(info) == width && std::get<1>(info) == height &&
257 std::get<2>(info) == depth && std::get<3>(info) == format) {
258 SDL_Surface* surface = *it;
266 SDL_Surface* surface =
271 std::unique_ptr<SDL_Surface, util::SDL_Surface_Deleter>(surface);
272 surfaces_[surface] = std::move(surface_ptr);
274 std::make_tuple(width, height, depth, format);
314 if (sheet_index < 0 || sheet_index >= 223) {
315 LOG_WARN(
"Arena",
"Invalid sheet index %d, ignoring notification",
321 if (!sheet.is_active() || !sheet.surface()) {
323 "Sheet %d not active or no surface, skipping notification",
329 if (sheet.texture()) {
331 LOG_DEBUG(
"Arena",
"Queued texture update for modified sheet %d",
336 LOG_DEBUG(
"Arena",
"Queued texture creation for modified sheet %d",
345 LOG_DEBUG(
"Arena",
"Palette modified: group='%s', palette=%d",
346 group_name.c_str(), palette_index);
351 callback(group_name, palette_index);
352 }
catch (
const std::exception& e) {
353 LOG_ERROR(
"Arena",
"Exception in palette listener %d: %s",
id, e.what());
363 LOG_DEBUG(
"Arena",
"Registered palette listener with ID %d",
id);
371 LOG_DEBUG(
"Arena",
"Unregistered palette listener with ID %d", listener_id);
Resource management arena for efficient graphics memory handling.
std::unordered_map< SDL_Surface *, std::unique_ptr< SDL_Surface, util::SDL_Surface_Deleter > > surfaces_
void Initialize(IRenderer *renderer)
struct yaze::gfx::Arena::TexturePool texture_pool_
SDL_Surface * AllocateSurface(int width, int height, int depth, int format)
std::unordered_map< TextureHandle, std::unique_ptr< SDL_Texture, util::SDL_Texture_Deleter > > textures_
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
int RegisterPaletteListener(PaletteChangeCallback callback)
Register a callback for palette change notifications.
std::array< uint16_t, kTotalTiles > layer2_buffer_
std::function< void(const std::string &group_name, int palette_index)> PaletteChangeCallback
void FreeSurface(SDL_Surface *surface)
void ProcessTextureQueue(IRenderer *renderer)
std::array< gfx::Bitmap, 223 > gfx_sheets_
bool ProcessSingleTexture(IRenderer *renderer)
Process a single texture command for frame-budget-aware loading.
std::unordered_map< int, PaletteChangeCallback > palette_listeners_
std::vector< TextureCommand > texture_command_queue_
std::array< uint16_t, kTotalTiles > layer1_buffer_
void NotifySheetModified(int sheet_index)
Notify Arena that a graphics sheet has been modified.
struct yaze::gfx::Arena::SurfacePool surface_pool_
void UnregisterPaletteListener(int listener_id)
Unregister a palette change listener.
int next_palette_listener_id_
void NotifyPaletteModified(const std::string &group_name, int palette_index=-1)
Notify all listeners that a palette has been modified.
Represents a bitmap image optimized for SNES ROM hacking.
uint32_t generation() const
Defines an abstract interface for all rendering operations.
virtual TextureHandle CreateTexture(int width, int height)=0
Creates a new, empty texture.
virtual void UpdateTexture(TextureHandle texture, const Bitmap &bitmap)=0
Updates a texture with the pixel data from a Bitmap.
virtual void DestroyTexture(TextureHandle texture)=0
Destroys a texture and frees its associated resources.
void LogTextureCreation(const std::string &location, bool has_palette, int color_count)
static PaletteDebugger & Get()
void LogPaletteApplication(const std::string &location, int palette_id, bool success, const std::string &reason="")
void LogSurfaceState(const std::string &location, SDL_Surface *surface)
#define LOG_DEBUG(category, format,...)
#define LOG_ERROR(category, format,...)
#define LOG_WARN(category, format,...)
Uint32 GetSnesPixelFormat(int format)
Convert bitmap format enum to SDL pixel format.
SDL2/SDL3 compatibility layer.
static constexpr size_t MAX_POOL_SIZE
std::vector< SDL_Surface * > available_surfaces_
std::unordered_map< SDL_Surface *, std::tuple< int, int, int, int > > surface_info_
std::vector< TextureHandle > available_textures_
std::unordered_map< TextureHandle, std::pair< int, int > > texture_sizes_