From 54a50d4231255eec1b1a01636884dfea6a990969 Mon Sep 17 00:00:00 2001 From: Patryk Obara Date: Fri, 13 Mar 2020 18:01:49 +0100 Subject: [PATCH] Replace Lock/UnlockTexture with UpdateTexture Lock/UnlockTexture is stable and works very well on Linux and with OpenGL texture driver and on Linux and Windows, but it's usage caused problems with content of updated texture when used with drivers: 'direct3d11' on Windows and 'metal' on macOS. Also, Lock/Unlock turned out to be the root cause of deadlocks for 'opengl' driver on AmigaOS. According to SDL2 documentation, using Lock/UnlockTexture is supposed to be faster, but in DOSBox usecase we couldn't confirm significant performance change - there are some community reports indicating, that UpdateTexture might be actually faster (but we couldn't confirm it either). Discussion on this topic can be found on SDL forum: https://forums.libsdl.org/viewtopic.php?t=9728 In our case, switch to UpdateTexture has no serious negative impact, but makes the behaviour more robust across the board. --- src/gui/sdlmain.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp index 5471da00..79fe6348 100644 --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -221,6 +221,7 @@ enum PRIORITY_LEVELS { PRIORITY_LEVEL_HIGHEST }; + struct SDL_Block { bool inited; bool active; //If this isn't set don't draw @@ -293,6 +294,7 @@ struct SDL_Block { const char *rendererDriver; int displayNumber; struct { + SDL_Surface *input_surface = nullptr; SDL_Texture *texture = nullptr; SDL_PixelFormat *pixelFormat = nullptr; } texture; @@ -988,6 +990,7 @@ dosurface: rendering drivers, "opengles" being a notable exception */ sdl.texture.texture = SDL_CreateTexture(sdl.renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); + /* SDL_PIXELFORMAT_ABGR8888 (not RGB) is the only supported format for the "opengles" driver */ if (!sdl.texture.texture) { @@ -1001,6 +1004,13 @@ dosurface: LOG_MSG("SDL:Can't create texture, falling back to surface"); goto dosurface; } + + sdl.texture.input_surface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0); + if (!sdl.texture.input_surface) { + LOG_MSG("SDL: Error while preparing texture input"); + goto dosurface; + } + SDL_SetRenderDrawColor(sdl.renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); sdl.desktop.type=SCREEN_TEXTURE; Uint32 pixelFormat; @@ -1408,7 +1418,6 @@ bool GFX_StartUpdate(uint8_t * &pixels, int &pitch) if (!sdl.active || sdl.updating) return false; - void *tex_pixels = nullptr; switch (sdl.desktop.type) { case SCREEN_SURFACE: pixels = static_cast(sdl.surface->pixels); @@ -1420,9 +1429,9 @@ bool GFX_StartUpdate(uint8_t * &pixels, int &pitch) sdl.updating = true; return true; case SCREEN_TEXTURE: - if (SDL_LockTexture(sdl.texture.texture, nullptr, &tex_pixels, &pitch) < 0) - return false; - pixels = static_cast(tex_pixels); + assert(sdl.texture.input_surface); + pixels = static_cast(sdl.texture.input_surface->pixels); + pitch = sdl.texture.input_surface->pitch; sdl.updating = true; return true; #if C_OPENGL @@ -1475,7 +1484,11 @@ void GFX_EndUpdate( const Bit16u *changedLines ) { } break; case SCREEN_TEXTURE: - SDL_UnlockTexture(sdl.texture.texture); + assert(sdl.texture.input_surface); + SDL_UpdateTexture(sdl.texture.texture, + nullptr, // update entire texture + sdl.texture.input_surface->pixels, + sdl.texture.input_surface->pitch); SDL_RenderClear(sdl.renderer); SDL_RenderCopy(sdl.renderer, sdl.texture.texture, NULL, &sdl.clip); SDL_RenderPresent(sdl.renderer); @@ -1592,6 +1605,10 @@ static void CleanupSDLResources() SDL_DestroyTexture(sdl.texture.texture); sdl.texture.texture = nullptr; } + if (sdl.texture.input_surface) { + SDL_FreeSurface(sdl.texture.input_surface); + sdl.texture.input_surface = nullptr; + } if (sdl.renderer) { SDL_DestroyRenderer(sdl.renderer); sdl.renderer = nullptr;