wine-detection. gpu debug/validation command line args

This commit is contained in:
jacob 2026-02-26 23:05:36 -06:00
parent 3061bba8e0
commit 58543ac517
11 changed files with 337 additions and 138 deletions

View File

@ -791,6 +791,7 @@ Inline u64 MixU64s(u64 seed_a, u64 seed_b)
b32 Panic(String msg); b32 Panic(String msg);
Callstack CaptureCallstack(u64 skip_frames); Callstack CaptureCallstack(u64 skip_frames);
b32 IsRunningInDebugger(void); b32 IsRunningInDebugger(void);
b32 IsRunningInWine(void);
i64 TimeNs(void); i64 TimeNs(void);
void TrueRand(String buffer); void TrueRand(String buffer);
CpuTopologyInfo GetCpuTopologyInfo(void); CpuTopologyInfo GetCpuTopologyInfo(void);

View File

@ -102,6 +102,11 @@ b32 IsRunningInDebugger(void)
return IsDebuggerPresent(); return IsDebuggerPresent();
} }
b32 IsRunningInWine(void)
{
return W32.wine_version.len > 0;
}
i64 TimeNs(void) i64 TimeNs(void)
{ {
LARGE_INTEGER qpc; LARGE_INTEGER qpc;
@ -445,10 +450,12 @@ i32 W32_Main(void)
// Get raw args from command line // Get raw args from command line
Arena *perm = PermArena(); Arena *perm = PermArena();
String cmdline_str = Zi;
{ {
StringList args_list = Zi; StringList args_list = Zi;
{ {
LPCWSTR cmdline_wstr = GetCommandLineW(); wchar_t *cmdline_wstr = GetCommandLineW();
cmdline_str = StringFromWstrNoLimit(perm, cmdline_wstr);
i32 argc = 0; i32 argc = 0;
LPWSTR *argv = CommandLineToArgvW(cmdline_wstr, &argc); LPWSTR *argv = CommandLineToArgvW(cmdline_wstr, &argc);
for (i32 i = 0; i < argc; ++i) for (i32 i = 0; i < argc; ++i)
@ -461,6 +468,24 @@ i32 W32_Main(void)
W32.raw_command_line = args_list; W32.raw_command_line = args_list;
} }
// Detect wine
{
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
if (ntdll)
{
typedef char *W32_WineVersionFunc(void);
W32_WineVersionFunc *wine_version_func = (W32_WineVersionFunc *)GetProcAddress(ntdll, "wine_get_version");
if (wine_version_func)
{
char *wine_version_cstr = wine_version_func();
if (wine_version_cstr)
{
W32.wine_version = PushString(perm, StringFromCstrNoLimit(wine_version_cstr));
}
}
}
}
////////////////////////////// //////////////////////////////
//- Bootstrap //- Bootstrap
@ -541,7 +566,11 @@ i32 W32_Main(void)
// Bootstrap log system // Bootstrap log system
W32_BootstrapLogs(); W32_BootstrapLogs();
LogInfoF("Main thread ID: %F", FmtUint(ThreadId())); LogInfoF("Command line: [%F]", FmtString(cmdline_str));
if (W32.wine_version.len > 0)
{
LogInfoF("Wine version: \"%F\"", FmtString(W32.wine_version));
}
if (appdir_error.len > 0) if (appdir_error.len > 0)
{ {
LogError(appdir_error); LogError(appdir_error);

View File

@ -65,6 +65,7 @@ Struct(W32_Ctx)
{ {
SYSTEM_INFO info; SYSTEM_INFO info;
u32 main_thread_id; u32 main_thread_id;
String wine_version;
Atomic32 shutdown; Atomic32 shutdown;
Atomic32 exit_code; Atomic32 exit_code;

View File

@ -4,7 +4,7 @@
#define SIM_PHYSICS_SUBSTEPS 4 #define SIM_PHYSICS_SUBSTEPS 4
#define SIM_TICKS_PER_SECOND 32 #define SIM_TICKS_PER_SECOND 64
#define SIM_TICK_INTERVAL_NS (NsFromSeconds(1) / SIM_TICKS_PER_SECOND) #define SIM_TICK_INTERVAL_NS (NsFromSeconds(1) / SIM_TICKS_PER_SECOND)
// Like USER_INTERP_RATIO, but applies to snapshots received by the local sim from the // Like USER_INTERP_RATIO, but applies to snapshots received by the local sim from the
// master sim (how far back in time should the client render the server's state) // master sim (how far back in time should the client render the server's state)
@ -12,8 +12,6 @@
#define GPU_NAMES IsRtcEnabled #define GPU_NAMES IsRtcEnabled
#define GPU_DEBUG 0
#define GPU_DEBUG_VALIDATION 0
#define GPU_SHADER_PRINT 1 #define GPU_SHADER_PRINT 1
#define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64); #define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64);

View File

@ -10,9 +10,25 @@ void G_Bootstrap(void)
Arena *perm = PermArena(); Arena *perm = PermArena();
// NOTE: Nsight seems to have trouble attaching when independent devices are enabled // NOTE: Nsight seems to have trouble attaching when independent devices are enabled
G_D12.independent_devices_enabled = !CommandlineArgFromName(Lit("no-independent-d3d12-device")).exists; G_D12.independent_devices_enabled = !CommandlineArgFromName(Lit("no-d3d12-independent-devices")).exists;
LogInfoF("D3D12 independent devices enabled: %F", FmtSint(G_D12.independent_devices_enabled)); G_D12.validation_layer_enabled = CommandlineArgFromName(Lit("gpu-debug-validation")).exists;
G_D12.debug_layer_enabled = G_D12.validation_layer_enabled || CommandlineArgFromName(Lit("gpu-debug")).exists;
if (G_D12.independent_devices_enabled && IsRunningInWine())
{
LogInfoF("Wine detected, disabling D3D12 independent devices");
G_D12.independent_devices_enabled = 0;
}
LogInfoF("D3D12 independent devices enabled: %F", FmtSint(G_D12.independent_devices_enabled));
LogInfoF("D3D12 debug layer enabled: %F", FmtSint(G_D12.debug_layer_enabled));
LogInfoF("D3D12 validation layer enabled: %F", FmtSint(G_D12.validation_layer_enabled));
//////////////////////////////
//- Initialize independent device factory with Agility SDK
if (G_D12.independent_devices_enabled)
{
////////////////////////////// //////////////////////////////
//- Extract agility SDK //- Extract agility SDK
@ -59,17 +75,18 @@ void G_Bootstrap(void)
////////////////////////////// //////////////////////////////
//- Create device factory //- Create device factory
if (G_D12.independent_devices_enabled)
{ {
D3D12GetInterface(&CLSID_D3D12SDKConfiguration, &IID_ID3D12SDKConfiguration1, (void **)&G_D12.sdk_config); D3D12GetInterface(&CLSID_D3D12SDKConfiguration, &IID_ID3D12SDKConfiguration1, (void **)&G_D12.independent.sdk_config);
// Create device factory // Create device factory
char *sdk_dir_path_cstr = CstrFromString(scratch.arena, PathFromString(scratch.arena, sdk_dir_path, '\\')); char *sdk_dir_path_cstr = CstrFromString(scratch.arena, PathFromString(scratch.arena, sdk_dir_path, '\\'));
HRESULT hr = ID3D12SDKConfiguration1_CreateDeviceFactory( HRESULT hr = ID3D12SDKConfiguration1_CreateDeviceFactory(
G_D12.sdk_config, G_D12.independent.sdk_config,
sdk_ver_num, sdk_ver_num,
sdk_dir_path_cstr, sdk_dir_path_cstr,
&IID_ID3D12DeviceFactory, &IID_ID3D12DeviceFactory,
(void **)&G_D12.device_factory (void **)&G_D12.independent.device_factory
); );
if (FAILED(hr)) if (FAILED(hr))
{ {
@ -77,17 +94,18 @@ void G_Bootstrap(void)
} }
// Enable debug layer // Enable debug layer
if (GPU_DEBUG) if (G_D12.debug_layer_enabled)
{ {
ID3D12Debug1 *debug = 0; ID3D12Debug1 *debug = 0;
ID3D12DeviceFactory_GetConfigurationInterface(G_D12.device_factory, &CLSID_D3D12Debug, &IID_ID3D12Debug1, (void **)&debug); ID3D12DeviceFactory_GetConfigurationInterface(G_D12.independent.device_factory, &CLSID_D3D12Debug, &IID_ID3D12Debug1, (void **)&debug);
ID3D12Debug1_EnableDebugLayer(debug); ID3D12Debug1_EnableDebugLayer(debug);
if (GPU_DEBUG_VALIDATION) if (G_D12.validation_layer_enabled)
{ {
ID3D12Debug1_SetEnableGPUBasedValidation(debug, 1); ID3D12Debug1_SetEnableGPUBasedValidation(debug, 1);
} }
} }
} }
}
////////////////////////////// //////////////////////////////
//- Initialize device //- Initialize device
@ -98,7 +116,7 @@ void G_Bootstrap(void)
// Create dxgi factory // Create dxgi factory
{ {
u32 dxgi_factory_flags = 0; u32 dxgi_factory_flags = 0;
if (GPU_DEBUG) if (G_D12.debug_layer_enabled)
{ {
dxgi_factory_flags |= DXGI_CREATE_FACTORY_DEBUG; dxgi_factory_flags |= DXGI_CREATE_FACTORY_DEBUG;
} }
@ -133,7 +151,7 @@ void G_Bootstrap(void)
{ {
if (G_D12.independent_devices_enabled) if (G_D12.independent_devices_enabled)
{ {
hr = ID3D12DeviceFactory_CreateDevice(G_D12.device_factory, (IUnknown *)adapter, D3D_FEATURE_LEVEL_12_0, &IID_ID3D12Device10, (void **)&device); hr = ID3D12DeviceFactory_CreateDevice(G_D12.independent.device_factory, (IUnknown *)adapter, D3D_FEATURE_LEVEL_12_0, &IID_ID3D12Device10, (void **)&device);
} }
else else
{ {
@ -237,17 +255,8 @@ void G_Bootstrap(void)
G_D12.device = device; G_D12.device = device;
} }
// Retrieve device configuration
{
hr = ID3D12Device_QueryInterface(G_D12.device, &IID_ID3D12DeviceConfiguration, (void **)&G_D12.device_config);
if (FAILED(hr))
{
Panic(Lit("Failed to query ID3D12DeviceConfiguration interface"));
}
}
// Enable debug layer breaks // Enable debug layer breaks
if (GPU_DEBUG) if (G_D12.debug_layer_enabled)
{ {
// Enable D3D12 Debug break // Enable D3D12 Debug break
{ {
@ -275,11 +284,17 @@ void G_Bootstrap(void)
} }
} }
// Log device configuration // Retrieve device configuration
if (G_D12.independent_devices_enabled) if (G_D12.independent_devices_enabled)
{ {
hr = ID3D12Device_QueryInterface(G_D12.device, &IID_ID3D12DeviceConfiguration, (void **)&G_D12.independent.device_config);
if (FAILED(hr))
{
Panic(Lit("Failed to query ID3D12DeviceConfiguration interface"));
}
D3D12_DEVICE_CONFIGURATION_DESC desc = Zi; D3D12_DEVICE_CONFIGURATION_DESC desc = Zi;
ID3D12DeviceConfiguration_GetDesc(G_D12.device_config, &desc); ID3D12DeviceConfiguration_GetDesc(G_D12.independent.device_config, &desc);
StringList flags_list = Zi; StringList flags_list = Zi;
{ {
if (desc.Flags & D3D12_DEVICE_FLAG_DEBUG_LAYER_ENABLED) PushStringToList(scratch.arena, &flags_list, Lit("D3D12_DEVICE_FLAG_DEBUG_LAYER_ENABLED")); if (desc.Flags & D3D12_DEVICE_FLAG_DEBUG_LAYER_ENABLED) PushStringToList(scratch.arena, &flags_list, Lit("D3D12_DEVICE_FLAG_DEBUG_LAYER_ENABLED"));
@ -439,7 +454,7 @@ void G_Bootstrap(void)
desc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED | D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED; desc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED | D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED;
if (G_D12.independent_devices_enabled) if (G_D12.independent_devices_enabled)
{ {
hr = ID3D12DeviceConfiguration_SerializeVersionedRootSignature(G_D12.device_config, &desc, &blob, 0); hr = ID3D12DeviceConfiguration_SerializeVersionedRootSignature(G_D12.independent.device_config, &desc, &blob, 0);
} }
else else
{ {
@ -1111,7 +1126,6 @@ i64 G_D12_CommitRawCommandList(G_D12_RawCommandList *cl)
{ {
completion_target = ++queue->commit_fence_target; completion_target = ++queue->commit_fence_target;
cl->commit_fence_target = completion_target; cl->commit_fence_target = completion_target;
ID3D12CommandQueue_Signal(queue->d3d_queue, queue->commit_fence, completion_target); ID3D12CommandQueue_Signal(queue->d3d_queue, queue->commit_fence, completion_target);
// Append // Append

View File

@ -442,8 +442,10 @@ Struct(G_D12_AsyncCtx)
Struct(G_D12_Ctx) Struct(G_D12_Ctx)
{ {
b32 independent_devices_enabled;
IsolatedAtomic64 resource_creation_gen; IsolatedAtomic64 resource_creation_gen;
b32 independent_devices_enabled;
b32 debug_layer_enabled;
b32 validation_layer_enabled;
// Stats // Stats
Atomic64 arenas_count; Atomic64 arenas_count;
@ -476,10 +478,15 @@ Struct(G_D12_Ctx)
Mutex free_swapchains_mutex; Mutex free_swapchains_mutex;
G_D12_Swapchain *first_free_swapchain; G_D12_Swapchain *first_free_swapchain;
// Device // Independent device (only valid when independent_devices_enabled = 1)
struct
{
ID3D12SDKConfiguration1 *sdk_config; ID3D12SDKConfiguration1 *sdk_config;
ID3D12DeviceConfiguration *device_config; ID3D12DeviceConfiguration *device_config;
ID3D12DeviceFactory *device_factory; ID3D12DeviceFactory *device_factory;
} independent;
// Device
IDXGIFactory6 *dxgi_factory; IDXGIFactory6 *dxgi_factory;
IDXGIAdapter3 *dxgi_adapter; IDXGIAdapter3 *dxgi_adapter;
ID3D12Device10 *device; ID3D12Device10 *device;

View File

@ -2067,6 +2067,10 @@ P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick)
frame->world = world; frame->world = world;
frame->tick = tick; frame->tick = tick;
frame->time_ns = src_frame->time_ns; frame->time_ns = src_frame->time_ns;
frame->assembled_at_ns = src_frame->assembled_at_ns;
frame->base_time_ns = src_frame->base_time_ns;
frame->base_predict_from = src_frame->base_predict_from;
frame->base_predict_to = src_frame->base_predict_to;
frame->first_ent = &P_NilEnt; frame->first_ent = &P_NilEnt;
frame->last_ent = &P_NilEnt; frame->last_ent = &P_NilEnt;
@ -2412,8 +2416,8 @@ void P_StepFrame(P_Frame *frame)
{ {
if (Vec2Len(guy->v) > 0.001) if (Vec2Len(guy->v) > 0.001)
{ {
// f32 damp_force = TweakFloat("Guy damp force", 50, 0, 100); f32 damp_force = TweakFloat("Guy damp force", 50, 0, 100);
f32 damp_force = TweakFloat("Guy damp force", 0, 0, 100); // f32 damp_force = TweakFloat("Guy damp force", 0, 0, 100);
Vec2 damp = MulVec2(NegVec2(guy->v), damp_force * sim_dt); Vec2 damp = MulVec2(NegVec2(guy->v), damp_force * sim_dt);
guy->v = AddVec2(guy->v, damp); guy->v = AddVec2(guy->v, damp);
} }

View File

@ -369,6 +369,14 @@ Struct(P_Frame)
u64 fragments_count; u64 fragments_count;
u64 received_fragments_count; u64 received_fragments_count;
u64 received_fragment_bits[(P_MaxFrameSnapshotFragments + 63) / 64]; u64 received_fragment_bits[(P_MaxFrameSnapshotFragments + 63) / 64];
i64 assembled_at_ns;
//////////////////////////////
//- Prediction state
i64 base_time_ns;
i64 base_predict_from;
i64 base_predict_to;
}; };
Struct(P_FrameBin) Struct(P_FrameBin)

View File

@ -102,7 +102,7 @@ void S_TickForever(WaveLaneCtx *lane)
// TODO: Keep old frames around for player snapshot deltas // TODO: Keep old frames around for player snapshot deltas
P_ClearFrames(world, I64Min, prev_world_frame->tick - 1); P_ClearFrames(world, I64Min, prev_world_frame->tick - 1);
i64 time_ns = TimeNs(); i64 begin_time_ns = TimeNs();
////////////////////////////// //////////////////////////////
//- Swap //- Swap
@ -417,21 +417,27 @@ void S_TickForever(WaveLaneCtx *lane)
//- Apply bot controls //- Apply bot controls
{ {
b32 bot_movement_enabled = TweakBool("Bot movement enabled", 1); f32 move_bias = TweakFloat("Bot movement bias", 1, -1, 1);
f32 move_frequency = TweakFloat("Bot movement frequency", 0, 0, 10);
f32 turn_frequency = TweakFloat("Bot turn frequency", 0, 0, 10);
// b32 bot_movement_enabled = TweakBool("Bot movement enabled", 1);
for (P_Ent *bot = P_FirstEnt(world_frame); !P_IsEntNil(bot); bot = P_NextEnt(bot)) for (P_Ent *bot = P_FirstEnt(world_frame); !P_IsEntNil(bot); bot = P_NextEnt(bot))
{ {
if (bot->is_bot) if (bot->is_bot)
{ {
if (bot_movement_enabled) i64 alive_time_ns = world_frame->time_ns - bot->created_at_ns;
{ f64 alive_time = SecondsFromNs(alive_time_ns);
i64 alive_time_ns = time_ns - bot->created_at_ns; // i64 frequency_ns = NsFromSeconds(0.1);
i64 frequency_ns = NsFromSeconds(0.1); // bot->control.move.y = SinF32((f64)alive_time_ns / (f64)frequency_ns);
bot->control.move.y = SinF32((f64)alive_time_ns / (f64)frequency_ns);
} f32 move_t = alive_time * move_frequency * Tau;
else f32 look_t = alive_time * turn_frequency * Tau;
{
ZeroStruct(&bot->control.move); bot->control.move.y = SinF32(move_t);
} bot->control.move.y += move_bias;
bot->control.look = MulVec2(VEC2(CosF32(look_t), SinF32(look_t)), 3);
DEBUGBREAKABLE;
} }
} }
} }
@ -988,7 +994,7 @@ void S_TickForever(WaveLaneCtx *lane)
if (!shutdown) if (!shutdown)
{ {
i64 step_dt_ns = SIM_TICK_INTERVAL_NS; i64 step_dt_ns = SIM_TICK_INTERVAL_NS;
PLT_SleepFrame(time_ns, step_dt_ns); PLT_SleepFrame(begin_time_ns, step_dt_ns);
} }
} }

View File

@ -364,7 +364,7 @@ void V_TickForever(WaveLaneCtx *lane)
P_World *sim_world = P_AcquireWorld(); P_World *sim_world = P_AcquireWorld();
i64 cur_predict_world_seq = 0; i64 cur_predict_world_seq = 0;
P_World *predict_worlds[2] = Zi; P_World *predict_worlds[V_MaxInterpRatio] = Zi;
for (i64 predict_world_idx = 0; predict_world_idx < countof(predict_worlds); ++predict_world_idx) for (i64 predict_world_idx = 0; predict_world_idx < countof(predict_worlds); ++predict_world_idx)
{ {
predict_worlds[predict_world_idx] = P_AcquireWorld(); predict_worlds[predict_world_idx] = P_AcquireWorld();
@ -388,8 +388,9 @@ void V_TickForever(WaveLaneCtx *lane)
f64 most_recent_rtt = 0; f64 most_recent_rtt = 0;
// i64 smoothed_rtt_ns = 0; // i64 smoothed_rtt_ns = 0;
f64 smoothed_rtt = 0.0;
// f64 smoothed_rtt = 0.300; // f64 smoothed_rtt = 0.300;
f64 smoothed_rtt = 1.00; // f64 smoothed_rtt = 1.00;
// f64 smoothed_rtt = 2; // f64 smoothed_rtt = 2;
f32 smooth_remote_buffered_ticks = 0; f32 smooth_remote_buffered_ticks = 0;
@ -576,6 +577,8 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Begin frame //- Begin frame
i64 prev_frame_ack = ack;
V.cur_frame_tick += 1; V.cur_frame_tick += 1;
V_Frame *prev_frame = V_PrevFrame(); V_Frame *prev_frame = V_PrevFrame();
V_Frame *frame = V_CurrentFrame(); V_Frame *frame = V_CurrentFrame();
@ -1016,11 +1019,10 @@ void V_TickForever(WaveLaneCtx *lane)
Vec2 look_pos = frame->look; Vec2 look_pos = frame->look;
look_pos = RotateVec2(look_pos, InvertRot(rot)); look_pos = RotateVec2(look_pos, InvertRot(rot));
P_Ent *player = P_EntFromKey(frame->local_world->last_frame, V.player_key); P_Ent *follow = P_EntFromKey(frame->local_world->last_frame, V.follow_key);
P_Ent *guy = P_EntFromKey(frame->local_world->last_frame, player->guy); Vec2 follow_center = P_WorldShapeFromEnt(follow).centroid;
Vec2 guy_center = P_WorldShapeFromEnt(guy).centroid;
Vec2 screen_center = MulVec2(frame->screen_dims, 0.5); Vec2 screen_center = MulVec2(frame->screen_dims, 0.5);
target_camera_pos = guy_center; target_camera_pos = follow_center;
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(look_pos, look_ratio)); target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(look_pos, look_ratio));
target_camera_zoom = 1; target_camera_zoom = 1;
} }
@ -1028,6 +1030,12 @@ void V_TickForever(WaveLaneCtx *lane)
target_camera_pos.y = ClampF32(target_camera_pos.y, -world_pitch / 2, world_pitch / 2); target_camera_pos.y = ClampF32(target_camera_pos.y, -world_pitch / 2, world_pitch / 2);
target_camera_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom); target_camera_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom);
if (IsNan(target_camera_pos.x) || IsNan(target_camera_pos.y) || IsNan(target_camera_zoom))
{
target_camera_pos = VEC2(0, 0);
target_camera_zoom = 1;
}
// Interpolate camera // Interpolate camera
{ {
if (prev_frame->tick == 0) if (prev_frame->tick == 0)
@ -1302,6 +1310,7 @@ void V_TickForever(WaveLaneCtx *lane)
ack = dst_tick; ack = dst_tick;
ack_dt_ns = ack_received_at_ns - frame->time_ns; ack_dt_ns = ack_received_at_ns - frame->time_ns;
ack_received_at_ns = frame->time_ns; ack_received_at_ns = frame->time_ns;
dst_frame->assembled_at_ns = frame->time_ns;
} }
} }
} }
@ -1569,6 +1578,8 @@ void V_TickForever(WaveLaneCtx *lane)
} }
} }
P_Frame *ack_frame = P_FrameFromTick(sim_world, ack);
////////////////////////////// //////////////////////////////
//- Predict //- Predict
@ -1608,7 +1619,7 @@ void V_TickForever(WaveLaneCtx *lane)
i64 max_predict_ticks = SIM_TICKS_PER_SECOND; i64 max_predict_ticks = SIM_TICKS_PER_SECOND;
last_predict_tick = predict_to; last_predict_tick = predict_to;
first_predict_tick = ack; first_predict_tick = ack;
first_predict_tick = MaxI64(first_predict_tick, last_predict_tick - max_predict_ticks); // first_predict_tick = MaxI64(first_predict_tick, last_predict_tick - max_predict_ticks);
} }
@ -1629,12 +1640,23 @@ void V_TickForever(WaveLaneCtx *lane)
if (ack != prev_frame_ack)
{
ack_frame->base_time_ns = ack_frame->time_ns;
ack_frame->base_predict_from = ack_frame->tick;
ack_frame->base_predict_to = predict_to;
cur_predict_world_seq += 1;
}
// Predict // Predict
P_World *predict_world = predict_worlds[cur_predict_world_seq % countof(predict_worlds)]; P_World *predict_world = predict_worlds[cur_predict_world_seq % countof(predict_worlds)];
P_World *prev_predict_world = predict_worlds[MaxI64(cur_predict_world_seq - 1, 0) % countof(predict_worlds)];
P_Frame *predict_frame = predict_world->last_frame; P_Frame *predict_frame = predict_world->last_frame;
{ {
if (predict_world->tiles_hash != sim_world->tiles_hash) if (predict_world->tiles_hash != sim_world->tiles_hash)
@ -1645,7 +1667,8 @@ void V_TickForever(WaveLaneCtx *lane)
predict_world->seed = sim_world->seed; predict_world->seed = sim_world->seed;
// P_ClearFrames(predict_world, I64Min, MinI64(first_predict_tick - 1, prev_frame->blend_from_tick - 1)); // P_ClearFrames(predict_world, I64Min, MinI64(first_predict_tick - 1, prev_frame->blend_from_tick - 1));
P_ClearFrames(predict_world, I64Min, MinI64(first_predict_tick - 2, prev_frame->blend_from_tick - 1)); // P_ClearFrames(predict_world, I64Min, MinI64(first_predict_tick - 2, prev_frame->blend_from_tick - 1));
// P_ClearFrames(predict_world, I64Min, MinI64(first_predict_tick - V_MaxInterpRatio, prev_frame->blend_from_tick - 1));
predict_frame = P_PushFrame(predict_world, P_FrameFromTick(sim_world, first_predict_tick), first_predict_tick); predict_frame = P_PushFrame(predict_world, P_FrameFromTick(sim_world, first_predict_tick), first_predict_tick);
for (i64 predict_tick = first_predict_tick + 1; predict_tick <= last_predict_tick; ++predict_tick) for (i64 predict_tick = first_predict_tick + 1; predict_tick <= last_predict_tick; ++predict_tick)
@ -1866,8 +1889,8 @@ void V_TickForever(WaveLaneCtx *lane)
frame->local_world->seed = predict_world->seed; frame->local_world->seed = predict_world->seed;
P_ClearFrames(frame->local_world, I64Min, I64Max); P_ClearFrames(frame->local_world, I64Min, I64Max);
i64 target_blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor; // i64 target_blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor;
// i64 target_blend_dt_ns = frame->dt_ns; i64 target_blend_dt_ns = frame->dt_ns;
i64 blend_dt_ns = frame->dt_ns; i64 blend_dt_ns = frame->dt_ns;
V.target_blend_time_ns += target_blend_dt_ns; V.target_blend_time_ns += target_blend_dt_ns;
@ -1876,14 +1899,16 @@ void V_TickForever(WaveLaneCtx *lane)
// How many ticks back in time should the user thread blend between? // How many ticks back in time should the user thread blend between?
// <Delay> = <USER_INTERP_RATIO> * <Tick interval> // <Delay> = <USER_INTERP_RATIO> * <Tick interval>
// E.g: At 1.5, the world will render 75ms back in time if the sim runs at 50tps // E.g: At 1.5, the world will render 75ms back in time if the sim runs at 50tps
f32 interp_ratio = TweakFloat("Interpolation ratio", 1.2, 0, 5); f32 interp_ratio = TweakFloat("Interpolation ratio", 1.2, 0, V_MaxInterpRatio);
if (predict_to != prev_frame_predict_to) if (ack != prev_frame_ack)
{ {
i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio; i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio;
V.target_blend_time_ns = predict_world->last_frame->time_ns - delay_ns; V.target_blend_time_ns = ack_frame->time_ns - delay_ns;
} }
f64 blend_to_target_lerp_rate = 0.05; // f64 blend_to_target_lerp_rate = 0.05;
f64 blend_to_target_lerp_rate = 1;
// f64 blend_to_target_lerp_rate = 1;
V.blend_time_ns = LerpI64(V.blend_time_ns, V.target_blend_time_ns, blend_to_target_lerp_rate); V.blend_time_ns = LerpI64(V.blend_time_ns, V.target_blend_time_ns, blend_to_target_lerp_rate);
if (AbsI64(V.blend_time_ns - V.target_blend_time_ns) > (SIM_TICK_INTERVAL_NS * interp_ratio * 2)) if (AbsI64(V.blend_time_ns - V.target_blend_time_ns) > (SIM_TICK_INTERVAL_NS * interp_ratio * 2))
{ {
@ -1891,24 +1916,107 @@ void V_TickForever(WaveLaneCtx *lane)
V.blend_time_ns = V.target_blend_time_ns; V.blend_time_ns = V.target_blend_time_ns;
} }
if (TweakBool("Interpolation enabled", 1)) if (TweakBool("Interpolation enabled", 0))
{ {
P_Frame *left_predict_frame = &P_NilFrame; P_Frame *left_predict_frame = &P_NilFrame;
P_Frame *right_predict_frame = &P_NilFrame; P_Frame *right_predict_frame = &P_NilFrame;
for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev)
// for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev)
// {
// if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns)
// {
// right_predict_frame = tmp;
// left_predict_frame = tmp->prev;
// break;
// }
// }
{ {
if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) for (
i64 predict_world_seq = cur_predict_world_seq;
predict_world_seq > MaxI64(0, cur_predict_world_seq - countof(predict_worlds));
--predict_world_seq
)
{ {
right_predict_frame = tmp; i64 tmp_right_predict_world_idx = predict_world_seq % countof(predict_worlds);
left_predict_frame = tmp->prev; i64 tmp_left_predict_world_idx = (predict_world_seq - 1) % countof(predict_worlds);
P_World *tmp_right_world = predict_worlds[tmp_right_predict_world_idx];
P_World *tmp_left_world = predict_worlds[tmp_left_predict_world_idx];
// P_Frame *tmp_right = P_FrameFromTick(tmp_right_world, tmp_right_world->last_frame->base_predict_to);
// P_Frame *tmp_left = P_FrameFromTick(tmp_left_world, tmp_left_world->last_frame->base_predict_to);
// P_Frame *tmp_right = tmp_right_world->last_frame;
// P_Frame *tmp_left = tmp_left_world->last_frame;
P_Frame *tmp_right = P_FrameFromTick(tmp_right_world, tmp_right_world->last_frame->base_predict_from);
P_Frame *tmp_left = P_FrameFromTick(tmp_left_world, tmp_left_world->last_frame->base_predict_from);
// P_Frame *tmp_right = tmp_right_world->last_frame;
// P_Frame *tmp_left = tmp_left_world->last_frame;
if (tmp_right->base_time_ns >= V.blend_time_ns && tmp_left->base_time_ns <= V.blend_time_ns)
{
right_predict_frame = tmp_right;
left_predict_frame = tmp_left;
break; break;
} }
} }
// for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev)
// {
// if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns)
// {
// right_predict_frame = tmp;
// break;
// }
// }
// for (P_Frame *tmp = prev_predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev)
// {
// if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns)
// {
// left_predict_frame = tmp->prev;
// break;
// }
// }
}
// for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev)
// {
// if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns)
// {
// right_predict_frame = tmp;
// break;
// }
// }
// for (P_Frame *tmp = prev_predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev)
// {
// if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns)
// {
// left_predict_frame = tmp->prev;
// break;
// }
// }
if (P_IsFrameNil(left_predict_frame) || P_IsFrameNil(right_predict_frame)) if (P_IsFrameNil(left_predict_frame) || P_IsFrameNil(right_predict_frame))
{ {
LogDebugF("Missing blend");
right_predict_frame = predict_world->last_frame; right_predict_frame = predict_world->last_frame;
left_predict_frame = right_predict_frame->prev; // left_predict_frame = right_predict_frame->prev;
left_predict_frame = right_predict_frame;
} }
frame->blend_from_tick = left_predict_frame->tick; frame->blend_from_tick = left_predict_frame->tick;
@ -1916,6 +2024,9 @@ void V_TickForever(WaveLaneCtx *lane)
local_frame = P_PushFrame(frame->local_world, left_predict_frame, left_predict_frame->tick); local_frame = P_PushFrame(frame->local_world, left_predict_frame, left_predict_frame->tick);
{ {
P_Frame *left_sim_frame = left_predict_frame;
P_Frame *right_sim_frame = right_predict_frame;
// P_Frame *left_sim_frame = predict_world->first_frame; // P_Frame *left_sim_frame = predict_world->first_frame;
// P_Frame *right_sim_frame = left_sim_frame->next; // P_Frame *right_sim_frame = left_sim_frame->next;
@ -1926,12 +2037,17 @@ void V_TickForever(WaveLaneCtx *lane)
// P_Frame *right_sim_frame = P_FrameFromTick(sim_world, ack - 1); // P_Frame *right_sim_frame = P_FrameFromTick(sim_world, ack - 1);
// P_Frame *left_sim_frame = right_sim_frame->prev; // P_Frame *left_sim_frame = right_sim_frame->prev;
P_Frame *right_sim_frame = P_FrameFromTick(sim_world, right_predict_frame->src_tick); // P_Frame *right_sim_frame = P_FrameFromTick(sim_world, right_predict_frame->src_tick);
P_Frame *left_sim_frame = right_sim_frame->prev; // P_Frame *left_sim_frame = right_sim_frame->prev;
f64 blend_t = (f64)(V.blend_time_ns - left_predict_frame->base_time_ns) / (f64)(right_predict_frame->base_time_ns - left_predict_frame->base_time_ns);
if (IsInf(blend_t))
{
blend_t = 1;
}
f64 blend_t = (f64)(V.blend_time_ns - left_predict_frame->time_ns) / (f64)(right_predict_frame->time_ns - left_predict_frame->time_ns);
LogDebugF("blend_t: %F", FmtFloat(blend_t));
for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{ {
@ -2103,6 +2219,12 @@ void V_TickForever(WaveLaneCtx *lane)
P_Ent *local_player = P_EntFromKey(frame->local_world->last_frame, V.player_key); P_Ent *local_player = P_EntFromKey(frame->local_world->last_frame, V.player_key);
P_Ent *local_guy = P_EntFromKey(frame->local_world->last_frame, local_player->guy); P_Ent *local_guy = P_EntFromKey(frame->local_world->last_frame, local_player->guy);
P_Ent *local_follow = P_EntFromKey(frame->local_world->last_frame, V.follow_key);
if (P_IsEntNil(local_follow))
{
local_follow = local_guy;
V.follow_key = local_guy->key;
}
////////////////////////////// //////////////////////////////
//- Compute crosshair position //- Compute crosshair position
@ -2111,7 +2233,8 @@ void V_TickForever(WaveLaneCtx *lane)
if (!P_IsEntNil(local_guy)) if (!P_IsEntNil(local_guy))
{ {
P_Ent *ent = local_guy; // P_Ent *ent = local_guy;
P_Ent *ent = local_follow;
P_Anim anim = P_AnimFromEnt(local_frame, ent); P_Anim anim = P_AnimFromEnt(local_frame, ent);
SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq); SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq);
@ -2311,11 +2434,17 @@ void V_TickForever(WaveLaneCtx *lane)
} }
} }
if (frame->held_buttons[Button_V])
{
if (frame->held_buttons[Button_Shift])
{
V.follow_key = local_guy->key;
}
else if (!P_IsEntNil(hovered_ent))
{
V.follow_key = hovered_ent->key;
}
}
////////////////////////////// //////////////////////////////
//- Draw entities //- Draw entities
@ -2725,9 +2854,9 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Push test emitter //- Push test emitter
// if (frame->held_buttons[Button_F]) if (frame->held_buttons[Button_F])
// if (frame->held_buttons[Button_F] && !prev_frame->held_buttons[Button_F]) // if (frame->held_buttons[Button_F] && !prev_frame->held_buttons[Button_F])
if (0) // if (0)
{ {
{ {
V_Emitter emitter = Zi; V_Emitter emitter = Zi;
@ -2787,9 +2916,9 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Push test explosion //- Push test explosion
// if (frame->held_buttons[Button_G]) if (frame->held_buttons[Button_G])
// if (frame->held_buttons[Button_G] && !prev_frame->held_buttons[Button_G]) // if (frame->held_buttons[Button_G] && !prev_frame->held_buttons[Button_G])
if (0) // if (0)
{ {
// Fire // Fire
{ {
@ -5313,7 +5442,6 @@ void V_TickForever(WaveLaneCtx *lane)
G_DumbMemoryLayoutSync(cl, screen_target, G_Layout_DirectQueue_General); G_DumbMemoryLayoutSync(cl, screen_target, G_Layout_DirectQueue_General);
} }
////////////////////////////// //////////////////////////////
//- Set UI box texture //- Set UI box texture

View File

@ -218,6 +218,8 @@ Enum(V_DrawFlag)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ State types //~ State types
#define V_MaxInterpRatio 4
Struct(V_Frame) Struct(V_Frame)
{ {
Arena *arena; Arena *arena;
@ -255,6 +257,7 @@ Struct(V_Frame)
Struct(V_Ctx) Struct(V_Ctx)
{ {
P_EntKey player_key; P_EntKey player_key;
P_EntKey follow_key;
i64 panels_count; i64 panels_count;
i64 windows_count; i64 windows_count;