diff --git a/CMakeLists.txt b/CMakeLists.txt index 951160a3b..e0110c69f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -612,6 +612,7 @@ foreach( SDL1_VIDEO_MODE_BPP SDL1_VIDEO_MODE_FLAGS SDL1_FORCE_SVID_VIDEO_MODE + SDL1_FORCE_DIRECT_RENDER HAS_KBCTRL KBCTRL_BUTTON_DPAD_LEFT KBCTRL_BUTTON_DPAD_RIGHT diff --git a/Source/dx.cpp b/Source/dx.cpp index 255cc6911..a49443e21 100644 --- a/Source/dx.cpp +++ b/Source/dx.cpp @@ -39,16 +39,45 @@ SDL_Surface *renderer_texture_surface = nullptr; /** 8-bit surface that we render to */ SDL_Surface *pal_surface; +/** Whether we render directly to the screen surface, i.e. `pal_surface == GetOutputSurface()` */ +bool RenderDirectlyToOutputSurface; + +namespace { + +bool CanRenderDirectlyToOutputSurface() +{ +#ifdef USE_SDL1 +#ifdef SDL1_FORCE_DIRECT_RENDER + return true; +#else + auto *outputSurface = GetOutputSurface(); + return ((outputSurface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF + && outputSurface->w == gnScreenWidth && outputSurface->h == gnScreenHeight + && outputSurface->format->BitsPerPixel == 8); +#endif +#else // !USE_SDL1 + return false; +#endif +} + +} // namespace + static void dx_create_back_buffer() { - pal_surface = SDL_CreateRGBSurfaceWithFormat( - /*flags=*/0, - /*width=*/gnScreenWidth, - /*height=*/gnScreenHeight, - /*depth=*/8, - SDL_PIXELFORMAT_INDEX8); - if (pal_surface == nullptr) { - ErrSdl(); + if (CanRenderDirectlyToOutputSurface()) { + Log("{}", "Will render directly to the SDL output surface"); + pal_surface = GetOutputSurface(); + RenderDirectlyToOutputSurface = true; + } else { + pal_surface = SDL_CreateRGBSurfaceWithFormat( + /*flags=*/0, + /*width=*/gnScreenWidth, + /*height=*/gnScreenHeight, + /*depth=*/8, + SDL_PIXELFORMAT_INDEX8); + if (pal_surface == nullptr) { + ErrSdl(); + } } #ifndef USE_SDL1 @@ -194,6 +223,8 @@ void InitPalette() void BltFast(SDL_Rect *src_rect, SDL_Rect *dst_rect) { + if (RenderDirectlyToOutputSurface) + return; Blit(pal_surface, src_rect, dst_rect); } @@ -315,6 +346,8 @@ void RenderPresent() if (SDL_Flip(surface) <= -1) { ErrSdl(); } + if (RenderDirectlyToOutputSurface) + pal_surface = GetOutputSurface(); LimitFrameRate(); #endif } diff --git a/Source/dx.h b/Source/dx.h index a52da3db9..1c2dbbad5 100644 --- a/Source/dx.h +++ b/Source/dx.h @@ -9,6 +9,9 @@ namespace devilution { +/** Whether we render directly to the screen surface, i.e. `pal_surface == GetOutputSurface()` */ +extern bool RenderDirectlyToOutputSurface; + CelOutputBuffer GlobalBackBuffer(); void dx_init(); diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index 96177336a..a9dea66fe 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -143,7 +143,7 @@ static void BlitCursor(BYTE *dst, int dst_pitch, BYTE *src, int src_pitch) /** * @brief Remove the cursor from the buffer */ -static void scrollrt_draw_cursor_back_buffer(const CelOutputBuffer &out) +static void UndrawCursor(const CelOutputBuffer &out) { if (sgdwCursWdt == 0) { return; @@ -159,12 +159,10 @@ static void scrollrt_draw_cursor_back_buffer(const CelOutputBuffer &out) } /** - * @brief Draw the cursor on the given buffer + * @brief Save the content behind the cursor to a temporary buffer, then draw the cursor. */ -static void scrollrt_draw_cursor_item(const CelOutputBuffer &out) +static void DrawCursor(const CelOutputBuffer &out) { - assert(!sgdwCursWdt); - if (pcurs <= CURSOR_NONE || cursW == 0 || cursH == 0) { return; } @@ -1426,7 +1424,7 @@ static void DoBlitScreen(Sint16 dwX, Sint16 dwY, Uint16 dwWdt, Uint16 dwHgt) */ static void DrawMain(int dwHgt, bool draw_desc, bool draw_hp, bool draw_mana, bool draw_sbar, bool draw_btn) { - if (!gbActive) { + if (!gbActive || RenderDirectlyToOutputSurface) { return; } @@ -1481,18 +1479,19 @@ void scrollrt_draw_game_screen(bool draw_cursor) if (draw_cursor) { lock_buf(0); - scrollrt_draw_cursor_item(GlobalBackBuffer()); + DrawCursor(GlobalBackBuffer()); unlock_buf(0); } DrawMain(hgt, false, false, false, false, false); + RenderPresent(); + if (draw_cursor) { lock_buf(0); - scrollrt_draw_cursor_back_buffer(GlobalBackBuffer()); + UndrawCursor(GlobalBackBuffer()); unlock_buf(0); } - RenderPresent(); } /** @@ -1526,6 +1525,7 @@ void DrawAndBlit() lock_buf(0); const CelOutputBuffer &out = GlobalBackBuffer(); + UndrawCursor(out); nthread_UpdateProgressToNextGameTick(); @@ -1550,7 +1550,7 @@ void DrawAndBlit() hgt = gnScreenHeight; } DrawXPBar(out); - scrollrt_draw_cursor_item(out); + DrawCursor(out); DrawFPS(out); @@ -1558,9 +1558,6 @@ void DrawAndBlit() DrawMain(hgt, ddsdesc, drawhpflag, drawmanaflag, drawsbarflag, drawbtnflag); - lock_buf(0); - scrollrt_draw_cursor_back_buffer(GlobalBackBuffer()); - unlock_buf(0); RenderPresent(); drawhpflag = false; diff --git a/Source/utils/display.cpp b/Source/utils/display.cpp index fe718e01e..023ebd902 100644 --- a/Source/utils/display.cpp +++ b/Source/utils/display.cpp @@ -39,11 +39,13 @@ Uint16 gnViewportHeight; void SetVideoMode(int width, int height, int bpp, uint32_t flags) { Log("Setting video mode {}x{} bpp={} flags=0x{:08X}", width, height, bpp, flags); - SDL_SetVideoMode(width, height, bpp, flags); + ghMainWnd = SDL_SetVideoMode(width, height, bpp, flags); + if (ghMainWnd == nullptr) { + ErrSdl(); + } const SDL_VideoInfo ¤t = *SDL_GetVideoInfo(); Log("Video mode is now {}x{} bpp={} flags=0x{:08X}", current.current_w, current.current_h, current.vfmt->BitsPerPixel, SDL_GetVideoSurface()->flags); - ghMainWnd = SDL_GetVideoSurface(); } void SetVideoModeToPrimary(bool fullscreen, int width, int height)