From 520dd6c87471159121565429cfdc5a905f1acc67 Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 24 Jun 2025 15:30:14 -0500 Subject: [PATCH] pipeline cache --- res/sh/material.hlsl | 2 +- src/gp.h | 13 ++ src/gp_dx12.c | 375 +++++++++++++++++++++++++++---------------- src/gstat.h | 2 - src/resource.c | 3 +- src/user.c | 10 +- 6 files changed, 265 insertions(+), 140 deletions(-) diff --git a/res/sh/material.hlsl b/res/sh/material.hlsl index bc4122e9..a257276e 100644 --- a/res/sh/material.hlsl +++ b/res/sh/material.hlsl @@ -73,6 +73,6 @@ struct ps_output { SH_ENTRY(ROOTSIG) struct ps_output ps(struct ps_input input) { struct ps_output output; - output.SV_Target = g_nuri_textures[NURI(input.vs.texture_nuri)].Sample(g_sampler, input.vs.uv) * input.vs.tint_lin; + output.SV_Target = g_nuri_textures[NURI(input.vs.texture_nuri)].Sample(g_sampler, input.vs.uv) * input.vs.tint_lin * 1; return output; } diff --git a/src/gp.h b/src/gp.h index e61314be..16998703 100644 --- a/src/gp.h +++ b/src/gp.h @@ -125,6 +125,19 @@ void gp_push_cmd(struct gp_handle gp_flow, struct gp_cmd_params params); void gp_dispatch(struct gp_dispatch_params params); +/* ========================== * + * Memory info + * ========================== */ + +struct gp_memory_info { + u64 local_used; + u64 local_budget; + u64 non_local_used; + u64 non_local_budget; +}; + +struct gp_memory_info gp_query_memory_info(void); + /* ========================== * * Present * ========================== */ diff --git a/src/gp_dx12.c b/src/gp_dx12.c index 353f1344..25b2ca22 100644 --- a/src/gp_dx12.c +++ b/src/gp_dx12.c @@ -60,27 +60,31 @@ #endif struct shader_desc { - char *file; - char *func; + struct string file; + struct string func; }; struct pipeline_desc { - char *name; + struct string name; struct shader_desc vs; struct shader_desc ps; u32 flags; }; struct pipeline { - b32 valid; + b32 success; struct arena *arena; struct string name; + u64 hash; - u32 num_errors; struct pipeline_error *first_error; struct pipeline_error *last_error; i64 compilation_time; + struct dict *dependencies; + + /* Lock global pipelines mutex before accessing */ + i64 refcount; struct pipeline_desc desc; ID3D12PipelineState *pso; @@ -92,6 +96,18 @@ struct pipeline_error { struct pipeline_error *next; }; +struct pipeline_include { + struct string name; + u64 name_hash; + struct pipeline_include *next; +}; + +struct pipeline_scope { + struct arena *arena; + struct dict *refs; + struct pipeline_scope *next_free; +}; + struct command_queue { D3D12_COMMAND_LIST_TYPE type; ID3D12CommandQueue *cq; @@ -243,7 +259,10 @@ GLOBAL struct { /* Pipeline cache */ struct sys_mutex *pipelines_mutex; struct arena *pipelines_arena; - struct dict *pipelines_dict; + struct dict *pipeline_descs; + struct dict *top_pipelines; /* Latest pipelines */ + struct dict *top_successful_pipelines; /* Latest pipelines that successfully compiled */ + struct pipeline_scope *first_free_pipeline_scope; /* Factory */ IDXGIFactory6 *factory; @@ -318,7 +337,9 @@ struct gp_startup_receipt gp_startup(struct work_startup_receipt *work_sr) /* Initialize pipeline cache */ G.pipelines_mutex = sys_mutex_alloc(); G.pipelines_arena = arena_alloc(GIGABYTE(64)); - G.pipelines_dict = dict_init(G.pipelines_arena, 1024); + G.pipeline_descs = dict_init(G.pipelines_arena, 1024); + G.top_pipelines = dict_init(G.pipelines_arena, 1024); + G.top_successful_pipelines = dict_init(G.pipelines_arena, 1024); /* Initialize dx12 */ dx12_init_device(); @@ -604,71 +625,60 @@ INTERNAL void dx12_init_objects(void) * Dx12 pipeline initialization * ========================== */ -/* TDOO: Rename 'mesh shader' to 'triangle shader' or something */ -/* TODO: Move shader structs into shared C-HLSL header file */ - -/* ============= */ -/* Mesh pipeline */ - -/* ============= */ -/* Material pipeline */ - -#if 0 -PACK(struct fx_material_constant { - struct mat4x4 vp; - u32 instance_offset; -}); - -PACK(struct fx_material_instance { - struct xform xf; - struct v2 uv0; - struct v2 uv1; - u32 tint_srgb; - f32 emittance; -}); -#endif - -/* ============= */ -/* Grid pipeline */ - -/* ============= */ -/* Init pipelines */ - INTERNAL READONLY struct pipeline g_nil_pipeline = ZI; -INTERNAL READONLY struct pipeline_desc g_pipeline_descs[] = { - /* Material pipeline */ - { - .name = "material", - .vs = { "sh/material.hlsl", "vs" }, - .ps = { "sh/material.hlsl", "ps" } - }, - /* Blit pipeline */ - { - .name = "blit", - .vs = { "sh/blit.hlsl", "vs" }, - .ps = { "sh/blit.hlsl", "ps" } - } -}; -INTERNAL struct pipeline **pipeline_alloc_from_descs(struct arena *arena, u64 num_pipelines, struct pipeline_desc *descs); +INTERNAL void pipeline_alloc_from_descs(u64 num_pipelines, struct pipeline_desc *descs, struct pipeline **pipelines_out); INTERNAL void pipeline_release(struct pipeline *pipeline); -INTERNAL void pipeline_register(struct pipeline *pipeline); +INTERNAL void pipeline_register(u64 num_pipelines, struct pipeline **pipelines); INTERNAL void dx12_init_pipelines(void) { __prof; struct arena_temp scratch = scratch_begin_no_conflict(); - struct pipeline **pipelines = pipeline_alloc_from_descs(scratch.arena, ARRAY_COUNT(g_pipeline_descs), g_pipeline_descs); - for (u64 i = 0; i < ARRAY_COUNT(g_pipeline_descs); ++i) { - struct pipeline *pipeline = pipelines[i]; - if (pipeline->num_errors > 0) { - sys_panic(pipeline->first_error->msg); - pipeline_release(pipeline); - } else { - pipeline->valid = true; - pipeline_register(pipeline); + + /* Register pipeline descs */ + { + /* Material pipeline */ + { + struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc); + desc->name = LIT("material"); + desc->vs.file = LIT("sh/material.hlsl"); + desc->ps.file = LIT("sh/material.hlsl"); + desc->vs.func = LIT("vs"); + desc->ps.func = LIT("ps"); + dict_set(G.pipelines_arena, G.pipeline_descs, hash_fnv64(HASH_FNV64_BASIS, desc->name), (u64)desc); + } + /* Blit pipeilne */ + { + struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc); + desc->name = LIT("blit"); + desc->vs.file = LIT("sh/blit.hlsl"); + desc->ps.file = LIT("sh/blit.hlsl"); + desc->vs.func = LIT("vs"); + desc->ps.func = LIT("ps"); + dict_set(G.pipelines_arena, G.pipeline_descs, hash_fnv64(HASH_FNV64_BASIS, desc->name), (u64)desc); } } + + /* Compile pipelines */ + u32 num_pipelines = 0; + struct pipeline_desc *descs = arena_push_dry(scratch.arena, struct pipeline_desc); + for (struct dict_entry *entry = G.pipeline_descs->first; entry; entry = entry->next) { + struct pipeline_desc *desc = (struct pipeline_desc *)entry->value; + *arena_push(scratch.arena, struct pipeline_desc) = *desc; + ++num_pipelines; + } + struct pipeline **pipelines = arena_push_array(scratch.arena, struct pipeline *, num_pipelines); + pipeline_alloc_from_descs(num_pipelines, descs, pipelines); + for (u32 i = 0; i < num_pipelines; ++i) { + struct pipeline *pipeline = pipelines[i]; + if (!pipeline->success) { + struct string msg = pipeline->first_error ? pipeline->first_error->msg : LIT("Unknown error"); + sys_panic(msg); + } + } + pipeline_register(num_pipelines, pipelines); + scratch_end(scratch); } @@ -680,6 +690,7 @@ struct dx12_include_handler { ID3DInclude d3d_handler; ID3DIncludeVtbl vtbl; struct pipeline *pipeline; + struct sys_mutex *pipeline_mutex; u64 num_open_resources; struct resource open_resources[1024]; }; @@ -692,11 +703,19 @@ INTERNAL HRESULT dx12_include_open(ID3DInclude *d3d_handler, D3D_INCLUDE_TYPE in HRESULT result = E_FAIL; struct dx12_include_handler *handler = (struct dx12_include_handler *)d3d_handler; struct string name = string_from_cstr_no_limit((char *)name_cstr); + u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); if (handler->num_open_resources >= ARRAY_COUNT(handler->open_resources)) { sys_panic(LIT("Dx12 include handler resource overflow")); } + struct sys_lock lock = sys_mutex_lock_e(handler->pipeline_mutex); + { + struct pipeline *pipeline = handler->pipeline; + dict_set(pipeline->arena, pipeline->dependencies, hash, 1); + } + sys_mutex_unlock(&lock); + struct resource *res = &handler->open_resources[handler->num_open_resources++]; *res = resource_open(name); if (resource_exists(res)) { @@ -736,6 +755,7 @@ INTERNAL struct dx12_include_handler *dx12_include_handler_alloc(struct arena *a handler->vtbl.Open = dx12_include_open; handler->vtbl.Close = dx12_include_close; handler->pipeline = pipeline; + handler->pipeline_mutex = sys_mutex_alloc(); return handler; } @@ -747,6 +767,7 @@ INTERNAL void dx12_include_handler_release(struct dx12_include_handler *handler) resource_close(res); } handler->num_open_resources = 0; + sys_mutex_release(handler->pipeline_mutex); } enum shader_compile_task_kind { @@ -785,11 +806,9 @@ INTERNAL WORK_TASK_FUNC_DEF(shader_compile_task, comp_arg_raw) ID3DBlob *blob = NULL; ID3DBlob *error_blob = NULL; - struct string file_name = string_from_cstr_no_limit(shader_desc.file); - struct string func_name = string_from_cstr_no_limit(shader_desc.func); - if (resource_exists(shader_res)) { struct dx12_include_handler *include_handler = dx12_include_handler_alloc(scratch.arena, pipeline); + char *func_cstr = cstr_from_string(scratch.arena, shader_desc.func); u32 d3d_compile_flags = D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES; #if DX12_SHADER_DEBUG @@ -801,9 +820,9 @@ INTERNAL WORK_TASK_FUNC_DEF(shader_compile_task, comp_arg_raw) /* Compile shader */ { struct string shader_src = resource_get_data(shader_res); - logf_info("Compiling shader \"%F:%F\"", FMT_STR(file_name), FMT_STR(func_name)); + logf_info("Compiling shader \"%F:%F\"", FMT_STR(shader_desc.file), FMT_STR(shader_desc.func)); /* Compile shader */ - struct string friendly_name = string_cat(scratch.arena, LIT("res/"), file_name); + struct string friendly_name = string_cat(scratch.arena, LIT("res/"), shader_desc.file); char *friendly_name_cstr = cstr_from_string(scratch.arena, friendly_name); char *target = NULL; switch (kind) { @@ -821,7 +840,7 @@ INTERNAL WORK_TASK_FUNC_DEF(shader_compile_task, comp_arg_raw) { "SH_CPU", "0" }, { NULL, NULL } }; - HRESULT hr = D3DCompile(shader_src.text, shader_src.len, friendly_name_cstr, defines, (ID3DInclude *)include_handler, shader_desc.func, target, d3d_compile_flags, 0, &blob, &error_blob); + HRESULT hr = D3DCompile(shader_src.text, shader_src.len, friendly_name_cstr, defines, (ID3DInclude *)include_handler, func_cstr, target, d3d_compile_flags, 0, &blob, &error_blob); success = SUCCEEDED(hr) && !error_blob; } @@ -846,15 +865,10 @@ INTERNAL WORK_TASK_FUNC_DEF(shader_compile_task, comp_arg_raw) * Pipeline * ========================== */ -struct pipeline_load_task_arg { - struct pipeline *pipeline; -}; - INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw) { __prof; - struct pipeline_load_task_arg *load_arg = (struct pipeline_load_task_arg *)load_arg_raw; - struct pipeline *pipeline = load_arg->pipeline; + struct pipeline *pipeline = (struct pipeline *)load_arg_raw; struct pipeline_desc desc = pipeline->desc; struct arena_temp scratch = scratch_begin_no_conflict(); @@ -867,22 +881,21 @@ INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw) struct string error_str = LIT("Unknown error"); - struct string vs_filename = string_from_cstr_no_limit(desc.vs.file); - struct string ps_filename = string_from_cstr_no_limit(desc.ps.file); - - b32 ps_res_is_shared = string_eq(vs_filename, ps_filename); - struct resource vs_res = resource_open(vs_filename); + b32 ps_res_is_shared = string_eq(desc.vs.file, desc.ps.file); + struct resource vs_res = resource_open(desc.vs.file); struct resource ps_res = vs_res; if (!ps_res_is_shared) { - ps_res = resource_open(ps_filename); + ps_res = resource_open(desc.ps.file); } + dict_set(pipeline->arena, pipeline->dependencies, hash_fnv64(HASH_FNV64_BASIS, desc.vs.file), 1); + dict_set(pipeline->arena, pipeline->dependencies, hash_fnv64(HASH_FNV64_BASIS, desc.ps.file), 1); if (success) { if (!resource_exists(&vs_res)) { - error_str = string_format(scratch.arena, LIT("Shader source \"%F\" not found"), FMT_STR(vs_filename)); + error_str = string_format(scratch.arena, LIT("Shader source \"%F\" not found"), FMT_STR(desc.vs.file)); success = false; } else if (!resource_exists(&ps_res)) { - error_str = string_format(scratch.arena, LIT("Shader source \"%F\" not found"), FMT_STR(ps_filename)); + error_str = string_format(scratch.arena, LIT("Shader source \"%F\" not found"), FMT_STR(desc.ps.file)); success = false; } } @@ -1056,12 +1069,12 @@ INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw) pipeline->first_error = error; } pipeline->last_error = error; - ++pipeline->num_errors; } pipeline->pso = pso; pipeline->rootsig = rootsig; pipeline->compilation_time = sys_time_ns() - start_ns; + pipeline->success = success; resource_close(&vs_res); if (!ps_res_is_shared) { @@ -1086,13 +1099,10 @@ INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw) scratch_end(scratch); } -INTERNAL struct pipeline **pipeline_alloc_from_descs(struct arena *arena, u64 num_pipelines, struct pipeline_desc *descs) +/* Expects `descs` and `pipelines_out` to be arrays of length `num_pipelines` */ +INTERNAL void pipeline_alloc_from_descs(u64 num_pipelines, struct pipeline_desc *descs, struct pipeline **pipelines_out) { __prof; - struct pipeline **pipelines = arena_push_array(arena, struct pipeline *, num_pipelines); - struct pipeline_load_task_arg *task_args = arena_push_array(arena, struct pipeline_load_task_arg, num_pipelines); - - /* Load pipelines */ struct work_slate ws = work_slate_begin(); for (u64 i = 0; i < num_pipelines; ++i) { struct pipeline_desc desc = descs[i]; @@ -1101,72 +1111,125 @@ INTERNAL struct pipeline **pipeline_alloc_from_descs(struct arena *arena, u64 nu struct arena *pipeline_arena = arena_alloc(MEGABYTE(64)); pipeline = arena_push(pipeline_arena, struct pipeline); pipeline->arena = pipeline_arena; - pipelines[i] = pipeline; + pipelines_out[i] = pipeline; } pipeline->desc = desc; - pipeline->name = string_copy(pipeline->arena, string_from_cstr_no_limit(desc.name)); - - struct pipeline_load_task_arg *arg = &task_args[i]; - arg->pipeline = pipeline; - - work_slate_push_task(&ws, pipeline_load_task, arg); + pipeline->name = string_copy(pipeline->arena, desc.name); + pipeline->hash = hash_fnv64(HASH_FNV64_BASIS, pipeline->name); + pipeline->dependencies = dict_init(pipeline->arena, 64); + work_slate_push_task(&ws, pipeline_load_task, pipeline); } struct work_handle work = work_slate_end_and_help(&ws, WORK_PRIORITY_HIGH); work_wait(work); - - return pipelines; } INTERNAL void pipeline_release(struct pipeline *pipeline) { __prof; + /* FIXME: Delayed release based on queue fence */ + (UNUSED)pipeline; +#if 0 if (pipeline->pso) { ID3D12PipelineState_Release(pipeline->pso); } arena_release(pipeline->arena); +#endif } /* ========================== * * Pipeline cache * ========================== */ -struct pipeline_scope { - i32 _; -}; - INTERNAL struct pipeline_scope *pipeline_scope_begin(void) { - return NULL; + struct pipeline_scope *scope = NULL; + { + struct sys_lock lock = sys_mutex_lock_e(G.pipelines_mutex); + if (G.first_free_pipeline_scope) { + scope = G.first_free_pipeline_scope; + G.first_free_pipeline_scope = scope->next_free; + } + sys_mutex_unlock(&lock); + } + struct arena *arena = NULL; + if (scope) { + arena = scope->arena; + } else { + arena = arena_alloc(MEGABYTE(64)); + } + arena_reset(arena); + scope = arena_push(arena, struct pipeline_scope); + scope->arena = arena; + scope->refs = dict_init(scope->arena, 64); + return scope; } INTERNAL void pipeline_scope_end(struct pipeline_scope *scope) { - (UNUSED)scope; + struct sys_lock lock = sys_mutex_lock_e(G.pipelines_mutex); + { + for (struct dict_entry *entry = scope->refs->first; entry; entry = entry->next) { + struct pipeline *pipeline = (struct pipeline *)entry->value; + if (--pipeline->refcount <= 0) { + pipeline_release(pipeline); + } + } + scope->next_free = G.first_free_pipeline_scope; + G.first_free_pipeline_scope = scope; + } + sys_mutex_unlock(&lock); } INTERNAL struct pipeline *pipeline_from_name(struct pipeline_scope *scope, struct string name) { - (UNUSED)scope; - - struct pipeline *pipeline = &g_nil_pipeline; + struct pipeline *pipeline = NULL; u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); - struct sys_lock lock = sys_mutex_lock_s(G.pipelines_mutex); - { - struct pipeline *res = dict_get(G.pipelines_dict, hash); - if (res) { - pipeline = res; + + pipeline = dict_get(scope->refs, hash); + if (!pipeline) { + { + struct sys_lock lock = sys_mutex_lock_e(G.pipelines_mutex); + struct pipeline *res = dict_get(G.top_successful_pipelines, hash); + if (res) { + pipeline = res; + ++pipeline->refcount; + } + sys_mutex_unlock(&lock); + } + if (pipeline) { + dict_set(scope->arena, scope->refs, hash, (u64)pipeline); } } - sys_mutex_unlock(&lock); - return pipeline; + + return pipeline ? pipeline : &g_nil_pipeline; } -INTERNAL void pipeline_register(struct pipeline *pipeline) +INTERNAL void pipeline_register(u64 num_pipelines, struct pipeline **pipelines) { - u64 hash = hash_fnv64(HASH_FNV64_BASIS, pipeline->name); struct sys_lock lock = sys_mutex_lock_e(G.pipelines_mutex); { - dict_set(G.pipelines_arena, G.pipelines_dict, hash, pipeline); + for (u64 i = 0; i < num_pipelines; ++i) { + struct pipeline *pipeline = pipelines[i]; + u64 hash = pipeline->hash; + /* Insert into top dict */ + { + struct pipeline *old_pipeline = (struct pipeline *)dict_get(G.top_pipelines, hash); + if (old_pipeline && --old_pipeline->refcount <= 0) { + pipeline_release(old_pipeline); + } + dict_set(G.pipelines_arena, G.top_pipelines, hash, (u64)pipeline); + ++pipeline->refcount; + } + /* Insert into success dict */ + if (pipeline->success) { + struct pipeline *old_pipeline = (struct pipeline *)dict_get(G.top_successful_pipelines, hash); + if (old_pipeline && --old_pipeline->refcount <= 0) { + pipeline_release(old_pipeline); + } + dict_set(G.pipelines_arena, G.top_successful_pipelines, hash, (u64)pipeline); + ++pipeline->refcount; + } + } } sys_mutex_unlock(&lock); } @@ -1174,15 +1237,32 @@ INTERNAL void pipeline_register(struct pipeline *pipeline) #if RESOURCE_RELOADING INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(pipeline_resource_watch_callback, name) { -#if 0 - if (shader_set_dirty(name)) { - logf_debug("Shader source file \"%F\" has changed", FMT_STR(name)); + struct arena_temp scratch = scratch_begin_no_conflict(); + + /* Find dirty pipelines */ + u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); + u32 num_pipelines = 0; + struct pipeline_desc *pipeline_descs = arena_push_dry(scratch.arena, struct pipeline_desc); + { + struct sys_lock lock = sys_mutex_lock_s(G.pipelines_mutex); + for (struct dict_entry *entry = G.top_pipelines->first; entry; entry = entry->next) { + struct pipeline *pipeline = (struct pipeline *)entry->value; + if (dict_get(pipeline->dependencies, hash) == 1) { + *arena_push(scratch.arena, struct pipeline_desc) = pipeline->desc; + ++num_pipelines; + } + } + sys_mutex_unlock(&lock); } -#else - (UNUSED)name; + + /* Recompile dirty pipelines */ + struct pipeline **pipelines = arena_push_array(scratch.arena, struct pipeline *, num_pipelines); + pipeline_alloc_from_descs(num_pipelines, pipeline_descs, pipelines); + pipeline_register(num_pipelines, pipelines); + + scratch_end(scratch); #endif } -#endif /* ========================== * * Descriptor @@ -2075,7 +2155,7 @@ void gp_dispatch(struct gp_dispatch_params params) struct pipeline_scope *pipeline_scope = pipeline_scope_begin(); struct pipeline *material_pipeline = pipeline_from_name(pipeline_scope, LIT("material")); - if (material_pipeline->valid) { + if (material_pipeline->success) { struct command_list *cl = command_list_open(G.cq_direct); { struct dx12_resource *target = handle_get_data(params.draw_target, DX12_HANDLE_KIND_RESOURCE); @@ -2166,16 +2246,14 @@ void gp_dispatch(struct gp_dispatch_params params) } /* ========================== * - * Swapchain + * Memory info * ========================== */ -/* ========================== * - * Present - * ========================== */ - -#if GSTAT_ENABLED || PROFILING -INTERNAL void query_memory_info(void) +#if 0 +struct gp_memory_info gp_query_memory_info(void) { + struct gp_memory_info res = ZI; + HRESULT hr = 0; IDXGIAdapter3 *dxgiAdapter3 = NULL; struct DXGI_QUERY_VIDEO_MEMORY_INFO info = ZI; @@ -2215,13 +2293,44 @@ INTERNAL void query_memory_info(void) if (dxgiAdapter3) { IDXGIAdapter_Release(dxgiAdapter3); } + + return res; } #else -INTERNAL void query_memory_info(void) +struct gp_memory_info gp_query_memory_info(void) { + struct gp_memory_info res = ZI; + + HRESULT hr = 0; + IDXGIAdapter3 *dxgiAdapter3 = NULL; + if (SUCCEEDED(hr)) { + hr = IDXGIAdapter_QueryInterface(G.adapter, &IID_IDXGIAdapter3, (void **)&dxgiAdapter3); + ASSERT(SUCCEEDED(hr)); + } + if (SUCCEEDED(hr)) { + struct DXGI_QUERY_VIDEO_MEMORY_INFO info = ZI; + IDXGIAdapter3_QueryVideoMemoryInfo(dxgiAdapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info); + res.local_used = info.CurrentUsage; + res.local_budget = info.Budget; + } + if (SUCCEEDED(hr)) { + struct DXGI_QUERY_VIDEO_MEMORY_INFO info = ZI; + IDXGIAdapter3_QueryVideoMemoryInfo(dxgiAdapter3, 0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &info); + res.non_local_used = info.CurrentUsage; + res.non_local_budget = info.Budget; + } + if (dxgiAdapter3) { + IDXGIAdapter_Release(dxgiAdapter3); + } + return res; } #endif + +/* ========================== * + * Present + * ========================== */ + INTERNAL struct dx12_resource *update_swapchain(struct sys_window *window, struct v2i32 resolution) { __prof; @@ -2299,7 +2408,7 @@ INTERNAL void present_blit(struct dx12_resource *dst, struct dx12_resource *src, __prof; struct pipeline_scope *pipeline_scope = pipeline_scope_begin(); struct pipeline *blit_pipeline = pipeline_from_name(pipeline_scope, LIT("blit")); - if (blit_pipeline->valid) { + if (blit_pipeline->success) { struct command_list *cl = command_list_open(G.cq_direct); { /* Upload dummmy vert & index buffer */ @@ -2366,8 +2475,6 @@ INTERNAL void present_blit(struct dx12_resource *dst, struct dx12_resource *src, void gp_present(struct sys_window *window, struct v2i32 backbuffer_resolution, struct gp_handle texture, struct xform texture_xf, i32 vsync) { - query_memory_info(); - //sys_sleep(0.1); struct dx12_resource *backbuffer_resource = update_swapchain(window, backbuffer_resolution); diff --git a/src/gstat.h b/src/gstat.h index b2d2c955..ca2ee7c6 100644 --- a/src/gstat.h +++ b/src/gstat.h @@ -10,8 +10,6 @@ struct _gstats { struct atomic_u64 GSTAT_SOCK_BYTES_SENT; struct atomic_u64 GSTAT_SOCK_BYTES_RECEIVED; - struct atomic_u64 GSTAT_VRAM_USAGE; - struct atomic_u64 GSTAT_VRAM_BUDGET; struct atomic_u64 GSTAT_MEMORY_COMMITTED; struct atomic_u64 GSTAT_MEMORY_RESERVED; struct atomic_u64 GSTAT_NUM_ARENAS; diff --git a/src/resource.c b/src/resource.c index d0f5984a..2e1635df 100644 --- a/src/resource.c +++ b/src/resource.c @@ -213,8 +213,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(resource_watch_monitor_thread_entry_poi /* NOTE: We separate the responsibilities of monitoring directory changes * & dispatching watch callbacks into two separate threads so that we can delay - * the dispatch of these callbacks, allowing for deduplication of file - * modification notifications. */ + * the dispatch, allowing for deduplication of file modification notifications. */ #define WATCH_DISPATCHER_DELAY_SECONDS 0.050 #define WATCH_DISPATCHER_DEDUP_DICT_BINS 128 diff --git a/src/user.c b/src/user.c index 7c486aac..ba6e1f04 100644 --- a/src/user.c +++ b/src/user.c @@ -1930,6 +1930,12 @@ INTERNAL void user_update(void) } } + /* ========================== * + * Query vram + * ========================== */ + + struct gp_memory_info vram = gp_query_memory_info(); + /* ========================== * * Draw global debug info * ========================== */ @@ -2019,7 +2025,9 @@ INTERNAL void user_update(void) text.len += string_copy(temp.arena, LIT("\n")).len; text.len += string_copy(temp.arena, LIT("\n")).len; - text.len += string_format(temp.arena, LIT("Video memory usage: %F MiB"), FMT_FLOAT((f64)gstat_get(GSTAT_VRAM_USAGE) / 1024 / 1024)).len; + text.len += string_format(temp.arena, LIT("Video memory (GPU): %F MiB"), FMT_FLOAT((f64)vram.local_used / 1024 / 1024)).len; + text.len += string_copy(temp.arena, LIT("\n")).len; + text.len += string_format(temp.arena, LIT("Video memory (shared): %F MiB"), FMT_FLOAT((f64)vram.non_local_used / 1024 / 1024)).len; //text.len += string_copy(temp.arena, LIT("\n")).len; //text.len += string_copy(temp.arena, LIT("\n")).len;