Harbor

Changelog 5077ac31d71a

dispatch proof executor

@sky · 1 month ago · parent f35fa16a57a3
1 added 4 modified 0 deleted
backend/vulkan/vk_backend.odin +3 -2 modified
3 unchanged lines hidden
4 4 import gpu "../../core"
5 5 import "../../pipeline"
6 6 import "core:log"
7 + import "core:os"
7 8 import vk "vendor:vulkan"
8 9
9 10 // --- Global Vulkan state ---
124 unchanged lines hidden
134 135 }
135 136 g_vk = state
136 137
137 - // Create Vulkan instance
138 - inst, inst_ok := gpu.create_instance(title, true)
138 + enable_validation := os.get_env("GPU_VK_VALIDATION", context.temp_allocator) != "0"
139 + inst, inst_ok := gpu.create_instance(title, enable_validation)
139 140 if !inst_ok {
140 141 log.error("gpu/vk: failed to create Vulkan instance")
141 142 free(state)
405 unchanged lines hidden
compiler/executor.odin modified

Diff hidden because this file has more than 800 lines.

examples/parity_stencil_clip/main.odin +226 -0 added
1 + package main
2 +
3 + import "core:fmt"
4 + import "core:mem"
5 + import "core:os"
6 +
7 + import bk "../../backend"
8 + import compiler "../../compiler"
9 + import app "../../app"
10 + import gpu "../.."
11 + import ir "../../render_ir"
12 + import resource "../../resource"
13 +
14 + WIDTH :: u32(256)
15 + HEIGHT :: u32(256)
16 +
17 + VERTEX_SHADER :: `
18 + vertex main
19 + in position: vec3 @location(0)
20 + in normal: vec3 @location(1)
21 + in uv: vec2 @location(2)
22 + out position: vec4 @builtin(position)
23 + do
24 + position = vec4(position.x, position.y, 0.0, 1.0)
25 + end
26 + `
27 +
28 + FRAGMENT_SHADER :: `
29 + fragment main
30 + out color: vec4
31 + do
32 + color = vec4(240.0 / 255.0, 48.0 / 255.0, 96.0 / 255.0, 1.0)
33 + end
34 + `
35 +
36 + quad_vertices :: proc(x0, y0, x1, y1: f32) -> [6]resource.Mesh_Vertex_PNU {
37 + n := [3]f32{0, 0, 1}
38 + return {
39 + {position = {x0, y0, 0}, normal = n, tex_coord = {0, 0}},
40 + {position = {x1, y0, 0}, normal = n, tex_coord = {1, 0}},
41 + {position = {x1, y1, 0}, normal = n, tex_coord = {1, 1}},
42 + {position = {x0, y0, 0}, normal = n, tex_coord = {0, 0}},
43 + {position = {x1, y1, 0}, normal = n, tex_coord = {1, 1}},
44 + {position = {x0, y1, 0}, normal = n, tex_coord = {0, 1}},
45 + }
46 + }
47 +
48 + write_vertices :: proc(backend: ^bk.Backend, buffer: bk.Buffer_Handle, vertices: []resource.Mesh_Vertex_PNU) -> bool {
49 + ptr := backend.map_buffer(buffer)
50 + if ptr == nil {
51 + return false
52 + }
53 + defer backend.unmap_buffer(buffer)
54 + mem.copy(ptr, raw_data(vertices), len(vertices) * size_of(resource.Mesh_Vertex_PNU))
55 + return true
56 + }
57 +
58 + write_ppm_rgba8 :: proc(path: string, rgba: []u8, width, height: u32) -> bool {
59 + if len(path) == 0 || len(rgba) < int(width * height * 4) {
60 + return false
61 + }
62 + header := "P6\n256 256\n255\n"
63 + out := make([]u8, len(header) + int(width * height * 3))
64 + defer delete(out)
65 + for i in 0..<len(header) {
66 + out[i] = header[i]
67 + }
68 + dst := len(header)
69 + for i in 0..<int(width * height) {
70 + out[dst + i * 3 + 0] = rgba[i * 4 + 0]
71 + out[dst + i * 3 + 1] = rgba[i * 4 + 1]
72 + out[dst + i * 3 + 2] = rgba[i * 4 + 2]
73 + }
74 + err := os.write_entire_file(path, out)
75 + return err == nil
76 + }
77 +
78 + fail :: proc(message: string) {
79 + fmt.println(message)
80 + os.exit(1)
81 + }
82 +
83 + make_frame :: proc(negative: bool) -> (
84 + frame: ir.Frame_IR,
85 + color: ir.Resource_Handle,
86 + geometry: ir.Resource_Handle,
87 + coverage: ir.Resource_Handle,
88 + ) {
89 + frame = ir.init_frame_ir()
90 + color = ir.add_texture(&frame, "proof-color", WIDTH, HEIGHT, .R8G8B8A8_UNORM, {.Color_Attachment, .Sampled}, .Transient)
91 + depth := ir.add_texture(&frame, "proof-depth-stencil", WIDTH, HEIGHT, .D24_UNORM_S8_UINT, {.Depth_Stencil_Attachment}, .Transient)
92 + geometry = ir.add_buffer(
93 + &frame,
94 + "foreground-geometry",
95 + u64(6 * size_of(resource.Mesh_Vertex_PNU)),
96 + {.Vertex},
97 + {.Host_Visible, .Host_Coherent},
98 + .Transient,
99 + )
100 + coverage = ir.add_buffer(
101 + &frame,
102 + "mask-coverage",
103 + u64(6 * size_of(resource.Mesh_Vertex_PNU)),
104 + {.Vertex},
105 + {.Host_Visible, .Host_Coherent},
106 + .Transient,
107 + )
108 + pass_desc := ir.Pass_Desc{kind = .Render, name = "stencil-proof"}
109 + _ = ir.pass_add_color_target(
110 + &pass_desc,
111 + ir.make_color_target(color, .R8G8B8A8_UNORM, .Clear, .Store, {16.0 / 255.0, 16.0 / 255.0, 24.0 / 255.0, 1}),
112 + )
113 + ir.pass_set_depth_target(&pass_desc, ir.make_depth_target(depth, .D24_UNORM_S8_UINT, .Clear, .Store, 1))
114 + ir.pass_set_viewport(&pass_desc, {x = 0, y = 0, width = f32(WIDTH), height = f32(HEIGHT), min_depth = 0, max_depth = 1})
115 + ir.pass_set_scissor(&pass_desc, {x = 0, y = 0, width = WIDTH, height = HEIGHT})
116 + pass := ir.add_pass(&frame, pass_desc)
117 + target := ir.add_target(
118 + &frame,
119 + {
120 + kind = .Offscreen,
121 + name = "stencil-proof-target",
122 + width = WIDTH,
123 + height = HEIGHT,
124 + pass = pass,
125 + color_format = .R8G8B8A8_UNORM,
126 + depth_format = .D24_UNORM_S8_UINT,
127 + color_resource = color,
128 + depth_resource = depth,
129 + clear_color = {16.0 / 255.0, 16.0 / 255.0, 24.0 / 255.0, 1},
130 + clear_depth = 1,
131 + },
132 + )
133 + vs := ir.add_shader_source(&frame, "parity_stencil_clip.vert", .Vertex, VERTEX_SHADER)
134 + fs := ir.add_shader_source(&frame, "parity_stencil_clip.frag", .Fragment, FRAGMENT_SHADER)
135 + state := ir.default_graphics_pipeline_state()
136 + state.vertex_shader = vs
137 + state.fragment_shader = fs
138 + state.enable_blending = false
139 + pipeline := ir.add_graphics_pipeline(&frame, "foreground", state)
140 + mask := ir.add_mask(
141 + &frame,
142 + {
143 + target = target,
144 + name = "center-mask",
145 + source_kind = .Geometry_Coverage,
146 + layout_variant = .PNU,
147 + coverage_resource = coverage,
148 + vertex_count = 6,
149 + },
150 + )
151 + clip := ir.INVALID_CLIP
152 + if !negative {
153 + clip = ir.add_clip(&frame, {target = target, kind = .Mask, mask = mask})
154 + }
155 + _ = ir.add_draw_packet(
156 + &frame,
157 + pass,
158 + pipeline,
159 + .Vertex_Stream,
160 + {
161 + target = target,
162 + clip = clip,
163 + geometry = {kind = .Vertex_Stream, resource = geometry, vertex_count = 6},
164 + order = .Strict,
165 + },
166 + )
167 + return
168 + }
169 +
170 + main :: proc() {
171 + state, ok := app.init_window(i32(WIDTH), i32(HEIGHT), "GPU parity stencil clip")
172 + if !ok {
173 + fail("parity_stencil_clip: failed to initialize window/backend")
174 + }
175 + defer app.shutdown(&state)
176 +
177 + backend := gpu.get_backend()
178 + if backend == nil || backend.read_texture_rgba8 == nil {
179 + fail("parity_stencil_clip: backend readback unsupported")
180 + }
181 + backend.capabilities.features += {.Stencil_Clips}
182 +
183 + mode := os.get_env("GPU_PROOF_MODE", context.allocator)
184 + readback_path := os.get_env("GPU_PROOF_READBACK", context.allocator)
185 + profile_path := os.get_env("GPU_PROFILE_JSON", context.allocator)
186 + negative := mode == "negative"
187 +
188 + frame, color, geometry, coverage := make_frame(negative)
189 + defer ir.destroy_frame_ir(&frame)
190 +
191 + exec := compiler.init_execution_state(backend)
192 + defer compiler.destroy_execution_state(&exec)
193 + if !compiler.prepare_planned_frame(&exec, &frame) {
194 + fail("parity_stencil_clip: failed to prepare planned frame")
195 + }
196 + foreground := quad_vertices(-1, -1, 1, 1)
197 + mask := quad_vertices(-0.5, -0.5, 0.5, 0.5)
198 + foreground_buffer, fg_ok := compiler.prepared_buffer(&exec, geometry)
199 + mask_buffer, mask_ok := compiler.prepared_buffer(&exec, coverage)
200 + if !fg_ok || !mask_ok {
201 + fail("parity_stencil_clip: failed to resolve prepared buffers")
202 + }
203 + if !write_vertices(backend, foreground_buffer, foreground[:]) ||
204 + !write_vertices(backend, mask_buffer, mask[:]) {
205 + fail("parity_stencil_clip: failed to upload vertices")
206 + }
207 + if !compiler.execute_prepared_planned_frame(&exec, &frame, {0, 0, 0, 1}) {
208 + fail("parity_stencil_clip: failed to execute planned frame")
209 + }
210 +
211 + texture, tex_ok := compiler.prepared_texture(&exec, color)
212 + if !tex_ok {
213 + fail("parity_stencil_clip: failed to resolve readback target")
214 + }
215 + rgba := make([]u8, int(WIDTH * HEIGHT * 4))
216 + defer delete(rgba)
217 + if !backend.read_texture_rgba8({texture = texture, width = WIDTH, height = HEIGHT, current_layout = .Shader_Read_Only}, rgba) {
218 + fail("parity_stencil_clip: readback failed")
219 + }
220 + if !write_ppm_rgba8(readback_path, rgba, WIDTH, HEIGHT) {
221 + fail("parity_stencil_clip: failed to write readback")
222 + }
223 + if len(profile_path) > 0 {
224 + _ = gpu.write_profile(profile_path, 0, 1)
225 + }
226 + }
tests/compiler_executor_test.odin modified

Diff hidden because this file has more than 800 lines.

tools/test.lua +1 -0 modified
209 unchanged lines hidden
210 210 if opts.proof_mode then env.GPU_PROOF_MODE = opts.proof_mode end
211 211 if opts.proof_backend then env.GPU_PROOF_BACKEND = opts.proof_backend end
212 212 if opts.proof_scene then env.GPU_PROOF_SCENE = opts.proof_scene end
213 + if os.getenv("GPU_VK_VALIDATION") then env.GPU_VK_VALIDATION = os.getenv("GPU_VK_VALIDATION") end
213 214 if opts.seconds then env.GPU_TEST_SECONDS = opts.seconds end
214 215 if opts.frames then env.GPU_TEST_FRAMES = opts.frames end
215 216 if opts.screenshot then
202 unchanged lines hidden