shithub: choc

Download patch

ref: 777148cae2032bc2a33754329e7ecb52017a21cc
parent: 970a54d1cf2a980fd3bb5412d2e0cfc9ae8898ec
author: Fabian Greffrath <[email protected]>
date: Mon Jul 13 03:15:14 EDT 2015

Video: Add another intermediate upscaled RGBA buffer

So, now the rendering chain is as follows:

screenbuffer (8 bit paletted, 230x200) --> (blit) -->
rgbabuffer (RGBA, 320x200) --> (scaled blit) -->
rgbabuffer_scaled (RGBA, UPSCALE*(320x200)) --> (memcpy) -->
texture (ARGB8888, UPSCALE*(320x200)) --> (linear scaling) -->
renderer (320x(aspect?240:200)) --> scaled to fit screen

The advantage of the additional intermediate surface is that by first
upscaling by an integer factor and then linear downscaling again into
the renderer window we can preserve the pixelated look of "nearest"
scaling but at the same time benefit from the refined "linear" scaling
for the rendering of static objects like the status bar numbers.

--- a/src/i_video.c
+++ b/src/i_video.c
@@ -148,14 +148,17 @@
 
 // These are (1) the 320x200x8 paletted buffer that we draw to (i.e. the one
 // that holds I_VideoBuffer), (2) the 320x200x32 RGBA intermediate buffer that
-// we blit the former buffer to and (3) the texture that we load the RGBA
+// we blit the former buffer to, (3) another intermediate RGBA buffer upscaled
+// linearly by factor UPSCALE and (4) the texture that we load the upscaled RGBA
 // buffer to and that is scaled into the window by the renderer (see above).
 // TODO: Check if the intermediate RGBA buffer is still necessary in newer
 // SDL releases. It surely is in 2.0.2, i.e. it is currently impossible to
 // update the texture with the pixels from the 8-bit paletted buffer.
 
+#define UPSCALE	4
 static SDL_Surface *screenbuffer = NULL;
 static SDL_Surface *rgbabuffer = NULL;
+static SDL_Surface *rgbabuffer_upscaled = NULL;
 static SDL_Texture *texture = NULL;
 static int pitch;
 static void *pixels;
@@ -1103,14 +1106,15 @@
     // Blit from the fake 8-bit screen buffer to the intermediate
     // 32-bit RGBA buffer that we can load into the texture
 
-    SDL_LowerBlit(screenbuffer, &screenbuffer->clip_rect,
-                  rgbabuffer, &rgbabuffer->clip_rect);
+    SDL_BlitSurface(screenbuffer, NULL, rgbabuffer, NULL);
 
+    SDL_BlitScaled(rgbabuffer, NULL, rgbabuffer_upscaled, NULL);
+
     // Update the texture with the content of the 32-bit RGBA buffer
 
     if (!SDL_LockTexture(texture, NULL, &pixels, &pitch))
     {
-	memcpy(pixels, rgbabuffer->pixels, SCREENHEIGHT*pitch);
+	memcpy(pixels, rgbabuffer_upscaled->pixels, UPSCALE*SCREENHEIGHT*pitch);
 	SDL_UnlockTexture(texture);
     }
 
@@ -1788,10 +1792,12 @@
     }
 
     // Set the scaling quality: "nearest" is gritty and pixelated and resembles
-    // software scaling pretty well, "linear" and "best" look much softer and
-    // smoother. TODO: Turn this into a config option / command line parameter.
+    // software scaling pretty well, but unfortunately renders the status bar
+    // numbers with unconsistent widths; "linear" and "best" look much softer
+    // and smoother but do a better job at downscaling from the upscaled
+    // buffer to the texture.
 
-    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
+    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
 
     // Create window and renderer context at once. We set the window title
     // later anyway and leave the window position "undefined". If "flags"
@@ -1861,7 +1867,17 @@
                                       0, 0, 0, 0);
     SDL_FillRect(rgbabuffer, NULL, 0);
 
-    // Create the texture that the RGBA surface gets loaded into.
+    rgbabuffer_upscaled = SDL_CreateRGBSurface(0,
+                                      UPSCALE*SCREENWIDTH, UPSCALE*SCREENHEIGHT, 32,
+                                      0, 0, 0, 0);
+    SDL_FillRect(rgbabuffer_upscaled, NULL, 0);
+
+    // Prevent alpha-blending for scaled blitting
+
+    SDL_SetSurfaceBlendMode(rgbabuffer, SDL_BLENDMODE_NONE);
+    SDL_SetSurfaceBlendMode(rgbabuffer_upscaled, SDL_BLENDMODE_NONE);
+
+    // Create the texture that the upscaled RGBA surface gets loaded into.
     // SDL_TEXTUREACCESS_STREAMING means that this texture's content
     // are going to change frequently.
 
@@ -1868,7 +1884,7 @@
     texture = SDL_CreateTexture(renderer,
                                 SDL_PIXELFORMAT_ARGB8888,
                                 SDL_TEXTUREACCESS_STREAMING,
-                                SCREENWIDTH, SCREENHEIGHT);
+                                UPSCALE*SCREENWIDTH, UPSCALE*SCREENHEIGHT);
 
     // Save screen mode.