Harbor

Changelog 8a82680b8ebc

pin gpu imported mesh planned path

@sky · 1 month ago · parent 228921414be9
0 added 4 modified 0 deleted
gpu/compiler/executor.odin modified

Diff hidden because this file has more than 800 lines.

gpu/docs/gpu_intent_api.md +1 -1 modified
18 unchanged lines hidden
19 19
20 20 ## Execution model
21 21
22 - The authoritative runtime direction is a planned-IR executor: validation produces diagnostics, planning orders commands, and backend lowering walks the planned IR to issue backend operations. A gated backend-native planned draw path now handles materialized IR buffers, render passes, shaders, graphics pipelines, descriptor sets, direct indexed draws, and direct non-indexed draws. The current runtime translator that maps generated/imported producer forms into legacy 2D/3D renderer calls is migration-only. New backend parity work must not add feature-specific translator branches unless the branch is a temporary, tracked bridge with a removal path.
22 + The authoritative runtime direction is a planned-IR executor: validation produces diagnostics, planning orders commands, and backend lowering walks the planned IR to issue backend operations. A gated backend-native planned draw path now handles materialized IR buffers, render passes, shaders, graphics pipelines, descriptor sets, direct indexed draws, direct non-indexed draws, and supported borrowed imported mesh buffers. The current runtime translator that maps remaining generated/imported producer forms into legacy 2D/3D renderer calls is migration-only. New backend parity work must not add feature-specific translator branches unless the branch is a temporary, tracked bridge with a removal path.
23 23
24 24 Runtime lowering must not fail silently. If a command cannot be lowered, `gpu` records a structured diagnostic with the command handle and reason, then fails submission or mode classification explicitly.
25 25
227 unchanged lines hidden
gpu/frame_api.odin modified

Diff hidden because this file has more than 800 lines.

