mirror of https://github.com/inolen/redream.git
added host debug menu
added audio/video sync option enabled video sync by default
This commit is contained in:
parent
b3e1b38047
commit
a080c5d71f
190
src/emulator.c
190
src/emulator.c
|
@ -120,13 +120,7 @@ struct emu {
|
|||
list which will be processed the next time the threads are synchronized */
|
||||
struct list modified_textures;
|
||||
|
||||
/* debug stats */
|
||||
int frame_stats;
|
||||
float swap_times[360];
|
||||
int64_t last_swap;
|
||||
|
||||
/* debugging */
|
||||
int debug_menu;
|
||||
struct trace_writer *trace_writer;
|
||||
};
|
||||
|
||||
|
@ -469,102 +463,6 @@ static void emu_set_aspect_ratio(struct emu *emu, const char *new_ratio) {
|
|||
emu->aspect_ratio = i;
|
||||
}
|
||||
|
||||
static void emu_debug_menu(struct emu *emu) {
|
||||
#ifdef HAVE_IMGUI
|
||||
if (!emu->debug_menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (igBeginMainMenuBar()) {
|
||||
if (igBeginMenu("EMU", 1)) {
|
||||
if (igMenuItem("frame stats", NULL, emu->frame_stats, 1)) {
|
||||
emu->frame_stats = !emu->frame_stats;
|
||||
}
|
||||
if (!emu->trace_writer && igMenuItem("start trace", NULL, 0, 1)) {
|
||||
emu_start_tracing(emu);
|
||||
}
|
||||
if (emu->trace_writer && igMenuItem("stop trace", NULL, 1, 1)) {
|
||||
emu_stop_tracing(emu);
|
||||
}
|
||||
if (igMenuItem("clear texture cache", NULL, 0, 1)) {
|
||||
emu_dirty_textures(emu);
|
||||
}
|
||||
igEndMenu();
|
||||
}
|
||||
|
||||
igEndMainMenuBar();
|
||||
}
|
||||
|
||||
holly_debug_menu(emu->dc->holly);
|
||||
aica_debug_menu(emu->dc->aica);
|
||||
arm7_debug_menu(emu->dc->arm7);
|
||||
sh4_debug_menu(emu->dc->sh4);
|
||||
|
||||
/* add status */
|
||||
if (igBeginMainMenuBar()) {
|
||||
char status[128];
|
||||
int frames = (int)prof_counter_load(COUNTER_frames);
|
||||
int ta_renders = (int)prof_counter_load(COUNTER_ta_renders);
|
||||
int pvr_vblanks = (int)prof_counter_load(COUNTER_pvr_vblanks);
|
||||
int sh4_instrs = (int)(prof_counter_load(COUNTER_sh4_instrs) / 1000000.0f);
|
||||
int arm7_instrs =
|
||||
(int)(prof_counter_load(COUNTER_arm7_instrs) / 1000000.0f);
|
||||
|
||||
snprintf(status, sizeof(status), "FPS %3d RPS %3d VBS %3d SH4 %4d ARM %d",
|
||||
frames, ta_renders, pvr_vblanks, sh4_instrs, arm7_instrs);
|
||||
|
||||
/* right align */
|
||||
struct ImVec2 content;
|
||||
struct ImVec2 size;
|
||||
igGetContentRegionMax(&content);
|
||||
igCalcTextSize(&size, status, NULL, 0, 0.0f);
|
||||
igSetCursorPosX(content.x - size.x);
|
||||
igText(status);
|
||||
|
||||
igEndMainMenuBar();
|
||||
}
|
||||
|
||||
if (emu->frame_stats) {
|
||||
bool opened = true;
|
||||
|
||||
if (igBegin("frame stats", &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
/* memory accesses */
|
||||
{
|
||||
igValueInt("mmio reads", (int)prof_counter_load(COUNTER_mmio_read));
|
||||
igValueInt("mmio writes", (int)prof_counter_load(COUNTER_mmio_write));
|
||||
}
|
||||
|
||||
/* swap times */
|
||||
{
|
||||
struct ImVec2 graph_size = {300.0f, 50.0f};
|
||||
int num_swap_times = ARRAY_SIZE(emu->swap_times);
|
||||
|
||||
float min_time = FLT_MAX;
|
||||
float max_time = -FLT_MAX;
|
||||
float avg_time = 0.0f;
|
||||
for (int i = 0; i < num_swap_times; i++) {
|
||||
float time = emu->swap_times[i];
|
||||
min_time = MIN(min_time, time);
|
||||
max_time = MAX(max_time, time);
|
||||
avg_time += time;
|
||||
}
|
||||
avg_time /= num_swap_times;
|
||||
|
||||
igValueFloat("min swap time", min_time, "%.2f");
|
||||
igValueFloat("max swap time", max_time, "%.2f");
|
||||
igValueFloat("avg swap time", avg_time, "%.2f");
|
||||
igPlotLines("", emu->swap_times, num_swap_times,
|
||||
emu->frame % num_swap_times, NULL, 0.0f, 60.0f, graph_size,
|
||||
sizeof(float));
|
||||
}
|
||||
}
|
||||
igEnd();
|
||||
|
||||
emu->frame_stats = (int)opened;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* frame running logic
|
||||
*/
|
||||
|
@ -622,9 +520,6 @@ void emu_render_frame(struct emu *emu) {
|
|||
the host will render the ui completely unthrottled */
|
||||
uint32_t silence[AICA_SAMPLE_FREQ / 60] = {0};
|
||||
audio_push(emu->host, (int16_t *)silence, ARRAY_SIZE(silence));
|
||||
|
||||
emu_debug_menu(emu);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -678,20 +573,11 @@ void emu_render_frame(struct emu *emu) {
|
|||
---------------------------------------------------------------------------
|
||||
| emu_vblank_out sets EMU_ENDFRAME */
|
||||
|
||||
/* ensure the emulation thread isn't still executing a previous frame */
|
||||
if (emu->multi_threaded) {
|
||||
mutex_lock(emu->req_mutex);
|
||||
mutex_unlock(emu->req_mutex);
|
||||
}
|
||||
|
||||
/* build the debug menus before running the frame, while the two threads
|
||||
are synchronized */
|
||||
emu_debug_menu(emu);
|
||||
|
||||
/* request a frame to be ran */
|
||||
if (emu->multi_threaded) {
|
||||
mutex_lock(emu->req_mutex);
|
||||
|
||||
CHECK_EQ(emu->state, EMU_WAITING);
|
||||
emu->state = EMU_RUNFRAME;
|
||||
cond_signal(emu->req_cond);
|
||||
|
||||
|
@ -744,15 +630,68 @@ void emu_render_frame(struct emu *emu) {
|
|||
and vblank_out at this point, but there's no need to wait for it */
|
||||
}
|
||||
|
||||
void emu_debug_menu(struct emu *emu) {
|
||||
#ifdef HAVE_IMGUI
|
||||
/* ensure the emulation thread isn't still executing a previous frame */
|
||||
if (emu->multi_threaded) {
|
||||
mutex_lock(emu->req_mutex);
|
||||
CHECK_EQ(emu->state, EMU_WAITING);
|
||||
mutex_unlock(emu->req_mutex);
|
||||
}
|
||||
|
||||
if (igBeginMainMenuBar()) {
|
||||
if (igBeginMenu("EMU", 1)) {
|
||||
if (igMenuItem("clear texture cache", NULL, 0, 1)) {
|
||||
emu_dirty_textures(emu);
|
||||
}
|
||||
if (!emu->trace_writer && igMenuItem("start trace", NULL, 0, 1)) {
|
||||
emu_start_tracing(emu);
|
||||
}
|
||||
if (emu->trace_writer && igMenuItem("stop trace", NULL, 1, 1)) {
|
||||
emu_stop_tracing(emu);
|
||||
}
|
||||
igEndMenu();
|
||||
}
|
||||
|
||||
igEndMainMenuBar();
|
||||
}
|
||||
|
||||
holly_debug_menu(emu->dc->holly);
|
||||
aica_debug_menu(emu->dc->aica);
|
||||
arm7_debug_menu(emu->dc->arm7);
|
||||
sh4_debug_menu(emu->dc->sh4);
|
||||
|
||||
/* add status */
|
||||
if (igBeginMainMenuBar()) {
|
||||
char status[128];
|
||||
int frames = (int)prof_counter_load(COUNTER_frames);
|
||||
int ta_renders = (int)prof_counter_load(COUNTER_ta_renders);
|
||||
int pvr_vblanks = (int)prof_counter_load(COUNTER_pvr_vblanks);
|
||||
int sh4_instrs = (int)(prof_counter_load(COUNTER_sh4_instrs) / 1000000.0f);
|
||||
int arm7_instrs =
|
||||
(int)(prof_counter_load(COUNTER_arm7_instrs) / 1000000.0f);
|
||||
|
||||
snprintf(status, sizeof(status), "FPS %3d RPS %3d VBS %3d SH4 %4d ARM %d",
|
||||
frames, ta_renders, pvr_vblanks, sh4_instrs, arm7_instrs);
|
||||
|
||||
/* right align */
|
||||
struct ImVec2 content;
|
||||
struct ImVec2 size;
|
||||
igGetContentRegionMax(&content);
|
||||
igCalcTextSize(&size, status, NULL, 0, 0.0f);
|
||||
igSetCursorPosX(content.x - size.x);
|
||||
igText(status);
|
||||
|
||||
igEndMainMenuBar();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int emu_load(struct emu *emu, const char *path) {
|
||||
return dc_load(emu->dc, path);
|
||||
}
|
||||
|
||||
int emu_keydown(struct emu *emu, int port, int key, uint16_t value) {
|
||||
if (key == K_F1 && value) {
|
||||
emu->debug_menu = !emu->debug_menu;
|
||||
}
|
||||
|
||||
if (key >= K_CONT_C && key <= K_CONT_RTRIG) {
|
||||
dc_input(emu->dc, port, key - K_CONT_C, value);
|
||||
}
|
||||
|
@ -760,19 +699,6 @@ int emu_keydown(struct emu *emu, int port, int key, uint16_t value) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void emu_vid_swapped(struct emu *emu) {
|
||||
/* keep track of the time between swaps */
|
||||
int64_t now = time_nanoseconds();
|
||||
|
||||
if (emu->last_swap) {
|
||||
float swap_time_ms = (float)(now - emu->last_swap) / 1000000.0f;
|
||||
int num_swap_times = ARRAY_SIZE(emu->swap_times);
|
||||
emu->swap_times[emu->frame % num_swap_times] = swap_time_ms;
|
||||
}
|
||||
|
||||
emu->last_swap = now;
|
||||
}
|
||||
|
||||
void emu_vid_destroyed(struct emu *emu) {
|
||||
rb_for_each_entry_safe(tex, &emu->live_textures, struct emu_texture,
|
||||
live_it) {
|
||||
|
|
|
@ -12,10 +12,10 @@ void emu_destroy(struct emu *emu);
|
|||
|
||||
void emu_vid_created(struct emu *emu, struct render_backend *r);
|
||||
void emu_vid_destroyed(struct emu *emu);
|
||||
void emu_vid_swapped(struct emu *emu);
|
||||
int emu_keydown(struct emu *emu, int port, int key, uint16_t value);
|
||||
|
||||
int emu_load(struct emu *emu, const char *path);
|
||||
void emu_debug_menu(struct emu *emu);
|
||||
void emu_render_frame(struct emu *emu);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -57,6 +57,14 @@ struct host {
|
|||
int keymap[K_NUM_KEYS];
|
||||
SDL_GameController *controllers[INPUT_MAX_CONTROLLERS];
|
||||
} input;
|
||||
|
||||
struct {
|
||||
int show_menu;
|
||||
int show_times;
|
||||
unsigned frame;
|
||||
float swap_times[360];
|
||||
int64_t last_swap;
|
||||
} dbg;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -156,8 +164,7 @@ static void audio_destroy_device(struct host *host) {
|
|||
|
||||
static int audio_create_device(struct host *host) {
|
||||
/* SDL expects the number of buffered frames to be a power of two */
|
||||
int target_frames = MS_TO_AUDIO_FRAMES(OPTION_latency);
|
||||
target_frames = (int)npow2((uint32_t)target_frames);
|
||||
int target_frames = 1 << 12;
|
||||
|
||||
/* match AICA output format */
|
||||
SDL_AudioSpec want;
|
||||
|
@ -183,12 +190,6 @@ static int audio_create_device(struct host *host) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void audio_set_latency(struct host *host, int latency) {
|
||||
audio_destroy_device(host);
|
||||
int res = audio_create_device(host);
|
||||
CHECK(res);
|
||||
}
|
||||
|
||||
void audio_push(struct host *host, const int16_t *data, int num_frames) {
|
||||
if (!host->audio.dev) {
|
||||
return;
|
||||
|
@ -214,7 +215,12 @@ static void audio_shutdown(struct host *host) {
|
|||
}
|
||||
|
||||
static int audio_init(struct host *host) {
|
||||
if (!OPTION_audio) {
|
||||
/* reset */
|
||||
memset(&host->audio, 0, sizeof(host->audio));
|
||||
|
||||
/* if the audio sync is disabled, don't actually create a device, as audio
|
||||
playback won't be possible without resampling the data */
|
||||
if (!audio_sync_enabled()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -233,6 +239,11 @@ static int audio_init(struct host *host) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int audio_restart(struct host *host) {
|
||||
audio_shutdown(host);
|
||||
return audio_init(host);
|
||||
}
|
||||
|
||||
/*
|
||||
* video
|
||||
*/
|
||||
|
@ -263,9 +274,10 @@ static SDL_GLContext video_create_context(struct host *host) {
|
|||
SDL_GLContext ctx = SDL_GL_CreateContext(host->win);
|
||||
CHECK_NOTNULL(ctx, "video_create_context failed: %s", SDL_GetError());
|
||||
|
||||
/* disable vsync */
|
||||
int res = SDL_GL_SetSwapInterval(0);
|
||||
CHECK_EQ(res, 0, "video_create_context failed to disable vsync");
|
||||
/* force vsync */
|
||||
int vsync = video_sync_enabled();
|
||||
int res = SDL_GL_SetSwapInterval(vsync);
|
||||
CHECK_EQ(res, 0, "video_create_context failed to set swap interval");
|
||||
|
||||
/* link in gl functions at runtime */
|
||||
res = gladLoadGLLoader((GLADloadproc)&SDL_GL_GetProcAddress);
|
||||
|
@ -296,10 +308,18 @@ static void video_shutdown(struct host *host) {
|
|||
}
|
||||
|
||||
r_destroy(host->video.r);
|
||||
|
||||
video_destroy_context(host, host->video.ctx);
|
||||
}
|
||||
|
||||
static int video_init(struct host *host) {
|
||||
/* reset */
|
||||
memset(&host->video, 0, sizeof(host->video));
|
||||
|
||||
/* immediately poll window size for platforms like Android where the window
|
||||
starts fullscreen, ignoring the default width and height */
|
||||
SDL_GetWindowSize(host->win, &host->video.width, &host->video.height);
|
||||
|
||||
host->video.ctx = video_create_context(host);
|
||||
host->video.r = r_create(host->video.width, host->video.height);
|
||||
|
||||
|
@ -515,6 +535,11 @@ static void input_keydown(struct host *host, int port, int key,
|
|||
mapping is available */
|
||||
int mapping = host->input.keymap[key];
|
||||
|
||||
if (key == K_F1 && value) {
|
||||
host->dbg.show_menu = !host->dbg.show_menu;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (key == K_UNKNOWN) {
|
||||
break;
|
||||
|
@ -579,6 +604,9 @@ static void input_shutdown(struct host *host) {
|
|||
}
|
||||
|
||||
static int input_init(struct host *host) {
|
||||
/* reset */
|
||||
memset(&host->input, 0, sizeof(host->input));
|
||||
|
||||
/* SDL won't push events for joysticks which are already connected at init */
|
||||
int num_joysticks = SDL_NumJoysticks();
|
||||
|
||||
|
@ -623,9 +651,106 @@ int ui_load_game(struct host *host, const char *path) {
|
|||
static void host_swap_window(struct host *host) {
|
||||
SDL_GL_SwapWindow(host->win);
|
||||
|
||||
if (host->emu) {
|
||||
emu_vid_swapped(host->emu);
|
||||
/* keep track of the time between swaps */
|
||||
int64_t now = time_nanoseconds();
|
||||
|
||||
if (host->dbg.last_swap) {
|
||||
float swap_time_ms = (float)(now - host->dbg.last_swap) / 1000000.0f;
|
||||
int num_times = ARRAY_SIZE(host->dbg.swap_times);
|
||||
host->dbg.swap_times[host->dbg.frame % num_times] = swap_time_ms;
|
||||
}
|
||||
|
||||
host->dbg.last_swap = now;
|
||||
host->dbg.frame++;
|
||||
}
|
||||
|
||||
static void host_debug_menu(struct host *host) {
|
||||
#ifdef HAVE_IMGUI
|
||||
if (!host->dbg.show_menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (igBeginMainMenuBar()) {
|
||||
if (igBeginMenu("HOST", 1)) {
|
||||
if (igBeginMenu("sync", 1)) {
|
||||
struct {
|
||||
const char *desc;
|
||||
int enabled;
|
||||
} options[] = {
|
||||
{"audio", audio_sync_enabled()}, /* */
|
||||
{"video", video_sync_enabled()}, /* */
|
||||
};
|
||||
int num_options = (int)ARRAY_SIZE(options);
|
||||
|
||||
for (int i = 0; i < num_options; i++) {
|
||||
const char *desc = options[i].desc;
|
||||
int enabled = options[i].enabled;
|
||||
|
||||
if (igMenuItem(desc, NULL, enabled, 1)) {
|
||||
int len = strlen(OPTION_sync);
|
||||
|
||||
if (enabled) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (OPTION_sync[i] == desc[0]) {
|
||||
OPTION_sync[i] = OPTION_sync[len - 1];
|
||||
OPTION_sync[len - 1] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OPTION_sync[len] = desc[0];
|
||||
OPTION_sync[len + 1] = 0;
|
||||
}
|
||||
|
||||
OPTION_sync_dirty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
igEndMenu();
|
||||
}
|
||||
|
||||
if (igMenuItem("frame times", NULL, host->dbg.show_times, 1)) {
|
||||
host->dbg.show_times = !host->dbg.show_times;
|
||||
}
|
||||
|
||||
igEndMenu();
|
||||
}
|
||||
|
||||
igEndMainMenuBar();
|
||||
}
|
||||
|
||||
if (host->dbg.show_times) {
|
||||
bool opened = true;
|
||||
|
||||
if (igBegin("frame times", &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
struct ImVec2 graph_size = {300.0f, 50.0f};
|
||||
int num_times = ARRAY_SIZE(host->dbg.swap_times);
|
||||
|
||||
float min_time = FLT_MAX;
|
||||
float max_time = -FLT_MAX;
|
||||
float avg_time = 0.0f;
|
||||
for (int i = 0; i < num_times; i++) {
|
||||
float time = host->dbg.swap_times[i];
|
||||
min_time = MIN(min_time, time);
|
||||
max_time = MAX(max_time, time);
|
||||
avg_time += time;
|
||||
}
|
||||
avg_time /= num_times;
|
||||
|
||||
igValueFloat("min frame time", min_time, "%.2f");
|
||||
igValueFloat("max frame time", max_time, "%.2f");
|
||||
igValueFloat("avg frame time", avg_time, "%.2f");
|
||||
igPlotLines("", host->dbg.swap_times, num_times,
|
||||
host->dbg.frame % num_times, NULL, 0.0f, 60.0f, graph_size,
|
||||
sizeof(float));
|
||||
}
|
||||
igEnd();
|
||||
|
||||
host->dbg.show_times = (int)opened;
|
||||
}
|
||||
|
||||
emu_debug_menu(host->emu);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void host_poll_events(struct host *host) {
|
||||
|
@ -794,16 +919,19 @@ static void host_poll_events(struct host *host) {
|
|||
}
|
||||
|
||||
/* check for option changes at this time as well */
|
||||
if (OPTION_latency_dirty) {
|
||||
audio_set_latency(host, OPTION_latency);
|
||||
OPTION_latency_dirty = 0;
|
||||
}
|
||||
|
||||
if (OPTION_fullscreen_dirty) {
|
||||
video_set_fullscreen(host, OPTION_fullscreen);
|
||||
OPTION_fullscreen_dirty = 0;
|
||||
}
|
||||
|
||||
if (OPTION_sync_dirty) {
|
||||
int res = audio_restart(host);
|
||||
CHECK(res, "audio_restart failed");
|
||||
res = video_restart(host);
|
||||
CHECK(res, "video_restart failed");
|
||||
OPTION_sync_dirty = 0;
|
||||
}
|
||||
|
||||
/* update reverse button map when optionsc hange */
|
||||
int dirty_map = 0;
|
||||
|
||||
|
@ -849,10 +977,6 @@ static int host_init(struct host *host) {
|
|||
CHECK_NOTNULL(host->win, "host_create window creation failed: %s",
|
||||
SDL_GetError());
|
||||
|
||||
/* immediately poll window size for platforms like Android where the window
|
||||
starts fullscreen, ignoring the default width and height */
|
||||
SDL_GetWindowSize(host->win, &host->video.width, &host->video.height);
|
||||
|
||||
if (!audio_init(host)) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -968,6 +1092,7 @@ int main(int argc, char **argv) {
|
|||
imgui_begin_frame(host->imgui);
|
||||
|
||||
/* render emulator output and build up imgui buffers */
|
||||
host_debug_menu(host);
|
||||
emu_render_frame(host->emu);
|
||||
ui_build_menus(host->ui);
|
||||
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
#include "core/core.h"
|
||||
#include "host/keycode.h"
|
||||
|
||||
const int LATENCY_PRESETS[] = {45, 90, 180};
|
||||
const int NUM_LATENCY_PRESETS = ARRAY_SIZE(LATENCY_PRESETS);
|
||||
|
||||
const char *ASPECT_RATIOS[] = {
|
||||
"stretch", "16:9", "4:3",
|
||||
};
|
||||
|
@ -37,9 +34,8 @@ struct button_map BUTTONS[] = {
|
|||
const int NUM_BUTTONS = ARRAY_SIZE(BUTTONS);
|
||||
|
||||
/* host */
|
||||
DEFINE_OPTION_STRING(sync, "av", "Sync control");
|
||||
DEFINE_OPTION_INT(bios, 0, "Boot to bios");
|
||||
DEFINE_OPTION_INT(audio, 1, "Enable audio");
|
||||
DEFINE_PERSISTENT_OPTION_INT(latency, 50, "Preferred audio latency in ms");
|
||||
DEFINE_PERSISTENT_OPTION_INT(fullscreen, 0, "Start window fullscreen");
|
||||
DEFINE_PERSISTENT_OPTION_INT(key_a, 'l', "A button mapping");
|
||||
DEFINE_PERSISTENT_OPTION_INT(key_b, 'p', "B button mapping");
|
||||
|
@ -70,3 +66,23 @@ DEFINE_OPTION_INT(perf, 0, "Create maps for compiled code for use with perf");
|
|||
|
||||
/* ui */
|
||||
DEFINE_PERSISTENT_OPTION_STRING(gamedir, "", "Directories to scan for games");
|
||||
|
||||
int audio_sync_enabled() {
|
||||
const char *ptr = OPTION_sync;
|
||||
while (*ptr) {
|
||||
if (*(ptr++) == 'a') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int video_sync_enabled() {
|
||||
const char *ptr = OPTION_sync;
|
||||
while (*ptr) {
|
||||
if (*(ptr++) == 'v') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,6 @@ struct button_map {
|
|||
int *dirty;
|
||||
};
|
||||
|
||||
extern const int LATENCY_PRESETS[];
|
||||
extern const int NUM_LATENCY_PRESETS;
|
||||
|
||||
extern const char *ASPECT_RATIOS[];
|
||||
extern const int NUM_ASPECT_RATIOS;
|
||||
|
||||
|
@ -18,9 +15,8 @@ extern struct button_map BUTTONS[];
|
|||
extern const int NUM_BUTTONS;
|
||||
|
||||
/* host */
|
||||
DECLARE_OPTION_STRING(sync);
|
||||
DECLARE_OPTION_INT(bios);
|
||||
DECLARE_OPTION_INT(audio);
|
||||
DECLARE_OPTION_INT(latency);
|
||||
DECLARE_OPTION_INT(fullscreen);
|
||||
DECLARE_OPTION_INT(key_a);
|
||||
DECLARE_OPTION_INT(key_b);
|
||||
|
@ -52,4 +48,7 @@ DECLARE_OPTION_INT(perf);
|
|||
/* ui */
|
||||
DECLARE_OPTION_STRING(gamedir);
|
||||
|
||||
int audio_sync_enabled();
|
||||
int video_sync_enabled();
|
||||
|
||||
#endif
|
||||
|
|
18
src/ui.c
18
src/ui.c
|
@ -958,23 +958,7 @@ static void ui_audio_build(struct ui *ui) {
|
|||
igSetCursorPos(pos);
|
||||
igBeginChild("audio", size, false, ImGuiWindowFlags_NavFlattened);
|
||||
|
||||
igPushStyle_Btn();
|
||||
|
||||
{
|
||||
if (igOptionInt("Latency (ms)", OPTION_latency, btn_size)) {
|
||||
int next = 0;
|
||||
for (int i = 0; i < NUM_LATENCY_PRESETS; i++) {
|
||||
if (LATENCY_PRESETS[i] > OPTION_latency) {
|
||||
next = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
OPTION_latency = LATENCY_PRESETS[next];
|
||||
OPTION_latency_dirty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
igPopStyle_Btn();
|
||||
igText("Not available yet.");
|
||||
|
||||
igEndChild();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue