use root constants

This commit is contained in:
jacob 2025-06-23 16:38:55 -05:00
parent ccf47c03f6
commit 01aff521da
4 changed files with 251 additions and 155 deletions

View File

@ -6,8 +6,8 @@
#define DECL(t, n) t n : n
#define NURI(i) NonUniformResourceIndex(i)
#ifdef INTELLISENSE
# define INLINE
#if !SH_CPU
# define INLINE /* For intellisense */
#endif
/* Linear color from normalized sRGB */

View File

@ -5,7 +5,7 @@
* ========================== */
#define ROOTSIG \
"CBV(b0), " \
"RootConstants(num32BitConstants=16, b0), " \
"SRV(t0), " \
"DescriptorTable(SRV(t1, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE)), " \
"StaticSampler(s0, " \

View File

@ -3,6 +3,7 @@
#define SH_STRUCT(s) PACK(struct s)
#define SH_DECL(t, n) struct CAT(sh_, t) n
#define SH_ENTRY(rootsig) static
#define SH_ASSERT_32BIT(s, n) CT_ASSERT((sizeof(s) / 4) == n)
struct sh_uint { u32 v; };
INLINE struct sh_uint sh_uint_from_u32(u32 v)
@ -45,6 +46,7 @@ INLINE struct sh_float2x3 sh_float2x3_from_xform(struct xform v)
#define SH_STRUCT(s) struct s
#define SH_DECL(t, n) t n
#define SH_ENTRY(rootsig) [RootSignature(rootsig)]
#define SH_ASSERT_32BIT(s, n)
#endif
@ -55,6 +57,7 @@ INLINE struct sh_float2x3 sh_float2x3_from_xform(struct xform v)
SH_STRUCT(sh_material_constants {
SH_DECL(float4x4, projection);
});
SH_ASSERT_32BIT(struct sh_material_constants, 16); /* Expected 32bit root constant size in shader */
SH_STRUCT(sh_material_instance {
SH_DECL(float2x3, xf);

View File

@ -72,20 +72,24 @@ struct pipeline_desc {
};
struct pipeline {
b32 valid;
struct arena *arena;
struct string name;
u32 num_errors;
struct pipeline_error *first_error;
struct pipeline_error *last_error;
i64 compilation_time;
struct pipeline_desc desc;
ID3D12PipelineState *pso;
ID3D12RootSignature *rootsig;
};
struct pipeline_result {
struct pipeline pipeline;
i64 elapsed;
u64 errors_text_len;
u8 errors_text[KILOBYTE(16)];
};
struct pipeline_error {
struct string msg;
struct pipeline_error *next;
};
struct command_queue {
@ -236,22 +240,10 @@ GLOBAL struct {
struct arena *resources_arena;
struct dx12_resource *first_free_resource;
/* FIXME: Remove this (testing) */
struct pipeline test_pipeline;
/* Pipeline cache */
struct sys_mutex *pipelines_mutex;
struct arena *pipelines_arena;
struct dict *pipelines_dict;
/* Factory */
IDXGIFactory6 *factory;
@ -298,6 +290,10 @@ INTERNAL struct command_queue *command_queue_alloc(enum D3D12_COMMAND_LIST_TYPE
INTERNAL void command_queue_release(struct command_queue *cq);
INTERNAL void dx12_resource_release(struct dx12_resource *resource);
#if RESOURCE_RELOADING
INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(pipeline_resource_watch_callback, name);
#endif
struct gp_startup_receipt gp_startup(struct work_startup_receipt *work_sr)
{
__prof;
@ -319,12 +315,20 @@ struct gp_startup_receipt gp_startup(struct work_startup_receipt *work_sr)
G.resources_mutex = sys_mutex_alloc();
G.resources_arena = arena_alloc(GIGABYTE(64));
/* 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);
/* Initialize dx12 */
dx12_init_device();
dx12_init_objects();
dx12_init_pipelines();
/* Register callbacks */
#if RESOURCE_RELOADING
resource_register_watch_callback(pipeline_resource_watch_callback);
#endif
app_register_exit_callback(gp_shutdown);
struct gp_startup_receipt res = ZI;
@ -630,35 +634,35 @@ PACK(struct fx_material_instance {
/* ============= */
/* Init pipelines */
INTERNAL struct pipeline_result *pipeline_alloc_from_descs(struct arena *arena, u64 num_pipelines, struct pipeline_desc *descs);
INTERNAL void pipeline_release(struct pipeline *pipeline);
INTERNAL void dx12_init_pipelines(void)
{
__prof;
struct arena_temp scratch = scratch_begin_no_conflict();
struct pipeline_desc pipeline_descs[] = {
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" }
}
};
};
struct pipeline_result *results = pipeline_alloc_from_descs(scratch.arena, ARRAY_COUNT(pipeline_descs), pipeline_descs);
for (u64 i = 0; i < ARRAY_COUNT(pipeline_descs); ++i) {
struct pipeline_result *result = &results[i];
if (result->errors_text_len > 0) {
struct string msg = STRING(result->errors_text_len, result->errors_text);
sys_panic(msg);
pipeline_release(&result->pipeline);
INTERNAL struct pipeline **pipeline_alloc_from_descs(struct arena *arena, u64 num_pipelines, struct pipeline_desc *descs);
INTERNAL void pipeline_release(struct pipeline *pipeline);
INTERNAL void pipeline_register(struct pipeline *pipeline);
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 {
/* FIXME: remove this */
G.test_pipeline = result->pipeline;
pipeline->valid = true;
pipeline_register(pipeline);
}
}
scratch_end(scratch);
}
@ -838,7 +842,6 @@ INTERNAL WORK_TASK_FUNC_DEF(shader_compile_task, comp_arg_raw)
struct pipeline_load_task_arg {
struct pipeline *pipeline;
struct pipeline_result *result;
};
INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw)
@ -847,12 +850,11 @@ INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw)
struct pipeline_load_task_arg *load_arg = (struct pipeline_load_task_arg *)load_arg_raw;
struct pipeline *pipeline = load_arg->pipeline;
struct pipeline_desc desc = pipeline->desc;
struct pipeline_result *result = load_arg->result;
struct arena_temp scratch = scratch_begin_no_conflict();
{
i64 start_ns = sys_time_ns();
struct string pipeline_name = string_from_cstr_no_limit(desc.name);
struct string pipeline_name = pipeline->name;
logf_info("Loading pipeline \"%F\"", FMT_STR(pipeline_name));
b32 success = true;
HRESULT hr = 0;
@ -1040,13 +1042,20 @@ INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw)
error_str = error_blob_str;
}
}
result->errors_text_len = min_u64(error_str.len, ARRAY_COUNT(result->errors_text));
MEMCPY(result->errors_text, error_str.text, result->errors_text_len);
struct pipeline_error *error = arena_push(pipeline->arena, struct pipeline_error);
error->msg = string_copy(pipeline->arena, error_str);
if (pipeline->last_error) {
pipeline->last_error->next = error;
} else {
pipeline->first_error = error;
}
pipeline->last_error = error;
++pipeline->num_errors;
}
pipeline->pso = pso;
pipeline->rootsig = rootsig;
result->elapsed = sys_time_ns() - start_ns;
pipeline->compilation_time = sys_time_ns() - start_ns;
resource_close(&vs_res);
if (!ps_res_is_shared) {
@ -1071,30 +1080,35 @@ INTERNAL WORK_TASK_FUNC_DEF(pipeline_load_task, load_arg_raw)
scratch_end(scratch);
}
INTERNAL struct pipeline_result *pipeline_alloc_from_descs(struct arena *arena, u64 num_pipelines, struct pipeline_desc *descs)
INTERNAL struct pipeline **pipeline_alloc_from_descs(struct arena *arena, u64 num_pipelines, struct pipeline_desc *descs)
{
__prof;
struct pipeline_result *results = arena_push_array(arena, struct pipeline_result, num_pipelines);
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_result *result = &results[i];
struct pipeline *pipeline = &results->pipeline;
pipeline->desc = descs[i];
struct pipeline_desc desc = descs[i];
struct pipeline *pipeline = NULL;
{
struct arena *pipeline_arena = arena_alloc(MEGABYTE(64));
pipeline = arena_push(pipeline_arena, struct pipeline);
pipeline->arena = pipeline_arena;
pipelines[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;
arg->result = result;
work_slate_push_task(&ws, pipeline_load_task, arg);
}
struct work_handle work = work_slate_end_and_help(&ws, WORK_PRIORITY_HIGH);
work_wait(work);
return results;
return pipelines;
}
INTERNAL void pipeline_release(struct pipeline *pipeline)
@ -1103,8 +1117,66 @@ INTERNAL void pipeline_release(struct pipeline *pipeline)
if (pipeline->pso) {
ID3D12PipelineState_Release(pipeline->pso);
}
arena_release(pipeline->arena);
}
/* ========================== *
* Pipeline cache
* ========================== */
struct pipeline_scope {
i32 _;
};
INTERNAL struct pipeline_scope *pipeline_scope_begin(void)
{
return NULL;
}
INTERNAL void pipeline_scope_end(struct pipeline_scope *scope)
{
(UNUSED)scope;
}
INTERNAL struct pipeline *pipeline_from_name(struct pipeline_scope *scope, struct string name)
{
(UNUSED)scope;
struct pipeline *pipeline = &g_nil_pipeline;
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;
}
}
sys_mutex_unlock(&lock);
return pipeline;
}
INTERNAL void pipeline_register(struct pipeline *pipeline)
{
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);
}
sys_mutex_unlock(&lock);
}
#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));
}
#else
(UNUSED)name;
#endif
}
#endif
/* ========================== *
* Descriptor
@ -1771,6 +1843,25 @@ INTERNAL struct command_buffer *command_list_push_buffer(struct command_list *cl
return cb;
}
/* ========================== *
* Command root constant
* ========================== */
INTERNAL void command_list_set_root_constant(struct command_list *cl, void *src, u32 size)
{
if (size % 4 == 0) {
u32 num32bit = size / 4;
for (u32 i = 0; i < num32bit; ++i) {
u32 val = 0;
MEMCPY(&val, (((u32 *)src) + i), 4);
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstant(cl->cl, 0, val, i);
}
} else {
/* Root constant structs must pad to 32 bits */
ASSERT(false);
}
}
/* ========================== *
* Texture
* ========================== */
@ -1960,7 +2051,9 @@ void gp_dispatch(struct gp_dispatch_params params)
struct flow *flow = handle_get_data(params.flow, DX12_HANDLE_KIND_FLOW);
/* Material pass */
struct pipeline_scope *pipeline_scope = pipeline_scope_begin();
struct pipeline *material_pipeline = pipeline_from_name(pipeline_scope, LIT("material"));
if (material_pipeline->valid) {
struct command_list *cl = command_list_open(G.cq_direct);
{
struct dx12_resource *target = handle_get_data(params.draw_target, DX12_HANDLE_KIND_RESOURCE);
@ -2019,20 +2112,16 @@ void gp_dispatch(struct gp_dispatch_params params)
/* Material pass */
{
//struct pipeline *pipeline = dx12_get_pipeline(pipeline_scope, LIT("material"));
struct pipeline *pipeline = &G.test_pipeline;
u32 instance_count = instance_buffer->size / sizeof(struct sh_material_instance);
/* Bind pipeline */
ID3D12GraphicsCommandList_SetPipelineState(cl->cl, pipeline->pso);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(cl->cl, pipeline->rootsig);
ID3D12GraphicsCommandList_SetPipelineState(cl->cl, material_pipeline->pso);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(cl->cl, material_pipeline->rootsig);
/* Fill & bind constant buffer */
/* TODO: Move into root constant */
/* Set root constants */
struct sh_material_constants constants = ZI;
constants.projection = sh_float4x4_from_mat4x4(vp_matrix);
struct command_buffer *constant_buffer = command_list_push_buffer(cl, STRING_FROM_STRUCT(&constants));
ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(cl->cl, 0, constant_buffer->resource->gpu_address);
command_list_set_root_constant(cl, &constants, sizeof(constants));
/* Bind instance buffer */
ID3D12GraphicsCommandList_SetGraphicsRootShaderResourceView(cl->cl, 1, instance_buffer->resource->gpu_address);
@ -2059,11 +2148,14 @@ void gp_dispatch(struct gp_dispatch_params params)
}
}
command_list_close(cl);
}
pipeline_scope_end(pipeline_scope);
/* Reset flow */
sprite_scope_end(flow->sprite_scope);
flow->sprite_scope = sprite_scope_begin();
arena_reset(flow->material_instances_arena);
}
/* ========================== *
@ -2256,6 +2348,7 @@ void gp_present(struct sys_window *window, struct v2i32 backbuffer_resolution, s
//sys_sleep(0.1);
/* Present */
/* FIXME: Resource barrier */
HRESULT hr = IDXGISwapChain3_Present(G.swapchain, 0, 0);
if (!SUCCEEDED(hr)) {
ASSERT(false);