diff --git a/src/am_map.c b/src/am_map.c index 2d81b71c..9a00d1d6 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -1074,7 +1074,13 @@ void AM_Ticker (void) // static void AM_clearFB(int color) { - memset(fb, color, f_w*f_h); + int h = f_h; + byte *src = fb; + while (h--) + { + memset(src, color, f_w); + src += video.pitch; + } } // @@ -1252,7 +1258,7 @@ static void AM_drawFline_Vanilla(fline_t* fl, int color) } #endif -#define PUTDOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) +#define PUTDOT(xx,yy,cc) fb[(yy)*video.pitch+(xx)]=(cc) dx = fl->b.x - fl->a.x; ax = 2 * (dx<0 ? -dx : dx); diff --git a/src/d_main.c b/src/d_main.c index ad289eeb..0d5fdf59 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -210,7 +210,6 @@ void D_ProcessEvents (void) gamestate_t wipegamestate = GS_DEMOSCREEN; boolean screen_melt = true; extern int showMessages; -boolean enable_drs; void D_Display (void) { @@ -246,10 +245,14 @@ void D_Display (void) } } - enable_drs = true; - redrawsbar = false; + // save the current screen if about to wipe + if ((wipe = gamestate != wipegamestate) && NOTSTRICTMODE(screen_melt)) + wipe_StartScreen(0, 0, video.unscaledw, SCREENHEIGHT); + else + I_DynamicResolution(); + if (setsizeneeded) // change the view size if needed { R_ExecuteSetViewSize(); @@ -257,13 +260,6 @@ void D_Display (void) borderdrawcount = 3; } - // save the current screen if about to wipe - if ((wipe = gamestate != wipegamestate) && NOTSTRICTMODE(screen_melt)) - { - enable_drs = false; - wipe_StartScreen(0, 0, video.unscaledw, SCREENHEIGHT); - } - if (gamestate == GS_LEVEL && gametic) HU_Erase(); diff --git a/src/doomstat.h b/src/doomstat.h index 6f30d5f7..8bccef38 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -368,8 +368,6 @@ extern boolean precache; // to force a wipe on the next draw extern gamestate_t wipegamestate; -extern boolean enable_drs; - extern int mouseSensitivity_horiz; // killough extern int mouseSensitivity_vert; extern int mouseSensitivity_horiz_strafe; // [FG] strafe diff --git a/src/f_wipe.c b/src/f_wipe.c index 8cdc012a..025d047d 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -55,7 +55,7 @@ static void wipe_shittyColMajorXform(byte *array, int width, int height) static int wipe_initColorXForm(int width, int height, int ticks) { - memcpy(wipe_scr, wipe_scr_start, width*height); + V_PutBlock(0, 0, width, height, wipe_scr_start); return 0; } @@ -94,7 +94,7 @@ static int wipe_initMelt(int width, int height, int ticks) col_y = Z_Malloc(num_columns * sizeof(*col_y), PU_STATIC, NULL); // copy start screen to main screen - memcpy(wipe_scr, wipe_scr_start, width*height); + V_PutBlock(0, 0, width, height, wipe_scr_start); // makes this wipe faster (in theory) // to have stuff in column-major format @@ -152,14 +152,14 @@ static int wipe_doMelt(int width, int height, int ticks) for (y = 0; y < scroff; ++y) { *d = *s; - d += width; + d += video.pitch; s++; } s = wipe_scr_start + x * height; for (; y < height; ++y) { *d = *s; - d += width; + d += video.pitch; s++; } } diff --git a/src/i_video.c b/src/i_video.c index 3f3c903d..44b3dbf5 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -85,6 +85,7 @@ static SDL_Rect blit_rect = {0}; static int window_x, window_y; static int actualheight; +static int unscaled_actualheight; static int native_width; static int native_height; @@ -436,20 +437,6 @@ void I_StartFrame(void) static void UpdateRender(void) { - int i; - - // Copy linear video buffer to rectangle on surface - - byte *dest = screenbuffer->pixels; - const pixel_t *src = I_VideoBuffer; - - for (i = 0; i < blit_rect.h; ++i) - { - memcpy(dest, src, blit_rect.w); - dest += screenbuffer->w; - src += blit_rect.w; - } - SDL_LowerBlit(screenbuffer, &blit_rect, argbbuffer, &blit_rect); SDL_UpdateTexture(texture, &blit_rect, argbbuffer->pixels, argbbuffer->pitch); SDL_RenderClear(renderer); @@ -479,9 +466,13 @@ static int targetrefresh; static void ResetResolution(int height); static void ResetLogicalSize(void); -static void DynamicResolution(void) +void I_DynamicResolution(void) { + static int frame_counter; + static double averagepercent; + if (resolution_mode != RES_DRS || frametime_withoutpresent == 0 || + // Skip if frame time is too long (e.g. window event). frametime_withoutpresent > 1000000 / 15) { return; @@ -494,21 +485,29 @@ static void DynamicResolution(void) double actualpercent = actual / target; #define DRS_MIN_HEIGHT 400 - #define DRS_DELTA 0.5 + #define DRS_DELTA 0.01 #define DRS_GREATER (1 + DRS_DELTA) #define DRS_LESS (1 - DRS_DELTA) + // 100px step to make scaling artefacts less noticeable. + #define DRS_STEP (SCREENHEIGHT / 2) int newheight = 0; int oldheight = video.height; + // Decrease the resolution quickly, increase only when the average frame + // time is stable for the `targetrefresh` number of frames. + + frame_counter++; + averagepercent = (averagepercent + actualpercent) / frame_counter; + if (actualpercent > DRS_GREATER) { double reduction = (actualpercent - DRS_GREATER ) * 0.2; newheight = (int)MAX(DRS_MIN_HEIGHT, oldheight - oldheight * reduction); } - else if (actualpercent < DRS_LESS) + else if (averagepercent < DRS_LESS && frame_counter > targetrefresh) { - double addition = (DRS_LESS - actualpercent) * 0.25; + double addition = (DRS_LESS - averagepercent) * 0.25; newheight = (int)MIN(native_height_adjusted, oldheight + oldheight * addition); } else @@ -516,6 +515,17 @@ static void DynamicResolution(void) return; } + frame_counter = 0; + + int mul = (newheight + (DRS_STEP - 1)) / DRS_STEP; // integer round + + newheight = mul * DRS_STEP; + + if (newheight > native_height_adjusted) + { + newheight -= DRS_STEP; + } + if (newheight == oldheight) { return; @@ -563,8 +573,8 @@ void I_FinishUpdate(void) time = frametime_start - last_time; - // Update FPS counter every second - if (time >= 1000000) + // Update FPS counter every 10th of second + if (time >= 100000) { fps = (frame_counter * 1000000) / time; frame_counter = 0; @@ -574,13 +584,13 @@ void I_FinishUpdate(void) I_DrawDiskIcon(); + UpdateRender(); + if (frametime_start) { frametime_withoutpresent = I_GetTimeUS() - frametime_start; } - UpdateRender(); - SDL_RenderPresent(renderer); I_RestoreDiskBackground(); @@ -590,11 +600,6 @@ void I_FinishUpdate(void) I_ResetScreen(); need_reset = false; } - else if (enable_drs) - { - DynamicResolution(); - enable_drs = false; - } if (need_resize) { @@ -634,9 +639,9 @@ void I_FinishUpdate(void) // I_ReadScreen // -void I_ReadScreen(byte *scr) +void I_ReadScreen(byte *dst) { - memcpy(scr, I_VideoBuffer, video.width * video.height * sizeof(*I_VideoBuffer)); + V_GetBlock(0, 0, video.width, video.height, dst); } // @@ -962,18 +967,15 @@ static void I_GetWindowPosition(int *x, int *y, int w, int h) } } -static void ResetResolution(int height) +static double CurrentAspectRatio(void) { int w, h; - actualheight = use_aspect ? (int)(height * 1.2) : height; - video.height = height; - switch (widescreen) { case RATIO_ORIG: - w = 4; - h = 3; + w = SCREENWIDTH; + h = unscaled_actualheight; break; case RATIO_MATCH_SCREEN: w = native_width; @@ -1004,14 +1006,26 @@ static void ResetResolution(int height) aspect_ratio = 2.4; } - video.unscaledw = (int)(ACTUALHEIGHT * aspect_ratio); - video.width = (int)(actualheight * aspect_ratio); + return aspect_ratio; +} - // width and height shoud be even - video.unscaledw = (video.unscaledw + 1) & ~1; - video.width = (video.width + 1) & ~1; - video.height = (video.height + 1) & ~1; - actualheight = (actualheight + 1) & ~1; +static void ResetResolution(int height) +{ + double aspect_ratio = CurrentAspectRatio(); + + actualheight = use_aspect ? (int)(height * 1.2) : height; + video.height = height; + + video.unscaledw = (int)(unscaled_actualheight * aspect_ratio); + + // Unscaled widescreen 16:9 resolution truncates to 426x240, which is not + // quite 16:9. To avoid visual instability, we calculate the scaled width + // without the actual aspect ratio. For example, at 1280x720 we get + // 1278x720. + + double vertscale = (double)actualheight / (double)unscaled_actualheight; + video.width = (int)(video.unscaledw * vertscale); + video.width = (video.width + 1) & ~1; video.deltaw = (video.unscaledw - NONWIDEWIDTH) / 2; @@ -1025,7 +1039,7 @@ static void ResetResolution(int height) I_InitDiskFlash(); - I_Printf(VB_DEBUG, "ResetResolution: %dx%d", video.width, actualheight); + I_Printf(VB_DEBUG, "ResetResolution: %dx%d", video.width, video.height); } static void CreateUpscaledTexture(boolean force) @@ -1159,6 +1173,30 @@ void I_ResetTargetRefresh(void) static void I_InitVideoParms(void) { int p, tmp_scalefactor; + SDL_DisplayMode mode; + + if (SDL_GetCurrentDisplayMode(video_display, &mode)) + { + I_Error("Error getting display mode: %s", SDL_GetError()); + } + + native_width = mode.w; + native_height = mode.h; + native_refresh_rate = mode.refresh_rate; + + widescreen = default_widescreen; + + double aspect_ratio = CurrentAspectRatio(); + double native_aspect_ratio = (double)native_width / (double)native_height; + + if (widescreen && native_aspect_ratio < aspect_ratio) + { + native_height = (int)(native_width / aspect_ratio); + } + + native_height_adjusted = use_aspect ? (int)(native_height / 1.2) : native_height; + + unscaled_actualheight = use_aspect ? ACTUALHEIGHT: SCREENHEIGHT; I_ResetInvalidDisplayIndex(); resolution_mode = default_resolution_mode; @@ -1336,46 +1374,46 @@ static void I_InitGraphicsMode(void) static int CurrentResolutionMode(void) { + int height; + switch (resolution_mode) { case RES_ORIGINAL: - return SCREENHEIGHT; + height = SCREENHEIGHT; + break; case RES_DOUBLE: - return SCREENHEIGHT * 2; + height = SCREENHEIGHT * 2; + break; case RES_TRIPLE: - return SCREENHEIGHT * 3; - case RES_DRS: - return native_height_adjusted; + height = SCREENHEIGHT * 3; + break; default: - return native_height_adjusted; + height = native_height_adjusted; + break; } + + if (height > native_height_adjusted) + { + height = native_height_adjusted; + } + + return height; } static void CreateSurfaces(void) { int w, h; - SDL_DisplayMode mode; - - if (SDL_GetCurrentDisplayMode(video_display, &mode)) - { - I_Error("Error getting display mode: %s", SDL_GetError()); - } - - native_width = mode.w; - native_height = mode.h; - native_refresh_rate = mode.refresh_rate; w = native_width; - h = use_aspect ? (int)(native_height / 1.2) : native_height; - - native_height_adjusted = h; + h = native_height_adjusted; // [FG] For performance reasons, SDL2 insists that the screen pitch, i.e. // the *number of bytes* that one horizontal row of pixels occupy in // memory, must be a multiple of 4. w = (w + 3) & ~3; - h = (h + 3) & ~3; + + video.pitch = w; // [FG] create paletted frame buffer @@ -1389,12 +1427,7 @@ static void CreateSurfaces(void) 0, 0, 0, 0); SDL_FillRect(screenbuffer, NULL, 0); - if (I_VideoBuffer != NULL) - { - Z_Free(I_VideoBuffer); - } - - I_VideoBuffer = Z_Calloc(1, w * h * sizeof(*I_VideoBuffer), PU_STATIC, NULL); + I_VideoBuffer = screenbuffer->pixels; V_RestoreBuffer(); if (argbbuffer != NULL) diff --git a/src/i_video.h b/src/i_video.h index 2b6b01d4..8a564916 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -51,20 +51,22 @@ typedef enum // determines the hardware configuration // and sets up the video mode -void I_InitGraphics (void); +void I_InitGraphics(void); void I_ShutdownGraphics(void); // Takes full 8 bit values. -void I_SetPalette (byte* palette); +void I_SetPalette(byte* palette); -void I_FinishUpdate (void); +void I_FinishUpdate(void); -void I_ReadScreen (byte* scr); +void I_ReadScreen(byte* dst); void I_ResetScreen(void); // killough 10/98 void I_ResetTargetRefresh(void); void I_ToggleVsync(void); // [JN] Calls native SDL vsync toggle +void I_DynamicResolution(void); + extern boolean use_vsync; // killough 2/8/98: controls whether vsync is called extern boolean disk_icon; // killough 10/98 extern resolution_mode_t resolution_mode, default_resolution_mode; diff --git a/src/m_snapshot.c b/src/m_snapshot.c index 3c0985d0..6c001529 100644 --- a/src/m_snapshot.c +++ b/src/m_snapshot.c @@ -21,7 +21,6 @@ #include "doomtype.h" #include "doomstat.h" -#include "i_video.h" #include "m_io.h" #include "v_video.h" #include "r_main.h" @@ -123,7 +122,7 @@ static void M_TakeSnapshot (void) { for (x = video.deltaw; x < NONWIDEWIDTH + video.deltaw; x++) { - *p++ = s[V_ScaleY(y) * video.width + V_ScaleX(x)]; + *p++ = s[V_ScaleY(y) * video.pitch + V_ScaleX(x)]; } } @@ -164,7 +163,7 @@ boolean M_DrawSnapshot (int n, int x, int y, int w, int h) const fixed_t step_x = (SCREENWIDTH << FRACBITS) / rect.sw; const fixed_t step_y = (SCREENHEIGHT << FRACBITS) / rect.sh; - byte *dest = I_VideoBuffer + rect.sy * video.width + rect.sx; + byte *dest = I_VideoBuffer + rect.sy * video.pitch + rect.sx; fixed_t srcx, srcy; int destx, desty; @@ -172,7 +171,7 @@ boolean M_DrawSnapshot (int n, int x, int y, int w, int h) for (desty = 0, srcy = 0; desty < rect.sh; desty++, srcy += step_y) { - destline = dest + desty * video.width; + destline = dest + desty * video.pitch; srcline = snapshots[n] + (srcy >> FRACBITS) * SCREENWIDTH; for (destx = 0, srcx = 0; destx < rect.sw; destx++, srcx += step_x) diff --git a/src/r_draw.c b/src/r_draw.c index abbb0f9f..78b1818f 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -47,7 +47,7 @@ int viewwindowx; int viewwindowy; static byte **ylookup = NULL; static int *columnofs = NULL; -static int linesize = SCREENWIDTH; // killough 11/98 +static int linesize; // killough 11/98 // Color tables for different players, // translate a limited part to another @@ -824,7 +824,7 @@ void R_InitBuffer(void) { int i; - linesize = video.width; // killough 11/98 + linesize = video.pitch; // killough 11/98 // Handle resize, // e.g. smaller view windows @@ -896,7 +896,7 @@ void R_FillBackScreen (void) // Allocate the background buffer if necessary if (background_buffer == NULL) { - int size = video.width * video.height; + int size = video.pitch * video.height; background_buffer = Z_Malloc(size * sizeof(*background_buffer), PU_STATIC, NULL); } diff --git a/src/r_voxel.c b/src/r_voxel.c index 1a3bc2a6..fe42eca6 100644 --- a/src/r_voxel.c +++ b/src/r_voxel.c @@ -813,7 +813,7 @@ static void VX_DrawColumn (vissprite_t * spr, int x, int y) boolean shadow = ((spr->mobjflags & MF_SHADOW) != 0); - int linesize = video.width; + int linesize = video.pitch; byte * dest = I_VideoBuffer + viewwindowy * linesize + viewwindowx; // iterate over screen columns diff --git a/src/st_stuff.c b/src/st_stuff.c index 64f4d25a..b837e131 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -342,7 +342,7 @@ static void ST_DrawSolidBackground(int st_x) { for (x = 0; x < depth; x++) { - byte *c = st_backing_screen + V_ScaleY(y) * video.width + V_ScaleX(x + offset); + byte *c = st_backing_screen + V_ScaleY(y) * video.pitch + V_ScaleX(x + offset); r += pal[3 * c[0] + 0]; g += pal[3 * c[0] + 1]; b += pal[3 * c[0] + 2]; @@ -1327,14 +1327,7 @@ void ST_Init(void) void ST_InitRes(void) { - vrect_t rect; - - rect.x = 0; - rect.y = 0; - rect.w = video.unscaledw; - rect.h = StatusBarBufferHeight(); - - V_ScaleRect(&rect); + int height = V_ScaleY(StatusBarBufferHeight()); if (st_backing_screen) { @@ -1342,7 +1335,7 @@ void ST_InitRes(void) } // killough 11/98: allocate enough for hires - st_backing_screen = Z_Malloc(rect.sw * rect.sh * sizeof(*st_backing_screen), PU_STATIC, 0); + st_backing_screen = Z_Malloc(video.pitch * height * sizeof(*st_backing_screen), PU_STATIC, 0); } void ST_Warnings(void) diff --git a/src/v_video.c b/src/v_video.c index d77d2bc4..7ff20efd 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -920,7 +920,7 @@ void V_PutBlock(int x, int y, int width, int height, byte *src) void V_ShadeScreen(void) { - int y; + int x, y; byte *dest = dest_screen; const int targshade = 20, step = 2; static int oldtic = -1; @@ -932,9 +932,13 @@ void V_ShadeScreen(void) screenshade = 0; } - for (y = 0; y < video.width * video.height; y++) + for (y = 0; y < video.height; y++) { - dest[y] = colormaps[0][screenshade * 256 + dest[y]]; + for (x = 0; x < video.width; x++) + { + dest[x] = colormaps[0][screenshade * 256 + dest[x]]; + } + dest += linesize; } if (screenshade < targshade && gametic != oldtic) @@ -970,7 +974,7 @@ void V_Init(void) int i; fixed_t frac, lastfrac; - linesize = video.width; + linesize = video.pitch; video.xscale = (video.width << FRACBITS) / video.unscaledw; video.yscale = (video.height << FRACBITS) / SCREENHEIGHT; diff --git a/src/v_video.h b/src/v_video.h index 44ec9d25..e4f8cb23 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -93,6 +93,7 @@ typedef struct { int width; int height; + int pitch; int unscaledw; // unscaled width with correction for widecreen int deltaw; // widescreen delta