From f3dcd26ce73f40bc0993cae547c334c2f53d9218 Mon Sep 17 00:00:00 2001 From: Sven Balzer <4653051+Kyuusokuna@users.noreply.github.com> Date: Fri, 3 Jul 2026 14:42:20 +0200 Subject: [PATCH] move framebuffer management from the renderer to the app --- src/main.cpp | 24 ++++++++---- src/renderer.h | 14 ++++++- src/renderer_sdlgpu.c | 91 +++++++++++++++++++------------------------ src/renderer_wgpu.c | 90 +++++++++++++++++++++--------------------- 4 files changed, 115 insertions(+), 104 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 11efab6..4ddab1c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,6 +33,7 @@ using namespace glm; #define TILE_ATLAS_SIZE (512) static SDL_Window *window; +static R_Texture framebuffer; static R_Texture player_texture; static R_Texture tile_textures_atlas; @@ -458,7 +459,7 @@ static R_Texture create_texture(const char *path) { return NULL; } - R_Texture result = renderer_texture_create(channels == 4 ? R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB : R_TEXTURE_FORMAT_R8_UNORM, R_TEXTURE_USAGE_SAMPLED, 1, width, height, data, path); + R_Texture result = renderer_texture_create(channels == 4 ? R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB : R_TEXTURE_FORMAT_R8_UNORM, R_TEXTURE_USAGE_SAMPLED, false, width, height, data, path); if (!result) { log_error("Failed to load texture (\"%s\").", path_to_load); stbi_image_free(data); @@ -577,7 +578,7 @@ static bool load_map(const char *name, Map *result) { char buffer_name[256] = "Map "; SDL_strlcat(buffer_name, result->name, SDL_arraysize(buffer_name)); - result->texture = renderer_texture_create(R_TEXTURE_FORMAT_R16_UINT, R_TEXTURE_USAGE_STORAGE, 1, result->size.x, result->size.y, result->tiles, "map_texture"); + result->texture = renderer_texture_create(R_TEXTURE_FORMAT_R16_UINT, R_TEXTURE_USAGE_STORAGE, false, result->size.x, result->size.y, result->tiles, "map_texture"); SDL_Log("Loaded map file."); return true; @@ -658,7 +659,7 @@ static void change_map_size(Map *map, char direction, int amount) { player.position = clamp(player.position, i32vec2(0, 0), map->size - 2); - map->texture = renderer_texture_create(R_TEXTURE_FORMAT_R16_UINT, R_TEXTURE_USAGE_SAMPLED, 1, map->size.x, map->size.y, map->tiles, "map_texture"); + map->texture = renderer_texture_create(R_TEXTURE_FORMAT_R16_UINT, R_TEXTURE_USAGE_SAMPLED, false, map->size.x, map->size.y, map->tiles, "map_texture"); } static void blit(char *dst, Sint32 dst_pitch, Sint32 dst_x, Sint32 dst_y, char *src, Sint32 src_pitch, Sint32 width, Sint32 height, int components = 4) { @@ -755,13 +756,13 @@ static void setup_memory_functions() {} #endif static bool recreate_tile_textures() { - tile_textures_atlas = renderer_texture_create(R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB, R_TEXTURE_USAGE_SAMPLED, 1, TILE_ATLAS_SIZE, TILE_ATLAS_SIZE, NULL, "tile_atlas_texture"); + tile_textures_atlas = renderer_texture_create(R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB, R_TEXTURE_USAGE_SAMPLED, false, TILE_ATLAS_SIZE, TILE_ATLAS_SIZE, NULL, "tile_atlas_texture"); if (!tile_textures_atlas) { log_error("Failed to create texture."); return false; } - tile_textures_atlas_imgui = renderer_texture_create(R_TEXTURE_FORMAT_RGBA8_UNORM, R_TEXTURE_USAGE_SAMPLED, 1, TILE_ATLAS_SIZE, TILE_ATLAS_SIZE, NULL, "tile_atlas_texture imgui"); + tile_textures_atlas_imgui = renderer_texture_create(R_TEXTURE_FORMAT_RGBA8_UNORM, R_TEXTURE_USAGE_SAMPLED, false, TILE_ATLAS_SIZE, TILE_ATLAS_SIZE, NULL, "tile_atlas_texture imgui"); if (!tile_textures_atlas) { log_error("Failed to create texture."); return false; @@ -1368,7 +1369,7 @@ static void render_editor() { } } - renderer_frame_set_target(R_framebuffer, NULL, R_LOAD_OP_CLEAR, R_STORE_OP_STORE, { 0.01f, 0.01f, 0.01f, 0.01f }); + renderer_frame_set_target(framebuffer, R_surface, R_LOAD_OP_CLEAR, R_STORE_OP_STORE, { 0.01f, 0.01f, 0.01f, 0.01f }); { ZoneScopedN("Draw Map"); @@ -1524,7 +1525,7 @@ static void render_game() { } } - renderer_frame_set_target(R_framebuffer, NULL, R_LOAD_OP_CLEAR, R_STORE_OP_STORE, { 0.01f, 0.01f, 0.01f, 0.01f }); + renderer_frame_set_target(framebuffer, R_surface, R_LOAD_OP_CLEAR, R_STORE_OP_STORE, { 0.01f, 0.01f, 0.01f, 0.01f }); { ZoneScopedN("Draw Map"); @@ -1614,6 +1615,15 @@ static void render() { renderer_frame_begin(); + if (!framebuffer || renderer_texture_get_width(framebuffer) != renderer_texture_get_width(R_surface) || renderer_texture_get_height(framebuffer) != renderer_texture_get_height(R_surface)) { + if (framebuffer) { + renderer_texture_destroy(framebuffer); + framebuffer = NULL; + } + + framebuffer = renderer_texture_create(renderer_texture_get_format(R_surface), R_TEXTURE_USAGE_TARGET, true, renderer_texture_get_width(R_surface), renderer_texture_get_height(R_surface), NULL, "framebuffer"); + } + if (in_editor) { render_editor(); } else { diff --git a/src/renderer.h b/src/renderer.h index 5b7c633..8524782 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -83,18 +83,28 @@ typedef struct R_Draw_Resources { Uint16 num_fragment_uniform_buffers; } R_Draw_Resources; -extern R_Texture R_framebuffer; +extern R_Texture R_surface; bool renderer_init(SDL_Window *window); -R_Texture renderer_texture_create (R_Texture_Format format, R_Texture_Usage usage, Uint32 sample_count, Uint32 width, Uint32 height, void *data, const char *debug_name); +R_Texture renderer_texture_create (R_Texture_Format format, R_Texture_Usage usage, bool multisampled, Uint32 width, Uint32 height, void *data, const char *debug_name); void renderer_texture_update (R_Texture texture, Uint32 offset_x, Uint32 offset_y, Uint32 width, Uint32 height, void *data, Uint32 bytes_per_row); void renderer_texture_destroy(R_Texture texture); +Uint32 renderer_texture_get_width (R_Texture texture); +Uint32 renderer_texture_get_height (R_Texture texture); +bool renderer_texture_get_multisampled(R_Texture texture); +R_Texture_Format renderer_texture_get_format (R_Texture texture); + + R_Buffer renderer_buffer_create (R_Buffer_Usage usage, Uint32 num_bytes, void * data, const char *debug_name); void renderer_buffer_update (R_Buffer buffer, Uint32 offset, Uint32 num_bytes, void *data); void renderer_buffer_destroy(R_Buffer buffer); +Uint32 renderer_buffer_get_size (R_Buffer buffer); +R_Buffer_Usage renderer_buffer_get_usage(R_Buffer buffer); + + void renderer_frame_begin(); void renderer_frame_end(); diff --git a/src/renderer_sdlgpu.c b/src/renderer_sdlgpu.c index 5fe422b..02c8bb2 100644 --- a/src/renderer_sdlgpu.c +++ b/src/renderer_sdlgpu.c @@ -17,19 +17,16 @@ typedef struct R_Texture_Impl { Uint32 width; Uint32 height; - Uint32 sample_count; + bool multisampled; R_Texture_Format format; } R_Texture_Impl; -R_Texture R_framebuffer; +R_Texture R_surface; static SDL_Window *window; static SDL_GPUDevice *device; -static R_Texture_Format surface_format; -static SDL_GPUTexture *surface_texture; - -static R_Texture framebuffer; +static R_Texture_Impl surface; static SDL_GPUTransferBuffer *transfer_buffer; @@ -90,7 +87,7 @@ static SDL_GPUStoreOp store_ops[] = { }; static_assert(SDL_arraysize(store_ops) == R_STORE_OP_COUNT); -R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage, Uint32 sample_count, Uint32 width, Uint32 height, void *data, const char *debug_name) { +R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage, bool multisampled, Uint32 width, Uint32 height, void *data, const char *debug_name) { SDL_PropertiesID properties = SDL_CreateProperties(); SDL_SetStringProperty(properties, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, debug_name); @@ -102,7 +99,7 @@ R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage .height = height, .layer_count_or_depth = 1, .num_levels = 1, - .sample_count = sample_count == 1 ? SDL_GPU_SAMPLECOUNT_1 : SDL_GPU_SAMPLECOUNT_8, + .sample_count = multisampled ? SDL_GPU_SAMPLECOUNT_8 : SDL_GPU_SAMPLECOUNT_1, .props = properties, }); SDL_DestroyProperties(properties); @@ -120,8 +117,8 @@ R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage .width = width, .height = height, - .sample_count = sample_count, - .format = format, + .multisampled = multisampled, + .format = format, }; if (data) { @@ -165,6 +162,22 @@ void renderer_texture_destroy(R_Texture texture) { SDL_free(texture); } +Uint32 renderer_texture_get_width(R_Texture texture) { + return texture->width; +} + +Uint32 renderer_texture_get_height(R_Texture texture) { + return texture->height; +} + +bool renderer_texture_get_multisampled(R_Texture texture) { + return texture->multisampled; +} + +R_Texture_Format renderer_texture_get_format(R_Texture texture) { + return texture->format; +} + R_Buffer renderer_buffer_create(R_Buffer_Usage usage, Uint32 num_bytes, void *data, const char *debug_name) { R_Buffer_Impl *result = SDL_calloc(1, sizeof(R_Buffer_Impl)); if (!result) return NULL; @@ -246,22 +259,21 @@ void renderer_buffer_destroy(R_Buffer buffer) { SDL_free(buffer); } +Uint32 renderer_buffer_get_size(R_Buffer buffer) { + return buffer->num_bytes; +} + +R_Buffer_Usage renderer_buffer_get_usage(R_Buffer buffer){ + return buffer->usage; +} + void renderer_frame_begin() { - SDL_assert(R_framebuffer == NULL); + SDL_assert(R_surface == NULL); Uint32 surface_width = 0, surface_height = 0; - SDL_WaitAndAcquireGPUSwapchainTexture(render_command_buffer, window, &surface_texture, &surface_width, &surface_height); + SDL_WaitAndAcquireGPUSwapchainTexture(render_command_buffer, window, &surface.texture, &surface.width, &surface.height); - if (!framebuffer || framebuffer->width != surface_width || framebuffer->height != surface_height) { - if (framebuffer) { - renderer_texture_destroy(framebuffer); - framebuffer = NULL; - } - - framebuffer = renderer_texture_create(surface_format, R_TEXTURE_USAGE_TARGET, 8, surface_width, surface_height, NULL, "R_framebuffer"); - } - - R_framebuffer = framebuffer; + R_surface = &surface; } void renderer_frame_end() { @@ -273,36 +285,13 @@ void renderer_frame_end() { render_pass = NULL; } - render_pass = SDL_BeginGPURenderPass(render_command_buffer, - &(SDL_GPUColorTargetInfo){ - .texture = framebuffer->texture, - .mip_level = 0, - .layer_or_depth_plane = 0, - - .clear_color = { 0.0f, 0.0f, 0.0f, 0.0f }, - .load_op = SDL_GPU_LOADOP_LOAD, - .store_op = SDL_GPU_STOREOP_RESOLVE, - - .resolve_texture = surface_texture, - .resolve_mip_level = 0, - .resolve_layer = 0, - - .cycle = false, - .cycle_resolve_texture = false, - }, - 1, - NULL - ); - SDL_EndGPURenderPass(render_pass); - render_pass = NULL; - SDL_GPUFence *frame_fence = SDL_SubmitGPUCommandBufferAndAcquireFence(render_command_buffer); SDL_WaitForGPUFences(device, true, &frame_fence, 1); copy_command_buffer = SDL_AcquireGPUCommandBuffer(device); render_command_buffer = SDL_AcquireGPUCommandBuffer(device); - R_framebuffer = NULL; + R_surface = NULL; copy_pass = SDL_BeginGPUCopyPass(copy_command_buffer); } @@ -397,7 +386,7 @@ bool renderer_init(SDL_Window *window_) { SDL_SetGPUSwapchainParameters(device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR, SDL_GPU_PRESENTMODE_VSYNC); - surface_format = R_Texture_Format_from_SDL_GPUTextureFormat(SDL_GetGPUSwapchainTextureFormat(device, window)); + surface.format = R_Texture_Format_from_SDL_GPUTextureFormat(SDL_GetGPUSwapchainTextureFormat(device, window)); bilinear_sampler = SDL_CreateGPUSampler(device, &(SDL_GPUSamplerCreateInfo){ .min_filter = SDL_GPU_FILTER_LINEAR, @@ -542,7 +531,7 @@ bool renderer_init(SDL_Window *window_) { .target_info = { .color_target_descriptions = (SDL_GPUColorTargetDescription[]){ { - .format = texture_formats[surface_format], + .format = texture_formats[surface.format], .blend_state = { .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, @@ -674,7 +663,7 @@ bool renderer_init(SDL_Window *window_) { .target_info = { .color_target_descriptions = (SDL_GPUColorTargetDescription[]){ { - .format = texture_formats[surface_format], + .format = texture_formats[surface.format], .blend_state = { .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, @@ -806,7 +795,7 @@ bool renderer_init(SDL_Window *window_) { .target_info = { .color_target_descriptions = (SDL_GPUColorTargetDescription[]){ { - .format = texture_formats[surface_format], + .format = texture_formats[surface.format], .blend_state = { .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, @@ -851,7 +840,7 @@ bool renderer_init(SDL_Window *window_) { void ImGui_ImplRenderer_Init() { cImGui_ImplSDLGPU3_Init(&(ImGui_ImplSDLGPU3_InitInfo){ .Device = device, - .ColorTargetFormat = texture_formats[surface_format], + .ColorTargetFormat = texture_formats[surface.format], .MSAASamples = SDL_GPU_SAMPLECOUNT_8, .SwapchainComposition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR, .PresentMode = SDL_GPU_PRESENTMODE_VSYNC, diff --git a/src/renderer_wgpu.c b/src/renderer_wgpu.c index ac5d582..5545f74 100644 --- a/src/renderer_wgpu.c +++ b/src/renderer_wgpu.c @@ -16,11 +16,11 @@ typedef struct R_Texture_Impl { Uint32 width; Uint32 height; - Uint32 sample_count; + bool multisampled; R_Texture_Format format; } R_Texture_Impl; -R_Texture R_framebuffer; +R_Texture R_surface; static bool init_done; @@ -30,10 +30,8 @@ static WGPUDevice device; static WGPUQueue queue; static WGPUSurface surface; -static R_Texture_Format surface_format; static WGPUSurfaceConfiguration surface_configuration; -static WGPUSurfaceTexture surface_texture; -static WGPUTextureView surface_texture_view; +static R_Texture_Impl surface_texture; static R_Texture framebuffer; @@ -92,7 +90,7 @@ static WGPUStoreOp store_ops[] = { }; static_assert(SDL_arraysize(store_ops) == R_STORE_OP_COUNT); -R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage, Uint32 sample_count, Uint32 width, Uint32 height, void *data, const char *debug_name) { +R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage, bool multisampled, Uint32 width, Uint32 height, void *data, const char *debug_name) { WGPUTextureDescriptor descriptor = { .label = { .data = debug_name, .length = WGPU_STRLEN }, .usage = texture_usages[usage] | WGPUTextureUsage_CopyDst, @@ -100,7 +98,7 @@ R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage .size = { .width = width, .height = height, .depthOrArrayLayers = 1 }, .format = texture_formats[format], .mipLevelCount = 1, - .sampleCount = sample_count, + .sampleCount = multisampled ? 4 : 1, .viewFormatCount = 0, .viewFormats = NULL, }; @@ -153,8 +151,8 @@ R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage .width = width, .height = height, - .sample_count = sample_count, - .format = format, + .multisampled = multisampled, + .format = format, }; return result; @@ -185,6 +183,22 @@ void renderer_texture_destroy(R_Texture texture) { SDL_free(texture); } +Uint32 renderer_texture_get_width(R_Texture texture) { + return texture->width; +} + +Uint32 renderer_texture_get_height(R_Texture texture) { + return texture->height; +} + +bool renderer_texture_get_multisampled(R_Texture texture) { + return texture->multisampled; +} + +R_Texture_Format renderer_texture_get_format(R_Texture texture) { + return texture->format; +} + R_Buffer renderer_buffer_create(R_Buffer_Usage usage, Uint32 num_bytes, void *data, const char *debug_name) { WGPUBufferDescriptor descriptor = { .label = { .data = debug_name, .length = WGPU_STRLEN }, @@ -227,9 +241,17 @@ void renderer_buffer_destroy(R_Buffer buffer) { SDL_free(buffer); } +Uint32 renderer_buffer_get_size(R_Buffer buffer) { + return buffer->num_bytes; +} + +R_Buffer_Usage renderer_buffer_get_usage(R_Buffer buffer){ + return buffer->usage; +} + void renderer_frame_begin() { SDL_assert(command_encoder == NULL); - SDL_assert(R_framebuffer == NULL); + SDL_assert(R_surface == NULL); Sint32 window_width = 0, window_height = 0; SDL_GetWindowSizeInPixels(window, &window_width, &window_height); @@ -240,30 +262,25 @@ void renderer_frame_begin() { wgpuSurfaceConfigure(surface, &surface_configuration); } - wgpuSurfaceGetCurrentTexture(surface, &surface_texture); - if (surface_texture.status != WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal && surface_texture.status != WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get current surface texture (%x). Exiting.", surface_texture.status); + WGPUSurfaceTexture wgpu_surface_texture; + wgpuSurfaceGetCurrentTexture(surface, &wgpu_surface_texture); + if (wgpu_surface_texture.status != WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal && wgpu_surface_texture.status != WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal) { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get current surface texture (%x). Exiting.", wgpu_surface_texture.status); SDL_assert_always(false); // TODO: recovery on outdated or device loss return; } - surface_texture_view = wgpuTextureCreateView(surface_texture.texture, NULL); - - if (!framebuffer || framebuffer->width != surface_configuration.width || framebuffer->height != surface_configuration.height) { - if (framebuffer) { - renderer_texture_destroy(framebuffer); - framebuffer = NULL; - } - - framebuffer = renderer_texture_create(surface_format, R_TEXTURE_USAGE_TARGET, 4, surface_configuration.width, surface_configuration.height, NULL, "R_framebuffer"); - } + surface_texture.texture = wgpu_surface_texture.texture; + surface_texture.view = wgpuTextureCreateView(wgpu_surface_texture.texture, NULL); + surface_texture.width = surface_configuration.width; + surface_texture.height = surface_configuration.height; command_encoder = wgpuDeviceCreateCommandEncoder(device, NULL); - R_framebuffer = framebuffer; + R_surface = &surface_texture; } void renderer_frame_end() { SDL_assert(command_encoder); - SDL_assert(R_framebuffer); + SDL_assert(R_surface); if (pass_encoder) { wgpuRenderPassEncoderEnd(pass_encoder); @@ -271,23 +288,8 @@ void renderer_frame_end() { pass_encoder = NULL; } - pass_encoder = wgpuCommandEncoderBeginRenderPass(command_encoder, &(WGPURenderPassDescriptor){ - .colorAttachmentCount = 1, - .colorAttachments = &(WGPURenderPassColorAttachment) { - .view = framebuffer->view, - .depthSlice = WGPU_DEPTH_SLICE_UNDEFINED, - .resolveTarget = surface_texture_view, - .loadOp = WGPULoadOp_Load, - .storeOp = WGPUStoreOp_Discard, - .clearValue = { .r = 0.0f, .g = 0.0f, .b = 0.0f, .a = 0.0f }, - }, - }); - wgpuRenderPassEncoderEnd(pass_encoder); - wgpuRenderPassEncoderRelease(pass_encoder); - pass_encoder = NULL; - - wgpuTextureViewRelease(surface_texture_view); - surface_texture_view = NULL; + wgpuTextureViewRelease(surface_texture.view); + surface_texture.view = NULL; WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(command_encoder, NULL); wgpuCommandEncoderRelease(command_encoder); @@ -300,7 +302,7 @@ void renderer_frame_end() { wgpuTextureRelease(surface_texture.texture); surface_texture.texture = NULL; - R_framebuffer = NULL; + R_surface = NULL; } void renderer_frame_set_target(R_Texture target, R_Texture resolve_target, R_Load_Op load_op, R_Store_Op store_op, R_Color clear_color) { @@ -628,7 +630,7 @@ bool renderer_init(SDL_Window *window_) { return false; } - surface_format = R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB; + surface_texture.format = R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB; surface_configuration = (WGPUSurfaceConfiguration){ .device = device, .format = WGPUTextureFormat_BGRA8UnormSrgb,