Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a config option that can reduce lag #44

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions smw.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
# Automatically save state on quit and reload on start
Autosave = 0

# Disable the SDL_Delay that happens each frame (Gives slightly better perf if your
# display is set to exactly 60hz)
# Disable the manual delaying without vsync that happens each frame. Instead,
# rely on vsync to do frame timing. Results in frames never being dropped at
# the cost of more lag, but be sure to set your display to 60hz when using
# this.
DisableFrameDelay = 0

# Save a snapshot each time a level is completed
Expand Down Expand Up @@ -31,7 +33,19 @@ NoSpriteLimits = 1

# Use either SDL, SDL-Software, or OpenGL as the output method
# SDL-Software rendering might give better performance on Raspberry pi.
#OutputMethod = SDL
OutputMethod = SDL

# The type of display sync to use, when vsync is not forced on ( Disabled, Vsync, or Adaptive )
# Vsync is forced on when DisableFrameDelay is 1. Disabled and Vsync should
# always work. Disabled produces less lag than Vsync, at the cost of possible
# tearing. Adaptive sync is only supported when OutputMethod is OpenGL. If your
# setup supports FreeSync or G-Sync, you'll get least-lag-no-tearing with frame
# delay not disabled, adaptive sync, and OpenGL output method. Choosing
# adaptive sync with OpenGL output method when your setup doesn't support
# adaptive sync can result in using vsync instead.
#DisplaySync = Disabled
DisplaySync = Vsync
#DisplaySync = Adaptive

# Set to true to use linear filtering. Gives less crisp pixels. Works with SDL and OpenGL.
#LinearFiltering = 0
Expand Down
5 changes: 5 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,11 @@ static bool HandleIniConfig(int section, const char *key, char *value) {
g_config.output_method = StringEqualsNoCase(value, "SDL-Software") ? kOutputMethod_SDLSoftware :
StringEqualsNoCase(value, "OpenGL") ? kOutputMethod_OpenGL : kOutputMethod_SDL;
return true;
} else if (StringEqualsNoCase(key, "DisplaySync")) {
g_config.display_sync = StringEqualsNoCase(value, "Disabled") ? 0 :
StringEqualsNoCase(value, "Vsync") ? 1 :
StringEqualsNoCase(value, "Adaptive") ? -1 : 0;
return true;
} else if (StringEqualsNoCase(key, "LinearFiltering")) {
return ParseBool(value, &g_config.linear_filtering);
} else if (StringEqualsNoCase(key, "NoSpriteLimits")) {
Expand Down
1 change: 1 addition & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef struct Config {
uint8 enable_msu;
bool resume_msu;
bool disable_frame_delay;
int display_sync;
bool save_playthrough;
uint8 msuvolume;
uint32 features0;
Expand Down
50 changes: 28 additions & 22 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <sys/types.h>
#include <unistd.h>
#endif
#define NANOTIME_IMPLEMENTATION
#include "third_party/nanotime/nanotime.h"

#include "assets/smw_assets.h"

Expand Down Expand Up @@ -263,7 +265,26 @@ static bool SdlRenderer_Init(SDL_Window *window) {

SDL_Renderer *renderer = SDL_CreateRenderer(g_window, -1,
g_config.output_method == kOutputMethod_SDLSoftware ? SDL_RENDERER_SOFTWARE :
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_RENDERER_ACCELERATED | (g_config.disable_frame_delay || g_config.display_sync == 1 ? SDL_RENDERER_PRESENTVSYNC : 0));
if (g_config.disable_frame_delay) {
printf("Using vsync without frame delay\n");
}
else {
switch (g_config.display_sync) {
case 0:
printf("Disabled vsync\n");
break;
case 1:
printf("Using vsync\n");
break;
case -1:
printf("Attempted to use adaptive sync when not supported; defaulting to disabled vsync\n");
break;
default:
printf("Invalid g_config.display_func value of %d; defaulting to disabled vsync\n", g_config.display_sync);
break;
}
}
if (renderer == NULL) {
printf("Failed to create renderer: %s\n", SDL_GetError());
return false;
Expand Down Expand Up @@ -314,7 +335,7 @@ static void SdlRenderer_EndDraw(void) {
// printf("%f ms\n", v * 1000);
SDL_RenderClear(g_renderer);
SDL_RenderCopy(g_renderer, g_texture, &g_sdl_renderer_rect, NULL);
SDL_RenderPresent(g_renderer); // vsyncs to 60 FPS?
SDL_RenderPresent(g_renderer);
}

static const struct RendererFuncs kSdlRendererFuncs = {
Expand Down Expand Up @@ -478,12 +499,12 @@ error_reading:;
HandleCommand(kKeys_Load + 0, true);

bool running = true;
uint32 lastTick = SDL_GetTicks();
uint32 curTick = 0;
uint32 frameCtr = 0;
uint8 audiopaused = true;
bool has_bug_in_title = false;
GamepadInfo *gi;
nanotime_step_data stepper;
nanotime_step_init(&stepper, NANOTIME_NSEC_PER_SEC / 60, nanotime_now_max(), nanotime_now, nanotime_sleep);

while (running) {
SDL_Event event;
Expand Down Expand Up @@ -546,7 +567,7 @@ error_reading:;
}

if (g_paused) {
SDL_Delay(16);
nanotime_sleep(stepper.sleep_duration);
continue;
}

Expand Down Expand Up @@ -576,24 +597,9 @@ error_reading:;
}
}

// if vsync isn't working, delay manually
curTick = SDL_GetTicks();

// If not leaning on vsync to do timing, delay manually
if (!g_snes->disableRender && !g_config.disable_frame_delay) {
static const uint8 delays[3] = { 17, 17, 16 }; // 60 fps
lastTick += delays[frameCtr % 3];

if (lastTick > curTick) {
uint32 delta = lastTick - curTick;
if (delta > 500) {
lastTick = curTick - 500;
delta = 500;
}
// printf("Sleeping %d\n", delta);
SDL_Delay(delta);
} else if (curTick - lastTick > 500) {
lastTick = curTick;
}
nanotime_step(&stepper);
}
}

Expand Down
26 changes: 25 additions & 1 deletion src/opengl.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,31 @@ static bool OpenGLRenderer_Init(SDL_Window *window) {
SDL_GLContext context = SDL_GL_CreateContext(window);
(void)context;

SDL_GL_SetSwapInterval(1);
if (g_config.disable_frame_delay) {
SDL_GL_SetSwapInterval(1);
printf("Using vsync without frame delay\n");
}
else if (SDL_GL_SetSwapInterval(g_config.display_sync) < 0) {
SDL_GL_SetSwapInterval(0);
printf("Disabled vsync; chosen display sync setting not supported\n");
}
else {
switch (g_config.display_sync) {
case 0:
printf("Disabled vsync\n");
break;
case 1:
printf("Using vsync\n"); break;
break;
case -1:
printf("Using adaptive sync\n");
break;
default:
printf("Unknown value of g_config.display_sync: %d\n", g_config.display_sync);
break;
}
}

ogl_LoadFunctions();

if (!ogl_IsVersionGEQ(3, 3))
Expand Down
Loading