From: Brendan Hansen Date: Wed, 20 Oct 2021 04:09:12 +0000 (-0500) Subject: multi-threaded X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=ebb6edca902bdcde829ead0b98de325fadfbc654;p=onyx-particle-sim.git multi-threaded --- diff --git a/src/physics.onyx b/src/physics.onyx index 855ae0c..b59c512 100644 --- a/src/physics.onyx +++ b/src/physics.onyx @@ -53,7 +53,7 @@ body_accumulate_move :: (body: ^Body, qt_bodies: ^QuadTree(^Body), dt: f32) { force := V2f.{0,0}; #persist #thread_local other_bodies: [..] ^Body; - if other_bodies.data == null do array.init(^other_bodies); + if other_bodies.capacity == 0 do array.init(^other_bodies, 128); array.clear(^other_bodies); qt_bodies->query(AABB.{ body.pos.x - 300, body.pos.y - 300, 600, 600 }, ^other_bodies); diff --git a/src/quadtree.onyx b/src/quadtree.onyx index b49f001..abc5b96 100644 --- a/src/quadtree.onyx +++ b/src/quadtree.onyx @@ -1,5 +1,7 @@ #private_file array :: package core.array +use package core.intrinsics.onyx + AABB :: struct { x, y : f32; w, h : f32; @@ -38,7 +40,7 @@ QuadTree :: struct (T: type_expr) { sw = null; point_count = 0; - for i: POINTS_PER_NODE do points[i] = null; + for i: POINTS_PER_NODE do points[i] = __zero_value(T); } subdivide :: (use q: ^QuadTree($T), a: Allocator) { diff --git a/src/settings.onyx b/src/settings.onyx index e3d3bd1..6f26131 100644 --- a/src/settings.onyx +++ b/src/settings.onyx @@ -48,7 +48,7 @@ generate_random_settings :: (settings: ^Sim_Settings) { settings.near_repulsive_force = 100; settings.universe_scale = 20; - settings.thread_count = 4; + settings.thread_count = 1; memory.alloc_slice(^settings.body_relations, num_body_types * num_body_types); for i: num_body_types { diff --git a/src/sim.onyx b/src/sim.onyx index a450d00..7c504f7 100644 --- a/src/sim.onyx +++ b/src/sim.onyx @@ -24,9 +24,25 @@ Sim_State :: struct { qt_pool_buffer : [] QuadTree(^Body); qt_pool_allocator : alloc.pool.PoolAllocator(QuadTree(^Body)); qt_body_allocator : Allocator; + + thread_data : [] Thread_Data; + threads : [] thread.Thread; +} + +Thread_Data :: struct { + id : i32; + state: ^Sim_State; } -#thread_local state: Sim_State; +body_program : gl.GLProgram; +body_buffer : gl.GLBuffer; +circle_mesh : gl.GLVertexArrayObject; +thread_sync_barrier : sync.Barrier; +frame_sync_sema : sync.Semaphore; +global_dt := 0.016f; +keys: Set(i32); + +#thread_local state: ^Sim_State; sim_state_init :: (state: ^Sim_State) { array.init(^state.bodies); @@ -51,11 +67,20 @@ sim_state_init :: (state: ^Sim_State) { state.qt_body_allocator = alloc.pool.make_allocator(^state.qt_pool_allocator); state.qt_bodies->init(AABB.{ -2000, -2000, 4000, 4000 }); -} -body_program : gl.GLProgram; -body_buffer : gl.GLBuffer; -circle_mesh : gl.GLVertexArrayObject; + keys->init(); + + sync.barrier_init(^thread_sync_barrier, global_settings.thread_count); + sync.semaphore_init(^frame_sync_sema, 0); + + memory.alloc_slice(^state.threads, global_settings.thread_count); + memory.alloc_slice(^state.thread_data, global_settings.thread_count); + + for i: global_settings.thread_count { + state.thread_data[i] = .{ i, state }; + thread.spawn(^state.threads[i], ^state.thread_data[i], thread_processing); + } +} create_circle_mesh :: () -> gl.GLVertexArrayObject { vao := gl.createVertexArray(); @@ -87,17 +112,16 @@ create_circle_mesh :: () -> gl.GLVertexArrayObject { return vao; } +paused := false; handle_event :: (ev) => { switch ev.kind { case .KeyDown { - switch ev.keyboard.keycode { - case 38 do state.camera.offset.y -= 6; - case 40 do state.camera.offset.y += 6; - case 39 do state.camera.offset.x += 6; - case 37 do state.camera.offset.x -= 6; - case 65 do state.camera.scale /= 1.02; - case 81 do state.camera.scale *= 1.02; - } + keys->insert(ev.keyboard.keycode); + } + + case .KeyUp { + if ev.keyboard.keycode == #char "p" do paused = !paused; + keys->remove(ev.keyboard.keycode); } case .Resize { @@ -127,19 +151,44 @@ handle_event :: (ev) => { } update :: (dt: f32) { - state.qt_bodies->init(.{ -2000, -2000, 4000, 4000 }); - state.qt_pool_allocator = alloc.pool.make(state.qt_pool_buffer); + global_dt = dt; + + if keys->has(38) do state.camera.offset.y -= 6; + if keys->has(40) do state.camera.offset.y += 6; + if keys->has(39) do state.camera.offset.x += 6; + if keys->has(37) do state.camera.offset.x -= 6; + if keys->has(65) do state.camera.scale /= 1.02; + if keys->has(81) do state.camera.scale *= 1.02; +} - for ^it: state.bodies { - state.qt_bodies->insert(it, state.qt_body_allocator); - } +update_bodies_partial :: (index: i32) { + low := index * (global_settings.body_count / global_settings.thread_count); + high := (index + 1) * (global_settings.body_count / global_settings.thread_count); - for i: state.bodies.count { - body_accumulate_move(^state.bodies[i], ^state.qt_bodies, dt); - } + for i: low .. high do body_accumulate_move(^state.bodies[i], ^state.qt_bodies, global_dt); + sync.barrier_wait(^thread_sync_barrier); + for i: low .. high do body_apply_move(^state.bodies[i], global_dt); +} + +thread_processing :: (td: ^Thread_Data) { + thread_id := td.id; + state = td.state; - for i: state.bodies.count { - body_apply_move(^state.bodies[i], dt); + while true { + if thread_id == 0 { + state.qt_bodies->init(.{ -2000, -2000, 4000, 4000 }); + state.qt_pool_allocator = alloc.pool.make(state.qt_pool_buffer); + + for ^it: state.bodies { + state.qt_bodies->insert(it, state.qt_body_allocator); + } + } + + sync.barrier_wait(^thread_sync_barrier); + update_bodies_partial(thread_id); + sync.barrier_wait(^thread_sync_barrier); + + sync.semaphore_wait(^frame_sync_sema); } } @@ -166,6 +215,8 @@ draw :: () { gl.bindVertexArray(circle_mesh); gl.drawElementsInstanced(gl.TRIANGLE_FAN, 12, gl.UNSIGNED_BYTE, 0, state.bodies.count); gl.bindVertexArray(-1); + + sync.semaphore_post(^frame_sync_sema, 0 if paused else global_settings.thread_count); } main :: (args) => { @@ -184,7 +235,8 @@ main :: (args) => { planet_colors := cast(^f32) global_settings.body_color.data; gl.uniform3fv(planet_colors_loc, .{ ~~planet_colors, global_settings.body_type_count }); - sim_state_init(^state); + state = make(Sim_State); + sim_state_init(state); gl.bindVertexArray(circle_mesh); body_buffer = gl.createBuffer(); diff --git a/src/vecmath.onyx b/src/vecmath.onyx index 6b35887..e724ffe 100644 --- a/src/vecmath.onyx +++ b/src/vecmath.onyx @@ -7,21 +7,21 @@ V2f :: struct { x, y: f32; } -#operator+ (a, b: V2f) => V2f.{ a.x + b.x, a.y + b.y }; -#operator- (a, b: V2f) => V2f.{ a.x - b.x, a.y - b.y }; -#operator* (a: V2f, s: f32) => V2f.{ a.x * s, a.y * s }; +#operator+ macro (a, b: V2f) => V2f.{ a.x + b.x, a.y + b.y }; +#operator- macro (a, b: V2f) => V2f.{ a.x - b.x, a.y - b.y }; +#operator* macro (a: V2f, s: f32) => V2f.{ a.x * s, a.y * s }; -#operator+= (a: ^V2f, b: V2f) { +#operator+= macro (a: ^V2f, b: V2f) { a.x += b.x; a.y += b.y; } -#operator-= (a: ^V2f, b: V2f) { +#operator-= macro (a: ^V2f, b: V2f) { a.x -= b.x; a.y -= b.y; } -#operator*= (a: ^V2f, s: f32) { +#operator*= macro (a: ^V2f, s: f32) { a.x += s; a.y += s; }