sdl12-compat: Use linear filtering by default for Logical Scaling

From 67ab18625fff848ab79268a8b2e7bc4772065d83 Mon Sep 17 00:00:00 2001
From: David Gow <[EMAIL REDACTED]>
Date: Mon, 31 May 2021 17:35:16 +0800
Subject: [PATCH] Use linear filtering by default for Logical Scaling

Decouple the scaling used for Logical Scaling from
SDL_RENDER_SCALE_QUALITY (which defaults to nearest-neighbour) for
non-OpenGL based windows, and use linear scaling by default.

Introduce the new 'SDL12COMPAT_SCALE_METHOD' environment variable, which
can be set to 'nearest' to get nearest neighbour filtering.

For OpenGL Logical Scaling, also support the SDL12COMPAT_SCALE_METHOD
environment variable.

Unless you're exceptionally lucky with your screen resolution being an
integer multiple of the underlying game resolution, nearest-neighbour
filtering looks terrible in most cases.
---
 src/SDL12_compat.c | 13 ++++++++++---
 src/SDL20_syms.h   |  3 +++
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/SDL12_compat.c b/src/SDL12_compat.c
index e67a53a..371d7ec 100644
--- a/src/SDL12_compat.c
+++ b/src/SDL12_compat.c
@@ -3530,8 +3530,11 @@ SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags12)
 
     } else {
         /* always use a renderer for non-OpenGL windows. */
-        const char *env = SDL20_getenv("SDL12COMPAT_SYNC_TO_VBLANK");
-        const SDL_bool want_vsync = (env && SDL20_atoi(env)) ? SDL_TRUE : SDL_FALSE;
+        const char *vsync_env = SDL20_getenv("SDL12COMPAT_SYNC_TO_VBLANK");
+        const char *old_scale_quality = SDL20_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
+        const char *scale_method_env = SDL20_getenv("SDL12COMPAT_SCALE_METHOD");
+        const SDL_bool want_vsync = (vsync_env && SDL20_atoi(vsync_env)) ? SDL_TRUE : SDL_FALSE;
+        const SDL_bool want_nearest = (scale_method_env && !SDL20_strcmp(scale_method_env, "nearest"));
         SDL_RendererInfo rinfo;
         SDL_assert(!VideoGLContext20);  /* either a new window or we destroyed all this */
         if (!VideoRenderer20 && want_vsync) {
@@ -3570,7 +3573,9 @@ SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags12)
             VideoConvertSurface20 = NULL;
         }
 
+        SDL20_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, want_nearest?"0":"1");
         VideoTexture20 = SDL20_CreateTexture(VideoRenderer20, rinfo.texture_formats[0], SDL_TEXTUREACCESS_STREAMING, width, height);
+        SDL20_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, old_scale_quality);
         if (!VideoTexture20) {
             return EndVidModeCreate();
         }
@@ -4630,6 +4635,8 @@ SDL_GL_SwapBuffers(void)
     if (VideoWindow20) {
         if (OpenGLLogicalScalingFBO != 0) {
             const GLboolean has_scissor = OpenGLFuncs.glIsEnabled(GL_SCISSOR_TEST);
+            const char *scale_method_env = SDL20_getenv("SDL12COMPAT_SCALE_METHOD");
+            const SDL_bool want_nearest = (scale_method_env && !SDL20_strcmp(scale_method_env, "nearest"));
             GLfloat clearcolor[4];
             float want_aspect, real_aspect;
             int drawablew, drawableh;
@@ -4672,7 +4679,7 @@ SDL_GL_SwapBuffers(void)
             OpenGLFuncs.glClear(GL_COLOR_BUFFER_BIT);
             OpenGLFuncs.glBlitFramebuffer(0, 0, OpenGLLogicalScalingWidth, OpenGLLogicalScalingHeight,
                                           dstrect.x, dstrect.y, dstrect.x + dstrect.w, dstrect.y + dstrect.h,
-                                          GL_COLOR_BUFFER_BIT, GL_LINEAR);
+                                          GL_COLOR_BUFFER_BIT, want_nearest?GL_NEAREST:GL_LINEAR);
             OpenGLFuncs.glBindFramebuffer(GL_FRAMEBUFFER, 0);
             SDL20_GL_SwapWindow(VideoWindow20);
             OpenGLFuncs.glClearColor(clearcolor[0], clearcolor[1], clearcolor[2], clearcolor[3]);
diff --git a/src/SDL20_syms.h b/src/SDL20_syms.h
index b3665c8..861b07d 100644
--- a/src/SDL20_syms.h
+++ b/src/SDL20_syms.h
@@ -49,6 +49,9 @@ SDL20_SYM(Uint32,WasInit,(Uint32 a),(a),return)
 SDL20_SYM(char*,GetError,(void),(),return)
 SDL20_SYM_VARARGS(int,SetError,(const char *fmt, ...))
 
+SDL20_SYM(const char *,GetHint,(const char *a),(a),return)
+SDL20_SYM(SDL_bool,SetHint,(const char *a, const char *b),(a, b),return)
+
 SDL20_SYM(int,Error,(SDL_errorcode a),(a),return)
 SDL20_SYM_PASSTHROUGH(void,ClearError,(void),(),)
 SDL20_SYM(void,Quit,(void),(),)