automatically split particle emitter uploads

This commit is contained in:
jacob 2026-01-08 06:01:17 -06:00
parent 52ecdf378b
commit d6d3c8915f
7 changed files with 201 additions and 196 deletions

View File

@ -3329,7 +3329,7 @@ void G_D12_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame
} }
else 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; G_D12.free_releases.last = async->free_releases.last;
async->free_releases.first = 0; async->free_releases.first = 0;

View File

@ -319,7 +319,7 @@ Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal)
return result; 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; S_CollisionResult result = Zi;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
@ -496,9 +496,8 @@ S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Ve
////////////////////////////// //////////////////////////////
//- EPA //- EPA
// Find dir from origin to closest edge
Vec2 normal = Zi; Vec2 normal = Zi;
Vec2 sweep_dir = NormVec2(sweep);
b32 is_sweeping = !IsVec2Zero(sweep_dir);
S_MenkowskiSimplex closest_feature = Zi; S_MenkowskiSimplex closest_feature = Zi;
{ {
S_MenkowskiPoint *proto = 0; S_MenkowskiPoint *proto = 0;
@ -522,40 +521,10 @@ S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Ve
{ {
++epa_iterations; ++epa_iterations;
// Find dir from origin to closest edge
// FIXME: Winding order of ps & pe index // FIXME: Winding order of ps & pe index
S_MenkowskiPoint closest_a = Zi; S_MenkowskiPoint closest_a = Zi;
S_MenkowskiPoint closest_b = Zi; S_MenkowskiPoint closest_b = Zi;
u32 closest_b_index = 0; u32 closest_b_index = 0;
{
if (is_sweeping)
{
// 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);
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 // Find edge segment on prototype closest to the origin
f32 closest_len_sq = Inf; f32 closest_len_sq = Inf;
@ -579,7 +548,6 @@ S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Ve
} }
} }
} }
}
Vec2 vab = SubVec2(closest_b.p, closest_a.p); Vec2 vab = SubVec2(closest_b.p, closest_a.p);
// Find new point in dir // Find new point in dir
@ -1090,9 +1058,16 @@ S_RaycastResult S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir)
return result; 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 //~ Lookup helpers
@ -1626,21 +1601,59 @@ void S_TickForever(WaveLaneCtx *lane)
for (S_Ent *firer = S_FirstEnt(world); firer->valid; firer = S_NextEnt(firer)) for (S_Ent *firer = S_FirstEnt(world); firer->valid; firer = S_NextEnt(firer))
{ {
if (firer->fire_held) if (firer->fire_held)
{
// i64 fire_delta_ns = world->time_ns - firer->last_fire_ns;
// i64 single_bullet_delta_ns = NsFromSeconds(1) / firer->fire_rate;
// i64 tick_bullets_count = sim_dt * firer->fire_rate;
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; Xform firer_xf = firer->xf;
S_Shape firer_world_shape = S_MulXformShape(firer_xf, firer->local_shape); 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); S_Ent *bullet = S_PushTempEnt(frame_arena, &bullets_to_spawn);
bullet->is_bullet = 1; bullet->is_bullet = 1;
bullet->key = S_RandKey(); bullet->key = S_RandKey();
f32 speed = 40 * sim_dt;
bullet->bullet_start = firer_world_shape.centroid; // FIXME: Remove this
bullet->bullet_end = AddVec2(bullet->bullet_start, MulVec2(NormVec2(firer->look), speed)); 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; bullet->bullet_firer = firer->key;
} }
} }
firer->last_fire_ns = world->time_ns;
}
}
}
S_SpawnEntsFromList(world_arena, world, bullets_to_spawn); S_SpawnEntsFromList(world_arena, world, bullets_to_spawn);
} }
@ -1673,19 +1686,22 @@ void S_TickForever(WaveLaneCtx *lane)
Xform victim_xf = victim->xf; Xform victim_xf = victim->xf;
S_Shape victim_world_shape = S_MulXformShape(victim_xf, victim->local_shape); S_Shape victim_world_shape = S_MulXformShape(victim_xf, victim->local_shape);
S_RaycastResult raycast = S_RaycastShape(victim_world_shape, ray_start, ray_dir); S_RaycastResult entrance_raycast = S_RaycastShape(victim_world_shape, ray_start, ray_dir);
if (raycast.is_intersecting) Vec2 entrance = entrance_raycast.p;
if (entrance_raycast.is_intersecting)
{ {
Vec2 hit = raycast.p; S_RaycastResult exit_raycast = S_RaycastShape(victim_world_shape, ray_start, NegVec2(ray_dir));
Vec2 dir_to_hit = SubVec2(hit, ray_start); Vec2 exit = exit_raycast.p;
if (DotVec2(ray_dir, dir_to_hit) <= 0 || Vec2LenSq(dir_to_hit) <= Vec2LenSq(ray_dir)) 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) if (len_sq < closest_len_sq)
{ {
closest_len_sq = len_sq; closest_len_sq = len_sq;
closest_victim = victim; 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 //- Debug draw entities

View File

@ -72,6 +72,8 @@ Struct(S_Ent)
Vec2 look; Vec2 look;
f32 fire_held; f32 fire_held;
// TODO: Remove this (weapon testing)
i64 last_fire_ns;
b32 has_weapon; b32 has_weapon;
S_Key bullet_firer; 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); 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); 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); S_RaycastResult S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir);
Vec2 S_EdgePointFromShape(S_Shape shape, Vec2 dir);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Lookup helpers //~ Lookup helpers

