From 9e0696d18382b8e94f5c2c9d6c6f895473c426c7 Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 25 Jun 2025 20:25:08 -0500 Subject: [PATCH] push & process commands separately --- res/sh/material.hlsl | 2 - res/sh/sh_common.h | 3 - src/draw.c | 63 ++--- src/draw.h | 32 +-- src/gp.h | 37 +-- src/gp_dx12.c | 550 +++++++++++++++++++++++++++---------------- src/sprite.c | 2 - src/user.c | 4 +- 8 files changed, 417 insertions(+), 276 deletions(-) diff --git a/res/sh/material.hlsl b/res/sh/material.hlsl index 668fdb5c..0d9e9aa3 100644 --- a/res/sh/material.hlsl +++ b/res/sh/material.hlsl @@ -33,7 +33,6 @@ struct vs_input { }; struct vs_output { - nointerpolation DECLS(uint, flags); nointerpolation DECLS(int, tex_nurid); nointerpolation DECLS(int, grid_id); DECLS(float2, uv); @@ -56,7 +55,6 @@ SH_ENTRY(ROOTSIG) struct vs_output vs(struct vs_input input) struct vs_output output; output.SV_Position = mul(g_constants.projection, float4(world_pos, 0, 1)); - output.flags = instance.flags; output.tex_nurid = instance.tex_nurid; output.grid_id = instance.grid_id; output.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0)); diff --git a/res/sh/sh_common.h b/res/sh/sh_common.h index 160e5e0f..c6d5f3c8 100644 --- a/res/sh/sh_common.h +++ b/res/sh/sh_common.h @@ -73,15 +73,12 @@ SH_ASSERT_32BIT(struct sh_blit_constants, 18); /* Expected 32bit root constant * Material shader structures * ========================== */ -#define SH_MATERIAL_FLAG_NONE (0) - 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(uint, flags); SH_DECL(int, tex_nurid); SH_DECL(int, grid_id); SH_DECL(float2x3, xf); diff --git a/src/draw.c b/src/draw.c index 43f13be5..1f9262f8 100644 --- a/src/draw.c +++ b/src/draw.c @@ -28,7 +28,7 @@ struct draw_startup_receipt draw_startup(struct gp_startup_receipt *gp_sr, * Texture * ========================== */ -void draw_texture(struct gp_handle flow, struct draw_texture_params params) +void draw_texture(struct gp_flow *flow, struct draw_texture_params params) { struct gp_cmd_desc cmd = ZI; cmd.kind = GP_CMD_KIND_DRAW_MATERIAL; @@ -38,25 +38,25 @@ void draw_texture(struct gp_handle flow, struct draw_texture_params params) cmd.material.clip = params.clip; cmd.material.tint = params.tint; cmd.material.emittance = params.emittance; - gp_push_cmd(flow, cmd); + gp_push_cmd(flow, &cmd); } /* ========================== * * Fill shapes * ========================== */ -void draw_poly_ex(struct gp_handle flow, struct v2_array vertices, struct gp_indices indices, u32 color) +void draw_poly_ex(struct gp_flow *flow, struct v2_array vertices, struct gp_indices indices, u32 color) { struct gp_cmd_desc cmd = ZI; cmd.kind = GP_CMD_KIND_DRAW_SHAPE; cmd.shape.vertices = vertices; cmd.shape.indices = indices; cmd.shape.color = color; - gp_push_cmd(flow, cmd); + gp_push_cmd(flow, &cmd); } /* Draws a filled polygon using triangles in a fan pattern */ -void draw_poly(struct gp_handle flow, struct v2_array vertices, u32 color) +void draw_poly(struct gp_flow *flow, struct v2_array vertices, u32 color) { if (vertices.count >= 3) { struct arena_temp scratch = scratch_begin_no_conflict(); @@ -82,7 +82,7 @@ void draw_poly(struct gp_handle flow, struct v2_array vertices, u32 color) } } -void draw_circle(struct gp_handle flow, struct v2 pos, f32 radius, u32 color, u32 detail) +void draw_circle(struct gp_flow *flow, struct v2 pos, f32 radius, u32 color, u32 detail) { struct arena_temp scratch = scratch_begin_no_conflict(); @@ -105,7 +105,7 @@ void draw_circle(struct gp_handle flow, struct v2 pos, f32 radius, u32 color, u3 scratch_end(scratch); } -void draw_quad(struct gp_handle flow, struct quad quad, u32 color) +void draw_quad(struct gp_flow *flow, struct quad quad, u32 color) { LOCAL_PERSIST u32 indices_array[6] = { 0, 1, 2, @@ -120,7 +120,7 @@ void draw_quad(struct gp_handle flow, struct quad quad, u32 color) * Line shapes * ========================== */ -void draw_gradient_line(struct gp_handle flow, struct v2 start, struct v2 end, f32 thickness, u32 start_color, u32 end_color) +void draw_gradient_line(struct gp_flow *flow, struct v2 start, struct v2 end, f32 thickness, u32 start_color, u32 end_color) { #if 0 struct quad quad = quad_from_line(start, end, thickness); @@ -133,19 +133,19 @@ void draw_gradient_line(struct gp_handle flow, struct v2 start, struct v2 end, f #endif } -void draw_line(struct gp_handle flow, struct v2 start, struct v2 end, f32 thickness, u32 color) +void draw_line(struct gp_flow *flow, struct v2 start, struct v2 end, f32 thickness, u32 color) { struct quad quad = quad_from_line(start, end, thickness); draw_quad(flow, quad, color); } -void draw_ray(struct gp_handle flow, struct v2 pos, struct v2 rel, f32 thickness, u32 color) +void draw_ray(struct gp_flow *flow, struct v2 pos, struct v2 rel, f32 thickness, u32 color) { struct quad quad = quad_from_ray(pos, rel, thickness); draw_quad(flow, quad, color); } -void draw_poly_line(struct gp_handle flow, struct v2_array points, b32 loop, f32 thickness, u32 color) +void draw_poly_line(struct gp_flow *flow, struct v2_array points, b32 loop, f32 thickness, u32 color) { if (points.count >= 2) { for (u64 i = 1; i < points.count; ++i) { @@ -163,7 +163,7 @@ void draw_poly_line(struct gp_handle flow, struct v2_array points, b32 loop, f32 } } -void draw_circle_line(struct gp_handle flow, struct v2 pos, f32 radius, f32 thickness, u32 color, u32 detail) +void draw_circle_line(struct gp_flow *flow, struct v2 pos, f32 radius, f32 thickness, u32 color, u32 detail) { struct arena_temp scratch = scratch_begin_no_conflict(); @@ -186,14 +186,14 @@ void draw_circle_line(struct gp_handle flow, struct v2 pos, f32 radius, f32 thic scratch_end(scratch); } -void draw_quad_line(struct gp_handle flow, struct quad quad, f32 thickness, u32 color) +void draw_quad_line(struct gp_flow *flow, struct quad quad, f32 thickness, u32 color) { struct v2 points[] = { quad.p0, quad.p1, quad.p2, quad.p3 }; struct v2_array a = { .points = points, .count = ARRAY_COUNT(points) }; draw_poly_line(flow, a, true, thickness, color); } -void draw_arrow_line(struct gp_handle flow, struct v2 start, struct v2 end, f32 thickness, f32 arrowhead_height, u32 color) +void draw_arrow_line(struct gp_flow *flow, struct v2 start, struct v2 end, f32 thickness, f32 arrowhead_height, u32 color) { const f32 head_width_ratio = 0.5f; /* Width of arrowhead relative to its length */ @@ -223,13 +223,13 @@ void draw_arrow_line(struct gp_handle flow, struct v2 start, struct v2 end, f32 draw_quad(flow, line_quad, color); } -void draw_arrow_ray(struct gp_handle flow, struct v2 pos, struct v2 rel, f32 thickness, f32 arrowhead_height, u32 color) +void draw_arrow_ray(struct gp_flow *flow, struct v2 pos, struct v2 rel, f32 thickness, f32 arrowhead_height, u32 color) { struct v2 end = v2_add(pos, rel); draw_arrow_line(flow, pos, end, thickness, arrowhead_height, color); } -void draw_collider_line(struct gp_handle flow, struct collider_shape shape, struct xform shape_xf, f32 thickness, u32 color, u32 detail) +void draw_collider_line(struct gp_flow *flow, struct collider_shape shape, struct xform shape_xf, f32 thickness, u32 color, u32 detail) { struct arena_temp scratch = scratch_begin_no_conflict(); struct v2_array poly = ZI; @@ -258,24 +258,29 @@ void draw_collider_line(struct gp_handle flow, struct collider_shape shape, stru * Grid * ========================== */ -void draw_grid(struct gp_handle flow, struct xform xf, u32 bg0_color, u32 bg1_color, u32 line_color, u32 x_color, u32 y_color, f32 thickness, f32 spacing, struct v2 offset) +void draw_grid(struct gp_flow *flow, struct xform xf, u32 bg0_color, u32 bg1_color, u32 line_color, u32 x_color, u32 y_color, f32 thickness, f32 spacing, struct v2 offset) { - struct gp_grid_desc grid = ZI; - grid.bg0_color = bg0_color; - grid.bg1_color = bg1_color; - grid.line_color = line_color; - grid.x_color = x_color; - grid.y_color = y_color; - grid.line_thickness = thickness; - grid.line_spacing = spacing; - grid.offset = offset; + i32 grid_id = 0; + { + struct gp_cmd_desc cmd = ZI; + cmd.kind = GP_CMD_KIND_PUSH_GRID; + cmd.grid.bg0_color = bg0_color; + cmd.grid.bg1_color = bg1_color; + cmd.grid.line_color = line_color; + cmd.grid.x_color = x_color; + cmd.grid.y_color = y_color; + cmd.grid.line_thickness = thickness; + cmd.grid.line_spacing = spacing; + cmd.grid.offset = offset; + grid_id = gp_push_cmd(flow, &cmd); + } struct gp_cmd_desc cmd = ZI; cmd.kind = GP_CMD_KIND_DRAW_MATERIAL; cmd.material.xf = xf; cmd.material.tint = COLOR_WHITE; - cmd.material.grid = &grid; - gp_push_cmd(flow, cmd); + cmd.material.grid_cmd_id = grid_id; + gp_push_cmd(flow, &cmd); } /* ========================== * @@ -283,7 +288,7 @@ void draw_grid(struct gp_handle flow, struct xform xf, u32 bg0_color, u32 bg1_co * ========================== */ /* Returns the rect of the text area */ -struct rect draw_text(struct gp_handle flow, struct draw_text_params params) +struct rect draw_text(struct gp_flow *flow, struct draw_text_params params) { __prof; struct arena_temp scratch = scratch_begin_no_conflict(); diff --git a/src/draw.h b/src/draw.h index b26001a8..5616b542 100644 --- a/src/draw.h +++ b/src/draw.h @@ -29,47 +29,47 @@ struct draw_texture_params { f32 emittance; }; -void draw_texture(struct gp_handle flow, struct draw_texture_params params); +void draw_texture(struct gp_flow *flow, struct draw_texture_params params); /* ========================== * * Fill shapes * ========================== */ -void draw_poly_ex(struct gp_handle flow, struct v2_array vertices, struct gp_indices indices, u32 color); +void draw_poly_ex(struct gp_flow *flow, struct v2_array vertices, struct gp_indices indices, u32 color); -void draw_poly(struct gp_handle flow, struct v2_array points, u32 color); +void draw_poly(struct gp_flow *flow, struct v2_array points, u32 color); -void draw_circle(struct gp_handle flow, struct v2 pos, f32 radius, u32 color, u32 detail); +void draw_circle(struct gp_flow *flow, struct v2 pos, f32 radius, u32 color, u32 detail); -void draw_quad(struct gp_handle flow, struct quad quad, u32 color); +void draw_quad(struct gp_flow *flow, struct quad quad, u32 color); /* ========================== * * Line shapes * ========================== */ -void draw_gradient_line(struct gp_handle flow, struct v2 start, struct v2 end, f32 thickness, u32 start_color, u32 end_color); +void draw_gradient_line(struct gp_flow *flow, struct v2 start, struct v2 end, f32 thickness, u32 start_color, u32 end_color); -void draw_line(struct gp_handle flow, struct v2 start, struct v2 end, f32 thickness, u32 color); +void draw_line(struct gp_flow *flow, struct v2 start, struct v2 end, f32 thickness, u32 color); -void draw_ray(struct gp_handle flow, struct v2 pos, struct v2 rel, f32 thickness, u32 color); +void draw_ray(struct gp_flow *flow, struct v2 pos, struct v2 rel, f32 thickness, u32 color); -void draw_poly_line(struct gp_handle flow, struct v2_array points, b32 loop, f32 thickness, u32 color); +void draw_poly_line(struct gp_flow *flow, struct v2_array points, b32 loop, f32 thickness, u32 color); -void draw_circle_line(struct gp_handle flow, struct v2 pos, f32 radius, f32 thickness, u32 color, u32 detail); +void draw_circle_line(struct gp_flow *flow, struct v2 pos, f32 radius, f32 thickness, u32 color, u32 detail); -void draw_quad_line(struct gp_handle flow, struct quad quad, f32 thickness, u32 color); +void draw_quad_line(struct gp_flow *flow, struct quad quad, f32 thickness, u32 color); -void draw_arrow_line(struct gp_handle flow, struct v2 start, struct v2 end, f32 thickness, f32 arrowhead_height, u32 color); +void draw_arrow_line(struct gp_flow *flow, struct v2 start, struct v2 end, f32 thickness, f32 arrowhead_height, u32 color); -void draw_arrow_ray(struct gp_handle flow, struct v2 pos, struct v2 rel, f32 thickness, f32 arrowhead_height, u32 color); +void draw_arrow_ray(struct gp_flow *flow, struct v2 pos, struct v2 rel, f32 thickness, f32 arrowhead_height, u32 color); -void draw_collider_line(struct gp_handle flow, struct collider_shape shape, struct xform shape_xf, f32 thickness, u32 color, u32 detail); +void draw_collider_line(struct gp_flow *flow, struct collider_shape shape, struct xform shape_xf, f32 thickness, u32 color, u32 detail); /* ========================== * * Grid * ========================== */ -void draw_grid(struct gp_handle flow, struct xform xf, u32 bg0_color, u32 bg1_color, u32 line_color, u32 x_color, u32 y_color, f32 thickness, f32 spacing, struct v2 offset); +void draw_grid(struct gp_flow *flow, struct xform xf, u32 bg0_color, u32 bg1_color, u32 line_color, u32 x_color, u32 y_color, f32 thickness, f32 spacing, struct v2 offset); /* ========================== * * Text @@ -117,6 +117,6 @@ struct draw_text_params { struct string str; }; -struct rect draw_text(struct gp_handle flow, struct draw_text_params params); +struct rect draw_text(struct gp_flow *flow, struct draw_text_params params); #endif diff --git a/src/gp.h b/src/gp.h index 4d3ddde0..159b6778 100644 --- a/src/gp.h +++ b/src/gp.h @@ -63,28 +63,18 @@ struct v2i32 gp_texture_get_size(struct gp_handle texture); * Flow * ========================== */ -struct gp_indices { - u32 count; - u32 *indices; -}; - enum gp_cmd_kind { GP_CMD_KIND_NONE, GP_CMD_KIND_DRAW_SHAPE, GP_CMD_KIND_DRAW_MATERIAL, + GP_CMD_KIND_PUSH_GRID, NUM_GP_CMD_KINDS }; -struct gp_grid_desc { - f32 line_thickness; - f32 line_spacing; - struct v2 offset; - u32 bg0_color; - u32 bg1_color; - u32 line_color; - u32 x_color; - u32 y_color; +struct gp_indices { + u32 count; + u32 *indices; }; struct gp_cmd_desc { @@ -97,27 +87,38 @@ struct gp_cmd_desc { struct clip_rect clip; u32 tint; f32 emittance; - struct gp_grid_desc *grid; + i32 grid_cmd_id; } material; struct { struct v2_array vertices; struct gp_indices indices; u32 color; } shape; + struct { + f32 line_thickness; + f32 line_spacing; + struct v2 offset; + u32 bg0_color; + u32 bg1_color; + u32 line_color; + u32 x_color; + u32 y_color; + } grid; }; }; struct gp_dispatch_params { - struct gp_handle flow; + struct gp_flow *flow; struct gp_handle draw_target; struct rect draw_target_viewport; struct xform draw_target_view; b32 clear_target; }; -struct gp_handle gp_flow_alloc(void); +struct gp_flow *gp_flow_alloc(void); -void gp_push_cmd(struct gp_handle gp_flow, struct gp_cmd_desc params); +/* Returns a cmd id internal to the flow */ +i32 gp_push_cmd(struct gp_flow *gp_flow, struct gp_cmd_desc *desc); void gp_dispatch(struct gp_dispatch_params params); diff --git a/src/gp_dx12.c b/src/gp_dx12.c index 413bd5bf..9f5da069 100644 --- a/src/gp_dx12.c +++ b/src/gp_dx12.c @@ -121,13 +121,14 @@ struct command_queue { D3D12_COMMAND_LIST_TYPE type; ID3D12CommandQueue *cq; struct arena *arena; - struct sys_mutex *mutex; + struct sys_mutex *submitted_command_lists_mutex; struct command_list *first_submitted_command_list; struct command_list *last_submitted_command_list; - struct atomic_u64 fence_target; - ID3D12Fence *fence; + struct sys_mutex *submit_fence_mutex; + u64 submit_fence_target; + ID3D12Fence *submit_fence; #if PROFILING struct __prof_dx12_ctx *prof; @@ -138,7 +139,7 @@ struct command_list { struct command_queue *cq; struct ID3D12CommandAllocator *ca; struct ID3D12GraphicsCommandList *cl; - struct sys_lock global_lock; + struct sys_lock global_record_lock; struct command_descriptor_heap *first_command_descriptor_heap; struct command_buffer *first_command_buffer; @@ -195,17 +196,10 @@ struct descriptor { struct dx12_resource { ID3D12Resource *resource; enum D3D12_RESOURCE_STATES state; -#if 0 - D3D12_CPU_DESCRIPTOR_HANDLE cbv_handle; - D3D12_CPU_DESCRIPTOR_HANDLE srv_handle; - D3D12_CPU_DESCRIPTOR_HANDLE uav_handle; - D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle; -#else struct descriptor *cbv_descriptor; struct descriptor *srv_descriptor; struct descriptor *uav_descriptor; struct descriptor *rtv_descriptor; -#endif D3D12_GPU_VIRTUAL_ADDRESS gpu_address; /* NOTE: 0 for textures */ @@ -213,6 +207,20 @@ struct dx12_resource { struct dx12_resource *next_free; }; +struct swapchain_buffer { + struct swapchain *swapchain; + ID3D12Resource *resource; + struct descriptor *rtv_descriptor; + D3D12_RESOURCE_STATES state; +}; + +struct swapchain { + IDXGISwapChain3 *swapchain; + HWND hwnd; + struct v2i32 resolution; + struct swapchain_buffer buffers[DX12_SWAPCHAIN_BUFFER_COUNT]; +}; + struct cpu_descriptor_heap { enum D3D12_DESCRIPTOR_HEAP_TYPE type; struct arena *arena; @@ -231,7 +239,6 @@ struct cpu_descriptor_heap { enum handle_kind { DX12_HANDLE_KIND_NONE, DX12_HANDLE_KIND_RESOURCE, - DX12_HANDLE_KIND_FLOW, NUM_DX12_HANDLE_KINDS }; @@ -299,18 +306,15 @@ GLOBAL struct { /* Command queues */ /* TODO: Add optional mode to route everything to direct queue */ - struct sys_mutex *global_command_list_mutex; + struct sys_mutex *global_command_list_record_mutex; + struct sys_mutex *global_command_list_submit_mutex; struct command_queue *cq_direct; struct command_queue *cq_compute; struct command_queue *cq_copy_critical; struct command_queue *cq_copy_background; /* Swapchain */ - HWND swapchain_hwnd; - struct v2i32 swapchain_resolution; - u32 swapchain_frame_index; - IDXGISwapChain3 *swapchain; - struct dx12_resource *swapchain_resources[DX12_SWAPCHAIN_BUFFER_COUNT]; + struct swapchain swapchain; } G = ZI, DEBUG_ALIAS(G, G_gp_dx12); /* ========================== * @@ -378,10 +382,7 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(gp_shutdown) __prof; #if DX12_DEBUG /* Release objects to make live object reporting less noisy */ - for (u64 i = 0; i < ARRAY_COUNT(G.swapchain_resources); ++i) { - dx12_resource_release(G.swapchain_resources[i]); - } - IDXGISwapChain3_Release(G.swapchain); + //IDXGISwapChain3_Release(G.swapchain); command_queue_release(G.cq_copy_background); command_queue_release(G.cq_copy_critical); command_queue_release(G.cq_compute); @@ -441,20 +442,27 @@ INTERNAL struct handle_entry *handle_get_entry(struct gp_handle handle, struct s return res; } -INTERNAL void *handle_get_data(struct gp_handle handle, enum handle_kind kind) +INTERNAL void *handle_get_data_locked(struct gp_handle handle, enum handle_kind kind, struct sys_lock *lock) { - (UNUSED)kind; + sys_assert_locked_e_or_s(lock, G.handle_entries_mutex); void *data = NULL; if (handle.gen) { - struct sys_lock lock = sys_mutex_lock_s(G.handle_entries_mutex); - { - struct handle_entry *entry = handle_get_entry(handle, &lock); - data = entry->data; + struct handle_entry *entry = handle_get_entry(handle, lock); + data = entry->data; #if RTC - /* Handle should match expected kind */ - ASSERT(entry->kind == kind); + /* Handle should match expected kind */ + ASSERT(entry->kind == kind); #endif - } + } + return data; +} + +INTERNAL void *handle_get_data(struct gp_handle handle, enum handle_kind kind) +{ + void *data = NULL; + if (handle.gen) { + struct sys_lock lock = sys_mutex_lock_e(G.handle_entries_mutex); + data = handle_get_data_locked(handle, kind, &lock); sys_mutex_unlock(&lock); } return data; @@ -670,7 +678,8 @@ INTERNAL void dx12_init_objects(void) G.rtv_heap = cpu_descriptor_heap_alloc(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); /* Create command queues */ - G.global_command_list_mutex = sys_mutex_alloc(); + G.global_command_list_record_mutex = sys_mutex_alloc(); + G.global_command_list_submit_mutex = sys_mutex_alloc(); G.cq_direct = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, LIT("Direct queue")); G.cq_compute = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_COMPUTE, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, LIT("Compute queue")); G.cq_copy_critical = command_queue_alloc(D3D12_COMMAND_LIST_TYPE_COPY, D3D12_COMMAND_QUEUE_PRIORITY_HIGH, LIT("High priority copy queue")); @@ -1402,6 +1411,17 @@ INTERNAL struct descriptor *descriptor_alloc(struct cpu_descriptor_heap *dh) return d; } +INTERNAL void descriptor_release(struct descriptor *descriptor) +{ + struct cpu_descriptor_heap *dh = descriptor->heap; + struct sys_lock lock = sys_mutex_lock_e(dh->mutex); + { + descriptor->next_free = dh->first_free_descriptor; + dh->first_free_descriptor = descriptor; + } + sys_mutex_unlock(&lock); +} + /* ========================== * * CPU descriptor heap * ========================== */ @@ -1456,16 +1476,42 @@ INTERNAL void cpu_descriptor_heap_release(struct cpu_descriptor_heap *dh) struct flow { struct arena *arena; - /* Below fields are reset each dispatch */ - struct sprite_scope *sprite_scope; - struct arena *material_instances_arena; - struct arena *material_grids_arena; + /* Material instances */ + u32 num_material_instance_descs; + struct arena *material_instance_descs_arena; + + /* Grids */ + u32 num_material_grid_descs; + struct arena *material_grid_descs_arena; + + /* Shapes */ struct arena *shape_verts_arena; struct arena *shape_indices_arena; struct flow *next_free; }; +struct material_instance_desc { + struct xform xf; + struct sprite_tag sprite; + struct gp_handle texture; + struct clip_rect clip; + u32 tint; + f32 emittance; + i32 grid_id; +}; + +struct material_grid_desc { + f32 line_thickness; + f32 line_spacing; + struct v2 offset; + u32 bg0_color; + u32 bg1_color; + u32 line_color; + u32 x_color; + u32 y_color; +}; + INTERNAL struct flow *flow_alloc(void) { __prof; @@ -1476,9 +1522,8 @@ INTERNAL struct flow *flow_alloc(void) flow->arena = arena; } - flow->sprite_scope = sprite_scope_begin(); - flow->material_instances_arena = arena_alloc(GIGABYTE(1)); - flow->material_grids_arena = arena_alloc(GIGABYTE(1)); + flow->material_instance_descs_arena = arena_alloc(GIGABYTE(1)); + flow->material_grid_descs_arena = arena_alloc(GIGABYTE(1)); flow->shape_verts_arena = arena_alloc(GIGABYTE(1)); flow->shape_indices_arena = arena_alloc(GIGABYTE(1)); @@ -1488,90 +1533,81 @@ INTERNAL struct flow *flow_alloc(void) INTERNAL void flow_reset(struct flow *flow) { __prof; - sprite_scope_end(flow->sprite_scope); - flow->sprite_scope = sprite_scope_begin(); - arena_reset(flow->material_instances_arena); - arena_reset(flow->material_grids_arena); + + /* Reset material instances */ + flow->num_material_instance_descs = 0; + arena_reset(flow->material_instance_descs_arena); + + /* Reset grids */ + flow->num_material_grid_descs = 0; + arena_reset(flow->material_grid_descs_arena); + + /* Reset shapes */ arena_reset(flow->shape_verts_arena); arena_reset(flow->shape_indices_arena); } -struct gp_handle gp_flow_alloc(void) +struct gp_flow *gp_flow_alloc(void) { __prof; struct flow *flow = flow_alloc(); - return handle_alloc(DX12_HANDLE_KIND_FLOW, flow); + return (struct gp_flow *)flow; } -void gp_push_cmd(struct gp_handle gp_flow, struct gp_cmd_desc desc) +i32 gp_push_cmd(struct gp_flow *gp_flow, struct gp_cmd_desc *cmd_desc) { __prof; - struct flow *flow = handle_get_data(gp_flow, DX12_HANDLE_KIND_FLOW); + i32 ret = 0; + struct flow *flow = (struct flow *)gp_flow; if (flow) { - switch (desc.kind) { + switch (cmd_desc->kind) { default: break; case GP_CMD_KIND_DRAW_MATERIAL: { - i32 texture_id = -1; - { - struct dx12_resource *texture = NULL; - if (desc.material.texture.gen != 0) { - texture = handle_get_data(desc.material.texture, DX12_HANDLE_KIND_RESOURCE); - } else if (desc.material.sprite.hash != 0) { - struct sprite_texture *st = sprite_texture_from_tag_async(flow->sprite_scope, desc.material.sprite); - texture = handle_get_data(st->texture, DX12_HANDLE_KIND_RESOURCE); - } - if (texture) { - texture_id = texture->srv_descriptor->index; - } - } - - i32 grid_id = -1; - if (desc.material.grid) { - struct gp_grid_desc *grid_desc = desc.material.grid; - struct sh_material_grid *grid = arena_push(flow->material_grids_arena, struct sh_material_grid); - grid->line_thickness = sh_float_from_f32(grid_desc->line_thickness); - grid->line_spacing = sh_float_from_f32(grid_desc->line_spacing); - grid->offset = sh_float2_from_v2(grid_desc->offset); - grid->bg0_srgb = sh_uint_from_u32(grid_desc->bg0_color); - grid->bg1_srgb = sh_uint_from_u32(grid_desc->bg1_color); - grid->line_srgb = sh_uint_from_u32(grid_desc->line_color); - grid->x_srgb = sh_uint_from_u32(grid_desc->x_color); - grid->y_srgb = sh_uint_from_u32(grid_desc->y_color); - grid_id = ((u8 *)grid - arena_base(flow->material_grids_arena)) / sizeof(grid); - } - - if (texture_id >= 0 || grid_id >= 0) { - struct sh_material_instance *instance = arena_push(flow->material_instances_arena, struct sh_material_instance); - instance->flags = sh_uint_from_u32(SH_MATERIAL_FLAG_NONE); - instance->tex_nurid = sh_int_from_i32(texture_id); - instance->grid_id = sh_int_from_i32(grid_id); - instance->xf = sh_float2x3_from_xform(desc.material.xf); - instance->uv0 = sh_float2_from_v2(desc.material.clip.p0); - instance->uv1 = sh_float2_from_v2(desc.material.clip.p1); - instance->tint_srgb = sh_uint_from_u32(desc.material.tint); - instance->emittance = sh_float_from_f32(desc.material.emittance); - } + struct material_instance_desc *instance_desc = arena_push(flow->material_instance_descs_arena, struct material_instance_desc); + instance_desc->xf = cmd_desc->material.xf; + instance_desc->sprite = cmd_desc->material.sprite; + instance_desc->texture = cmd_desc->material.texture; + instance_desc->clip = cmd_desc->material.clip; + instance_desc->tint = cmd_desc->material.tint; + instance_desc->emittance = cmd_desc->material.emittance; + instance_desc->grid_id = cmd_desc->material.grid_cmd_id - 1; + ret = ++flow->num_material_instance_descs; } break; case GP_CMD_KIND_DRAW_SHAPE: { - u32 color = desc.shape.color; - u32 vert_offset = flow->shape_verts_arena->pos / sizeof(struct sh_shape_vert); - struct sh_shape_vert *verts = arena_push_array_no_zero(flow->shape_verts_arena, struct sh_shape_vert, desc.shape.vertices.count); - u32 *indices = arena_push_array_no_zero(flow->shape_indices_arena, u32, desc.shape.indices.count); - for (u32 i = 0; i < desc.shape.vertices.count; ++i) { + u32 color = cmd_desc->shape.color; + struct sh_shape_vert *verts = arena_push_array_no_zero(flow->shape_verts_arena, struct sh_shape_vert, cmd_desc->shape.vertices.count); + u32 *indices = arena_push_array_no_zero(flow->shape_indices_arena, u32, cmd_desc->shape.indices.count); + for (u32 i = 0; i < cmd_desc->shape.vertices.count; ++i) { struct sh_shape_vert *v = &verts[i]; - v->pos = sh_float2_from_v2(desc.shape.vertices.points[i]); + v->pos = sh_float2_from_v2(cmd_desc->shape.vertices.points[i]); v->color_srgb = sh_uint_from_u32(color); } - for (u32 i = 0; i < desc.shape.indices.count; ++i) { - indices[i] = desc.shape.indices.indices[i] + vert_offset; + u32 vert_offset = verts - (struct sh_shape_vert *)arena_base(flow->shape_verts_arena); + for (u32 i = 0; i < cmd_desc->shape.indices.count; ++i) { + indices[i] = cmd_desc->shape.indices.indices[i] + vert_offset; } } break; + + case GP_CMD_KIND_PUSH_GRID: + { + struct material_grid_desc *grid_desc = arena_push(flow->material_grid_descs_arena, struct material_grid_desc); + grid_desc->line_thickness = cmd_desc->grid.line_thickness; + grid_desc->line_spacing = cmd_desc->grid.line_spacing; + grid_desc->offset = cmd_desc->grid.offset; + grid_desc->bg0_color = cmd_desc->grid.bg0_color; + grid_desc->bg1_color = cmd_desc->grid.bg1_color; + grid_desc->line_color = cmd_desc->grid.line_color; + grid_desc->x_color = cmd_desc->grid.x_color; + grid_desc->y_color = cmd_desc->grid.y_color; + ret = ++flow->num_material_grid_descs; + } break; } } + return ret; } /* ========================== * @@ -1641,43 +1677,10 @@ INTERNAL struct dx12_resource *dx12_resource_alloc(D3D12_HEAP_PROPERTIES heap_pr return r; } -INTERNAL struct dx12_resource *dx12_resource_alloc_from_swapchain_buffer(ID3D12Resource *buff, struct v2i32 texture_size) -{ - __prof; - struct dx12_resource *r = NULL; - { - struct sys_lock lock = sys_mutex_lock_e(G.resources_mutex); - if (G.first_free_resource) { - r = G.first_free_resource; - G.first_free_resource = r->next_free; - } else { - r = arena_push_no_zero(G.resources_arena, struct dx12_resource); - } - sys_mutex_unlock(&lock); - } - MEMZERO_STRUCT(r); - - /* FIXME: Initialize dx12 resource struct here */ - - r->resource = buff; - r->rtv_descriptor = descriptor_alloc(G.rtv_heap); - r->texture_size = texture_size; - r->state = D3D12_RESOURCE_STATE_PRESENT; /* FIXME */ - - ID3D12Device_CreateRenderTargetView(G.device, r->resource, NULL, r->rtv_descriptor->handle); - - return r; -} - INTERNAL void dx12_resource_release(struct dx12_resource *t) { __prof; - (UNUSED)t; -} - -INTERNAL void dx12_resource_release_now(struct dx12_resource *t) -{ - __prof; + /* TODO */ (UNUSED)t; } @@ -1717,8 +1720,9 @@ INTERNAL struct command_queue *command_queue_alloc(enum D3D12_COMMAND_LIST_TYPE cq = arena_push(arena, struct command_queue); cq->arena = arena; } - cq->mutex = sys_mutex_alloc(); cq->type = type; + cq->submitted_command_lists_mutex = sys_mutex_alloc(); + cq->submit_fence_mutex = sys_mutex_alloc(); D3D12_COMMAND_QUEUE_DESC desc = ZI; desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; @@ -1729,7 +1733,7 @@ INTERNAL struct command_queue *command_queue_alloc(enum D3D12_COMMAND_LIST_TYPE sys_panic(LIT("Failed to create command queue")); } - hr = ID3D12Device_CreateFence(G.device, 0, 0, &IID_ID3D12Fence, (void **)&cq->fence); + hr = ID3D12Device_CreateFence(G.device, 0, 0, &IID_ID3D12Fence, (void **)&cq->submit_fence); if (FAILED(hr)) { sys_panic(LIT("Failed to create command queue fence")); } @@ -1755,16 +1759,16 @@ INTERNAL void command_queue_release(struct command_queue *cq) INTERNAL struct command_list *command_list_open(struct command_queue *cq) { __prof; - u64 queue_fence_value = ID3D12Fence_GetCompletedValue(cq->fence); + u64 completed_fence_value = ID3D12Fence_GetCompletedValue(cq->submit_fence); struct command_list *cl = NULL; struct ID3D12GraphicsCommandList *old_cl = NULL; struct ID3D12CommandAllocator *old_ca = NULL; { - struct sys_lock lock = sys_mutex_lock_e(cq->mutex); + struct sys_lock lock = sys_mutex_lock_e(cq->submitted_command_lists_mutex); /* Find first command list ready for reuse */ for (struct command_list *tmp = cq->first_submitted_command_list; tmp; tmp = tmp->next_submitted) { - if (queue_fence_value >= tmp->submitted_fence_target) { + if (completed_fence_value >= tmp->submitted_fence_target) { cl = tmp; break; } @@ -1792,7 +1796,7 @@ INTERNAL struct command_list *command_list_open(struct command_queue *cq) } MEMZERO_STRUCT(cl); cl->cq = cq; - cl->global_lock = sys_mutex_lock_s(G.global_command_list_mutex); + cl->global_record_lock = sys_mutex_lock_s(G.global_command_list_record_mutex); HRESULT hr = 0; /* FIXME: Determine command list type from command queue */ @@ -1816,7 +1820,7 @@ INTERNAL struct command_list *command_list_open(struct command_queue *cq) } } - /* Close */ + /* Reset */ hr = ID3D12CommandAllocator_Reset(cl->ca); if (FAILED(hr)) { sys_panic(LIT("Failed to reset command allocator")); @@ -1836,24 +1840,37 @@ INTERNAL u64 command_list_close(struct command_list *cl) __prof; struct command_queue *cq = cl->cq; - /* Close & execute */ - HRESULT hr = ID3D12GraphicsCommandList_Close(cl->cl); - if (FAILED(hr)) { - sys_panic(LIT("Failed to close command list before execution")); + /* Close */ + { + __profscope(Close DX12 command list); + HRESULT hr = ID3D12GraphicsCommandList_Close(cl->cl); + if (FAILED(hr)) { + /* TODO: Don't panic */ + sys_panic(LIT("Failed to close command list before execution")); + } } - ID3D12CommandQueue_ExecuteCommandLists(cq->cq, 1, (ID3D12CommandList **)&cl->cl); - /* Queue fence signal */ - /* FIXME: Wrap execute & signal in mutex */ - u64 target_fence_value = atomic_u64_eval_add_u64(&cq->fence_target, 1) + 1; - ID3D12CommandQueue_Signal(cq->cq, cq->fence, target_fence_value); + /* Submit */ + u64 submit_fence_target = 0; + { + __profscope(Execute); + struct sys_lock global_lock = sys_mutex_lock_s(G.global_command_list_submit_mutex); + struct sys_lock fence_lock = sys_mutex_lock_e(cq->submit_fence_mutex); + { + submit_fence_target = ++cq->submit_fence_target; + ID3D12CommandQueue_ExecuteCommandLists(cq->cq, 1, (ID3D12CommandList **)&cl->cl); + ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, submit_fence_target); + } + sys_mutex_unlock(&fence_lock); + sys_mutex_unlock(&global_lock); + } /* Add descriptor heaps to submitted list */ { struct sys_lock lock = sys_mutex_lock_e(G.command_descriptor_heaps_mutex); for (struct command_descriptor_heap *cdh = cl->first_command_descriptor_heap; cdh; cdh = cdh->next_in_command_list) { cdh->submitted_cq = cq; - cdh->submitted_fence_target = target_fence_value; + cdh->submitted_fence_target = submit_fence_target; if (G.last_submitted_command_descriptor_heap) { G.last_submitted_command_descriptor_heap->next_submitted = cdh; } else { @@ -1870,7 +1887,7 @@ INTERNAL u64 command_list_close(struct command_list *cl) for (struct command_buffer *cb = cl->first_command_buffer; cb; cb = cb->next_in_command_list) { struct command_buffer_group *group = cb->group; cb->submitted_cq = cq; - cb->submitted_fence_target = target_fence_value; + cb->submitted_fence_target = submit_fence_target; if (group->last_submitted) { group->last_submitted->next_submitted = cb; } else { @@ -1882,10 +1899,10 @@ INTERNAL u64 command_list_close(struct command_list *cl) } /* Add command list to submitted list */ - sys_mutex_unlock(&cl->global_lock); - cl->submitted_fence_target = target_fence_value; + sys_mutex_unlock(&cl->global_record_lock); + cl->submitted_fence_target = submit_fence_target; { - struct sys_lock lock = sys_mutex_lock_e(cq->mutex); + struct sys_lock lock = sys_mutex_lock_e(cq->submitted_command_lists_mutex); if (cq->last_submitted_command_list) { cq->last_submitted_command_list->next_submitted = cl; } else { @@ -1895,7 +1912,7 @@ INTERNAL u64 command_list_close(struct command_list *cl) sys_mutex_unlock(&lock); } - return target_fence_value; + return submit_fence_target; } /* ========================== * @@ -1917,8 +1934,8 @@ INTERNAL struct command_descriptor_heap *command_list_push_descriptor_heap(struc /* Find first heap ready for reuse */ for (struct command_descriptor_heap *tmp = G.first_submitted_command_descriptor_heap; tmp; tmp = tmp->next_submitted) { /* TODO: Cache completed fence values */ - u64 queue_fence_value = ID3D12Fence_GetCompletedValue(tmp->submitted_cq->fence); - if (queue_fence_value >= tmp->submitted_fence_target) { + u64 completed_fence_value = ID3D12Fence_GetCompletedValue(tmp->submitted_cq->submit_fence); + if (completed_fence_value >= tmp->submitted_fence_target) { cdh = tmp; break; } @@ -2032,8 +2049,8 @@ INTERNAL struct command_buffer *command_list_push_buffer(struct command_list *cl /* Find first command buffer ready for reuse */ for (struct command_buffer *tmp = cb_group->first_submitted; tmp; tmp = tmp->next_submitted) { /* TODO: Cache completed fence values */ - u64 queue_fence_value = ID3D12Fence_GetCompletedValue(tmp->submitted_cq->fence); - if (queue_fence_value >= tmp->submitted_fence_target) { + u64 completed_fence_value = ID3D12Fence_GetCompletedValue(tmp->submitted_cq->submit_fence); + if (completed_fence_value >= tmp->submitted_fence_target) { cb = tmp; break; } @@ -2319,10 +2336,13 @@ struct gp_handle gp_texture_alloc(enum gp_texture_format format, u32 flags, stru /* Wait */ /* TODO: Return async waitable to caller */ - HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); - ID3D12Fence_SetEventOnCompletion(cq->fence, fence_target, event); - WaitForSingleObject(event, INFINITE); - CloseHandle(event); + { + __profscope(Wait for upload); + HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); + ID3D12Fence_SetEventOnCompletion(cq->submit_fence, fence_target, event); + WaitForSingleObject(event, INFINITE); + CloseHandle(event); + } } return handle_alloc(DX12_HANDLE_KIND_RESOURCE, r); @@ -2353,9 +2373,10 @@ INLINE struct mat4x4 calculate_vp(struct xform view, f32 viewport_width, f32 vie void gp_dispatch(struct gp_dispatch_params params) { __prof; + struct arena_temp scratch = scratch_begin_no_conflict(); + struct flow *flow = (struct flow *)params.flow; - struct flow *flow = handle_get_data(params.flow, DX12_HANDLE_KIND_FLOW); - + struct sprite_scope *sprite_scope = sprite_scope_begin(); struct pipeline_scope *pipeline_scope = pipeline_scope_begin(); struct pipeline *material_pipeline = pipeline_from_name(pipeline_scope, LIT("material")); struct pipeline *shape_pipeline = pipeline_from_name(pipeline_scope, LIT("shape")); @@ -2372,9 +2393,64 @@ void gp_dispatch(struct gp_dispatch_params params) struct command_buffer *dummy_vertex_buffer = command_list_push_buffer(cl, STRING(0, 0)); struct command_buffer *quad_index_buffer = command_list_push_buffer(cl, STRING_FROM_ARRAY(quad_indices)); + /* Process flow data into uploadable data */ + struct sh_material_instance *material_instances = arena_push_array_no_zero(scratch.arena, struct sh_material_instance, flow->num_material_instance_descs); + struct sh_material_grid *grids = arena_push_array_no_zero(scratch.arena, struct sh_material_grid, flow->num_material_grid_descs); + { + __profscope(Process flow data); + + /* Process material instances */ + { + __profscope(Process material instances); + struct sys_lock handles_lock = sys_mutex_lock_s(G.handle_entries_mutex); + for (u32 i = 0; i < flow->num_material_instance_descs; ++i) { + struct material_instance_desc *desc = &((struct material_instance_desc *)arena_base(flow->material_instance_descs_arena))[i]; + struct sh_material_instance *instance = &material_instances[i]; + i32 texture_id = -1; + { + struct dx12_resource *texture = NULL; + if (desc->texture.gen != 0) { + texture = handle_get_data_locked(desc->texture, DX12_HANDLE_KIND_RESOURCE, &handles_lock); + } else if (desc->sprite.hash != 0) { + struct sprite_texture *st = sprite_texture_from_tag_async(sprite_scope, desc->sprite); + texture = handle_get_data_locked(st->texture, DX12_HANDLE_KIND_RESOURCE, &handles_lock); + } + if (texture) { + texture_id = texture->srv_descriptor->index; + } + } + instance->tex_nurid = sh_int_from_i32(texture_id); + instance->grid_id = sh_int_from_i32(desc->grid_id); + instance->xf = sh_float2x3_from_xform(desc->xf); + instance->uv0 = sh_float2_from_v2(desc->clip.p0); + instance->uv1 = sh_float2_from_v2(desc->clip.p1); + instance->tint_srgb = sh_uint_from_u32(desc->tint); + instance->emittance = sh_float_from_f32(desc->emittance); + } + sys_mutex_unlock(&handles_lock); + } + + /* Process grids */ + { + __profscope(Process grids); + for (u32 i = 0; i < flow->num_material_grid_descs; ++i) { + struct material_grid_desc *desc = &((struct material_grid_desc *)arena_base(flow->material_grid_descs_arena))[i]; + struct sh_material_grid *grid = &grids[i]; + grid->line_thickness = sh_float_from_f32(desc->line_thickness); + grid->line_spacing = sh_float_from_f32(desc->line_spacing); + grid->offset = sh_float2_from_v2(desc->offset); + grid->bg0_srgb = sh_uint_from_u32(desc->bg0_color); + grid->bg1_srgb = sh_uint_from_u32(desc->bg1_color); + grid->line_srgb = sh_uint_from_u32(desc->line_color); + grid->x_srgb = sh_uint_from_u32(desc->x_color); + grid->y_srgb = sh_uint_from_u32(desc->y_color); + } + } + } + /* Upload buffers */ - struct command_buffer *material_instance_buffer = command_list_push_buffer(cl, STRING_FROM_ARENA(flow->material_instances_arena)); - struct command_buffer *material_grid_buffer = command_list_push_buffer(cl, STRING_FROM_ARENA(flow->material_grids_arena)); + struct command_buffer *material_instance_buffer = command_list_push_buffer(cl, STRING(sizeof(*material_instances) * flow->num_material_instance_descs, (u8 *)material_instances)); + struct command_buffer *grid_buffer = command_list_push_buffer(cl, STRING(sizeof(*grids) * flow->num_material_grid_descs, (u8 *)grids)); struct command_buffer *shape_verts_buffer = command_list_push_buffer(cl, STRING_FROM_ARENA(flow->shape_verts_arena)); struct command_buffer *shape_indices_buffer = command_list_push_buffer(cl, STRING_FROM_ARENA(flow->shape_indices_arena)); @@ -2409,7 +2485,7 @@ void gp_dispatch(struct gp_dispatch_params params) ID3D12GraphicsCommandList_SetGraphicsRootShaderResourceView(cl->cl, 1, material_instance_buffer->resource->gpu_address); /* Set grid buffer */ - ID3D12GraphicsCommandList_SetGraphicsRootShaderResourceView(cl->cl, 2, material_grid_buffer->resource->gpu_address); + ID3D12GraphicsCommandList_SetGraphicsRootShaderResourceView(cl->cl, 2, grid_buffer->resource->gpu_address); /* Set descriptor heap */ ID3D12DescriptorHeap *heaps[] = { descriptor_heap->heap }; @@ -2469,7 +2545,10 @@ void gp_dispatch(struct gp_dispatch_params params) } command_list_close(cl); pipeline_scope_end(pipeline_scope); + sprite_scope_end(sprite_scope); + flow_reset(flow); + scratch_end(scratch); } /* ========================== * @@ -2505,36 +2584,60 @@ struct gp_memory_info gp_query_memory_info(void) } /* ========================== * - * Present + * Swapchain * ========================== */ -INTERNAL struct dx12_resource *update_swapchain(struct sys_window *window, struct v2i32 resolution) +INTERNAL struct swapchain_buffer *update_swapchain(struct swapchain *swapchain, struct sys_window *window, struct v2i32 resolution) { __prof; - HWND hwnd = (HWND)sys_window_get_internal_handle(window); - b32 should_rebuild = !v2i32_eq(G.swapchain_resolution, resolution); + resolution.x = max_i32(resolution.x, 1); + resolution.y = max_i32(resolution.y, 1); + b32 should_rebuild = !v2i32_eq(swapchain->resolution, resolution); if (should_rebuild) { HRESULT hr = 0; + struct command_queue *cq = G.cq_direct; + HWND hwnd = (HWND)sys_window_get_internal_handle(window); + if (swapchain->swapchain) { + ASSERT(hwnd == swapchain->hwnd); - if (G.swapchain) { - ASSERT(hwnd == G.swapchain_hwnd); - /* Resize existing swapchain */ - /* FIXME: Fence */ + /* Lock direct queue submissions (in case any write to backbuffer) */ + /* TODO: Less overkill approach - Only flush present_blit since we know it's the only operation targeting backbuffer */ + //struct sys_lock lock = sys_mutex_lock_e(cq->submit_fence_mutex); + DEBUGBREAKABLE; + struct sys_lock lock = sys_mutex_lock_e(G.global_command_list_record_mutex); + { + /* Flush direct queue */ + //ID3D12CommandQueue_Signal(cq->cq, cq->submit_fence, ++cq->submit_fence_target); + { + HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); + ID3D12Fence_SetEventOnCompletion(cq->submit_fence, cq->submit_fence_target, event); + WaitForSingleObject(event, INFINITE); + CloseHandle(event); + } - /* Release resources */ - for (u32 i = 0; i < ARRAY_COUNT(G.swapchain_resources); ++i) { - struct dx12_resource *resource = G.swapchain_resources[i]; - dx12_resource_release_now(resource); + /* Release buffers */ + for (u32 i = 0; i < ARRAY_COUNT(swapchain->buffers); ++i) { + struct swapchain_buffer *sb = &swapchain->buffers[i]; + descriptor_release(sb->rtv_descriptor); + ID3D12Resource_Release(sb->resource); + } + + /* Resize buffers */ + hr = IDXGISwapChain_ResizeBuffers(swapchain->swapchain, 0, resolution.x, resolution.y, DXGI_FORMAT_UNKNOWN, DX12_SWAPCHAIN_FLAGS); + if (FAILED(hr)) { + /* TODO: Don't panic */ + sys_panic(LIT("Failed to resize swapchain")); + } } - - /* Resize buffers */ - IDXGISwapChain_ResizeBuffers(G.swapchain, 0, resolution.x, resolution.y, DXGI_FORMAT_UNKNOWN, DX12_SWAPCHAIN_FLAGS); + sys_mutex_unlock(&lock); } else { /* Create swapchain1 */ IDXGISwapChain1 *swapchain1 = NULL; { DXGI_SWAP_CHAIN_DESC1 desc = ZI; desc.Format = DX12_SWAPCHAIN_FORMAT; + desc.Width = resolution.x; + desc.Height = resolution.y; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.BufferUsage = DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT; @@ -2543,44 +2646,54 @@ INTERNAL struct dx12_resource *update_swapchain(struct sys_window *window, struc desc.Flags = DX12_SWAPCHAIN_FLAGS; desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - hr = IDXGIFactory2_CreateSwapChainForHwnd(G.factory, (IUnknown *)G.cq_direct->cq, hwnd, &desc, NULL, NULL, &swapchain1); + hr = IDXGIFactory2_CreateSwapChainForHwnd(G.factory, (IUnknown *)cq->cq, hwnd, &desc, NULL, NULL, &swapchain1); if (FAILED(hr)) { - dx12_init_error(LIT("Failed to create IDXGISwapChain1")); + sys_panic(LIT("Failed to create IDXGISwapChain1")); } } /* Upgrade to swapchain3 */ - hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&G.swapchain); + hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain->swapchain); if (FAILED(hr)) { - dx12_init_error(LIT("Failed to create IDXGISwapChain3")); + sys_panic(LIT("Failed to create IDXGISwapChain3")); } /* Disable Alt+Enter changing monitor resolution to match window size */ IDXGIFactory_MakeWindowAssociation(G.factory, hwnd, DXGI_MWA_NO_ALT_ENTER); IDXGISwapChain1_Release(swapchain1); - G.swapchain_hwnd = hwnd; + swapchain->hwnd = hwnd; } /* Allocate swapchain resources */ - for (u32 i = 0; i < ARRAY_COUNT(G.swapchain_resources); ++i) { + for (u32 i = 0; i < ARRAY_COUNT(swapchain->buffers); ++i) { ID3D12Resource *resource = NULL; - hr = IDXGISwapChain3_GetBuffer(G.swapchain, i, &IID_ID3D12Resource, (void **)&resource); + hr = IDXGISwapChain3_GetBuffer(swapchain->swapchain, i, &IID_ID3D12Resource, (void **)&resource); if (FAILED(hr)) { /* TODO: Don't panic */ - dx12_init_error(LIT("Failed to get swapchain buffer")); + sys_panic(LIT("Failed to get swapchain buffer")); } - G.swapchain_resources[i] = dx12_resource_alloc_from_swapchain_buffer(resource, resolution); + struct swapchain_buffer *sb = &swapchain->buffers[i]; + MEMZERO_STRUCT(sb); + sb->swapchain = swapchain; + sb->resource = resource; + sb->rtv_descriptor = descriptor_alloc(G.rtv_heap); + sb->state = D3D12_RESOURCE_STATE_COMMON; + ID3D12Device_CreateRenderTargetView(G.device, sb->resource, NULL, sb->rtv_descriptor->handle); } - G.swapchain_resolution = resolution; + swapchain->resolution = resolution; } - G.swapchain_frame_index = IDXGISwapChain3_GetCurrentBackBufferIndex(G.swapchain); - return G.swapchain_resources[G.swapchain_frame_index]; + u32 backbuffer_index = IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain->swapchain); + return &swapchain->buffers[backbuffer_index]; } -INTERNAL void present_blit(struct dx12_resource *dst, struct dx12_resource *src, struct xform src_xf) +/* ========================== * + * Present + * ========================== */ + +INTERNAL void present_blit(struct swapchain_buffer *dst, struct dx12_resource *src, struct xform src_xf) { __prof; struct pipeline_scope *pipeline_scope = pipeline_scope_begin(); @@ -2589,6 +2702,7 @@ INTERNAL void present_blit(struct dx12_resource *dst, struct dx12_resource *src, struct command_list *cl = command_list_open(G.cq_direct); { __profscope_dx12(cl->cq->prof, cl->cl, Blit, RGB32_F(0.5, 0.2, 0.2)); + struct swapchain *swapchain = dst->swapchain; /* Upload dummmy vert & index buffer */ /* TODO: Make these static */ @@ -2600,13 +2714,25 @@ INTERNAL void present_blit(struct dx12_resource *dst, struct dx12_resource *src, /* Upload descriptor heap */ struct command_descriptor_heap *descriptor_heap = command_list_push_descriptor_heap(cl, G.cbv_srv_uav_heap); - struct rect viewport_rect = RECT_FROM_V2(V2(0, 0), V2(dst->texture_size.x, dst->texture_size.y)); + struct rect viewport_rect = RECT_FROM_V2(V2(0, 0), V2(swapchain->resolution.x, swapchain->resolution.y)); D3D12_VIEWPORT viewport = viewport_from_rect(viewport_rect); D3D12_RECT scissor = scissor_from_rect(viewport_rect); struct mat4x4 vp_matrix = calculate_vp(src_xf, viewport.Width, viewport.Height); /* Transition dst to render target */ - dx12_resource_barrier(cl->cl, dst, D3D12_RESOURCE_STATE_RENDER_TARGET); + { + struct D3D12_RESOURCE_TRANSITION_BARRIER rtb = ZI; + rtb.pResource = dst->resource; + rtb.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + rtb.StateBefore = dst->state; + rtb.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; + struct D3D12_RESOURCE_BARRIER rb = ZI; + rb.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + rb.Flags = 0; + rb.Transition = rtb; + ID3D12GraphicsCommandList_ResourceBarrier(cl->cl, 1, &rb); + dst->state = rtb.StateAfter; + } ID3D12GraphicsCommandList_OMSetRenderTargets(cl->cl, 1, &dst->rtv_descriptor->handle, false, NULL); /* Clear */ @@ -2641,24 +2767,38 @@ INTERNAL void present_blit(struct dx12_resource *dst, struct dx12_resource *src, ID3D12GraphicsCommandList_IASetIndexBuffer(cl->cl, &ibv); ID3D12GraphicsCommandList_DrawIndexedInstanced(cl->cl, 6, 1, 0, 0, 0); - /* Set dst to presentable */ - dx12_resource_barrier(cl->cl, dst, D3D12_RESOURCE_STATE_PRESENT); + /* Transition dst to presentable */ + { + struct D3D12_RESOURCE_TRANSITION_BARRIER rtb = ZI; + rtb.pResource = dst->resource; + rtb.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + rtb.StateBefore = dst->state; + rtb.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + struct D3D12_RESOURCE_BARRIER rb = ZI; + rb.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + rb.Flags = 0; + rb.Transition = rtb; + ID3D12GraphicsCommandList_ResourceBarrier(cl->cl, 1, &rb); + dst->state = rtb.StateAfter; + } + ID3D12GraphicsCommandList_OMSetRenderTargets(cl->cl, 1, &dst->rtv_descriptor->handle, false, NULL); } command_list_close(cl); } pipeline_scope_end(pipeline_scope); } -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 backresolution, struct gp_handle texture, struct xform texture_xf, i32 vsync) { __prof; //sys_sleep(0.1); - struct dx12_resource *backbuffer_resource = update_swapchain(window, backbuffer_resolution); + struct swapchain *swapchain = &G.swapchain; + struct swapchain_buffer *swapchain_buffer = update_swapchain(swapchain, window, backresolution); struct dx12_resource *texture_resource = handle_get_data(texture, DX12_HANDLE_KIND_RESOURCE); /* Blit */ - present_blit(backbuffer_resource, texture_resource, texture_xf); + present_blit(swapchain_buffer, texture_resource, texture_xf); //sys_sleep(0.1); @@ -2666,7 +2806,7 @@ void gp_present(struct sys_window *window, struct v2i32 backbuffer_resolution, s /* FIXME: Resource barrier */ { __profscope(Present); - HRESULT hr = IDXGISwapChain3_Present(G.swapchain, 0, 0); + HRESULT hr = IDXGISwapChain3_Present(swapchain->swapchain, 0, 0); if (!SUCCEEDED(hr)) { ASSERT(false); } @@ -2675,8 +2815,9 @@ void gp_present(struct sys_window *window, struct v2i32 backbuffer_resolution, s #if PROFILING { - /* Lock because command shouldn't be recording during a frame mark */ - struct sys_lock lock = sys_mutex_lock_e(G.global_command_list_mutex); + __profscope(Mark queue frames); + /* Lock because frame marks shouldn't occur while command lists are recording */ + struct sys_lock lock = sys_mutex_lock_e(G.global_command_list_record_mutex); __prof_dx12_new_frame(G.cq_direct->prof); __prof_dx12_new_frame(G.cq_compute->prof); __prof_dx12_new_frame(G.cq_copy_critical->prof); @@ -2684,6 +2825,7 @@ void gp_present(struct sys_window *window, struct v2i32 backbuffer_resolution, s sys_mutex_unlock(&lock); } { + __profscope(Collect queues); __prof_dx12_collect(G.cq_direct->prof); __prof_dx12_collect(G.cq_compute->prof); __prof_dx12_collect(G.cq_copy_critical->prof); @@ -2692,7 +2834,7 @@ void gp_present(struct sys_window *window, struct v2i32 backbuffer_resolution, s #endif - (UNUSED)backbuffer_resolution; + (UNUSED)backresolution; (UNUSED)texture; (UNUSED)texture_xf; (UNUSED)vsync; diff --git a/src/sprite.c b/src/sprite.c index 5d389799..64ac41f0 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -898,8 +898,6 @@ INTERNAL struct sprite_scope_cache_ref *cache_lookup(struct sprite_scope *scope, INTERNAL struct sprite_scope_cache_ref *cache_entry_from_tag(struct sprite_scope *scope, struct sprite_tag tag, enum cache_entry_kind kind, b32 force_new) { - __prof; - struct cache_entry_hash hash = cache_entry_hash_from_tag_hash(tag.hash, kind); u64 bin_index = hash.v % CACHE_BINS_COUNT; struct sprite_scope_cache_ref *scope_ref = NULL; diff --git a/src/user.c b/src/user.c index a926dadf..cb1f3d49 100644 --- a/src/user.c +++ b/src/user.c @@ -73,8 +73,8 @@ GLOBAL struct { /* Gpu handles */ struct gp_handle user_texture; - struct gp_handle world_gp_flow; - struct gp_handle ui_gp_flow; + struct gp_flow *world_gp_flow; + struct gp_flow *ui_gp_flow; struct xform world_to_user_xf;