From 7b0c95d403634a3d408512e5fc02d6e8a021fbfc Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 17 Jun 2025 17:39:23 -0500 Subject: [PATCH] don't expose backbuffer texture to user (blit internally during present) --- src/gpu.h | 11 ++-- src/gpu_dx11.c | 113 ++++++++++++++++++++++++++++++++---------- src/gpu_dx12.c | 2 +- src/playback_wasapi.c | 17 ------- src/user.c | 45 +++-------------- 5 files changed, 100 insertions(+), 88 deletions(-) diff --git a/src/gpu.h b/src/gpu.h index da6aac47..264670ab 100644 --- a/src/gpu.h +++ b/src/gpu.h @@ -131,13 +131,12 @@ struct gpu_handle gpu_dispatch_state_alloc(void); void gpu_dispatch(struct gpu_handle gpu_dispatch_state, struct gpu_dispatch_params params); /* ========================== * - * Backbuffer + * Present * ========================== */ -/* Returns a texture representing the internal backbuffer. Lifetime is managed by gpu layer. */ -struct gpu_handle gpu_recreate_backbuffer(struct v2i32 size); - -/* Presents the backbuffer to the screen */ -void gpu_swap_backbuffer(i32 vsync); +/* 1. Ensures the backbuffer is at size `backbuffer_resolution` + * 2. Blits `texture` to the backbuffer using `texture_xf` (applied to centered unit square) + * 3. Presents the backbuffer */ +void gpu_present(struct v2i32 backbuffer_resolution, struct gpu_handle texture, struct xform texture_xf, i32 vsync); #endif diff --git a/src/gpu_dx11.c b/src/gpu_dx11.c index 11deb892..b4939852 100644 --- a/src/gpu_dx11.c +++ b/src/gpu_dx11.c @@ -47,6 +47,24 @@ #define DX11_SWAPCHAIN_FORMAT (DXGI_FORMAT_R8G8B8A8_UNORM) #define DX11_SWAPCHAIN_RTV_FORMAT (DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) + + + + + + + + + +/* FIXME: Remove this */ +#include "draw.h" + + + + + + + enum dx11_shader_kind { DX11_SHADER_KIND_NONE, DX11_SHADER_KIND_MESH, @@ -187,7 +205,6 @@ struct dx11_texture { ID3D11Texture2D *texture; ID3D11ShaderResourceView *srv; ID3D11RenderTargetView *rtv; - b32 is_backbuffer; struct v2i32 size; struct dx11_texture *next_free; }; @@ -226,6 +243,9 @@ GLOBAL struct { struct dx11_texture backbuffer_texture; i64 last_backbuffer_resize_ns; + struct gpu_handle present_blit_plan; + struct gpu_handle present_blit_dispatch_state; + ID3D11BlendState *blend_state; ID3D11RasterizerState *rasterizer_state; ID3D11DepthStencilState *depth_stencil_state; @@ -403,7 +423,6 @@ struct gpu_startup_receipt gpu_startup(struct work_startup_receipt *work_sr, str G.dev = device; G.devcon = context; G.swapchain = swapchain; - G.backbuffer_texture.is_backbuffer = true; /* Create the swapchain waitable object */ #if DX11_WAIT_FRAME_LATENCY @@ -528,6 +547,9 @@ struct gpu_startup_receipt gpu_startup(struct work_startup_receipt *work_sr, str resource_register_watch_callback(shader_resource_watch_callback); #endif + G.present_blit_plan = gpu_plan_alloc(); + G.present_blit_dispatch_state = gpu_dispatch_state_alloc(); + return (struct gpu_startup_receipt) { 0 }; } @@ -1087,22 +1109,20 @@ INTERNAL struct dx11_texture *dx11_texture_alloc(enum DXGI_FORMAT format, u32 fl INTERNAL void dx11_texture_release(struct dx11_texture *t) { - if (!t->is_backbuffer) { - { - struct sys_lock lock = sys_mutex_lock_e(&G.textures_mutex); - t->next_free = G.first_free_texture; - G.first_free_texture = t; - sys_mutex_unlock(&lock); - } - if (t->rtv) { - ID3D11RenderTargetView_Release(t->rtv); - } - if (t->srv) { - ID3D11ShaderResourceView_Release(t->srv); - } - if (t->texture) { - ID3D11Texture2D_Release(t->texture); - } + { + struct sys_lock lock = sys_mutex_lock_e(&G.textures_mutex); + t->next_free = G.first_free_texture; + G.first_free_texture = t; + sys_mutex_unlock(&lock); + } + if (t->rtv) { + ID3D11RenderTargetView_Release(t->rtv); + } + if (t->srv) { + ID3D11ShaderResourceView_Release(t->srv); + } + if (t->texture) { + ID3D11Texture2D_Release(t->texture); } } @@ -1135,6 +1155,7 @@ void gpu_texture_clear(struct gpu_handle target_texture, u32 clear_color) __prof; struct dx11_texture *t = (struct dx11_texture *)target_texture.v; if (t->rtv) { + __profscope_dx11(G.profiling_ctx, Clear, RGB32_F(0.5, 0.1, 0.1)); f32 r = (f32)((clear_color >> 0) & 0xFF) / 255.0f; f32 g = (f32)((clear_color >> 8) & 0xFF) / 255.0f; f32 b = (f32)((clear_color >> 16) & 0xFF) / 255.0f; @@ -1952,10 +1973,9 @@ INTERNAL struct DXGI_QUERY_VIDEO_MEMORY_INFO get_memory_info(void) } #endif -struct gpu_handle gpu_recreate_backbuffer(struct v2i32 size) +INTERNAL void present_resize(struct v2i32 size) { - struct gpu_handle res = ZI; - + __prof; /* Delay backbuffer recreation so that we don't recreate it too quickly. * It seems that doing this without a delay too often will cause windows * to eventually just display a blackscreen rather than the backbuffer @@ -1986,16 +2006,45 @@ struct gpu_handle gpu_recreate_backbuffer(struct v2i32 size) rtv_desc.Format = DX11_SWAPCHAIN_RTV_FORMAT; rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; ID3D11Device_CreateRenderTargetView(G.dev, (ID3D11Resource *)G.backbuffer_texture.texture, &rtv_desc, &G.backbuffer_texture.rtv); - - res.v = (u64)&G.backbuffer_texture; - return res; } -void gpu_swap_backbuffer(i32 vsync) +INTERNAL void present_blit(struct dx11_texture *dst, struct dx11_texture *src, struct xform src_xf) { __prof; -#if RESOURCE_RELOADING + __profscope_dx11(G.profiling_ctx, Blit, RGB32_F(0.3, 0.1, 0.1)); + struct gpu_handle src_texture_handle = { .v = (u64)src }; + struct gpu_handle dst_texture_handle = { .v = (u64)dst }; + + /* Draw texture to backbuffer texture */ + /* TODO: Specialized blit shader */ + { + struct draw_texture_params params = DRAW_TEXTURE_PARAMS(.xf = src_xf, .texture = src_texture_handle); + draw_texture(G.present_blit_plan, params); + } + + /* Send plans to GPU */ + gpu_submit_plan(G.present_blit_plan); + + /* Clear textures */ + gpu_texture_clear(dst_texture_handle, RGBA32_F(0, 0, 0, 1)); + + /* Render to backbuffer texture */ + { + struct gpu_dispatch_params params = ZI; + params.plan = G.present_blit_plan; + params.draw_target = dst_texture_handle; + params.draw_target_viewport = RECT_FROM_V2(V2(0, 0), V2(dst->size.x, dst->size.y)); + params.draw_target_view = XFORM_IDENT; + gpu_dispatch(G.present_blit_dispatch_state, params); + } +} + +void gpu_present(struct v2i32 backbuffer_resolution, struct gpu_handle texture, struct xform texture_xf, i32 vsync) +{ + __prof; + /* Reload dirty shaders */ +#if RESOURCE_RELOADING for (u64 i = DX11_SHADER_KIND_NONE + 1; i < NUM_DX11_SHADER_KINDS; ++i) { struct dx11_shader_desc *desc = &G.shader_info[i]; if (shader_unset_dirty(desc)) { @@ -2004,8 +2053,8 @@ void gpu_swap_backbuffer(i32 vsync) } #endif + /* Track vram usage */ #if GSTAT_ENABLED || PROFILING - /* Check vram usage */ { struct DXGI_QUERY_VIDEO_MEMORY_INFO info = get_memory_info(); u64 vram = info.CurrentUsage; @@ -2035,6 +2084,7 @@ void gpu_swap_backbuffer(i32 vsync) } #endif + /* Wait */ i32 flags = 0; if (vsync) { if (G.swapchain_waitable != NULL) { @@ -2047,6 +2097,15 @@ void gpu_swap_backbuffer(i32 vsync) #endif } + /* Resize backbuffer */ + if (!v2i32_eq(G.backbuffer_texture.size, backbuffer_resolution)) { + present_resize(backbuffer_resolution); + } + + /* Blit to backbuffer */ + present_blit(&G.backbuffer_texture, (struct dx11_texture *)texture.v, texture_xf); + + /* Present */ gpu_capture_image_for_profiler(); { __profscope(Present); diff --git a/src/gpu_dx12.c b/src/gpu_dx12.c index 3587225c..388a39ec 100644 --- a/src/gpu_dx12.c +++ b/src/gpu_dx12.c @@ -1819,7 +1819,7 @@ struct gpu_handle gpu_recreate_backbuffer(struct v2i32 size) return res; } -void gpu_swap_backbuffer(i32 vsync) +void gpu_present(i32 vsync) { (UNUSED)vsync; } diff --git a/src/playback_wasapi.c b/src/playback_wasapi.c index 23ffcb34..9e7d66c6 100644 --- a/src/playback_wasapi.c +++ b/src/playback_wasapi.c @@ -12,23 +12,6 @@ #include "atomic.h" #include "app.h" - - - - - -void bla(void); -void bla(void) -{ - (UNUSED)bla; - DEBUGBREAKABLE; -} -#define NTDDI_WIN11_DT 0 - - - - - #define COBJMACROS #define WIN32_LEAN_AND_MEAN #define UNICODE diff --git a/src/user.c b/src/user.c index 5076a71f..2fb87150 100644 --- a/src/user.c +++ b/src/user.c @@ -72,7 +72,6 @@ GLOBAL struct { /* Gpu handles */ struct gpu_handle user_texture; - struct gpu_handle backbuffer_texture; struct gpu_handle world_gpu_plan; struct gpu_handle ui_gpu_plan; @@ -2069,32 +2068,15 @@ INTERNAL void user_update(void) __profscope(render); struct rect user_viewport = RECT_FROM_V2(V2(0, 0), G.user_size); - struct rect backbuffer_viewport = RECT_FROM_V2(V2(0, 0), G.screen_size); struct v2i32 user_resolution = v2_round_to_int(user_viewport.size); - struct v2i32 backbuffer_resolution = v2_round_to_int(backbuffer_viewport.size); + struct v2i32 backbuffer_resolution = v2_round_to_int(G.screen_size); - /* Allocate target textures */ - { - - /* User texture */ - if (!G.user_texture.v || !v2i32_eq(gpu_texture_get_size(G.user_texture), user_resolution)) { - if (G.user_texture.v) { - gpu_release(G.user_texture); - } - G.user_texture = gpu_texture_alloc(GPU_TEXTURE_FORMAT_R8G8B8A8_UNORM, GPU_TEXTURE_FLAG_TARGETABLE, user_resolution, NULL); + /* Allocate user texture */ + if (!G.user_texture.v || !v2i32_eq(gpu_texture_get_size(G.user_texture), user_resolution)) { + if (G.user_texture.v) { + gpu_release(G.user_texture); } - - /* Backbuffer texture */ - if (!G.backbuffer_texture.v || !v2i32_eq(gpu_texture_get_size(G.backbuffer_texture), backbuffer_resolution)) { - G.backbuffer_texture = gpu_recreate_backbuffer(backbuffer_resolution); - } - } - - /* Draw user texture to backbuffer texture */ - { - struct xform xf = XFORM_TRS(.t = v2_mul(V2(backbuffer_resolution.x, backbuffer_resolution.y), 0.5), .s = G.user_size); - struct draw_texture_params params = DRAW_TEXTURE_PARAMS(.xf = xf, .texture = G.user_texture); - draw_texture(G.backbuffer_gpu_plan, params); + G.user_texture = gpu_texture_alloc(GPU_TEXTURE_FORMAT_R8G8B8A8_UNORM, GPU_TEXTURE_FLAG_TARGETABLE, user_resolution, NULL); } /* Send plans to GPU */ @@ -2104,7 +2086,6 @@ INTERNAL void user_update(void) /* Clear textures */ gpu_texture_clear(G.user_texture, 0); - gpu_texture_clear(G.backbuffer_texture, RGBA32_F(0, 0, 0, 1)); /* Render world to user texture */ { @@ -2126,18 +2107,8 @@ INTERNAL void user_update(void) gpu_dispatch(G.user_dispatch_state, params); } - /* Render to backbuffer texture */ - { - struct gpu_dispatch_params params = ZI; - params.plan = G.backbuffer_gpu_plan; - params.draw_target = G.backbuffer_texture; - params.draw_target_viewport = backbuffer_viewport; - params.draw_target_view = XFORM_IDENT; - gpu_dispatch(G.backbuffer_dispatch_state, params); - } - - /* Swap backbuffer */ - gpu_swap_backbuffer(VSYNC_ENABLED); + /* Present user texture */ + gpu_present(backbuffer_resolution, G.user_texture, XFORM_TRS(.t = v2_mul(G.screen_size, 0.5), .s = G.user_size), VSYNC_ENABLED); } /* ========================== *