diff --git a/src/gpu/gpu_common.c b/src/gpu/gpu_common.c index 3e3f52cb..8005afd4 100644 --- a/src/gpu/gpu_common.c +++ b/src/gpu/gpu_common.c @@ -58,7 +58,7 @@ void G_BootstrapCommon(void) } //////////////////////////////////////////////////////////// -//~ Helpers +//~ Utils //- Arena @@ -71,17 +71,12 @@ G_ArenaHandle G_PermArena(void) return G_tl.gpu_perm; } -//- Cpu -> Gpu upload +//- Push resource from cpu -G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc) +G_ResourceHandle G_PushBufferFromCpuCopy_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc) { G_ResourceHandle buffer = G_PushResource(gpu_arena, cl, (G_ResourceDesc) { .kind = G_ResourceKind_Buffer, .buffer = desc }); G_CopyCpuToBuffer(cl, buffer, 0, src.text, RNGU64(0, src.len)); - G_MemorySync( - cl, buffer, - G_Stage_Copy, G_Access_CopyWrite, - G_Stage_All, G_Access_All - ); return buffer; } diff --git a/src/gpu/gpu_common.h b/src/gpu/gpu_common.h index 17d44e61..d498f85a 100644 --- a/src/gpu/gpu_common.h +++ b/src/gpu/gpu_common.h @@ -23,17 +23,17 @@ extern ThreadLocal G_ThreadLocalCtx G_tl; void G_BootstrapCommon(void); //////////////////////////////////////////////////////////// -//~ Helpers +//~ Utils //- Arena G_ArenaHandle G_PermArena(void); -//- Cpu -> Gpu upload +//- Push resource from cpu -G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc); -#define G_PushBufferFromString(_arena, _cl, _src, ...) \ - G_PushBufferFromString_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ }) +G_ResourceHandle G_PushBufferFromCpuCopy_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc); +#define G_PushBufferFromCpuCopy(_arena, _cl, _src, ...) \ + G_PushBufferFromCpuCopy_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ }) //- Viewport / scissor diff --git a/src/gpu/gpu_core.h b/src/gpu/gpu_core.h index 5cc5ca06..d26ba2bc 100644 --- a/src/gpu/gpu_core.h +++ b/src/gpu/gpu_core.h @@ -212,15 +212,15 @@ Enum(G_Stage) G_Stage_Indirect = (1 << 8), // Aggregate stages - G_Stage_AllDraw = G_Stage_IndexAssembly | - G_Stage_VertexShading | - G_Stage_PixelShading | - G_Stage_DepthStencil | - G_Stage_RenderTarget, + G_Stage_Drawing = G_Stage_IndexAssembly | + G_Stage_VertexShading | + G_Stage_PixelShading | + G_Stage_DepthStencil | + G_Stage_RenderTarget, - G_Stage_AllShading = G_Stage_ComputeShading | - G_Stage_VertexShading | - G_Stage_PixelShading, + G_Stage_Shading = G_Stage_ComputeShading | + G_Stage_VertexShading | + G_Stage_PixelShading, G_Stage_All = 0xFFFFFFFF }; @@ -409,8 +409,9 @@ Enum(G_ResourceFlag) G_ResourceFlag_AllowShaderReadWrite = (1 << 0), G_ResourceFlag_AllowRenderTarget = (1 << 1), G_ResourceFlag_AllowDepthStencil = (1 << 2), - G_ResourceFlag_HostMemory = (1 << 3), // Resource will be mapped into the cpu's address space - G_ResourceFlag_Uncached = (1 << 4), // Cpu writes will be combined & reads will be uncached + G_ResourceFlag_ZeroMemory = (1 << 3), + G_ResourceFlag_HostMemory = (1 << 4), // Resource will be mapped into the cpu's address space + G_ResourceFlag_Uncached = (1 << 5), // Cpu writes will be combined & reads will be uncached }; Struct(G_BufferDesc) diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.c b/src/gpu/gpu_dx12/gpu_dx12_core.c index 4df53a1c..f196a070 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.c +++ b/src/gpu/gpu_dx12/gpu_dx12_core.c @@ -898,6 +898,8 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle ////////////////////////////// //- Initialize heap info + b32 can_reuse = 0; + D3D12_HEAP_FLAGS heap_flags = 0; D3D12_HEAP_PROPERTIES heap_props = Zi; b32 should_map = 0; @@ -913,7 +915,15 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle heap_kind = G_D12_ResourceHeapKind_CpuWriteCombined; } } - heap_flags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED; + if (flags & G_ResourceFlag_ZeroMemory) + { + can_reuse = 0; + } + else + { + can_reuse = 1; + heap_flags |= D3D12_HEAP_FLAG_CREATE_NOT_ZEROED; + } // Heap props if (heap_kind == G_D12_ResourceHeapKind_Cpu) { @@ -986,7 +996,6 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle // Pop reset resource resource = gpu_arena->reset_resources.first; - b32 is_reusing = 0; if (resource) { DllQueueRemove(gpu_arena->reset_resources.first, gpu_arena->reset_resources.last, resource); @@ -1004,9 +1013,9 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle } } - // TODO: Less stringent reset constraints. We could even create textures as placed resources and reset their underlying heaps. - is_reusing = MatchStruct(&compare_d3d_desc, &d3d_desc); - if (!is_reusing) + // TODO: Less stringent reuse constraints. We could even create textures as placed resources and reset their underlying heaps. + can_reuse = can_reuse && MatchStruct(&compare_d3d_desc, &d3d_desc); + if (!can_reuse) { // Push releasable to command list { @@ -1035,10 +1044,11 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle } else { + can_reuse = 0; resource = PushStruct(gpu_arena->arena, G_D12_Resource); } - if (!is_reusing) + if (!can_reuse) { resource->d3d_desc = d3d_desc; } @@ -1126,11 +1136,19 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle } ////////////////////////////// - //- Transition layout if reusing + //- Barrier if reusing - if (is_reusing) + // TODO: These barriers are too cautious; it's rare that an arena would ever be reset mid-command list. + if (can_reuse) { - G_DumbMemoryLayoutSync(cl_handle, G_D12_MakeHandle(G_ResourceHandle, resource), desc.texture.initial_layout); + if (is_buffer) + { + G_DumbMemorySync(cl_handle, G_D12_MakeHandle(G_ResourceHandle, resource)); + } + else if (is_texture) + { + G_DumbMemoryLayoutSync(cl_handle, G_D12_MakeHandle(G_ResourceHandle, resource), desc.texture.initial_layout); + } } return G_D12_MakeHandle(G_ResourceHandle, resource); @@ -2717,7 +2735,7 @@ G_QueueCompletions G_CompletionValuesFromQueues(G_QueueMask queue_mask) { if (queue_mask & (1 << queue_kind)) { - completions.v[queue_kind] = G_CompletionTargetFromQueue(queue_kind); + completions.v[queue_kind] = G_CompletionValueFromQueue(queue_kind); } } return completions; @@ -3279,7 +3297,7 @@ void G_D12_TickAsync(WaveLaneCtx *lane, AsyncFrameLaneCtx *base_async_lane_frame G_D12_Releasable *release = async->pending_releases.first; if (release) { - G_QueueCompletions completions = G_CompletionTargetsFromQueues(G_QueueMask_All); + G_QueueCompletions completions = G_CompletionValuesFromQueues(G_QueueMask_All); while (release) { G_D12_Releasable *next = release->next; diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index b5e54db9..639b0ba9 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -1,4 +1,5 @@ S_Ctx S = Zi; +ThreadLocal S_ThreadLocalCtx S_tl = Zi; Readonly S_Ent S_NilEnt = { .last_xf = CompXformIdentity, @@ -86,10 +87,9 @@ String S_NameFromTileKind(S_TileKind kind) //////////////////////////////////////////////////////////// //~ Delta helpers -Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta) +void S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta) { // FIXME: Bounds check tile deltas - Rng2I32 dirty_tile_rect = Zi; if (0) { } @@ -142,7 +142,6 @@ Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta) world->tiles[tile_idx] = src_tile; } } - dirty_tile_rect = range; } //- Tile range else if (delta->kind == S_DeltaKind_Tile) @@ -158,10 +157,7 @@ Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta) world->tiles[tile_idx] = (u8)tile; } } - dirty_tile_rect = range; } - - return dirty_tile_rect; } //////////////////////////////////////////////////////////// @@ -314,9 +310,9 @@ Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal) return result; } -S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep) +S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep) { - S_CollisionData result = Zi; + S_CollisionResult result = Zi; TempArena scratch = BeginScratchNoConflict(); f32 tolerance = 0.00005f; // How close can non-overlapping shapes be before collision is considered @@ -926,16 +922,16 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1, Vec2 s return result; } -S_RaycastData S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir) +S_RaycastResult S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir) { - S_RaycastData result = Zi; + S_RaycastResult result = Zi; // HACK: Create line shape as large as the world and perform a collision test Vec2 ray_shape_p0 = ray_start; Vec2 ray_shape_p1 = AddVec2(ray_start, MulVec2(NormVec2(ray_dir), S_WorldPitch * 1.414213562)); S_Shape ray_shape = S_ShapeFromDesc(.count = 2, .points = { ray_shape_p0, ray_shape_p1 }); - S_CollisionData cls = S_CollisionDataFromShapes(ray_shape, shape, ray_dir); + S_CollisionResult cls = S_CollisionResultFromShapes(ray_shape, shape, ray_dir); result.is_intersecting = cls.collision_points_count > 0; result.normal = NegVec2(cls.collision_normal); result.p = cls.closest_p1; @@ -992,7 +988,7 @@ S_Ent *S_NextEnt(S_Ent *e) void S_DebugDrawPoint(Vec2 p, Vec4 srgb) { - if (S.debug_draw_enabled) + if (S_tl.is_sim_tick_thread && S.debug_draw_enabled) { S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc); desc->kind = S_DebugDrawKind_Point; @@ -1003,7 +999,7 @@ void S_DebugDrawPoint(Vec2 p, Vec4 srgb) void S_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb) { - if (S.debug_draw_enabled) + if (S_tl.is_sim_tick_thread && S.debug_draw_enabled) { S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc); desc->kind = S_DebugDrawKind_Line; @@ -1015,7 +1011,7 @@ void S_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb) void S_DebugDrawRect(Rng2 rect, Vec4 srgb) { - if (S.debug_draw_enabled) + if (S_tl.is_sim_tick_thread && S.debug_draw_enabled) { S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc); desc->kind = S_DebugDrawKind_Rect; @@ -1026,7 +1022,7 @@ void S_DebugDrawRect(Rng2 rect, Vec4 srgb) void S_DebugDrawShape(S_Shape shape, Vec4 srgb) { - if (S.debug_draw_enabled) + if (S_tl.is_sim_tick_thread && S.debug_draw_enabled) { S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc); desc->kind = S_DebugDrawKind_Shape; @@ -1040,6 +1036,7 @@ void S_DebugDrawShape(S_Shape shape, Vec4 srgb) void S_TickForever(WaveLaneCtx *lane) { + S_tl.is_sim_tick_thread = 1; Arena *perm = PermArena(); Arena *frame_arena = AcquireArena(Gibi(64)); @@ -1348,7 +1345,7 @@ void S_TickForever(WaveLaneCtx *lane) // Vec2 shape0_pt = S_SupportPointFromShape(shape0, shape_dir); // Vec2 shape1_pt = S_SupportPointFromShape(shape1, neg_shape_dir); - S_CollisionData collision_data = S_CollisionDataFromShapes(shape0, shape1, VEC2(0, 0)); + S_CollisionResult collision_data = S_CollisionResultFromShapes(shape0, shape1, VEC2(0, 0)); Vec2 shape0_pt = collision_data.closest_p0; Vec2 shape1_pt = collision_data.closest_p1; @@ -1410,61 +1407,120 @@ void S_TickForever(WaveLaneCtx *lane) // TODO: Not like this - { - Struct(S_Bullet) - { - Vec2 start; - Vec2 dir; + // { + // Struct(S_Bullet) + // { + // Vec2 start; + // Vec2 dir; - f32 speed; - }; + // f32 speed; + // }; - PERSIST i64 bullets_count = 1; - PERSIST S_Bullet *bullets = 0; - if (!bullets) - { - bullets = PushStruct(PermArena(), S_Bullet); - S_Bullet *bullet = &bullets[0]; - bullet->start = VEC2(1, 0); - bullet->dir = NormVec2(VEC2(1, -1)); - bullet->speed = 1; - } + // PERSIST i64 bullets_count = 1; + // PERSIST S_Bullet *bullets = 0; + // if (!bullets) + // { + // bullets = PushStruct(PermArena(), S_Bullet); + // S_Bullet *bullet = &bullets[0]; + // bullet->start = VEC2(1, 0); + // bullet->dir = NormVec2(VEC2(1, -1)); + // bullet->speed = 1; + // } - for (i64 bullet_idx = 0; bullet_idx < bullets_count; ++bullet_idx) - { - S_Bullet *bullet = &bullets[bullet_idx]; + // for (i64 bullet_idx = 0; bullet_idx < bullets_count; ++bullet_idx) + // { + // S_Bullet *bullet = &bullets[bullet_idx]; - // Raycast - for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent)) - { - Xform xf = ent->xf; - S_Shape world_shape = S_MulXformShape(xf, ent->local_shape); + // // Raycast + // for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent)) + // { + // Xform xf = ent->xf; + // S_Shape world_shape = S_MulXformShape(xf, ent->local_shape); - if (ent == S_FirstEnt(world)) - { - bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius)); - bullet->dir = NormVec2(ent->look); - } - else - { - S_RaycastData raycast = S_RaycastShape(world_shape, bullet->start, bullet->dir); - Vec2 isect = raycast.p; + // if (ent == S_FirstEnt(world)) + // { + // bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius)); + // bullet->dir = NormVec2(ent->look); + // } + // else + // { + // S_RaycastResult raycast = S_RaycastShape(world_shape, bullet->start, bullet->dir); + // Vec2 isect = raycast.p; - if (raycast.is_intersecting) - { - S_DebugDrawPoint(isect, Color_Green); - S_DebugDrawLine(isect, AddVec2(isect, MulVec2(raycast.normal, 0.5)), Color_White); - } - else - { - S_DebugDrawPoint(isect, Color_Purple); - } - } - } + // if (raycast.is_intersecting) + // { + // S_DebugDrawPoint(isect, Color_Green); + // S_DebugDrawLine(isect, AddVec2(isect, MulVec2(raycast.normal, 0.5)), Color_White); + // } + // else + // { + // S_DebugDrawPoint(isect, Color_Purple); + // } + // } + // } - S_DebugDrawLine(bullet->start, AddVec2(bullet->start, Vec2WithLen(bullet->dir, 0.5)), Color_Red); - } - } + // S_DebugDrawLine(bullet->start, AddVec2(bullet->start, Vec2WithLen(bullet->dir, 0.5)), Color_Red); + // } + // } + + + + + + // // Struct(S_Bullet) + // // { + // // Vec2 start; + // // Vec2 dir; + + // // f32 speed; + // // }; + + // // PERSIST i64 bullets_count = 1; + // // PERSIST S_Bullet *bullets = 0; + // // if (!bullets) + // // { + // // bullets = PushStruct(PermArena(), S_Bullet); + // // S_Bullet *bullet = &bullets[0]; + // // bullet->start = VEC2(1, 0); + // // bullet->dir = NormVec2(VEC2(1, -1)); + // // bullet->speed = 1; + // // } + + // // for (i64 bullet_idx = 0; bullet_idx < bullets_count; ++bullet_idx) + // // { + // // S_Bullet *bullet = &bullets[bullet_idx]; + + // // // Raycast + // // for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent)) + // // { + // // Xform xf = ent->xf; + // // S_Shape world_shape = S_MulXformShape(xf, ent->local_shape); + + // // if (ent == S_FirstEnt(world)) + // // { + // // bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius)); + // // bullet->dir = NormVec2(ent->look); + // // } + // // else + // // { + // // S_RaycastResult raycast = S_RaycastShape(world_shape, bullet->start, bullet->dir); + // // Vec2 isect = raycast.p; + + // // if (raycast.is_intersecting) + // // { + // // S_DebugDrawPoint(isect, Color_Green); + // // S_DebugDrawLine(isect, AddVec2(isect, MulVec2(raycast.normal, 0.5)), Color_White); + // // } + // // else + // // { + // // S_DebugDrawPoint(isect, Color_Purple); + // // } + // // } + // // } + + // // S_DebugDrawLine(bullet->start, AddVec2(bullet->start, Vec2WithLen(bullet->dir, 0.5)), Color_Red); + // // } + // } diff --git a/src/pp/pp_sim/pp_sim_core.h b/src/pp/pp_sim/pp_sim_core.h index 7f5290fd..7be9a0d6 100644 --- a/src/pp/pp_sim/pp_sim_core.h +++ b/src/pp/pp_sim/pp_sim_core.h @@ -120,7 +120,7 @@ Struct(S_ClippedLine) Vec2 a1_clipped, b1_clipped; }; -Struct(S_CollisionData) +Struct(S_CollisionResult) { // Contact manifold i32 collision_points_count; @@ -132,7 +132,7 @@ Struct(S_CollisionData) Vec2 closest_p1; }; -Struct(S_RaycastData) +Struct(S_RaycastResult) { Vec2 p; Vec2 normal; @@ -315,7 +315,13 @@ Struct(S_Ctx) S_OutputState output_states[2]; }; +Struct(S_ThreadLocalCtx) +{ + b32 is_sim_tick_thread; +}; + extern S_Ctx S; +extern ThreadLocal S_ThreadLocalCtx S_tl; extern Readonly S_Ent S_NilEnt; //////////////////////////////////////////////////////////// @@ -346,7 +352,7 @@ String S_NameFromTileKind(S_TileKind kind); //////////////////////////////////////////////////////////// //~ Delta helpers -Rng2I32 S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta); +void S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta); //////////////////////////////////////////////////////////// //~ Shape helpers @@ -366,8 +372,8 @@ 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_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep); -S_RaycastData S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir); +S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep); +S_RaycastResult S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir); //////////////////////////////////////////////////////////// //~ Lookup helpers diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 3fbf11e5..468b891c 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -313,6 +313,8 @@ void V_TickForever(WaveLaneCtx *lane) // 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; @@ -324,7 +326,6 @@ void V_TickForever(WaveLaneCtx *lane) G_RWStructuredBufferRef gpu_particles_ref = Zi; G_RWTexture2DRef gpu_decals_ref = Zi; { - // FIXME: Clear initial resource memory G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct); { // Init state buffer @@ -333,7 +334,7 @@ void V_TickForever(WaveLaneCtx *lane) gpu_perm, cl, V_GpuState, 1, - .flags = G_ResourceFlag_AllowShaderReadWrite + .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite ); gpu_state_ref = G_PushRWStructuredBufferRef(gpu_perm, gpu_state, V_GpuState); } @@ -344,7 +345,8 @@ void V_TickForever(WaveLaneCtx *lane) gpu_perm, cl, G_Format_R8_Uint, tiles_dims, - G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite + G_Layout_DirectQueue_ShaderRead, + .flags = G_ResourceFlag_ZeroMemory ); gpu_tiles_ref = G_PushTexture2DRef(gpu_perm, gpu_tiles); } @@ -354,7 +356,7 @@ void V_TickForever(WaveLaneCtx *lane) gpu_perm, cl, V_Particle, max_particles, - .flags = G_ResourceFlag_AllowShaderReadWrite + .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite ); gpu_particles_ref = G_PushRWStructuredBufferRef(gpu_perm, gpu_particles, V_Particle); } @@ -362,10 +364,12 @@ void V_TickForever(WaveLaneCtx *lane) { gpu_decals = G_PushTexture2D( gpu_perm, cl, - G_Format_R8_Uint, + // G_Format_R8_Uint, + // G_Format_R11G11B10_Float, + G_Format_R10G10B10A2_Unorm, decals_dims, G_Layout_DirectQueue_ShaderReadWrite, - .flags = G_ResourceFlag_AllowShaderReadWrite + .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite ); gpu_decals_ref = G_PushRWTexture2DRef(gpu_perm, gpu_decals); } @@ -582,6 +586,7 @@ void V_TickForever(WaveLaneCtx *lane) // FIXME: Only apply latest snapshot b32 received_unseen_tick = 0; + b32 tiles_dirty = 0; for (S_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next) { S_Snapshot *snapshot = &n->snapshot; @@ -592,17 +597,11 @@ void V_TickForever(WaveLaneCtx *lane) for (S_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next) { S_Delta *delta = &dn->delta; - Rng2I32 dirty_tile_rect = S_UpdateWorldFromDelta(world_arena, world, delta); - Vec2I32 dirty_tile_dims = DimsFromRng2I32(dirty_tile_rect); - if (dirty_tile_dims.x != 0 || dirty_tile_dims.y != 0) + if (delta->kind == S_DeltaKind_RawTiles || delta->kind == S_DeltaKind_Tile) { - G_CopyCpuToTexture( - frame->cl, - gpu_tiles, VEC3I32(dirty_tile_rect.p0.x, dirty_tile_rect.p0.y, 0), - world->tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1), - RNG3I32(VEC3I32(dirty_tile_rect.p0.x, dirty_tile_rect.p0.y, 0), VEC3I32(dirty_tile_rect.p1.x, dirty_tile_rect.p1.y, 1)) - ); + tiles_dirty = 1; } + S_UpdateWorldFromDelta(world_arena, world, delta); } received_unseen_tick = 1; } @@ -961,11 +960,12 @@ void V_TickForever(WaveLaneCtx *lane) S_Ent *player = S_EntFromKey(world, V.player_key); S_Ent *hovered_ent = &S_NilEnt; { + // TODO: Real world query S_Shape cursor_shape = S_ShapeFromDesc(.count = 1, .points = { frame->world_cursor }); 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_CollisionDataFromShapes(ent_shape, cursor_shape, VEC2(0, 0)).collision_points_count > 0; + b32 is_hovered = S_CollisionResultFromShapes(ent_shape, cursor_shape, VEC2(0, 0)).collision_points_count > 0; if (is_hovered) { hovered_ent = ent; @@ -2518,6 +2518,7 @@ void V_TickForever(WaveLaneCtx *lane) if (frame->held_buttons[Button_W]) move.y -= 1; if (frame->held_buttons[Button_S]) move.y += 1; } + f32 fire_held = frame->held_buttons[Button_M1]; Vec2 look = Zi; { Vec2 center = MulXformV2(player->xf, player->local_shape.centroid); @@ -2535,6 +2536,7 @@ void V_TickForever(WaveLaneCtx *lane) { frame->move = move; frame->look = look; + frame->fire_held = fire_held; } } @@ -2544,6 +2546,7 @@ void V_TickForever(WaveLaneCtx *lane) cmd->target = V.player_key; cmd->move = frame->move; cmd->look = frame->look; + cmd->fire_held = frame->fire_held; } ////////////////////////////// @@ -2562,6 +2565,108 @@ void V_TickForever(WaveLaneCtx *lane) } UnlockTicketMutex(&S.input_back_tm); + ////////////////////////////// + //- Process bullets + + // TODO: Not like this + + + { + for (S_Ent *firer = S_FirstEnt(world); firer->valid; firer = S_NextEnt(firer)) + { + if (firer->fire_held) + { + Xform firer_xf = firer->xf; + S_Shape firer_world_shape = S_MulXformShape(firer_xf, firer->local_shape); + + Vec2 ray_start = firer_world_shape.centroid; + Vec2 ray_dir = firer->look; + + // TODO: Real raycast query + S_Ent *closest_victim = &S_NilEnt; + S_RaycastResult victim_raycast = Zi; + { + f32 closest_len_sq = Inf; + for (S_Ent *victim = S_FirstEnt(world); victim->valid; victim = S_NextEnt(victim)) + { + if (victim != firer) + { + 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) + { + f32 len_sq = Vec2LenSq(SubVec2(raycast.p, ray_start)); + if (len_sq < closest_len_sq) + { + closest_len_sq = len_sq; + closest_victim = victim; + victim_raycast = raycast; + } + } + } + } + } + + if (closest_victim->valid) + { + 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; + } + V_ParticleFlag flags = 0; + emitter->flags = flags; + + Vec2 dir = victim_raycast.normal; + emitter->pos = victim_raycast.p; + + emitter->count = 50; + // emitter->count = 100; + // emitter->count = 500; + + emitter->speed = 20; + emitter->speed_spread = 40; + + emitter->velocity_falloff = 30; + emitter->velocity_falloff_spread = 60; + + emitter->angle = AngleFromVec2(dir); + // emitter->angle_spread = Tau / 4; + // emitter->angle_spread = Tau / 20; + emitter->angle_spread = Tau / 32; + + emitter->color_lin = LinearFromSrgb(VEC4(0.5, 0.1, 0.1, 1)); + emitter->color_spread = VEC3(0.1, 0, 0); + + // emitter->color = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1)); + + emitter->seed = RandU64FromState(&frame->rand); + // emitter->angle_spread = 1; + // emitter->angle_spread = 0.5; + // emitter->angle_spread = Tau; + + // V_DrawPoint(victim_raycast.p, Color_Green); + // V_DrawLine(victim_raycast.p, AddVec2(victim_raycast.p, MulVec2(victim_raycast.normal, 0.5)), Color_White); + } + + + // for (S_QueryResult query = S_FirstRaycast(wrold, ray_start, ray_dir); query. + // S_RaycastWorldResult hits = S_RaycastWorld(world, ray_start, ray_dir) + // { + // } + } + } + } + + + + + + ////////////////////////////// //- Render @@ -2664,11 +2769,7 @@ void V_TickForever(WaveLaneCtx *lane) } ////////////////////////////// - //- Build emitters - - i64 emitters_count = 0; - V_EmitterNode *first_emitter_node = 0; - V_EmitterNode *last_emitter_node = 0; + //- Spawn test emitter // Spawn test emitter @@ -2677,39 +2778,31 @@ void V_TickForever(WaveLaneCtx *lane) V_Emitter *emitter = 0; { V_EmitterNode *en = PushStruct(frame->arena, V_EmitterNode); - SllQueuePush(first_emitter_node, last_emitter_node, en); - emitters_count += 1; + SllQueuePush(frame->first_emitter_node, frame->last_emitter_node, en); + frame->emitters_count += 1; emitter = &en->emitter; } - emitter->particle_kind = V_ParticleKind_Test; Vec2 dir = frame->look; emitter->pos = frame->world_cursor; emitter->angle = AngleFromVec2(dir); - emitter->count = 100; + emitter->count = 25; + // emitter->count = 100; emitter->speed = 10; + 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; - } - - // Flatten emitters list - V_Emitter *flattened_emitters = PushStructsNoZero(frame->arena, V_Emitter, emitters_count); - { - i64 emitter_idx = 0; - for (V_EmitterNode *en = first_emitter_node; en; en = en->next) - { - flattened_emitters[emitter_idx] = en->emitter; - ++emitter_idx; - } + // emitter->angle_spread = Tau; } ////////////////////////////// - //- Push data to GPU + //- Begin gpu frame // Target G_ResourceHandle draw_target = G_PushTexture2D( @@ -2725,13 +2818,26 @@ void V_TickForever(WaveLaneCtx *lane) Rng2 scissor = RNG2(VEC2(viewport.p0.x, viewport.p0.y), VEC2(viewport.p1.x, viewport.p1.y)); // Verts - G_ResourceHandle dverts_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dverts_arena)); - G_ResourceHandle dvert_idxs_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dvert_idxs_arena)); + G_ResourceHandle dverts_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->dverts_arena)); + G_ResourceHandle dvert_idxs_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->dvert_idxs_arena)); G_StructuredBufferRef dverts_ro = G_PushStructuredBufferRef(frame->gpu_arena, dverts_buff, V_DVert); G_IndexBufferDesc dvert_idxs_ib = G_IdxBuff32(dvert_idxs_buff); // Emitters - G_ResourceHandle gpu_emitters = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStructs(flattened_emitters, emitters_count)); + G_ResourceHandle gpu_emitters = Zi; + { + // Flatten emitters list + V_Emitter *flattened_emitters = PushStructsNoZero(frame->arena, V_Emitter, frame->emitters_count); + { + i64 emitter_idx = 0; + for (V_EmitterNode *en = frame->first_emitter_node; en; en = en->next) + { + flattened_emitters[emitter_idx] = en->emitter; + ++emitter_idx; + } + } + gpu_emitters = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromStructs(flattened_emitters, frame->emitters_count)); + } G_StructuredBufferRef gpu_emitters_ref = G_PushStructuredBufferRef(frame->gpu_arena, gpu_emitters, V_Emitter); // Params @@ -2762,7 +2868,7 @@ void V_TickForever(WaveLaneCtx *lane) params.tiles = gpu_tiles_ref; params.shape_verts = dverts_ro; - params.emitters_count = emitters_count; + params.emitters_count = frame->emitters_count; params.emitters = gpu_emitters_ref; params.max_particles = max_particles; @@ -2770,9 +2876,23 @@ void V_TickForever(WaveLaneCtx *lane) params.decals = gpu_decals_ref; } - G_ResourceHandle gpu_params = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(¶ms)); + G_ResourceHandle gpu_params = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromStruct(¶ms)); G_StructuredBufferRef gpu_params_ref = G_PushStructuredBufferRef(frame->gpu_arena, gpu_params, V_GpuParams); + // Upload tiles + if (tiles_dirty) + { + LogDebugF("Uploading tiles to gpu"); + G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite); + G_CopyCpuToTexture( + frame->cl, + gpu_tiles, VEC3I32(0, 0, 0), + world->tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1), + RNG3I32(VEC3I32(0, 0, 0), VEC3I32(tiles_dims.x, tiles_dims.y, 1)) + ); + G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_ShaderRead); + } + // Constants G_SetConstant(frame->cl, V_ShaderConst_State, gpu_state_ref); G_SetConstant(frame->cl, V_ShaderConst_Params, gpu_params_ref); @@ -2782,37 +2902,41 @@ void V_TickForever(WaveLaneCtx *lane) G_DumbGlobalMemorySync(frame->cl); ////////////////////////////// - //- Utility pass + //- Setup pass // Clear decals if (should_clear_decals) { G_Compute(frame->cl, V_ClearDecalsCS, V_ThreadGroupSizeFromTexSize(decals_dims)); } + // Clear particles if (should_clear_particles) { G_Compute(frame->cl, V_ClearParticlesCS, V_ThreadGroupSizeFromBufferSize(max_particles)); } - G_DumbGlobalMemorySync(frame->cl); - - ////////////////////////////// - //- Discard pass - + // Discard render target G_DiscardRenderTarget(frame->cl, draw_target); + // Sync + G_DumbGlobalMemorySync(frame->cl); + ////////////////////////////// //- Particle simulation pass { // Emit particles - G_Compute(frame->cl, V_EmitParticlesCS, V_ThreadGroupSizeFromBufferSize(emitters_count)); + G_Compute(frame->cl, V_EmitParticlesCS, V_ThreadGroupSizeFromBufferSize(frame->emitters_count)); + // Barrier particles buffer G_DumbMemorySync(frame->cl, gpu_particles); // Simulate particles G_Compute(frame->cl, V_SimParticlesCS, V_ThreadGroupSizeFromBufferSize(max_particles)); + + // Barrier since decals 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 421ffa97..2d41d7da 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -1,22 +1,22 @@ //////////////////////////////////////////////////////////// //~ Command table -#define V_CmdsTableXMacro(X) \ - X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \ - X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \ - X(toggle_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_E, .ctrl = 1 ), V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \ - X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \ - X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \ - X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \ - X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \ - X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \ - X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \ - X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \ - X(spawn, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \ - X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_R ), ) \ - X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \ - X(clear_decals, Clear decals, V_CmdDescFlag_None, V_HOTKEY( Button_C ), ) \ - X(clear_particles, Clear particles, V_CmdDescFlag_None, V_HOTKEY( Button_C, .alt = 1 ), ) \ +#define V_CmdsTableXMacro(X) \ + X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \ + X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \ + X(toggle_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_E, .ctrl = 1 ), V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \ + X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \ + X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \ + X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \ + X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \ + X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \ + X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \ + X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \ + X(spawn, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \ + X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_R ), ) \ + X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \ + X(clear_decals, Clear decals, V_CmdDescFlag_None, V_HOTKEY( Button_C, .alt = 1 ), ) \ + X(clear_particles, Clear particles, V_CmdDescFlag_None, V_HOTKEY( Button_C ), ) \ /* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */ //////////////////////////////////////////////////////////// @@ -267,11 +267,17 @@ Struct(V_Frame) // Control Vec2 move; Vec2 look; + f32 fire_held; // Sim cmds u64 sim_cmds_count; S_CmdNode *first_sim_cmd_node; S_CmdNode *last_sim_cmd_node; + + // Emitters + i64 emitters_count; + V_EmitterNode *first_emitter_node; + V_EmitterNode *last_emitter_node; }; Struct(V_Ctx) diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 24d09c9a..9b9cf2f6 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -5,11 +5,11 @@ ComputeShader2D(V_ClearDecalsCS, 8, 8) { V_GpuParams params = G_Dereference(V_ShaderConst_Params)[0]; - RWTexture2D decals = G_Dereference(params.decals); + RWTexture2D decals = G_Dereference(params.decals); Vec2 decal_idx = SV_DispatchThreadID; if (decal_idx.x < countof(decals).x && decal_idx.y < countof(decals).y) { - decals[decal_idx] = V_ParticleKind_None; + decals[decal_idx] = 0; } } @@ -21,11 +21,10 @@ ComputeShader(V_ClearParticlesCS, 64) u32 particle_idx = SV_DispatchThreadID; if (particle_idx < params.max_particles) { - particles[particle_idx].kind = V_ParticleKind_None; + particles[particle_idx].exists = 0; } } - //////////////////////////////////////////////////////////// //~ Backdrop shader @@ -148,21 +147,38 @@ ComputeShader2D(V_BackdropCS, 8, 8) + // TODO: Remove this // Decals test { - RWTexture2D decals = G_Dereference(params.decals); + RWTexture2D decals = G_Dereference(params.decals); Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(world_pos, 1)); // Vec2 decal_uv = decal_pos / countof(decals); - V_ParticleKind decal = decals.Load(decal_pos); - - if (decal == V_ParticleKind_Test) + Vec4 decal = decals.Load(decal_pos); + if (decal.a != 0) { - result = Color_Yellow; - // result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1)); + result = decal; } } + + + // TODO: Remove this + // Decals test + // { + // RWTexture2D decals = G_Dereference(params.decals); + // Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(world_pos, 1)); + // // Vec2 decal_uv = decal_pos / countof(decals); + // V_ParticleKind decal = decals.Load(decal_pos); + + // if (decal == V_ParticleKind_Test) + // { + // // result = Color_Yellow; + // // result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1)); + // // result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 1)); + // } + // } + } target[SV_DispatchThreadID] = result; @@ -238,7 +254,7 @@ ComputeShader(V_EmitParticlesCS, 64) for (u32 particle_seq = first_particle_seq; particle_seq < last_particle_seq; ++particle_seq) { u32 particle_idx = particle_seq % params.max_particles; - particles[particle_idx].kind = emitter.particle_kind; + particles[particle_idx].exists = 1; particles[particle_idx].emitter_init_num = emitter_idx + 1; particles[particle_idx].idx_in_emitter = particles_created_count; particles_created_count += 1; @@ -253,14 +269,13 @@ ComputeShader(V_SimParticlesCS, 64) { V_GpuParams params = G_Dereference(V_ShaderConst_Params)[0]; RWStructuredBuffer particles = G_Dereference(params.particles); - RWTexture2D decals = G_Dereference(params.decals); - Texture2D tiles = G_Dereference(params.tiles); + RWTexture2D decals = G_Dereference(params.decals); u32 particle_idx = SV_DispatchThreadID; if (particle_idx < params.max_particles) { V_Particle particle = particles[particle_idx]; - if (particle.kind != V_ParticleKind_None) + if (particle.exists > 0) { // Initialize if (particle.emitter_init_num != 0) @@ -268,128 +283,57 @@ ComputeShader(V_SimParticlesCS, 64) V_Emitter emitter = G_Dereference(params.emitters)[particle.emitter_init_num - 1]; u64 seed = MixU64(emitter.seed + particle.idx_in_emitter); - u32 speed_noise = ((u32)seed >> 0) & 0xFFFF; - u32 angle_noise = ((u32)seed >> 16) & 0xFFFF; - f32 speed_rand = speed_noise / (f32)0xFFFF; - f32 angle_rand = angle_noise / (f32)0xFFFF; - f32 speed = emitter.speed + ((speed_rand - 0.5) * emitter.speed_spread); - f32 angle = emitter.angle + ((angle_rand - 0.5) * emitter.angle_spread); + // u32 speed_noise = (u32)((seed >> 0) & 0xFF); + // u32 angle_noise = (u32)((seed >> 8) & 0xFF); + + // u32 r_noise = (u32)((seed >> 8) & 0xFF); + // u32 g_noise = (u32)((seed >> 8) & 0xFF); + // u32 b_noise = (u32)((seed >> 8) & 0xFF); + // u32 a_noise = (u32)((seed >> 8) & 0xFF); + + // f32 speed_rand = speed_noise / (f32)0xFFFF; + // f32 angle_rand = angle_noise / (f32)0xFFFF; + + f32 rand_speed = (f32)((seed >> 0) & 0xFF) / (f32)0xFF - 0.5; + f32 rand_angle = (f32)((seed >> 8) & 0xFF) / (f32)0xFF - 0.5; + f32 rand_falloff = (f32)((seed >> 16) & 0xFF) / (f32)0xFF - 0.5; + f32 rand_r = (f32)((seed >> 24) & 0xFF) / (f32)0xFF - 0.5; + f32 rand_g = (f32)((seed >> 32) & 0xFF) / (f32)0xFF - 0.5; + f32 rand_b = (f32)((seed >> 48) & 0xFF) / (f32)0xFF - 0.5; + + f32 speed = emitter.speed + rand_speed * emitter.speed_spread; + f32 angle = emitter.angle + rand_angle * emitter.angle_spread; + f32 velocity_falloff = emitter.velocity_falloff + rand_falloff * emitter.velocity_falloff; + Vec3 color = emitter.color_lin.rgb + Vec3(rand_r, rand_g, rand_b) * emitter.color_spread; particle.pos = emitter.pos; particle.velocity = Vec2(cos(angle), sin(angle)) * speed; + particle.velocity_falloff = velocity_falloff; + particle.color = color; particle.emitter_init_num = 0; } // Simulate { - f32 dt = params.dt; - - Vec2 pos_a = particle.pos; - Vec2 pos_b = pos_a + particle.velocity * dt; - - // TODO: Don't query tiles - Vec2I32 tile_pos_a = S_TilePosFromWorldPos(pos_a); - S_TileKind tile_a = tiles.Load(Vec3I32(tile_pos_a, 0)); - b32 is_blocked_a = tile_a == S_TileKind_Wall; - - Vec2 pos_a_decal = mul(params.xf.world_to_decal, Vec3(pos_a, 1)); - Vec2 pos_b_decal = mul(params.xf.world_to_decal, Vec3(pos_b, 1)); - - Vec2 step_a = pos_a_decal; - Vec2 step_b = pos_b_decal; - Vec2 step_vab = step_b - step_a; - - f32 slope = step_vab.y / step_vab.x; - i32 x_dir = (step_vab.x >= 0) - (step_vab.x < 0); - - if (!is_blocked_a) - { - i32 step_x = step_a.x; - for (;;) - { - f32 step_y = step_a.y + slope * (step_x - step_a.x); - Vec2 step = Vec2(step_x, step_y); - - // TODO: Don't query tiles - Vec2 world_step = mul(params.xf.decal_to_world, Vec3(step, 1)); - Vec2I32 tile_pos = S_TilePosFromWorldPos(world_step); - S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0)); - - b32 is_blocked = tile == S_TileKind_Wall; - if (is_blocked) - { - // particle.velocity *= -1; - particle.velocity.y *= -1; - // particle.velocity.x *= -1; - break; - } - - step_x += x_dir; - if (x_dir > 0) - { - if (step_x > (step_b.x + x_dir)) - { - break; - } - } - else - { - if (step_x < (step_b.x + x_dir)) - { - break; - } - } - } - } - - // // Line walk - // // FIXME: Real line walk, not aabb check - // b32 is_blocked = 0; - // for (u32 step_y = step_a.y; step_y <= step_b.y; ++step_y) - // { - // for (u32 step_x = step_a.x; step_x <= step_b.x; ++step_x) - // { - // // TODO: Don't query tiles - // Vec2 world_step = mul(params.xf.decal_to_world, Vec3(step_x, step_y, 1)); - // Vec2I32 tile_pos = S_TilePosFromWorldPos(world_step); - // S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0)); - - // if (tile == S_TileKind_Wall) - // { - // if (is_blocked) - // { - // // particle.velocity *= -1; - // particle.velocity.x *= -1; - // break; - // } - // is_blocked = 1; - // } - // } - // } - - - - - // Vec2I32 tile_pos = S_TilePosFromWorldPos(pos_a); - // S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0)); - - - particle.pos = pos_a + particle.velocity * dt; - particle.velocity = lerp(particle.velocity, 0, 4 * params.dt); - - + particle.pos += particle.velocity * params.dt; + particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt); Vec2 decal_pos = mul(params.xf.world_to_decal, Vec3(particle.pos, 1)); if (decal_pos.x >= 0 && decal_pos.y >= 0 && decal_pos.x < countof(decals).x && decal_pos.y < countof(decals).y) { // FIXME: Atomic write - decals[floor(decal_pos)] = particle.kind; + decals[floor(decal_pos)] = Vec4(particle.color, 1); } else { // Prune out of bounds particle - particle.kind = V_ParticleKind_None; + particle.exists = 0; + } + + if (particle.exists < 0.0001) + { + particle.exists = 0; } } particles[particle_idx] = particle; diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index c6bed00d..f8952aa1 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -80,35 +80,47 @@ Struct(V_GpuParams) //////////////////////////////////////////////////////////// //~ Particle types -Enum(V_ParticleKind) +Enum(V_ParticleFlag) { - V_ParticleKind_None, - V_ParticleKind_Test + V_ParticleFlag_None = (0), }; Struct(V_Emitter) { - V_ParticleKind particle_kind; + V_ParticleFlag flags; Vec2 pos; - f32 angle; u32 count; - f32 speed; - u64 seed; - f32 angle_spread; + + f32 speed; f32 speed_spread; + + f32 angle; + f32 angle_spread; + + f32 velocity_falloff; + f32 velocity_falloff_spread; + + Vec4 color_lin; + Vec3 color_spread; }; // TODO: Pack this efficiently Struct(V_Particle) { - V_ParticleKind kind; + V_ParticleFlag flags; + u32 emitter_init_num; // if != 0, then initialize using emitter at index (emitter_init_num - 1) u32 idx_in_emitter; Vec2 pos; Vec2 velocity; + + f32 exists; + + f32 velocity_falloff; + Vec3 color; }; #if IsLanguageC diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 7970cc27..da7efc98 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -1695,7 +1695,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync) // Rects u64 rects_count = ArenaCount(frame->rects_arena, UI_DRect); - G_ResourceHandle rects_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->rects_arena)); + G_ResourceHandle rects_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromArena(frame->rects_arena)); G_StructuredBufferRef rects_ro = G_PushStructuredBufferRef(frame->gpu_arena, rects_buff, UI_DRect); // Params @@ -1708,7 +1708,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync) params.cursor_pos = frame->cursor_pos; params.aa = TweakFloat("UI anti-aliasing", 1, 0, 1); } - G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(¶ms)); + G_ResourceHandle params_buff = G_PushBufferFromCpuCopy(frame->gpu_arena, frame->cl, StringFromStruct(¶ms)); G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, UI_DParams); // Constants @@ -1721,6 +1721,7 @@ void UI_EndFrame(UI_Frame *frame, i32 vsync) //- Dispatch shaders //- Clear pass + { G_ClearRenderTarget(frame->cl, draw_target, VEC4(0, 0, 0, 0)); }