Harbor

Changelog 228921414be9

pin gpu planned draw integration

@sky · 1 month ago · parent 55c956421461
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. The current runtime translator that maps selected IR draw kinds 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, 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.
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 +176 -0 modified
5 unchanged lines hidden
6 6 import "core:testing"
7 7
8 8 mock_shader_desc: bk.Shader_Module_Desc
9 + mock_planned_begin_pass_count: int
10 + mock_planned_end_pass_count: int
11 + mock_planned_draw_count: int
12 + mock_planned_vertex_count: u32
13 + mock_planned_instance_count: u32
14 + mock_planned_bound_vertex_buffer: bk.Buffer_Handle
15 + mock_planned_bound_pipeline: bk.Pipeline_Handle
9 16
10 17 mock_create_shader_module :: proc(desc: bk.Shader_Module_Desc) -> (bk.Shader_Handle, bool) {
11 18 mock_shader_desc = desc
2 unchanged lines hidden
14 21
15 22 mock_destroy_shader :: proc(handle: bk.Shader_Handle) {}
16 23
24 + mock_planned_begin_render_pass :: proc(ctx: bk.Frame_Context, desc: bk.Render_Pass_Begin_Desc) {
25 + mock_planned_begin_pass_count += 1
26 + }
27 +
28 + mock_planned_begin_default_pass :: proc(ctx: bk.Frame_Context, clear_color: [4]f32) {
29 + mock_planned_begin_pass_count += 1
30 + }
31 +
32 + mock_planned_end_render_pass :: proc(ctx: bk.Frame_Context) {
33 + mock_planned_end_pass_count += 1
34 + }
35 +
36 + mock_planned_set_viewport :: proc(ctx: bk.Frame_Context, x, y, w, h: f32) {}
37 +
38 + mock_planned_set_scissor :: proc(ctx: bk.Frame_Context, x, y: i32, w, h: u32) {}
39 +
40 + mock_planned_get_extent :: proc() -> bk.Extent {
41 + return {width = 640, height = 480}
42 + }
43 +
44 + mock_planned_create_graphics_pipeline :: proc(
45 + desc: bk.Pipeline_Desc,
46 + ) -> (
47 + bk.Pipeline_Handle,
48 + bool,
49 + ) {
50 + return bk.Pipeline_Handle(31), true
51 + }
52 +
53 + mock_planned_destroy_graphics_pipeline :: proc(handle: bk.Pipeline_Handle) {}
54 +
55 + mock_planned_bind_graphics_pipeline :: proc(ctx: bk.Frame_Context, handle: bk.Pipeline_Handle) {
56 + mock_planned_bound_pipeline = handle
57 + }
58 +
59 + mock_planned_bind_vertex_buffer :: proc(ctx: bk.Frame_Context, handle: bk.Buffer_Handle) {
60 + mock_planned_bound_vertex_buffer = handle
61 + }
62 +
63 + mock_planned_bind_index_buffer :: proc(ctx: bk.Frame_Context, handle: bk.Buffer_Handle) {}
64 +
65 + mock_planned_draw :: proc(
66 + ctx: bk.Frame_Context,
67 + vertex_count, instance_count: u32,
68 + first_vertex: u32,
69 + first_instance: u32,
70 + ) {
71 + mock_planned_draw_count += 1
72 + mock_planned_vertex_count = vertex_count
73 + mock_planned_instance_count = instance_count
74 + }
75 +
76 + mock_planned_draw_indexed :: proc(
77 + ctx: bk.Frame_Context,
78 + index_count, instance_count: u32,
79 + first_index: u32,
80 + vertex_offset: i32,
81 + first_instance: u32,
82 + ) {}
83 +
84 + mock_planned_destroy_buffer :: proc(handle: bk.Buffer_Handle) {}
85 +
86 + mock_planned_destroy_render_pass :: proc(handle: bk.Render_Pass_Handle) {}
87 +
88 + mock_planned_destroy_framebuffer :: proc(handle: bk.Framebuffer_Handle) {}
89 +
90 + mock_planned_backend :: proc() -> bk.Backend {
91 + return {
92 + begin_render_pass = mock_planned_begin_render_pass,
93 + begin_default_pass = mock_planned_begin_default_pass,
94 + end_render_pass = mock_planned_end_render_pass,
95 + set_viewport = mock_planned_set_viewport,
96 + set_scissor = mock_planned_set_scissor,
97 + get_extent = mock_planned_get_extent,
98 + create_graphics_pipeline = mock_planned_create_graphics_pipeline,
99 + destroy_graphics_pipeline = mock_planned_destroy_graphics_pipeline,
100 + bind_graphics_pipeline = mock_planned_bind_graphics_pipeline,
101 + bind_vertex_buffer = mock_planned_bind_vertex_buffer,
102 + bind_index_buffer = mock_planned_bind_index_buffer,
103 + draw = mock_planned_draw,
104 + draw_indexed = mock_planned_draw_indexed,
105 + destroy_buffer = mock_planned_destroy_buffer,
106 + destroy_render_pass = mock_planned_destroy_render_pass,
107 + destroy_framebuffer = mock_planned_destroy_framebuffer,
108 + destroy_shader = mock_destroy_shader,
109 + }
110 + }
111 +
112 + reset_planned_mock :: proc() {
113 + mock_planned_begin_pass_count = 0
114 + mock_planned_end_pass_count = 0
115 + mock_planned_draw_count = 0
116 + mock_planned_vertex_count = 0
117 + mock_planned_instance_count = 0
118 + mock_planned_bound_vertex_buffer = bk.NULL_BUFFER
119 + mock_planned_bound_pipeline = bk.NULL_PIPELINE
120 + }
121 +
17 122 @(test)
18 123 test_compiler_materializes_offscreen_frame_target :: proc(t: ^testing.T) {
19 124 frame := ir.init_frame_ir()
277 unchanged lines hidden
297 402 testing.expect_value(t, mock_shader_desc.name, "compute.comp")
298 403 testing.expect(t, len(mock_shader_desc.data) > 0)
299 404 }
405 +
406 + @(test)
407 + test_compiler_executes_planned_vertex_stream_draw :: proc(t: ^testing.T) {
408 + reset_planned_mock()
409 + frame := ir.init_frame_ir()
410 + defer ir.destroy_frame_ir(&frame)
411 +
412 + buffer := ir.add_buffer(&frame, "vertices", 256, {.Vertex}, {.Device_Local}, .Persistent)
413 + pass := ir.add_pass(&frame, {kind = .Render, name = "main"})
414 + vertex_shader := ir.add_shader(&frame, {stage = .Vertex, name = "vs"})
415 + fragment_shader := ir.add_shader(&frame, {stage = .Fragment, name = "fs"})
416 + pipeline_state := ir.default_graphics_pipeline_state()
417 + pipeline_state.vertex_shader = vertex_shader
418 + pipeline_state.fragment_shader = fragment_shader
419 + pipeline := ir.add_graphics_pipeline(&frame, "pipeline", pipeline_state)
420 +
421 + packet := ir.Draw_Packet {
422 + geometry = {kind = .Vertex_Stream, resource = buffer, vertex_count = 6},
423 + order = .Strict,
424 + }
425 + _ = ir.add_draw_packet(&frame, pass, pipeline, .Vertex_Stream, packet, instance_count = 2)
426 +
427 + backend := mock_planned_backend()
428 + state := compiler.init_execution_state(&backend)
429 + defer compiler.destroy_execution_state_views(&state)
430 + append(
431 + &state.resources,
432 + compiler.Prepared_Resource {
433 + resource = buffer,
434 + kind = .Buffer,
435 + buffer = bk.Buffer_Handle(12),
436 + },
437 + )
438 + append(
439 + &state.passes,
440 + compiler.Prepared_Pass {
441 + pass = pass,
442 + render_pass = bk.Render_Pass_Handle(21),
443 + framebuffer = bk.Framebuffer_Handle(22),
444 + begin_desc = {
445 + pass = bk.Render_Pass_Handle(21),
446 + framebuffer = bk.Framebuffer_Handle(22),
447 + },
448 + },
449 + )
450 + append(
451 + &state.shaders,
452 + compiler.Prepared_Shader {
453 + shader = vertex_shader,
454 + stage = .Vertex,
455 + module = bk.Shader_Handle(41),
456 + },
457 + )
458 + append(
459 + &state.shaders,
460 + compiler.Prepared_Shader {
461 + shader = fragment_shader,
462 + stage = .Fragment,
463 + module = bk.Shader_Handle(42),
464 + },
465 + )
466 +
467 + testing.expect(t, compiler.execute_prepared_planned_commands(&state, &frame, {}, {0, 0, 0, 1}))
468 + testing.expect_value(t, mock_planned_begin_pass_count, 1)
469 + testing.expect_value(t, mock_planned_end_pass_count, 1)
470 + testing.expect_value(t, mock_planned_draw_count, 1)
471 + testing.expect_value(t, mock_planned_vertex_count, u32(6))
472 + testing.expect_value(t, mock_planned_instance_count, u32(2))
473 + testing.expect_value(t, mock_planned_bound_vertex_buffer, bk.Buffer_Handle(12))
474 + testing.expect_value(t, mock_planned_bound_pipeline, bk.Pipeline_Handle(31))
475 + }