Browse Source

🎉 SDL1: An option to render directly to video mem

Now that we no longer have a buffer border, we can render directly to
the video memory if the output surface is 8-bit and double buffering is
enabled.

Also adds a flag to force this even when double buffering is disabled,
because some systems emulate 8-bit mode with something else, so the
output is always buffered.

This required a tweak to the cursor to make sure that we clear it after
`SDL_Flip`.
pull/1952/head
Gleb Mazovetskiy 5 years ago committed by Anders Jenbo
parent
commit
cb9da2cadc
  1. 1
      CMakeLists.txt
  2. 49
      Source/dx.cpp
  3. 3
      Source/dx.h
  4. 23
      Source/scrollrt.cpp
  5. 6
      Source/utils/display.cpp

1
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

49
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
}

3
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();

23
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;

6
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 &current = *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)

Loading…
Cancel
Save