Diff hidden because this file has more than 800 lines.
| … | 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 | ||
Diff hidden because this file has more than 800 lines.
| … | 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 | + | } | |