View File

@ -72,18 +72,31 @@ String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey)
return StringFromList(arena, parts, Lit(" + ")); 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_Frame *frame = V_CurrentFrame();
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); V_EmitterNode *en = PushStruct(frame->arena, V_EmitterNode);
SllQueuePush(frame->first_emitter_node, frame->last_emitter_node, en); SllQueuePush(frame->first_emitter_node, frame->last_emitter_node, en);
frame->emitters_count += 1; frame->emitters_count += 1;
V_Emitter *emitter = &en->emitter; emitter = &en->emitter;
emitter->count = particle_count; }
*emitter = src;
emitter->count = MinI64(remaining_particles, split_threshold);
emitter->first_particle_seq = V.particle_seq; emitter->first_particle_seq = V.particle_seq;
V.particle_seq += emitter->count; V.particle_seq += emitter->count;
return emitter; remaining_particles -= split_threshold;
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -335,11 +348,6 @@ void V_TickForever(WaveLaneCtx *lane)
Vec2I32 tiles_dims = VEC2I32(S_TilesPitch, S_TilesPitch); Vec2I32 tiles_dims = VEC2I32(S_TilesPitch, S_TilesPitch);
Vec2I32 cells_dims = VEC2I32(V_CellsPerMeter * S_WorldPitch, V_CellsPerMeter * S_WorldPitch); 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 // Init gpu state
G_ResourceHandle gpu_state = Zi; G_ResourceHandle gpu_state = Zi;
G_ResourceHandle gpu_tiles = Zi; G_ResourceHandle gpu_tiles = Zi;
@ -380,7 +388,7 @@ void V_TickForever(WaveLaneCtx *lane)
gpu_particles = G_PushBuffer( gpu_particles = G_PushBuffer(
gpu_perm, cl, gpu_perm, cl,
V_Particle, V_Particle,
max_particles, V_MaxParticles,
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite
); );
gpu_particles_ref = G_PushRWStructuredBufferRef(gpu_perm, gpu_particles, V_Particle); 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)) for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
{ {
S_Shape ent_shape = S_MulXformShape(ent->xf, ent->local_shape); 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) if (is_hovered)
{ {
hovered_ent = ent; hovered_ent = ent;
@ -2648,39 +2656,46 @@ void V_TickForever(WaveLaneCtx *lane)
f32 angle = AngleFromVec2(PerpVec2(SubVec2(end, start))); f32 angle = AngleFromVec2(PerpVec2(SubVec2(end, start)));
// f32 angle = AngleFromVec2(NegVec2(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.lifetime = 1;
// emitter->flags |= V_ParticleFlag_StainTrail; // emitter.lifetime_spread = 2;
// emitter->lifetime = 1; emitter.count = particles_count;
// emitter->lifetime_spread = 2;
emitter->lifetime = 0.15; // emitter.lifetime = 1;
// emitter->lifetime = 0.04; // emitter.lifetime = 0.15;
emitter->lifetime_spread = emitter->lifetime * 2; emitter.lifetime = 0.075;
// emitter.lifetime = 0.05;
// emitter.lifetime = 0.04;
emitter.lifetime_spread = emitter.lifetime * 2;
emitter->angle = angle; emitter.angle = angle;
// emitter->angle_spread = Tau / 4; // emitter.angle_spread = Tau / 4;
emitter->angle_spread = Tau / 4; emitter.angle_spread = Tau / 4;
emitter->start = start; emitter.start = start;
emitter->end = end; 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.8, 0.8, 0.25));
emitter->color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1));
// emitter->color_spread = LinearFromSrgb(VEC4(0, 0, 0, 0.2)); // emitter.color_spread = LinearFromSrgb(VEC4(0, 0, 0, 0.2));
emitter->speed = 0; emitter.speed = 0;
emitter->speed_spread = 1; emitter.speed_spread = 1;
// emitter->speed = 1; // emitter.speed = 1;
// emitter->speed_spread = 1; // emitter.speed_spread = 1;
// emitter->velocity_falloff = 1; // emitter.velocity_falloff = 1;
// emitter->velocity_falloff_spread = 0; // 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 falloff = TweakFloat("Emitter falloff", 50, 0, 100);
f32 angle_spread = TweakFloat("Emitter angle spread", 0.1, 0, 1) * Tau; f32 angle_spread = TweakFloat("Emitter angle spread", 0.1, 0, 1) * Tau;
V_Emitter *emitter = V_PushEmitter(count); V_Emitter emitter = Zi;
emitter->flags = flags; {
emitter.count = count;
emitter.flags = flags;
// Vec2 dir = hit_entry_normal; // Vec2 dir = hit_entry_normal;
Vec2 dir = NormVec2(NegVec2(bullet_vel)); Vec2 dir = NormVec2(NegVec2(bullet_vel));
emitter->start = hit_entry; emitter.start = hit_entry;
emitter->end = emitter->start; emitter.end = emitter.start;
emitter->speed = speed; emitter.speed = speed;
emitter->speed_spread = speed * 2; emitter.speed_spread = speed * 2;
emitter->velocity_falloff = falloff; emitter.velocity_falloff = falloff;
emitter->velocity_falloff_spread = falloff * 1.5; emitter.velocity_falloff_spread = falloff * 1.5;
emitter->angle = AngleFromVec2(dir); emitter.angle = AngleFromVec2(dir);
// emitter->angle_spread = Tau / 4; // emitter.angle_spread = Tau / 4;
emitter->angle_spread = angle_spread; emitter.angle_spread = angle_spread;
// emitter->angle_spread = Tau / 32; // emitter.angle_spread = Tau / 32;
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_spread = VEC4(0.1, 0, 0, 0); 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.color = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1));
// emitter->angle_spread = 1;
// emitter->angle_spread = 0.5; // emitter.angle_spread = 1;
// emitter->angle_spread = Tau; // emitter.angle_spread = 0.5;
// emitter.angle_spread = Tau;
}
V_PushParticles(emitter);
// V_DrawPoint(victim_raycast.p, Color_Green); // V_DrawPoint(victim_raycast.p, Color_Green);
// V_DrawLine(victim_raycast.p, AddVec2(victim_raycast.p, MulVec2(victim_raycast.normal, 0.5)), Color_White); // 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]) if (frame->held_buttons[Button_F])
{ {
V_Emitter *emitter = V_PushEmitter(25);; V_Emitter emitter = Zi;
Vec2 dir = frame->look; Vec2 dir = frame->look;
emitter->start = frame->world_cursor; emitter.start = frame->world_cursor;
emitter->end = emitter->start; emitter.end = emitter.start;
emitter->angle = AngleFromVec2(dir); emitter.angle = AngleFromVec2(dir);
// emitter->count = 100; emitter.count = 128;
emitter->speed = 10; // 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->speed_spread = 1; // emitter.angle_spread = 1;
// emitter->angle_spread = 1; // emitter.angle_spread = 0.5;
// emitter->angle_spread = 0.5; emitter.angle_spread = Tau / 4;
emitter->angle_spread = Tau / 4; // emitter.angle_spread = Tau;
// emitter->angle_spread = Tau;
V_PushParticles(emitter);
} }
////////////////////////////// //////////////////////////////
@ -3064,8 +3086,8 @@ void V_TickForever(WaveLaneCtx *lane)
case S_DebugDrawKind_Shape: case S_DebugDrawKind_Shape:
{ {
S_Shape ui_shape = S_MulXformShape(frame->xf.world_to_ui, desc->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_Line);
// V_DrawShape(ui_shape, color, detail, V_DrawFlag_None); V_DrawShape(ui_shape, color, detail, V_DrawFlag_None);
} break; } break;
} }
} }
@ -3144,7 +3166,6 @@ void V_TickForever(WaveLaneCtx *lane)
params.emitters_count = frame->emitters_count; params.emitters_count = frame->emitters_count;
params.emitters = gpu_emitters_ref; params.emitters = gpu_emitters_ref;
params.max_particles = max_particles;
params.particles = gpu_particles_ref; params.particles = gpu_particles_ref;
params.should_clear_stains = should_clear_particles; params.should_clear_stains = should_clear_particles;
@ -3185,7 +3206,7 @@ void V_TickForever(WaveLaneCtx *lane)
// Clear particles // Clear particles
if (should_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 // Discard render target
@ -3205,7 +3226,7 @@ void V_TickForever(WaveLaneCtx *lane)
G_DumbMemorySync(frame->cl, gpu_particles); G_DumbMemorySync(frame->cl, gpu_particles);
// Simulate 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 // Barrier since stains were written
G_DumbGlobalMemorySync(frame->cl); G_DumbGlobalMemorySync(frame->cl);

View File

@ -315,7 +315,7 @@ V_Frame *V_LastFrame(void);
V_Cmd *V_PushVisCmd(String name); V_Cmd *V_PushVisCmd(String name);
S_Cmd *V_PushSimCmd(S_CmdKind kind); S_Cmd *V_PushSimCmd(S_CmdKind kind);
String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey); String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey);
V_Emitter *V_PushEmitter(u32 particle_count); void V_PushParticles(V_Emitter src);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Draw helpers //~ Draw helpers

