From 30e69c518bc928bd0907c7bd8eac5f00c400f863 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sun, 24 Jan 2021 12:08:37 +0100 Subject: Codechange: [SDL2] Rework how palette is updated It now follows more what the Win32 driver does, and has far less exceptions and special casing. MakePalette creates the Palette and prepares surface. UpdatePalette updates the Palette. CheckPaletteAnim checks if UpdatePalette needs to be called and marks the whole screen dirty so DrawSurfaceToScreen will do a full redraw. --- src/video/sdl2_v.cpp | 79 +++++++++++++++++++++------------------------------- src/video/sdl2_v.h | 1 + 2 files changed, 32 insertions(+), 48 deletions(-) (limited to 'src/video') diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp index 61edea6e0..28ce0f880 100644 --- a/src/video/sdl2_v.cpp +++ b/src/video/sdl2_v.cpp @@ -73,7 +73,7 @@ void VideoDriver_SDL::MakeDirty(int left, int top, int width, int height) _num_dirty_rects++; } -static void UpdatePalette(bool init = false) +static void UpdatePalette() { SDL_Color pal[256]; @@ -86,8 +86,19 @@ static void UpdatePalette(bool init = false) SDL_SetPaletteColors(_sdl_palette, pal, _local_palette.first_dirty, _local_palette.count_dirty); SDL_SetSurfacePalette(_sdl_surface, _sdl_palette); +} - if (_sdl_surface != _sdl_real_surface && init) { +static void MakePalette() +{ + if (_sdl_palette == nullptr) { + _sdl_palette = SDL_AllocPalette(256); + if (_sdl_palette == nullptr) usererror("SDL2: Couldn't allocate palette: %s", SDL_GetError()); + } + + _local_palette = _cur_palette; + UpdatePalette(); + + if (_sdl_surface != _sdl_real_surface) { /* When using a shadow surface, also set our palette on the real screen. This lets SDL * allocate as many colors (or approximations) as * possible, instead of using only the default SDL @@ -110,33 +121,22 @@ static void UpdatePalette(bool init = false) */ SDL_SetSurfacePalette(_sdl_real_surface, _sdl_palette); } - - if (_sdl_surface != _sdl_real_surface && !init) { - /* We're not using real hardware palette, but are letting SDL - * approximate the palette during shadow -> screen copy. To - * change the palette, we need to recopy the entire screen. - * - * Note that this operation can slow down the rendering - * considerably, especially since changing the shadow - * palette will need the next blit to re-detect the - * best mapping of shadow palette colors to real palette - * colors from scratch. - */ - SDL_BlitSurface(_sdl_surface, nullptr, _sdl_real_surface, nullptr); - SDL_UpdateWindowSurface(_sdl_window); - } } -static void InitPalette() +void VideoDriver_SDL::CheckPaletteAnim() { - _cur_palette.first_dirty = 0; - _cur_palette.count_dirty = 256; + if (_cur_palette.count_dirty == 0) return; + _local_palette = _cur_palette; - UpdatePalette(true); + this->MakeDirty(0, 0, _screen.width, _screen.height); } -static void CheckPaletteAnim() +static void DrawSurfaceToScreen() { + PerformanceMeasurer framerate(PFE_VIDEO); + + if (_num_dirty_rects == 0) return; + if (_cur_palette.count_dirty != 0) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); @@ -157,18 +157,8 @@ static void CheckPaletteAnim() } _cur_palette.count_dirty = 0; } -} - -static void DrawSurfaceToScreen() -{ - PerformanceMeasurer framerate(PFE_VIDEO); - int n = _num_dirty_rects; - if (n == 0) return; - - _num_dirty_rects = 0; - - if (n > MAX_DIRTY_RECTS) { + if (_num_dirty_rects > MAX_DIRTY_RECTS) { if (_sdl_surface != _sdl_real_surface) { SDL_BlitSurface(_sdl_surface, nullptr, _sdl_real_surface, nullptr); } @@ -176,13 +166,15 @@ static void DrawSurfaceToScreen() SDL_UpdateWindowSurface(_sdl_window); } else { if (_sdl_surface != _sdl_real_surface) { - for (int i = 0; i < n; i++) { + for (int i = 0; i < _num_dirty_rects; i++) { SDL_BlitSurface(_sdl_surface, &_dirty_rects[i], _sdl_real_surface, &_dirty_rects[i]); } } - SDL_UpdateWindowSurfaceRects(_sdl_window, _dirty_rects, n); + SDL_UpdateWindowSurfaceRects(_sdl_window, _dirty_rects, _num_dirty_rects); } + + _num_dirty_rects = 0; } static void DrawSurfaceToScreenThread() @@ -195,7 +187,6 @@ static void DrawSurfaceToScreenThread() _draw_signal->wait(*_draw_mutex); while (_draw_continue) { - CheckPaletteAnim(); /* Then just draw and wait till we stop */ DrawSurfaceToScreen(); _draw_signal->wait(lock); @@ -362,14 +353,6 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h, bool resize) _sdl_surface = _sdl_real_surface; } - if (_sdl_palette == nullptr) { - _sdl_palette = SDL_AllocPalette(256); - if (_sdl_palette == nullptr) { - DEBUG(driver, 0, "SDL_AllocPalette() failed: %s", SDL_GetError()); - return false; - } - } - /* Delay drawing for this cycle; the next cycle will redraw the whole screen */ _num_dirty_rects = 0; @@ -378,6 +361,8 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h, bool resize) _screen.pitch = _sdl_surface->pitch / (bpp / 8); _screen.dst_ptr = _sdl_surface->pixels; + MakePalette(); + /* When in full screen, we will always have the mouse cursor * within the window, even though SDL does not give us the * appropriate event to know this. */ @@ -385,7 +370,6 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h, bool resize) BlitterFactory::GetCurrentBlitter()->PostResize(); - InitPalette(); GameSizeChanged(); return true; } @@ -813,7 +797,7 @@ void VideoDriver_SDL::LoopOnce() if (_draw_mutex != nullptr) draw_lock.lock(); UpdateWindows(); - _local_palette = _cur_palette; + this->CheckPaletteAnim(); } else { /* Release the thread while sleeping */ if (_draw_mutex != nullptr) { @@ -837,7 +821,6 @@ void VideoDriver_SDL::LoopOnce() _draw_signal->notify_one(); } else { /* Oh, we didn't have threads, then just draw unthreaded */ - CheckPaletteAnim(); DrawSurfaceToScreen(); } } @@ -848,7 +831,7 @@ void VideoDriver_SDL::MainLoop() last_cur_ticks = cur_ticks; next_tick = cur_ticks + MILLISECONDS_PER_TICK; - CheckPaletteAnim(); + this->CheckPaletteAnim(); if (_draw_threaded) { /* Initialise the mutex first, because that's the thing we *need* diff --git a/src/video/sdl2_v.h b/src/video/sdl2_v.h index a72325674..d1c4d957c 100644 --- a/src/video/sdl2_v.h +++ b/src/video/sdl2_v.h @@ -50,6 +50,7 @@ private: void MainLoopCleanup(); bool CreateMainSurface(uint w, uint h, bool resize); bool CreateMainWindow(uint w, uint h); + void CheckPaletteAnim(); #ifdef __EMSCRIPTEN__ /* Convert a constant pointer back to a non-constant pointer to a member function. */ -- cgit v1.2.3-70-g09d2