From d6d3c8915fb24db92afad01b931b1e5a3c6e22eb Mon Sep 17 00:00:00 2001 From: jacob Date: Thu, 8 Jan 2026 06:01:17 -0600 Subject: [PATCH] automatically split particle emitter uploads --- src/gpu/gpu_dx12/gpu_dx12_core.c | 2 +- src/pp/pp_sim/pp_sim_core.c | 196 ++++++++++++++----------------- src/pp/pp_sim/pp_sim_core.h | 6 +- src/pp/pp_vis/pp_vis_core.c | 179 +++++++++++++++------------- src/pp/pp_vis/pp_vis_core.h | 2 +- src/pp/pp_vis/pp_vis_gpu.g | 6 +- src/pp/pp_vis/pp_vis_shared.cgh | 6 +- 7 files changed, 201 insertions(+), 196 deletions(-) diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.c b/src/gpu/gpu_dx12/gpu_dx12_core.c index f196a070..eb327a08 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.c +++ b/src/gpu/gpu_dx12/gpu_dx12_core.c @@ -3329,7 +3329,7 @@ void G_D12_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame } else { - G_D12.free_releases.first = async->free_releases.first;; + G_D12.free_releases.first = async->free_releases.first; } G_D12.free_releases.last = async->free_releases.last; async->free_releases.first = 0; diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index 1416d03d..02c1c207 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -319,7 +319,7 @@ Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal) return result; } -S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep) +S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1) { S_CollisionResult result = Zi; TempArena scratch = BeginScratchNoConflict(); @@ -496,9 +496,8 @@ S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Ve ////////////////////////////// //- EPA + // Find dir from origin to closest edge Vec2 normal = Zi; - Vec2 sweep_dir = NormVec2(sweep); - b32 is_sweeping = !IsVec2Zero(sweep_dir); S_MenkowskiSimplex closest_feature = Zi; { S_MenkowskiPoint *proto = 0; @@ -522,61 +521,30 @@ S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Ve { ++epa_iterations; - // Find dir from origin to closest edge // FIXME: Winding order of ps & pe index S_MenkowskiPoint closest_a = Zi; S_MenkowskiPoint closest_b = Zi; u32 closest_b_index = 0; { - if (is_sweeping) + // Find edge segment on prototype closest to the origin + f32 closest_len_sq = Inf; + for (u32 i = 0; i < proto_count; ++i) { - // Find edge segment on prototype furthest along the sweep direction - // FIXME: This is not very stable at the moment, needs refining - for (u32 i = 0; i < proto_count; ++i) + u32 a_index = i; + u32 b_index = (i < proto_count - 1) ? (i + 1) : 0; + S_MenkowskiPoint a = proto[a_index]; + S_MenkowskiPoint b = proto[b_index]; + Vec2 vab = SubVec2(b.p, a.p); + Vec2 vao = NegVec2(a.p); + f32 proj_ratio = ClampF32(DotVec2(vao, vab) / Vec2LenSq(vab), 0, 1); + Vec2 proj = AddVec2(a.p, MulVec2(vab, proj_ratio)); + f32 proj_len_sq = Vec2LenSq(proj); + if (proj_len_sq < closest_len_sq - min_unique_pt_dist_sq) { - u32 a_index = i; - u32 b_index = (i < proto_count - 1) ? (i + 1) : 0; - S_MenkowskiPoint a = proto[a_index]; - S_MenkowskiPoint b = proto[b_index]; - Vec2 vab = SubVec2(b.p, a.p); - if (WedgeVec2(vab, sweep_dir) * winding > 0) - { - f32 wedge_a = WedgeVec2(sweep_dir, a.p); - f32 wedge_b = WedgeVec2(sweep_dir, b.p); - i32 wedge_sign_a = (wedge_a >= 0) - (wedge_a < 0); - i32 wedge_sign_b = (wedge_b >= 0) - (wedge_b < 0); - if (wedge_sign_a != wedge_sign_b) - { - closest_a = a; - closest_b = b; - closest_b_index = b_index; - break; - } - } - } - } - else - { - // Find edge segment on prototype closest to the origin - f32 closest_len_sq = Inf; - for (u32 i = 0; i < proto_count; ++i) - { - u32 a_index = i; - u32 b_index = (i < proto_count - 1) ? (i + 1) : 0; - S_MenkowskiPoint a = proto[a_index]; - S_MenkowskiPoint b = proto[b_index]; - Vec2 vab = SubVec2(b.p, a.p); - Vec2 vao = NegVec2(a.p); - f32 proj_ratio = ClampF32(DotVec2(vao, vab) / Vec2LenSq(vab), 0, 1); - Vec2 proj = AddVec2(a.p, MulVec2(vab, proj_ratio)); - f32 proj_len_sq = Vec2LenSq(proj); - if (proj_len_sq < closest_len_sq - min_unique_pt_dist_sq) - { - closest_a = a; - closest_b = b; - closest_b_index = b_index; - closest_len_sq = proj_len_sq; - } + closest_a = a; + closest_b = b; + closest_b_index = b_index; + closest_len_sq = proj_len_sq; } } } @@ -1090,9 +1058,16 @@ S_RaycastResult S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir) return result; } - - - +Vec2 S_EdgePointFromShape(S_Shape shape, Vec2 dir) +{ + Vec2 result = shape.centroid; + S_RaycastResult raycast = S_RaycastShape(shape, shape.centroid, NegVec2(dir)); + if (raycast.is_intersecting) + { + result = raycast.p; + } + return result; +} //////////////////////////////////////////////////////////// //~ Lookup helpers @@ -1627,18 +1602,56 @@ void S_TickForever(WaveLaneCtx *lane) { if (firer->fire_held) { - Xform firer_xf = firer->xf; - S_Shape firer_world_shape = S_MulXformShape(firer_xf, firer->local_shape); + // i64 fire_delta_ns = world->time_ns - firer->last_fire_ns; - S_Ent *bullet = S_PushTempEnt(frame_arena, &bullets_to_spawn); - bullet->is_bullet = 1; - bullet->key = S_RandKey(); + // i64 single_bullet_delta_ns = NsFromSeconds(1) / firer->fire_rate; - f32 speed = 40 * sim_dt; + // i64 tick_bullets_count = sim_dt * firer->fire_rate; - bullet->bullet_start = firer_world_shape.centroid; - bullet->bullet_end = AddVec2(bullet->bullet_start, MulVec2(NormVec2(firer->look), speed)); - bullet->bullet_firer = firer->key; + f32 fire_rate = 50; + f32 bullets_per_fire = 3; + f32 spread = Tau * 0.05; + // f32 spread = Tau * 0.01; + f32 tweak_speed = TweakFloat("Bullet speed", 100, 1, 100); + + b32 can_fire = (firer->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= world->time_ns; + if (can_fire) + { + i64 tick_bullets_count = bullets_per_fire; + if (tick_bullets_count > 0) + { + Xform firer_xf = firer->xf; + S_Shape firer_world_shape = S_MulXformShape(firer_xf, firer->local_shape); + + Vec2 pos = S_EdgePointFromShape(firer_world_shape, firer->look); + + for (i64 bullet_idx = 0; bullet_idx < tick_bullets_count; ++bullet_idx) + { + S_Ent *bullet = S_PushTempEnt(frame_arena, &bullets_to_spawn); + bullet->is_bullet = 1; + bullet->key = S_RandKey(); + + + // FIXME: Remove this + PERSIST RandState rand = Zi; + f32 rand_speed = RandF64FromState(&rand, -0.5, 0.5); + f32 rand_angle = RandF64FromState(&rand, -0.5, 0.5); + + f32 speed = tweak_speed * sim_dt; + f32 angle = AngleFromVec2(firer->look); + + speed += (speed * 0.5) * rand_speed; + angle += rand_angle * spread; + + Vec2 dir = Vec2FromAngle(angle); + + bullet->bullet_start = pos; + bullet->bullet_end = AddVec2(bullet->bullet_start, MulVec2(dir, speed)); + bullet->bullet_firer = firer->key; + } + } + firer->last_fire_ns = world->time_ns; + } } } S_SpawnEntsFromList(world_arena, world, bullets_to_spawn); @@ -1673,19 +1686,22 @@ void S_TickForever(WaveLaneCtx *lane) Xform victim_xf = victim->xf; S_Shape victim_world_shape = S_MulXformShape(victim_xf, victim->local_shape); - S_RaycastResult raycast = S_RaycastShape(victim_world_shape, ray_start, ray_dir); - if (raycast.is_intersecting) + S_RaycastResult entrance_raycast = S_RaycastShape(victim_world_shape, ray_start, ray_dir); + Vec2 entrance = entrance_raycast.p; + if (entrance_raycast.is_intersecting) { - Vec2 hit = raycast.p; - Vec2 dir_to_hit = SubVec2(hit, ray_start); - if (DotVec2(ray_dir, dir_to_hit) <= 0 || Vec2LenSq(dir_to_hit) <= Vec2LenSq(ray_dir)) + S_RaycastResult exit_raycast = S_RaycastShape(victim_world_shape, ray_start, NegVec2(ray_dir)); + Vec2 exit = exit_raycast.p; + f32 da = DotVec2(ray_dir, SubVec2(entrance, ray_start)); + f32 db = DotVec2(ray_dir, SubVec2(exit, ray_start)); + if (db > 0 && (da <= Vec2LenSq(ray_dir) || da <= 0)) { - f32 len_sq = Vec2LenSq(SubVec2(raycast.p, ray_start)); + f32 len_sq = Vec2LenSq(SubVec2(entrance_raycast.p, ray_start)); if (len_sq < closest_len_sq) { closest_len_sq = len_sq; closest_victim = victim; - victim_raycast = raycast; + victim_raycast = entrance_raycast; } } } @@ -1839,46 +1855,6 @@ void S_TickForever(WaveLaneCtx *lane) - - ////////////////////////////// - //- Raycast testing - - // FIXME: Remove this - - - { - S_Ent *player = &S_NilEnt; - for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent)) - { - if (ent->is_player) - { - player = ent; - break; - } - } - - PERSIST Vec2 start = { 5, 1 }; - PERSIST Vec2 end = { 4, -1 }; - - Vec2 dir = SubVec2(end, start); - - Xform xf = player->xf; - S_Shape world_shape = S_MulXformShape(xf, player->local_shape); - - S_RaycastResult raycast = S_RaycastShape(world_shape, start, dir); - - S_DebugDrawPoint(raycast.p, Color_Blue); - S_DebugDrawLine(raycast.p, AddVec2(raycast.p, raycast.normal), Color_White); - } - - - - - - - - - ////////////////////////////// //- Debug draw entities diff --git a/src/pp/pp_sim/pp_sim_core.h b/src/pp/pp_sim/pp_sim_core.h index dd8a0023..85d98667 100644 --- a/src/pp/pp_sim/pp_sim_core.h +++ b/src/pp/pp_sim/pp_sim_core.h @@ -72,6 +72,8 @@ Struct(S_Ent) Vec2 look; f32 fire_held; + // TODO: Remove this (weapon testing) + i64 last_fire_ns; b32 has_weapon; S_Key bullet_firer; @@ -399,9 +401,11 @@ S_MenkowskiPoint S_MenkowskiPointFromShapes(S_Shape shape0, S_Shape shape1, Vec2 S_ClippedLine S_ClipLineToLine(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1, Vec2 normal); Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal); -S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep); +S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1); S_RaycastResult S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir); +Vec2 S_EdgePointFromShape(S_Shape shape, Vec2 dir); + //////////////////////////////////////////////////////////// //~ Lookup helpers diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 2f9564c1..32053202 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -72,18 +72,31 @@ String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey) return StringFromList(arena, parts, Lit(" + ")); } -V_Emitter *V_PushEmitter(u32 particle_count) +void V_PushParticles(V_Emitter src) { - particle_count = MinU32(particle_count, Mebi(1)); V_Frame *frame = V_CurrentFrame(); - V_EmitterNode *en = PushStruct(frame->arena, V_EmitterNode); - SllQueuePush(frame->first_emitter_node, frame->last_emitter_node, en); - frame->emitters_count += 1; - V_Emitter *emitter = &en->emitter; - emitter->count = particle_count; - emitter->first_particle_seq = V.particle_seq; - V.particle_seq += emitter->count; - return emitter; + i64 split_threshold = 256; // Arbitrary threshold. Lower counts cause less shader work but more cpu -> gpu upload bandwidth. + src.count = MinU64(src.count, V_MaxParticles); + if (src.seed == 0) + { + src.seed = RandU64FromState(&frame->rand); + } + i64 remaining_particles = src.count; + while (remaining_particles > 0) + { + V_Emitter *emitter = 0; + { + V_EmitterNode *en = PushStruct(frame->arena, V_EmitterNode); + SllQueuePush(frame->first_emitter_node, frame->last_emitter_node, en); + frame->emitters_count += 1; + emitter = &en->emitter; + } + *emitter = src; + emitter->count = MinI64(remaining_particles, split_threshold); + emitter->first_particle_seq = V.particle_seq; + V.particle_seq += emitter->count; + remaining_particles -= split_threshold; + } } //////////////////////////////////////////////////////////// @@ -335,11 +348,6 @@ void V_TickForever(WaveLaneCtx *lane) Vec2I32 tiles_dims = VEC2I32(S_TilesPitch, S_TilesPitch); Vec2I32 cells_dims = VEC2I32(V_CellsPerMeter * S_WorldPitch, V_CellsPerMeter * S_WorldPitch); - // u32 max_particles = Kibi(128); - // u32 max_particles = Mebi(1); - u32 max_particles = Mebi(2); - // u32 max_particles = Mebi(16); - // Init gpu state G_ResourceHandle gpu_state = Zi; G_ResourceHandle gpu_tiles = Zi; @@ -380,7 +388,7 @@ void V_TickForever(WaveLaneCtx *lane) gpu_particles = G_PushBuffer( gpu_perm, cl, V_Particle, - max_particles, + V_MaxParticles, .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite ); gpu_particles_ref = G_PushRWStructuredBufferRef(gpu_perm, gpu_particles, V_Particle); @@ -986,7 +994,7 @@ void V_TickForever(WaveLaneCtx *lane) for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent)) { S_Shape ent_shape = S_MulXformShape(ent->xf, ent->local_shape); - b32 is_hovered = S_CollisionResultFromShapes(ent_shape, cursor_shape, VEC2(0, 0)).collision_points_count > 0; + b32 is_hovered = S_CollisionResultFromShapes(ent_shape, cursor_shape).collision_points_count > 0; if (is_hovered) { hovered_ent = ent; @@ -2648,39 +2656,46 @@ void V_TickForever(WaveLaneCtx *lane) f32 angle = AngleFromVec2(PerpVec2(SubVec2(end, start))); // f32 angle = AngleFromVec2(NegVec2(SubVec2(end, start))); - V_Emitter *emitter = V_PushEmitter(particles_count); + V_Emitter emitter = Zi; + { + // emitter.flags |= V_ParticleFlag_StainOnPrune; + // emitter.flags |= V_ParticleFlag_StainTrail; - // emitter->flags |= V_ParticleFlag_StainOnPrune; - // emitter->flags |= V_ParticleFlag_StainTrail; + // emitter.lifetime = 1; + // emitter.lifetime_spread = 2; - // emitter->lifetime = 1; - // emitter->lifetime_spread = 2; + emitter.count = particles_count; - emitter->lifetime = 0.15; - // emitter->lifetime = 0.04; - emitter->lifetime_spread = emitter->lifetime * 2; + // emitter.lifetime = 1; + // emitter.lifetime = 0.15; + emitter.lifetime = 0.075; + // emitter.lifetime = 0.05; + // emitter.lifetime = 0.04; + emitter.lifetime_spread = emitter.lifetime * 2; - emitter->angle = angle; - // emitter->angle_spread = Tau / 4; - emitter->angle_spread = Tau / 4; + emitter.angle = angle; + // emitter.angle_spread = Tau / 4; + emitter.angle_spread = Tau / 4; - emitter->start = start; - emitter->end = end; + emitter.start = start; + emitter.end = end; - // emitter->color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); - // emitter->color_lin = LinearFromSrgb(VEC4(0.8, 0.8, 0.8, 0.25)); - emitter->color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); - // emitter->color_spread = LinearFromSrgb(VEC4(0, 0, 0, 0.2)); + // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.8, 0.8, 0.25)); + emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + // emitter.color_spread = LinearFromSrgb(VEC4(0, 0, 0, 0.2)); - emitter->speed = 0; - emitter->speed_spread = 1; + emitter.speed = 0; + emitter.speed_spread = 1; - // emitter->speed = 1; - // emitter->speed_spread = 1; + // emitter.speed = 1; + // emitter.speed_spread = 1; - // emitter->velocity_falloff = 1; - // emitter->velocity_falloff_spread = 0; + // emitter.velocity_falloff = 1; + // emitter.velocity_falloff_spread = 0; + } + V_PushParticles(emitter); } @@ -2814,35 +2829,40 @@ void V_TickForever(WaveLaneCtx *lane) f32 falloff = TweakFloat("Emitter falloff", 50, 0, 100); f32 angle_spread = TweakFloat("Emitter angle spread", 0.1, 0, 1) * Tau; - V_Emitter *emitter = V_PushEmitter(count); - emitter->flags = flags; + V_Emitter emitter = Zi; + { + emitter.count = count; + emitter.flags = flags; - // Vec2 dir = hit_entry_normal; - Vec2 dir = NormVec2(NegVec2(bullet_vel)); + // Vec2 dir = hit_entry_normal; + Vec2 dir = NormVec2(NegVec2(bullet_vel)); - emitter->start = hit_entry; - emitter->end = emitter->start; + emitter.start = hit_entry; + emitter.end = emitter.start; - emitter->speed = speed; - emitter->speed_spread = speed * 2; + emitter.speed = speed; + emitter.speed_spread = speed * 2; - emitter->velocity_falloff = falloff; - emitter->velocity_falloff_spread = falloff * 1.5; + emitter.velocity_falloff = falloff; + emitter.velocity_falloff_spread = falloff * 1.5; - emitter->angle = AngleFromVec2(dir); - // emitter->angle_spread = Tau / 4; - emitter->angle_spread = angle_spread; - // emitter->angle_spread = Tau / 32; + emitter.angle = AngleFromVec2(dir); + // emitter.angle_spread = Tau / 4; + emitter.angle_spread = angle_spread; + // emitter.angle_spread = Tau / 32; - emitter->color_lin = LinearFromSrgb(VEC4(0.5, 0.1, 0.1, 1)); - emitter->color_spread = VEC4(0.1, 0, 0, 0); + // emitter.color_lin = LinearFromSrgb(VEC4(0.5, 0.1, 0.1, 1)); + emitter.color_lin = LinearFromSrgb(VEC4(0.5, 0.1, 0.1, 1)); - // emitter->color = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1)); + emitter.color_spread = VEC4(0.1, 0, 0, 0); - emitter->seed = RandU64FromState(&frame->rand); - // emitter->angle_spread = 1; - // emitter->angle_spread = 0.5; - // emitter->angle_spread = Tau; + // emitter.color = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1)); + + // emitter.angle_spread = 1; + // emitter.angle_spread = 0.5; + // emitter.angle_spread = Tau; + } + V_PushParticles(emitter); // V_DrawPoint(victim_raycast.p, Color_Green); // V_DrawLine(victim_raycast.p, AddVec2(victim_raycast.p, MulVec2(victim_raycast.normal, 0.5)), Color_White); @@ -2957,24 +2977,26 @@ void V_TickForever(WaveLaneCtx *lane) if (frame->held_buttons[Button_F]) { - V_Emitter *emitter = V_PushEmitter(25);; + V_Emitter emitter = Zi; Vec2 dir = frame->look; - emitter->start = frame->world_cursor; - emitter->end = emitter->start; - emitter->angle = AngleFromVec2(dir); + emitter.start = frame->world_cursor; + emitter.end = emitter.start; + emitter.angle = AngleFromVec2(dir); - // emitter->count = 100; - emitter->speed = 10; + emitter.count = 128; + // emitter.count = 100; + emitter.speed = 10; - emitter->color_lin = LinearFromSrgb(Color_Yellow); + emitter.color_lin = LinearFromSrgb(Color_Yellow); - emitter->seed = RandU64FromState(&frame->rand); - emitter->speed_spread = 1; - // emitter->angle_spread = 1; - // emitter->angle_spread = 0.5; - emitter->angle_spread = Tau / 4; - // emitter->angle_spread = Tau; + emitter.speed_spread = 1; + // emitter.angle_spread = 1; + // emitter.angle_spread = 0.5; + emitter.angle_spread = Tau / 4; + // emitter.angle_spread = Tau; + + V_PushParticles(emitter); } ////////////////////////////// @@ -3064,8 +3086,8 @@ void V_TickForever(WaveLaneCtx *lane) case S_DebugDrawKind_Shape: { S_Shape ui_shape = S_MulXformShape(frame->xf.world_to_ui, desc->shape); - V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line); - // V_DrawShape(ui_shape, color, detail, V_DrawFlag_None); + // V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line); + V_DrawShape(ui_shape, color, detail, V_DrawFlag_None); } break; } } @@ -3144,7 +3166,6 @@ void V_TickForever(WaveLaneCtx *lane) params.emitters_count = frame->emitters_count; params.emitters = gpu_emitters_ref; - params.max_particles = max_particles; params.particles = gpu_particles_ref; params.should_clear_stains = should_clear_particles; @@ -3185,7 +3206,7 @@ void V_TickForever(WaveLaneCtx *lane) // Clear particles if (should_clear_particles) { - G_Compute(frame->cl, V_ClearParticlesCS, V_ThreadGroupSizeFromBufferSize(max_particles)); + G_Compute(frame->cl, V_ClearParticlesCS, V_ThreadGroupSizeFromBufferSize(V_MaxParticles)); } // Discard render target @@ -3205,7 +3226,7 @@ void V_TickForever(WaveLaneCtx *lane) G_DumbMemorySync(frame->cl, gpu_particles); // Simulate particles - G_Compute(frame->cl, V_SimParticlesCS, V_ThreadGroupSizeFromBufferSize(max_particles)); + G_Compute(frame->cl, V_SimParticlesCS, V_ThreadGroupSizeFromBufferSize(V_MaxParticles)); // Barrier since stains were written G_DumbGlobalMemorySync(frame->cl); diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 915f9c80..019cca77 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -315,7 +315,7 @@ V_Frame *V_LastFrame(void); V_Cmd *V_PushVisCmd(String name); S_Cmd *V_PushSimCmd(S_CmdKind kind); String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey); -V_Emitter *V_PushEmitter(u32 particle_count); +void V_PushParticles(V_Emitter src); //////////////////////////////////////////////////////////// //~ Draw helpers diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 61b67be4..b07275a6 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -24,7 +24,7 @@ ComputeShader(V_ClearParticlesCS, 64) V_GpuParams params = G_Dereference(V_ShaderConst_Params)[0]; RWStructuredBuffer particles = G_Dereference(params.particles); u32 particle_idx = SV_DispatchThreadID; - if (particle_idx < params.max_particles) + if (particle_idx < V_MaxParticles) { particles[particle_idx].exists = 0; } @@ -299,7 +299,7 @@ ComputeShader(V_EmitParticlesCS, 64) for (u32 i = 0; i < emitter.count; ++i) { u32 particle_seq = emitter.first_particle_seq + i; - u32 particle_idx = particle_seq % params.max_particles; + u32 particle_idx = particle_seq % (u32)V_MaxParticles; particles[particle_idx].exists = 1; particles[particle_idx].emitter_init_num = emitter_idx + 1; particles[particle_idx].seq = particle_seq; @@ -318,7 +318,7 @@ ComputeShader(V_SimParticlesCS, 64) RWTexture2D stains = G_Dereference(params.stains); u32 particle_idx = SV_DispatchThreadID; - if (particle_idx < params.max_particles) + if (particle_idx < V_MaxParticles) { V_Particle particle = particles[particle_idx]; if (particle.exists > 0) diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index 673a2bb5..c951607e 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -1,6 +1,11 @@ #define V_CellsPerMeter 40.0 #define V_CellsPerSqMeter (V_CellsPerMeter * V_CellsPerMeter) +// #define V_MaxParticles Kibi(128) +// #define V_MaxParticles Mebi(1) +#define V_MaxParticles Mebi(2) +// #define V_MaxParticles Mebi(16) + //////////////////////////////////////////////////////////// //~ Constant types @@ -73,7 +78,6 @@ Struct(V_GpuParams) u32 emitters_count; G_StructuredBufferRef emitters; - u32 max_particles; G_RWStructuredBufferRef particles; b32 should_clear_stains;