pipeline cache

This commit is contained in:
jacob 2025-06-24 15:30:14 -05:00
parent 214e794ec4
commit 520dd6c874
6 changed files with 265 additions and 140 deletions

View File

@ -73,6 +73,6 @@ struct ps_output {
SH_ENTRY(ROOTSIG) struct ps_output ps(struct ps_input input) SH_ENTRY(ROOTSIG) struct ps_output ps(struct ps_input input)
{ {
struct ps_output output; 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; return output;
} }

View File

@ -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); 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 * Present
* ========================== */ * ========================== */

View File

@ -60,27 +60,31 @@
#endif #endif
struct shader_desc { struct shader_desc {
char *file; struct string file;
char *func; struct string func;
}; };
struct pipeline_desc { struct pipeline_desc {
char *name; struct string name;
struct shader_desc vs; struct shader_desc vs;
struct shader_desc ps; struct shader_desc ps;
u32 flags; u32 flags;
}; };
struct pipeline { struct pipeline {
b32 valid; b32 success;
struct arena *arena; struct arena *arena;
struct string name; struct string name;
u64 hash;
u32 num_errors;
struct pipeline_error *first_error; struct pipeline_error *first_error;
struct pipeline_error *last_error; struct pipeline_error *last_error;
i64 compilation_time; i64 compilation_time;
struct dict *dependencies;
/* Lock global pipelines mutex before accessing */
i64 refcount;
struct pipeline_desc desc; struct pipeline_desc desc;
ID3D12PipelineState *pso; ID3D12PipelineState *pso;
@ -92,6 +96,18 @@ struct pipeline_error {
struct pipeline_error *next; 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 { struct command_queue {
D3D12_COMMAND_LIST_TYPE type; D3D12_COMMAND_LIST_TYPE type;
ID3D12CommandQueue *cq; ID3D12CommandQueue *cq;
@ -243,7 +259,10 @@ GLOBAL struct {
/* Pipeline cache */ /* Pipeline cache */
struct sys_mutex *pipelines_mutex; struct sys_mutex *pipelines_mutex;
struct arena *pipelines_arena; 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 */ /* Factory */
IDXGIFactory6 *factory; IDXGIFactory6 *factory;
@ -318,7 +337,9 @@ struct gp_startup_receipt gp_startup(struct work_startup_receipt *work_sr)
/* Initialize pipeline cache */ /* Initialize pipeline cache */
G.pipelines_mutex = sys_mutex_alloc(); G.pipelines_mutex = sys_mutex_alloc();
G.pipelines_arena = arena_alloc(GIGABYTE(64)); 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 */ /* Initialize dx12 */
dx12_init_device(); dx12_init_device();
@ -604,71 +625,60 @@ INTERNAL void dx12_init_objects(void)
* Dx12 pipeline initialization * 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 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_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) INTERNAL void dx12_init_pipelines(void)
{ {
__prof; __prof;
struct arena_temp scratch = scratch_begin_no_conflict(); 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) { /* Register pipeline descs */
struct pipeline *pipeline = pipelines[i]; {
if (pipeline->num_errors > 0) { /* Material pipeline */
sys_panic(pipeline->first_error->msg); {
pipeline_release(pipeline); struct pipeline_desc *desc = arena_push(G.pipelines_arena, struct pipeline_desc);
} else { desc->name = LIT("material");
pipeline->valid = true; desc->vs.file = LIT("sh/material.hlsl");
pipeline_register(pipeline); 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); scratch_end(scratch);
} }
@ -680,6 +690,7 @@ struct dx12_include_handler {
ID3DInclude d3d_handler; ID3DInclude d3d_handler;
ID3DIncludeVtbl vtbl; ID3DIncludeVtbl vtbl;
struct pipeline *pipeline; struct pipeline *pipeline;
struct sys_mutex *pipeline_mutex;
u64 num_open_resources; u64 num_open_resources;
struct resource open_resources[1024]; 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; HRESULT result = E_FAIL;
struct dx12_include_handler *handler = (struct dx12_include_handler *)d3d_handler; struct dx12_include_handler *handler = (struct dx12_include_handler *)d3d_handler;
struct string name = string_from_cstr_no_limit((char *)name_cstr); 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)) { if (handler->num_open_resources >= ARRAY_COUNT(handler->open_resources)) {
sys_panic(LIT("Dx12 include handler resource overflow")); 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++]; struct resource *res = &handler->open_resources[handler->num_open_resources++];
*res = resource_open(name); *res = resource_open(name);
if (resource_exists(res)) { 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.Open = dx12_include_open;
handler->vtbl.Close = dx12_include_close; handler->vtbl.Close = dx12_include_close;
handler->pipeline = pipeline; handler->pipeline = pipeline;
handler->pipeline_mutex = sys_mutex_alloc();
return handler; return handler;
} }
@ -747,6 +767,7 @@ INTERNAL void dx12_include_handler_release(struct dx12_include_handler *handler)
resource_close(res); resource_close(res);
} }
handler->num_open_resources = 0; handler->num_open_resources = 0;
sys_mutex_release(handler->pipeline_mutex);
} }
enum shader_compile_task_kind { enum shader_compile_task_kind {
@ -785,11 +806,9 @@ INTERNAL WORK_TASK_FUNC_DEF(shader_compile_task, comp_arg_raw)
ID3DBlob *blob = NULL; ID3DBlob *blob = NULL;
ID3DBlob *error_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)) { if (resource_exists(shader_res)) {
struct dx12_include_handler *include_handler = dx12_include_handler_alloc(scratch.arena, pipeline); 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; u32 d3d_compile_flags = D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES;
#if DX12_SHADER_DEBUG #if DX12_SHADER_DEBUG
@ -801,9 +820,9 @@ INTERNAL WORK_TASK_FUNC_DEF(shader_compile_task, comp_arg_raw)
/* Compile shader */ /* Compile shader */
{ {
struct string shader_src = resource_get_data(shader_res); 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 */ /* 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 *friendly_name_cstr = cstr_from_string(scratch.arena, friendly_name);
char *target = NULL; char *target = NULL;
switch (kind) { switch (kind) {
@ -821,7 +840,7 @@ INTERNAL WORK_TASK_FUNC_DEF(shader_compile_task, comp_arg_raw)
{ "SH_CPU", "0" }, { "SH_CPU", "0" },
{ NULL, NULL } { 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; success = SUCCEEDED(hr) && !error_blob;
} }
@ -846,15 +865,10 @@ INTERNAL WORK_TASK_FUNC_DEF(shader_compile_task, comp_arg_raw)
* Pipeline * Pipeline
* ========================== */ * ========================== */
struct pipeline_load_task_arg {
struct pipeline *pipeline;
};
INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw) INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw)
{ {
__prof; __prof;
struct pipeline_load_task_arg *load_arg = (struct pipeline_load_task_arg *)load_arg_raw; struct pipeline *pipeline = (struct pipeline *)load_arg_raw;
struct pipeline *pipeline = load_arg->pipeline;
struct pipeline_desc desc = pipeline->desc; struct pipeline_desc desc = pipeline->desc;
struct arena_temp scratch = scratch_begin_no_conflict(); 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 error_str = LIT("Unknown error");
struct string vs_filename = string_from_cstr_no_limit(desc.vs.file); b32 ps_res_is_shared = string_eq(desc.vs.file, desc.ps.file);
struct string ps_filename = string_from_cstr_no_limit(desc.ps.file); struct resource vs_res = resource_open(desc.vs.file);
b32 ps_res_is_shared = string_eq(vs_filename, ps_filename);
struct resource vs_res = resource_open(vs_filename);
struct resource ps_res = vs_res; struct resource ps_res = vs_res;
if (!ps_res_is_shared) { 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 (success) {
if (!resource_exists(&vs_res)) { 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; success = false;
} else if (!resource_exists(&ps_res)) { } 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; success = false;
} }
} }
@ -1056,12 +1069,12 @@ INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw)
pipeline->first_error = error; pipeline->first_error = error;
} }
pipeline->last_error = error; pipeline->last_error = error;
++pipeline->num_errors;
} }
pipeline->pso = pso; pipeline->pso = pso;
pipeline->rootsig = rootsig; pipeline->rootsig = rootsig;
pipeline->compilation_time = sys_time_ns() - start_ns; pipeline->compilation_time = sys_time_ns() - start_ns;
pipeline->success = success;
resource_close(&vs_res); resource_close(&vs_res);
if (!ps_res_is_shared) { if (!ps_res_is_shared) {
@ -1086,13 +1099,10 @@ INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw)
scratch_end(scratch); 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; __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(); struct work_slate ws = work_slate_begin();
for (u64 i = 0; i < num_pipelines; ++i) { for (u64 i = 0; i < num_pipelines; ++i) {
struct pipeline_desc desc = descs[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)); struct arena *pipeline_arena = arena_alloc(MEGABYTE(64));
pipeline = arena_push(pipeline_arena, struct pipeline); pipeline = arena_push(pipeline_arena, struct pipeline);
pipeline->arena = pipeline_arena; pipeline->arena = pipeline_arena;
pipelines[i] = pipeline; pipelines_out[i] = pipeline;
} }
pipeline->desc = desc; pipeline->desc = desc;
pipeline->name = string_copy(pipeline->arena, string_from_cstr_no_limit(desc.name)); pipeline->name = string_copy(pipeline->arena, desc.name);
pipeline->hash = hash_fnv64(HASH_FNV64_BASIS, pipeline->name);
struct pipeline_load_task_arg *arg = &task_args[i]; pipeline->dependencies = dict_init(pipeline->arena, 64);
arg->pipeline = pipeline; work_slate_push_task(&ws, pipeline_load_task, pipeline);
work_slate_push_task(&ws, pipeline_load_task, arg);
} }
struct work_handle work = work_slate_end_and_help(&ws, WORK_PRIORITY_HIGH); struct work_handle work = work_slate_end_and_help(&ws, WORK_PRIORITY_HIGH);
work_wait(work); work_wait(work);
return pipelines;
} }
INTERNAL void pipeline_release(struct pipeline *pipeline) INTERNAL void pipeline_release(struct pipeline *pipeline)
{ {
__prof; __prof;
/* FIXME: Delayed release based on queue fence */
(UNUSED)pipeline;
#if 0
if (pipeline->pso) { if (pipeline->pso) {
ID3D12PipelineState_Release(pipeline->pso); ID3D12PipelineState_Release(pipeline->pso);
} }
arena_release(pipeline->arena); arena_release(pipeline->arena);
#endif
} }
/* ========================== * /* ========================== *
* Pipeline cache * Pipeline cache
* ========================== */ * ========================== */
struct pipeline_scope {
i32 _;
};
INTERNAL struct pipeline_scope *pipeline_scope_begin(void) 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) 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) INTERNAL struct pipeline *pipeline_from_name(struct pipeline_scope *scope, struct string name)
{ {
(UNUSED)scope; struct pipeline *pipeline = NULL;
struct pipeline *pipeline = &g_nil_pipeline;
u64 hash = hash_fnv64(HASH_FNV64_BASIS, name); u64 hash = hash_fnv64(HASH_FNV64_BASIS, name);
struct sys_lock lock = sys_mutex_lock_s(G.pipelines_mutex);
{ pipeline = dict_get(scope->refs, hash);
struct pipeline *res = dict_get(G.pipelines_dict, hash); if (!pipeline) {
if (res) { {
pipeline = res; 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); 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); sys_mutex_unlock(&lock);
} }
@ -1174,15 +1237,32 @@ INTERNAL void pipeline_register(struct pipeline *pipeline)
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(pipeline_resource_watch_callback, name) INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(pipeline_resource_watch_callback, name)
{ {
#if 0 struct arena_temp scratch = scratch_begin_no_conflict();
if (shader_set_dirty(name)) {
logf_debug("Shader source file \"%F\" has changed", FMT_STR(name)); /* 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
} }
#endif
/* ========================== * /* ========================== *
* Descriptor * Descriptor
@ -2075,7 +2155,7 @@ void gp_dispatch(struct gp_dispatch_params params)
struct pipeline_scope *pipeline_scope = pipeline_scope_begin(); struct pipeline_scope *pipeline_scope = pipeline_scope_begin();
struct pipeline *material_pipeline = pipeline_from_name(pipeline_scope, LIT("material")); 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 command_list *cl = command_list_open(G.cq_direct);
{ {
struct dx12_resource *target = handle_get_data(params.draw_target, DX12_HANDLE_KIND_RESOURCE); 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
* ========================== */ * ========================== */
/* ========================== * #if 0
* Present struct gp_memory_info gp_query_memory_info(void)
* ========================== */
#if GSTAT_ENABLED || PROFILING
INTERNAL void query_memory_info(void)
{ {
struct gp_memory_info res = ZI;
HRESULT hr = 0; HRESULT hr = 0;
IDXGIAdapter3 *dxgiAdapter3 = NULL; IDXGIAdapter3 *dxgiAdapter3 = NULL;
struct DXGI_QUERY_VIDEO_MEMORY_INFO info = ZI; struct DXGI_QUERY_VIDEO_MEMORY_INFO info = ZI;
@ -2215,13 +2293,44 @@ INTERNAL void query_memory_info(void)
if (dxgiAdapter3) { if (dxgiAdapter3) {
IDXGIAdapter_Release(dxgiAdapter3); IDXGIAdapter_Release(dxgiAdapter3);
} }
return res;
} }
#else #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 #endif
/* ========================== *
* Present
* ========================== */
INTERNAL struct dx12_resource *update_swapchain(struct sys_window *window, struct v2i32 resolution) INTERNAL struct dx12_resource *update_swapchain(struct sys_window *window, struct v2i32 resolution)
{ {
__prof; __prof;
@ -2299,7 +2408,7 @@ INTERNAL void present_blit(struct dx12_resource *dst, struct dx12_resource *src,
__prof; __prof;
struct pipeline_scope *pipeline_scope = pipeline_scope_begin(); struct pipeline_scope *pipeline_scope = pipeline_scope_begin();
struct pipeline *blit_pipeline = pipeline_from_name(pipeline_scope, LIT("blit")); 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); struct command_list *cl = command_list_open(G.cq_direct);
{ {
/* Upload dummmy vert & index buffer */ /* 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) 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); //sys_sleep(0.1);
struct dx12_resource *backbuffer_resource = update_swapchain(window, backbuffer_resolution); struct dx12_resource *backbuffer_resource = update_swapchain(window, backbuffer_resolution);

View File

@ -10,8 +10,6 @@
struct _gstats { struct _gstats {
struct atomic_u64 GSTAT_SOCK_BYTES_SENT; struct atomic_u64 GSTAT_SOCK_BYTES_SENT;
struct atomic_u64 GSTAT_SOCK_BYTES_RECEIVED; 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_COMMITTED;
struct atomic_u64 GSTAT_MEMORY_RESERVED; struct atomic_u64 GSTAT_MEMORY_RESERVED;
struct atomic_u64 GSTAT_NUM_ARENAS; struct atomic_u64 GSTAT_NUM_ARENAS;

View File

@ -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 /* NOTE: We separate the responsibilities of monitoring directory changes
* & dispatching watch callbacks into two separate threads so that we can delay * & dispatching watch callbacks into two separate threads so that we can delay
* the dispatch of these callbacks, allowing for deduplication of file * the dispatch, allowing for deduplication of file modification notifications. */
* modification notifications. */
#define WATCH_DISPATCHER_DELAY_SECONDS 0.050 #define WATCH_DISPATCHER_DELAY_SECONDS 0.050
#define WATCH_DISPATCHER_DEDUP_DICT_BINS 128 #define WATCH_DISPATCHER_DEDUP_DICT_BINS 128

View File

@ -1930,6 +1930,12 @@ INTERNAL void user_update(void)
} }
} }
/* ========================== *
* Query vram
* ========================== */
struct gp_memory_info vram = gp_query_memory_info();
/* ========================== * /* ========================== *
* Draw global debug 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_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;
//text.len += string_copy(temp.arena, LIT("\n")).len; //text.len += string_copy(temp.arena, LIT("\n")).len;