gpu/tests/compiler_executor_test.odin +150 -4 modified
11 unchanged lines hidden
12 12 mock_planned_vertex_count: u32
13 13 mock_planned_instance_count: u32
14 14 mock_planned_bound_vertex_buffer: bk.Buffer_Handle
15 + mock_planned_bound_index_buffer: bk.Buffer_Handle
15 16 mock_planned_bound_pipeline: bk.Pipeline_Handle
17 + mock_planned_bound_descriptor: bk.Descriptor_Handle
18 + mock_planned_push_constant_size: u32
19 + mock_planned_indexed_count: u32
20 + mock_planned_trace: [32]string
21 + mock_planned_trace_count: int
16 22
23 + mock_planned_trace_add :: proc(name: string) {
24 + if mock_planned_trace_count < len(mock_planned_trace) {
25 + mock_planned_trace[mock_planned_trace_count] = name
26 + mock_planned_trace_count += 1
27 + }
28 + }
29 +
17 30 mock_create_shader_module :: proc(desc: bk.Shader_Module_Desc) -> (bk.Shader_Handle, bool) {
18 31 mock_shader_desc = desc
19 32 return bk.Shader_Handle(77), true
3 unchanged lines hidden
23 36
24 37 mock_planned_begin_render_pass :: proc(ctx: bk.Frame_Context, desc: bk.Render_Pass_Begin_Desc) {
25 38 mock_planned_begin_pass_count += 1
39 + mock_planned_trace_add("begin_render_pass")
26 40 }
27 41
28 42 mock_planned_begin_default_pass :: proc(ctx: bk.Frame_Context, clear_color: [4]f32) {
29 43 mock_planned_begin_pass_count += 1
44 + mock_planned_trace_add("begin_default_pass")
30 45 }
31 46
32 47 mock_planned_end_render_pass :: proc(ctx: bk.Frame_Context) {
33 48 mock_planned_end_pass_count += 1
49 + mock_planned_trace_add("end_render_pass")
34 50 }
35 51
36 - mock_planned_set_viewport :: proc(ctx: bk.Frame_Context, x, y, w, h: f32) {}
52 + mock_planned_set_viewport :: proc(ctx: bk.Frame_Context, x, y, w, h: f32) {
53 + mock_planned_trace_add("set_viewport")
54 + }
37 55
38 - mock_planned_set_scissor :: proc(ctx: bk.Frame_Context, x, y: i32, w, h: u32) {}
56 + mock_planned_set_scissor :: proc(ctx: bk.Frame_Context, x, y: i32, w, h: u32) {
57 + mock_planned_trace_add("set_scissor")
58 + }
39 59
40 60 mock_planned_get_extent :: proc() -> bk.Extent {
41 61 return {width = 640, height = 480}
12 unchanged lines hidden
54 74
55 75 mock_planned_bind_graphics_pipeline :: proc(ctx: bk.Frame_Context, handle: bk.Pipeline_Handle) {
56 76 mock_planned_bound_pipeline = handle
77 + mock_planned_trace_add("bind_pipeline")
57 78 }
58 79
80 + mock_planned_bind_descriptor_set :: proc(
81 + ctx: bk.Frame_Context,
82 + pipeline: bk.Pipeline_Handle,
83 + set: bk.Descriptor_Handle,
84 + index: u32,
85 + ) {
86 + mock_planned_bound_descriptor = set
87 + mock_planned_trace_add("bind_descriptor")
88 + }
89 +
90 + mock_planned_push_constants :: proc(
91 + ctx: bk.Frame_Context,
92 + pipeline: bk.Pipeline_Handle,
93 + stages: bk.Shader_Stage_Flags,
94 + offset, size: u32,
95 + data: rawptr,
96 + ) {
97 + mock_planned_push_constant_size = size
98 + mock_planned_trace_add("push_constants")
99 + }
100 +
59 101 mock_planned_bind_vertex_buffer :: proc(ctx: bk.Frame_Context, handle: bk.Buffer_Handle) {
60 102 mock_planned_bound_vertex_buffer = handle
103 + mock_planned_trace_add("bind_vertex_buffer")
61 104 }
62 105
63 - mock_planned_bind_index_buffer :: proc(ctx: bk.Frame_Context, handle: bk.Buffer_Handle) {}
106 + mock_planned_bind_index_buffer :: proc(ctx: bk.Frame_Context, handle: bk.Buffer_Handle) {
107 + mock_planned_bound_index_buffer = handle
108 + mock_planned_trace_add("bind_index_buffer")
109 + }
64 110
65 111 mock_planned_draw :: proc(
66 112 ctx: bk.Frame_Context,
4 unchanged lines hidden
71 117 mock_planned_draw_count += 1
72 118 mock_planned_vertex_count = vertex_count
73 119 mock_planned_instance_count = instance_count
120 + mock_planned_trace_add("draw")
74 121 }
75 122
76 123 mock_planned_draw_indexed :: proc(
2 unchanged lines hidden
79 126 first_index: u32,
80 127 vertex_offset: i32,
81 128 first_instance: u32,
82 - ) {}
129 + ) {
130 + mock_planned_draw_count += 1
131 + mock_planned_indexed_count = index_count
132 + mock_planned_instance_count = instance_count
133 + mock_planned_trace_add("draw_indexed")
134 + }
83 135
84 136 mock_planned_destroy_buffer :: proc(handle: bk.Buffer_Handle) {}
85 137
12 unchanged lines hidden
98 150 create_graphics_pipeline = mock_planned_create_graphics_pipeline,
99 151 destroy_graphics_pipeline = mock_planned_destroy_graphics_pipeline,
100 152 bind_graphics_pipeline = mock_planned_bind_graphics_pipeline,
153 + push_constants = mock_planned_push_constants,
154 + bind_descriptor_set = mock_planned_bind_descriptor_set,
101 155 bind_vertex_buffer = mock_planned_bind_vertex_buffer,
102 156 bind_index_buffer = mock_planned_bind_index_buffer,
103 157 draw = mock_planned_draw,
12 unchanged lines hidden
116 170 mock_planned_vertex_count = 0
117 171 mock_planned_instance_count = 0
118 172 mock_planned_bound_vertex_buffer = bk.NULL_BUFFER
173 + mock_planned_bound_index_buffer = bk.NULL_BUFFER
119 174 mock_planned_bound_pipeline = bk.NULL_PIPELINE
175 + mock_planned_bound_descriptor = bk.NULL_DESCRIPTOR
176 + mock_planned_push_constant_size = 0
177 + mock_planned_indexed_count = 0
178 + mock_planned_trace_count = 0
120 179 }
121 180
181 + mock_imported_draw_resolver :: proc(
182 + user_data: rawptr,
183 + frame: ^ir.Frame_IR,
184 + command: ir.Command_Handle,
185 + draw: ^ir.Draw_Command,
186 + out: ^compiler.Imported_Draw_Binding,
187 + ) -> bool {
188 + _ = user_data
189 + _ = frame
190 + _ = command
191 + _ = draw
192 + out.pipeline = bk.Pipeline_Handle(91)
193 + out.descriptor_sets[0] = bk.Descriptor_Handle(92)
194 + out.descriptor_set_indices[0] = 0
195 + out.descriptor_set_count = 1
196 + out.push_constant_stages = {.Vertex}
197 + out.push_constant_size = 16
198 + out.vertex_buffer = bk.Buffer_Handle(93)
199 + out.index_buffer = bk.Buffer_Handle(94)
200 + out.index_count = 36
201 + out.instance_count = 1
202 + out.indexed = true
203 + return true
204 + }
205 +
122 206 @(test)
123 207 test_compiler_materializes_offscreen_frame_target :: proc(t: ^testing.T) {
124 208 frame := ir.init_frame_ir()
347 unchanged lines hidden
472 556 testing.expect_value(t, mock_planned_instance_count, u32(2))
473 557 testing.expect_value(t, mock_planned_bound_vertex_buffer, bk.Buffer_Handle(12))
474 558 testing.expect_value(t, mock_planned_bound_pipeline, bk.Pipeline_Handle(31))
559 +
560 + reset_planned_mock()
561 + imported_frame := ir.init_frame_ir()
562 + defer ir.destroy_frame_ir(&imported_frame)
563 +
564 + imported_buffer := ir.add_buffer(
565 + &imported_frame,
566 + "imported-mesh",
567 + 0,
568 + {.Vertex, .Index},
569 + {},
570 + .Imported,
571 + )
572 + _ = ir.add_draw_packet(
573 + &imported_frame,
574 + ir.INVALID_PASS,
575 + ir.INVALID_PIPELINE,
576 + .Indexed_Mesh,
577 + {
578 + geometry = {kind = .Indexed_Mesh, resource = imported_buffer, index_count = 36},
579 + order = .Strict,
580 + },
581 + )
582 +
583 + imported_state := compiler.init_execution_state(&backend)
584 + defer compiler.destroy_execution_state(&imported_state)
585 + compiler.set_imported_draw_resolver(&imported_state, mock_imported_draw_resolver, nil)
586 +
587 + testing.expect(t, compiler.prepare_planned_frame(&imported_state, &imported_frame))
588 + testing.expect(
589 + t,
590 + compiler.execute_prepared_planned_commands(
591 + &imported_state,
592 + &imported_frame,
593 + {},
594 + {0, 0, 0, 1},
595 + ),
596 + )
597 + testing.expect_value(t, mock_planned_draw_count, 1)
598 + testing.expect_value(t, mock_planned_indexed_count, u32(36))
599 + testing.expect_value(t, mock_planned_bound_pipeline, bk.Pipeline_Handle(91))
600 + testing.expect_value(t, mock_planned_bound_descriptor, bk.Descriptor_Handle(92))
601 + testing.expect_value(t, mock_planned_bound_vertex_buffer, bk.Buffer_Handle(93))
602 + testing.expect_value(t, mock_planned_bound_index_buffer, bk.Buffer_Handle(94))
603 + testing.expect_value(t, mock_planned_push_constant_size, u32(16))
604 +
605 + expected := [?]string {
606 + "begin_default_pass",
607 + "set_viewport",
608 + "set_scissor",
609 + "bind_pipeline",
610 + "bind_descriptor",
611 + "push_constants",
612 + "bind_vertex_buffer",
613 + "bind_index_buffer",
614 + "draw_indexed",
615 + "end_render_pass",
616 + }
617 + testing.expect_value(t, mock_planned_trace_count, len(expected))
618 + for event, i in expected {
619 + testing.expect_value(t, mock_planned_trace[i], event)
620 + }
475 621 }