View File

@ -24,7 +24,7 @@ ComputeShader(V_ClearParticlesCS, 64)
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0]; V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(params.particles); RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(params.particles);
u32 particle_idx = SV_DispatchThreadID; u32 particle_idx = SV_DispatchThreadID;
if (particle_idx < params.max_particles) if (particle_idx < V_MaxParticles)
{ {
particles[particle_idx].exists = 0; particles[particle_idx].exists = 0;
} }
@ -299,7 +299,7 @@ ComputeShader(V_EmitParticlesCS, 64)
for (u32 i = 0; i < emitter.count; ++i) for (u32 i = 0; i < emitter.count; ++i)
{ {
u32 particle_seq = emitter.first_particle_seq + 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].exists = 1;
particles[particle_idx].emitter_init_num = emitter_idx + 1; particles[particle_idx].emitter_init_num = emitter_idx + 1;
particles[particle_idx].seq = particle_seq; particles[particle_idx].seq = particle_seq;
@ -318,7 +318,7 @@ ComputeShader(V_SimParticlesCS, 64)
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains); RWTexture2D<Vec4> stains = G_Dereference<Vec4>(params.stains);
u32 particle_idx = SV_DispatchThreadID; u32 particle_idx = SV_DispatchThreadID;
if (particle_idx < params.max_particles) if (particle_idx < V_MaxParticles)
{ {
V_Particle particle = particles[particle_idx]; V_Particle particle = particles[particle_idx];
if (particle.exists > 0) if (particle.exists > 0)

View File

@ -1,6 +1,11 @@
#define V_CellsPerMeter 40.0 #define V_CellsPerMeter 40.0
#define V_CellsPerSqMeter (V_CellsPerMeter * V_CellsPerMeter) #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 //~ Constant types
@ -73,7 +78,6 @@ Struct(V_GpuParams)
u32 emitters_count; u32 emitters_count;
G_StructuredBufferRef emitters; G_StructuredBufferRef emitters;
u32 max_particles;
G_RWStructuredBufferRef particles; G_RWStructuredBufferRef particles;
b32 should_clear_stains; b32 should_clear_stains;