mirror of https://github.com/sm64pc/sm64pc.git
parent
e93a2bc14e
commit
aa5fe5fafd
6
Makefile
6
Makefile
|
@ -573,16 +573,16 @@ endif
|
||||||
|
|
||||||
ifeq ($(WINDOWS_BUILD),1)
|
ifeq ($(WINDOWS_BUILD),1)
|
||||||
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS)
|
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS)
|
||||||
CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -pthread
|
CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv
|
||||||
|
|
||||||
else ifeq ($(TARGET_WEB),1)
|
else ifeq ($(TARGET_WEB),1)
|
||||||
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -s USE_SDL=2
|
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -s USE_SDL=2
|
||||||
CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -pthread -s USE_SDL=2
|
CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -s USE_SDL=2
|
||||||
|
|
||||||
# Linux / Other builds below
|
# Linux / Other builds below
|
||||||
else
|
else
|
||||||
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(PLATFORM_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS)
|
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(PLATFORM_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS)
|
||||||
CFLAGS := $(OPT_FLAGS) $(PLATFORM_CFLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -pthread
|
CFLAGS := $(OPT_FLAGS) $(PLATFORM_CFLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check for enhancement options
|
# Check for enhancement options
|
||||||
|
|
|
@ -1922,10 +1922,10 @@ index 243a704..193a245 100644
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) {
|
for (size_t i = 0; i < sizeof(windows_scancode_table) / sizeof(SDL_Scancode); i++) {
|
||||||
diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c
|
diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c
|
||||||
index 98ddf78..c86a04a 100644
|
index 923e7ea..4fe6161 100644
|
||||||
--- a/src/pc/pc_main.c
|
--- a/src/pc/pc_main.c
|
||||||
+++ b/src/pc/pc_main.c
|
+++ b/src/pc/pc_main.c
|
||||||
@@ -130,6 +130,25 @@ void send_display_list(struct SPTask *spTask) {
|
@@ -83,6 +83,25 @@ void send_display_list(struct SPTask *spTask) {
|
||||||
#define SAMPLES_LOW 528
|
#define SAMPLES_LOW 528
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1951,8 +1951,8 @@ index 98ddf78..c86a04a 100644
|
||||||
void produce_one_frame(void) {
|
void produce_one_frame(void) {
|
||||||
gfx_start_frame();
|
gfx_start_frame();
|
||||||
|
|
||||||
@@ -146,6 +165,11 @@ void produce_one_frame(void) {
|
@@ -110,6 +129,11 @@ void produce_one_frame(void) {
|
||||||
thread6_rumble_loop(NULL);
|
audio_api->play((u8 *)audio_buffer, 2 * num_audio_samples * 4);
|
||||||
|
|
||||||
gfx_end_frame();
|
gfx_end_frame();
|
||||||
+
|
+
|
||||||
|
@ -1962,4 +1962,4 @@ index 98ddf78..c86a04a 100644
|
||||||
+ gfx_end_frame();
|
+ gfx_end_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seperate the audio thread from the main thread so that your ears won't bleed at a low framerate
|
void audio_shutdown(void) {
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include "seq_ids.h"
|
#include "seq_ids.h"
|
||||||
#include "dialog_ids.h"
|
#include "dialog_ids.h"
|
||||||
#include "level_table.h"
|
#include "level_table.h"
|
||||||
#include "pc/pc_main.h"
|
|
||||||
|
|
||||||
#ifdef VERSION_EU
|
#ifdef VERSION_EU
|
||||||
#define EU_FLOAT(x) x ## f
|
#define EU_FLOAT(x) x ## f
|
||||||
|
@ -775,7 +774,6 @@ void create_next_audio_buffer(s16 *samples, u32 num_samples) {
|
||||||
update_game_sound();
|
update_game_sound();
|
||||||
sGameLoopTicked = 0;
|
sGameLoopTicked = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 writtenCmds;
|
s32 writtenCmds;
|
||||||
synthesis_execute(gAudioCmdBuffers[0], &writtenCmds, samples, num_samples);
|
synthesis_execute(gAudioCmdBuffers[0], &writtenCmds, samples, num_samples);
|
||||||
gAudioRandom = ((gAudioRandom + gAudioFrameCount) * gAudioFrameCount);
|
gAudioRandom = ((gAudioRandom + gAudioFrameCount) * gAudioFrameCount);
|
||||||
|
@ -2350,10 +2348,6 @@ void sound_reset(u8 presetId) {
|
||||||
sUnused8033323C = 0;
|
sUnused8033323C = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Wait for audio thread to finish rendering
|
|
||||||
pc_wait_for_audio();
|
|
||||||
pc_request_gameloop_wait();
|
|
||||||
|
|
||||||
sGameLoopTicked = 0;
|
sGameLoopTicked = 0;
|
||||||
disable_all_sequence_players();
|
disable_all_sequence_players();
|
||||||
sound_init();
|
sound_init();
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include "pc/platform.h"
|
#include "pc/platform.h"
|
||||||
#include "pc/fs/fs.h"
|
#include "pc/fs/fs.h"
|
||||||
#include "pc/thread.h"
|
|
||||||
|
|
||||||
#define ALIGN16(val) (((val) + 0xF) & ~0xF)
|
#define ALIGN16(val) (((val) + 0xF) & ~0xF)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include "seqplayer.h"
|
#include "seqplayer.h"
|
||||||
#include "synthesis.h"
|
#include "synthesis.h"
|
||||||
#include "pc/thread.h"
|
|
||||||
|
|
||||||
#ifdef VERSION_EU
|
#ifdef VERSION_EU
|
||||||
|
|
||||||
|
@ -55,13 +54,6 @@ void create_next_audio_buffer(s16 *samples, u32 num_samples) {
|
||||||
if (osRecvMesg(OSMesgQueues[1], &msg, OS_MESG_NOBLOCK) != -1) {
|
if (osRecvMesg(OSMesgQueues[1], &msg, OS_MESG_NOBLOCK) != -1) {
|
||||||
func_802ad7ec((u32) msg);
|
func_802ad7ec((u32) msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the game thread is resetting the sound, don't process any audio commands
|
|
||||||
pcthread_mutex_lock(&pcthread_game_mutex); bool reseting_sound = pcthread_game_reset_sound; pcthread_mutex_unlock(&pcthread_game_mutex);
|
|
||||||
if (reseting_sound) {
|
|
||||||
printf("Audio thread: Dropped 1 frame\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
synthesis_execute(gAudioCmdBuffers[0], &writtenCmds, samples, num_samples);
|
synthesis_execute(gAudioCmdBuffers[0], &writtenCmds, samples, num_samples);
|
||||||
gAudioRandom = ((gAudioRandom + gAudioFrameCount) * gAudioFrameCount);
|
gAudioRandom = ((gAudioRandom + gAudioFrameCount) * gAudioFrameCount);
|
||||||
gAudioRandom = gAudioRandom + writtenCmds / 8;
|
gAudioRandom = gAudioRandom + writtenCmds / 8;
|
||||||
|
|
|
@ -54,8 +54,6 @@ unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME
|
||||||
unsigned int configMusicVolume = MAX_VOLUME;
|
unsigned int configMusicVolume = MAX_VOLUME;
|
||||||
unsigned int configSfxVolume = MAX_VOLUME;
|
unsigned int configSfxVolume = MAX_VOLUME;
|
||||||
unsigned int configEnvVolume = MAX_VOLUME;
|
unsigned int configEnvVolume = MAX_VOLUME;
|
||||||
float configAudioRunahead = 0.f;
|
|
||||||
float configAudioSleep = 1.f;
|
|
||||||
|
|
||||||
// Keyboard mappings (VK_ values, by default keyboard/gamepad/mouse)
|
// Keyboard mappings (VK_ values, by default keyboard/gamepad/mouse)
|
||||||
unsigned int configKeyA[MAX_BINDS] = { 0x0026, 0x1000, 0x1103 };
|
unsigned int configKeyA[MAX_BINDS] = { 0x0026, 0x1000, 0x1103 };
|
||||||
|
@ -108,8 +106,6 @@ static const struct ConfigOption options[] = {
|
||||||
{.name = "music_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configMusicVolume},
|
{.name = "music_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configMusicVolume},
|
||||||
{.name = "sfx_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configSfxVolume},
|
{.name = "sfx_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configSfxVolume},
|
||||||
{.name = "env_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configEnvVolume},
|
{.name = "env_volume", .type = CONFIG_TYPE_UINT, .uintValue = &configEnvVolume},
|
||||||
{.name = "audio_sleep", .type = CONFIG_TYPE_FLOAT, .floatValue = &configAudioSleep},
|
|
||||||
{.name = "audio_runahead", .type = CONFIG_TYPE_FLOAT, .floatValue = &configAudioRunahead},
|
|
||||||
{.name = "key_a", .type = CONFIG_TYPE_BIND, .uintValue = configKeyA},
|
{.name = "key_a", .type = CONFIG_TYPE_BIND, .uintValue = configKeyA},
|
||||||
{.name = "key_b", .type = CONFIG_TYPE_BIND, .uintValue = configKeyB},
|
{.name = "key_b", .type = CONFIG_TYPE_BIND, .uintValue = configKeyB},
|
||||||
{.name = "key_start", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStart},
|
{.name = "key_start", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStart},
|
||||||
|
|
|
@ -23,8 +23,6 @@ extern unsigned int configMasterVolume;
|
||||||
extern unsigned int configMusicVolume;
|
extern unsigned int configMusicVolume;
|
||||||
extern unsigned int configSfxVolume;
|
extern unsigned int configSfxVolume;
|
||||||
extern unsigned int configEnvVolume;
|
extern unsigned int configEnvVolume;
|
||||||
extern float configAudioRunahead;
|
|
||||||
extern float configAudioSleep;
|
|
||||||
extern unsigned int configKeyA[];
|
extern unsigned int configKeyA[];
|
||||||
extern unsigned int configKeyB[];
|
extern unsigned int configKeyB[];
|
||||||
extern unsigned int configKeyStart[];
|
extern unsigned int configKeyStart[];
|
||||||
|
|
137
src/pc/pc_main.c
137
src/pc/pc_main.c
|
@ -1,9 +1,5 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h> //Header file for sleep(). man 3 sleep for details.
|
|
||||||
#include <time.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#ifdef TARGET_WEB
|
#ifdef TARGET_WEB
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
|
@ -29,7 +25,6 @@
|
||||||
#include "audio/audio_null.h"
|
#include "audio/audio_null.h"
|
||||||
|
|
||||||
#include "pc_main.h"
|
#include "pc_main.h"
|
||||||
#include "thread.h"
|
|
||||||
#include "cliopts.h"
|
#include "cliopts.h"
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include "controller/controller_api.h"
|
#include "controller/controller_api.h"
|
||||||
|
@ -39,7 +34,6 @@
|
||||||
#include "game/game_init.h"
|
#include "game/game_init.h"
|
||||||
#include "game/main.h"
|
#include "game/main.h"
|
||||||
#include "game/thread6.h"
|
#include "game/thread6.h"
|
||||||
#include "game/display.h"
|
|
||||||
|
|
||||||
#ifdef DISCORDRPC
|
#ifdef DISCORDRPC
|
||||||
#include "pc/discord/discordrpc.h"
|
#include "pc/discord/discordrpc.h"
|
||||||
|
@ -62,24 +56,10 @@ static struct AudioAPI *audio_api;
|
||||||
static struct GfxWindowManagerAPI *wm_api;
|
static struct GfxWindowManagerAPI *wm_api;
|
||||||
static struct GfxRenderingAPI *rendering_api;
|
static struct GfxRenderingAPI *rendering_api;
|
||||||
|
|
||||||
sys_thread_t pcthread_audio_id;
|
|
||||||
sys_mutex_t pcthread_audio_mutex = SYS_MUTEX_INITIALIZER;
|
|
||||||
bool pcthread_audio_init = false;
|
|
||||||
bool pcthread_audio_rendering = false;
|
|
||||||
sys_sem_t pcthread_audio_sema;
|
|
||||||
|
|
||||||
sys_mutex_t pcthread_game_mutex = SYS_MUTEX_INITIALIZER;
|
|
||||||
bool pcthread_game_loop_iterating = false;
|
|
||||||
bool pcthread_game_reset_sound = false;
|
|
||||||
bool pcthread_wait_for_gameloop = false;
|
|
||||||
sys_sem_t pcthread_game_sema;
|
|
||||||
|
|
||||||
extern void gfx_run(Gfx *commands);
|
extern void gfx_run(Gfx *commands);
|
||||||
extern void thread5_game_loop(void *arg);
|
extern void thread5_game_loop(void *arg);
|
||||||
extern void audio_game_loop_tick(void);
|
|
||||||
extern void create_next_audio_buffer(s16 *samples, u32 num_samples);
|
extern void create_next_audio_buffer(s16 *samples, u32 num_samples);
|
||||||
void game_loop_one_iteration(void);
|
void game_loop_one_iteration(void);
|
||||||
void* audio_thread();
|
|
||||||
|
|
||||||
void dispatch_audio_sptask(struct SPTask *spTask) {
|
void dispatch_audio_sptask(struct SPTask *spTask) {
|
||||||
}
|
}
|
||||||
|
@ -87,36 +67,9 @@ void dispatch_audio_sptask(struct SPTask *spTask) {
|
||||||
void set_vblank_handler(s32 index, struct VblankHandler *handler, OSMesgQueue *queue, OSMesg *msg) {
|
void set_vblank_handler(s32 index, struct VblankHandler *handler, OSMesgQueue *queue, OSMesg *msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a request for non-game threads to wait for the game thread to finish
|
|
||||||
void pc_request_gameloop_wait(void) {
|
|
||||||
sys_mutex_lock(&pcthread_game_mutex);
|
|
||||||
pcthread_wait_for_gameloop = true;
|
|
||||||
sys_mutex_unlock(&pcthread_game_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the audio thread to finish rendering audio
|
|
||||||
void pc_wait_for_audio(void) {
|
|
||||||
sys_semaphore_wait(&pcthread_audio_sema);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the audio thread is currently rendering audio
|
|
||||||
bool pc_check_audio_rendering(void) {
|
|
||||||
sys_mutex_lock(&pcthread_audio_mutex);
|
|
||||||
bool rendering = pcthread_audio_rendering;
|
|
||||||
sys_mutex_unlock(&pcthread_audio_mutex);
|
|
||||||
return rendering;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the game thread should finish before continuing
|
|
||||||
bool pc_check_gameloop_wait(void) {
|
|
||||||
sys_mutex_lock(&pcthread_game_mutex);
|
|
||||||
bool waiting = pcthread_wait_for_gameloop;
|
|
||||||
sys_mutex_unlock(&pcthread_game_mutex);
|
|
||||||
return waiting;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool inited = false;
|
static bool inited = false;
|
||||||
|
|
||||||
|
#include "game/display.h" // for gGlobalTimer
|
||||||
void send_display_list(struct SPTask *spTask) {
|
void send_display_list(struct SPTask *spTask) {
|
||||||
if (!inited) return;
|
if (!inited) return;
|
||||||
gfx_run((Gfx *)spTask->task.t.data_ptr);
|
gfx_run((Gfx *)spTask->task.t.data_ptr);
|
||||||
|
@ -133,92 +86,33 @@ void send_display_list(struct SPTask *spTask) {
|
||||||
void produce_one_frame(void) {
|
void produce_one_frame(void) {
|
||||||
gfx_start_frame();
|
gfx_start_frame();
|
||||||
|
|
||||||
game_loop_one_iteration();
|
|
||||||
|
|
||||||
// Post the game thread semaphore if the game thread requested it
|
|
||||||
sys_mutex_lock(&pcthread_game_mutex);
|
|
||||||
if (pcthread_wait_for_gameloop) {
|
|
||||||
sys_semaphore_post(&pcthread_game_sema);
|
|
||||||
pcthread_wait_for_gameloop = false;
|
|
||||||
}
|
|
||||||
sys_mutex_unlock(&pcthread_game_mutex);
|
|
||||||
|
|
||||||
thread6_rumble_loop(NULL);
|
|
||||||
|
|
||||||
gfx_end_frame();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seperate the audio thread from the main thread so that your ears won't bleed at a low framerate
|
|
||||||
void* audio_thread() {
|
|
||||||
// Keep track of the time in microseconds
|
|
||||||
const f64 frametime_micro = 16666.666; // 16.666666 ms = 60Hz; run this thread 60 times a second like the original game
|
|
||||||
f64 start_time;
|
|
||||||
f64 end_time;
|
|
||||||
bool doloop = true;
|
|
||||||
sys_semaphore_wait(&pcthread_game_sema);
|
|
||||||
while(doloop) {
|
|
||||||
start_time = sys_profile_time();
|
|
||||||
const f32 master_mod = (f32)configMasterVolume / 127.0f;
|
const f32 master_mod = (f32)configMasterVolume / 127.0f;
|
||||||
set_sequence_player_volume(SEQ_PLAYER_LEVEL, (f32)configMusicVolume / 127.0f * master_mod);
|
set_sequence_player_volume(SEQ_PLAYER_LEVEL, (f32)configMusicVolume / 127.0f * master_mod);
|
||||||
set_sequence_player_volume(SEQ_PLAYER_SFX, (f32)configSfxVolume / 127.0f * master_mod);
|
set_sequence_player_volume(SEQ_PLAYER_SFX, (f32)configSfxVolume / 127.0f * master_mod);
|
||||||
set_sequence_player_volume(SEQ_PLAYER_ENV, (f32)configEnvVolume / 127.0f * master_mod);
|
set_sequence_player_volume(SEQ_PLAYER_ENV, (f32)configEnvVolume / 127.0f * master_mod);
|
||||||
|
|
||||||
int samples_left = audio_api->buffered() - (audio_api->get_desired_buffered() * configAudioRunahead);
|
game_loop_one_iteration();
|
||||||
if (samples_left < 0) samples_left = 0;
|
thread6_rumble_loop(NULL);
|
||||||
|
|
||||||
|
int samples_left = audio_api->buffered();
|
||||||
u32 num_audio_samples = samples_left < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW;
|
u32 num_audio_samples = samples_left < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW;
|
||||||
// printf("Audio samples: %d %u\n", samples_left, num_audio_samples);
|
//printf("Audio samples: %d %u\n", samples_left, num_audio_samples);
|
||||||
s16 audio_buffer[SAMPLES_HIGH * 2];
|
s16 audio_buffer[SAMPLES_HIGH * 2 * 2];
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
/*if (audio_cnt-- == 0) {
|
/*if (audio_cnt-- == 0) {
|
||||||
audio_cnt = 2;
|
audio_cnt = 2;
|
||||||
}
|
}
|
||||||
u32 num_audio_samples = audio_cnt < 2 ? 528 : 544;*/
|
u32 num_audio_samples = audio_cnt < 2 ? 528 : 544;*/
|
||||||
|
create_next_audio_buffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples);
|
||||||
if (!pc_check_gameloop_wait()) {
|
|
||||||
sys_mutex_lock(&pcthread_audio_mutex);
|
|
||||||
pcthread_audio_rendering = true;
|
|
||||||
sys_mutex_unlock(&pcthread_audio_mutex);
|
|
||||||
create_next_audio_buffer(audio_buffer, num_audio_samples);
|
|
||||||
sys_semaphore_post(&pcthread_audio_sema);
|
|
||||||
sys_mutex_lock(&pcthread_audio_mutex);
|
|
||||||
pcthread_audio_rendering = false;
|
|
||||||
sys_mutex_unlock(&pcthread_audio_mutex);
|
|
||||||
} /* else {
|
|
||||||
printf("Audio thread: dropped frame\n");
|
|
||||||
} */
|
|
||||||
|
|
||||||
// printf("Audio samples before submitting: %d\n", audio_api->buffered());
|
|
||||||
audio_api->play((u8 *)audio_buffer, num_audio_samples * 4);
|
|
||||||
|
|
||||||
end_time = sys_profile_time();
|
|
||||||
|
|
||||||
// Sleep for the remaining time
|
|
||||||
f64 nap_time = (frametime_micro - (end_time - start_time)) * configAudioSleep;
|
|
||||||
// printf("Audio thread nap time: %f\n", nap_time);
|
|
||||||
if (nap_time > 0.0) sys_sleep(nap_time);
|
|
||||||
|
|
||||||
// Check if the game thread is still running
|
|
||||||
sys_mutex_lock(&pcthread_audio_mutex);
|
|
||||||
doloop = pcthread_audio_init;
|
|
||||||
sys_mutex_unlock(&pcthread_audio_mutex);
|
|
||||||
}
|
}
|
||||||
return NULL;
|
//printf("Audio samples before submitting: %d\n", audio_api->buffered());
|
||||||
}
|
|
||||||
|
|
||||||
void audio_thread_init() {
|
audio_api->play((u8 *)audio_buffer, 2 * num_audio_samples * 4);
|
||||||
pcthread_audio_init = true;
|
|
||||||
sys_semaphore_init(&pcthread_audio_sema, 0, 1);
|
gfx_end_frame();
|
||||||
sys_thread_create(&pcthread_audio_id, audio_thread, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_shutdown(void) {
|
void audio_shutdown(void) {
|
||||||
// Tell the audio thread to stop
|
|
||||||
sys_mutex_lock(&pcthread_audio_mutex);
|
|
||||||
pcthread_audio_init = false;
|
|
||||||
sys_mutex_unlock(&pcthread_audio_mutex);
|
|
||||||
sys_semaphore_wait(&pcthread_audio_sema); // Wait for the audio thread to finish rendering audio, then destroy it all
|
|
||||||
sys_thread_join(&pcthread_audio_id, NULL);
|
|
||||||
sys_semaphore_destroy(&pcthread_audio_sema);
|
|
||||||
|
|
||||||
if (audio_api) {
|
if (audio_api) {
|
||||||
if (audio_api->shutdown) audio_api->shutdown();
|
if (audio_api->shutdown) audio_api->shutdown();
|
||||||
audio_api = NULL;
|
audio_api = NULL;
|
||||||
|
@ -233,7 +127,6 @@ void game_deinit(void) {
|
||||||
controller_shutdown();
|
controller_shutdown();
|
||||||
audio_shutdown();
|
audio_shutdown();
|
||||||
gfx_shutdown();
|
gfx_shutdown();
|
||||||
sys_semaphore_destroy(&pcthread_game_sema);
|
|
||||||
inited = false;
|
inited = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,10 +257,6 @@ void main_func(void) {
|
||||||
emscripten_set_main_loop(em_main_loop, 0, 0);
|
emscripten_set_main_loop(em_main_loop, 0, 0);
|
||||||
request_anim_frame(on_anim_frame);
|
request_anim_frame(on_anim_frame);
|
||||||
#else
|
#else
|
||||||
// initialize multithreading
|
|
||||||
sys_semaphore_init(&pcthread_game_sema, 0, 0);
|
|
||||||
audio_thread_init();
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
wm_api->main_loop(produce_one_frame);
|
wm_api->main_loop(produce_one_frame);
|
||||||
#ifdef DISCORDRPC
|
#ifdef DISCORDRPC
|
||||||
|
|
|
@ -5,16 +5,9 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
void game_deinit(void);
|
void game_deinit(void);
|
||||||
void game_exit(void);
|
void game_exit(void);
|
||||||
|
|
||||||
void pc_request_gameloop_wait(void);
|
|
||||||
void pc_wait_for_audio(void);
|
|
||||||
bool pc_check_audio_rendering(void);
|
|
||||||
bool pc_check_gameloop_wait(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,13 +11,6 @@
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
#if !defined(HAVE_SDL2) && !defined(CLOCK_MONOTONIC)
|
|
||||||
#include <sys/time.h>
|
|
||||||
#elif defined(HAVE_SDL2)
|
|
||||||
// we can just ask SDL for most of this shit if we have it
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* NULL terminated list of platform specific read-only data paths */
|
/* NULL terminated list of platform specific read-only data paths */
|
||||||
/* priority is top first */
|
/* priority is top first */
|
||||||
const char *sys_ropaths[] = {
|
const char *sys_ropaths[] = {
|
||||||
|
@ -80,24 +73,6 @@ void sys_sleep(const uint64_t us) {
|
||||||
usleep(us);
|
usleep(us);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A high-resolution profiling timer. Returns the current time in microseconds.
|
|
||||||
double sys_profile_time(void) {
|
|
||||||
#if defined(HAVE_SDL2)
|
|
||||||
static double freq = 0.0;
|
|
||||||
if (freq == 0.0)
|
|
||||||
freq = (double)SDL_GetPerformanceFrequency() / 1000000.0;
|
|
||||||
return (double)SDL_GetPerformanceCounter() / freq;
|
|
||||||
#elif defined(CLOCK_MONOTONIC)
|
|
||||||
struct timespec tv;
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &tv);
|
|
||||||
return (double)tv.tv_nsec / 1000.0 + (double)tv.tv_sec * 1000000.0;
|
|
||||||
#else
|
|
||||||
struct timeval tv;
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
return (double)tv.tv_usec + (double)tv.tv_sec * 1000000.0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this calls a platform-specific impl function after forming the error message */
|
/* this calls a platform-specific impl function after forming the error message */
|
||||||
|
|
||||||
static void sys_fatal_impl(const char *msg) __attribute__ ((noreturn));
|
static void sys_fatal_impl(const char *msg) __attribute__ ((noreturn));
|
||||||
|
@ -114,6 +89,9 @@ void sys_fatal(const char *fmt, ...) {
|
||||||
|
|
||||||
#ifdef HAVE_SDL2
|
#ifdef HAVE_SDL2
|
||||||
|
|
||||||
|
// we can just ask SDL for most of this shit if we have it
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
// TEMPORARY: check the old save folder and copy contents to the new path
|
// TEMPORARY: check the old save folder and copy contents to the new path
|
||||||
// this will be removed after a while
|
// this will be removed after a while
|
||||||
static inline bool copy_userdata(const char *userdir) {
|
static inline bool copy_userdata(const char *userdir) {
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <semaphore.h>
|
|
||||||
|
|
||||||
/* Platform-specific functions and whatnot */
|
/* Platform-specific functions and whatnot */
|
||||||
|
|
||||||
|
@ -21,7 +18,6 @@ char *sys_strdup(const char *src);
|
||||||
char *sys_strlwr(char *src);
|
char *sys_strlwr(char *src);
|
||||||
int sys_strcasecmp(const char *s1, const char *s2);
|
int sys_strcasecmp(const char *s1, const char *s2);
|
||||||
void sys_sleep(const uint64_t us);
|
void sys_sleep(const uint64_t us);
|
||||||
double sys_profile_time(void);
|
|
||||||
|
|
||||||
// path stuff
|
// path stuff
|
||||||
const char *sys_user_path(void);
|
const char *sys_user_path(void);
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
#include "thread.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_THREADS
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <semaphore.h>
|
|
||||||
|
|
||||||
int sys_thread_create(sys_thread_t *thread, sys_thread_func_t func, void *arg) {
|
|
||||||
return pthread_create(thread, NULL, func, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
int sys_thread_join(sys_thread_t *thread, void **result) {
|
|
||||||
return pthread_join(*thread, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_mutex_lock(sys_mutex_t *mutex) {
|
|
||||||
pthread_mutex_lock(mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_mutex_unlock(sys_mutex_t *mutex) {
|
|
||||||
pthread_mutex_unlock(mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_semaphore_init(sys_sem_t *sem, int pshared, unsigned int value) {
|
|
||||||
sem_init(sem, pshared, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_semaphore_wait(sys_sem_t *sem) {
|
|
||||||
sem_wait(sem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_semaphore_post(sys_sem_t *sem) {
|
|
||||||
sem_post(sem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_semaphore_destroy(sys_sem_t *sem) {
|
|
||||||
sem_destroy(sem);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#error "Implement thread.c for your platform."
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,30 +0,0 @@
|
||||||
#ifndef _PC_THREAD_H
|
|
||||||
#define _PC_THREAD_H
|
|
||||||
|
|
||||||
// TODO: add other backends if required
|
|
||||||
#define HAVE_POSIX_THREADS 1
|
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_THREADS
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <semaphore.h>
|
|
||||||
typedef pthread_t sys_thread_t;
|
|
||||||
typedef void *(*sys_thread_func_t)(void *);
|
|
||||||
typedef pthread_mutex_t sys_mutex_t;
|
|
||||||
typedef sem_t sys_sem_t;
|
|
||||||
#define SYS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
|
||||||
#else
|
|
||||||
#error "Implement thread.c for your platform."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int sys_thread_create(sys_thread_t *thread, sys_thread_func_t func, void *arg);
|
|
||||||
int sys_thread_join(sys_thread_t *thread, void **result);
|
|
||||||
|
|
||||||
void sys_mutex_lock(sys_mutex_t *mutex);
|
|
||||||
void sys_mutex_unlock(sys_mutex_t *mutex);
|
|
||||||
|
|
||||||
void sys_semaphore_init(sys_sem_t *sem, int pshared, unsigned int value);
|
|
||||||
void sys_semaphore_wait(sys_sem_t *sem);
|
|
||||||
void sys_semaphore_post(sys_sem_t *sem);
|
|
||||||
void sys_semaphore_destroy(sys_sem_t *sem);
|
|
||||||
|
|
||||||
#endif // _PC_THREAD_H
|
|
Loading…
Reference in New Issue