2525#include " loadsave.h"
2626#include " pfile.h"
2727#include " plrmsg.h"
28+ #include " utils/log.hpp"
2829#include " utils/sdl_geometry.h"
2930#include " utils/sdl_thread.h"
3031
@@ -403,59 +404,89 @@ void DoLoad(interface_mode uMsg)
403404}
404405
405406struct {
406- uint32_t delayStart ;
407+ uint32_t loadStartedAt ;
407408 EventHandler prevHandler;
409+ bool skipRendering;
408410 bool done;
411+ uint32_t drawnProgress;
409412 std::array<SDL_Color, 256 > palette;
410413} ProgressEventHandlerState;
411414
415+ void InitRendering ()
416+ {
417+ // Blit the background once and then free it.
418+ DrawCutsceneBackground ();
419+ if (RenderDirectlyToOutputSurface && PalSurface != nullptr ) {
420+ // Render into all the backbuffers if there are multiple.
421+ const void *initialPixels = PalSurface->pixels ;
422+ if (DiabloUiSurface () == PalSurface)
423+ BltFast (nullptr , nullptr );
424+ RenderPresent ();
425+ while (PalSurface->pixels != initialPixels) {
426+ DrawCutsceneBackground ();
427+ if (DiabloUiSurface () == PalSurface)
428+ BltFast (nullptr , nullptr );
429+ RenderPresent ();
430+ }
431+ }
432+ FreeCutsceneBackground ();
433+
434+ // The loading thread sets `orig_palette`, so we make sure to use
435+ // our own palette for the fade-in.
436+ PaletteFadeIn (8 , ProgressEventHandlerState.palette );
437+ }
438+
439+ void CheckShouldSkipRendering ()
440+ {
441+ if (!ProgressEventHandlerState.skipRendering ) return ;
442+ const bool shouldSkip = ProgressEventHandlerState.loadStartedAt + *sgOptions.Gameplay .skipLoadingScreenThresholdMs > SDL_GetTicks ();
443+ if (shouldSkip) return ;
444+ ProgressEventHandlerState.skipRendering = false ;
445+ if (!HeadlessMode) InitRendering ();
446+ }
447+
412448void ProgressEventHandler (const SDL_Event &event, uint16_t modState)
413449{
414450 DisableInputEventHandler (event, modState);
415451 if (!IsCustomEvent (event.type )) return ;
416452
417- static uint32_t drawnProgress;
418- drawnProgress = 0 ;
419-
420453 const interface_mode customEvent = GetCustomEvent (event.type );
421454 switch (customEvent) {
422455 case WM_PROGRESS:
423- if (!HeadlessMode && drawnProgress != sgdwProgress) {
456+ if (!HeadlessMode && ProgressEventHandlerState. drawnProgress != sgdwProgress && !ProgressEventHandlerState. skipRendering ) {
424457 DrawCutsceneForeground ();
425- drawnProgress = sgdwProgress;
458+ ProgressEventHandlerState. drawnProgress = sgdwProgress;
426459 }
427460 break ;
428461 case WM_ERROR:
429462 app_fatal (*static_cast <std::string *>(event.user .data1 ));
430463 break ;
431464 case WM_DONE: {
432- // We may have loaded a new palette.
433- // Temporarily switch back to the load screen palette for fade out.
434- std::array<SDL_Color, 256 > prevPalette;
435- if (!HeadlessMode) {
436- prevPalette = orig_palette;
437- orig_palette = ProgressEventHandlerState.palette ;
438- ApplyGamma (logical_palette, orig_palette, 256 );
439- }
440- NewCursor (CURSOR_HAND);
441-
442- if (!HeadlessMode) {
443- assert (ghMainWnd);
444-
445- if (RenderDirectlyToOutputSurface && PalSurface != nullptr ) {
446- // Ensure that all back buffers have the full progress bar.
447- const void *initialPixels = PalSurface->pixels ;
448- do {
449- DrawCutsceneForeground ();
450- if (DiabloUiSurface () == PalSurface)
451- BltFast (nullptr , nullptr );
452- RenderPresent ();
453- } while (PalSurface->pixels != initialPixels);
465+ if (!ProgressEventHandlerState.skipRendering ) {
466+ NewCursor (CURSOR_HAND);
467+
468+ if (!HeadlessMode) {
469+ assert (ghMainWnd);
470+
471+ if (RenderDirectlyToOutputSurface && PalSurface != nullptr ) {
472+ // The loading thread sets `orig_palette`, so we make sure to use
473+ // our own palette for drawing the foreground.
474+ ApplyGamma (logical_palette, ProgressEventHandlerState.palette , 256 );
475+
476+ // Ensure that all back buffers have the full progress bar.
477+ const void *initialPixels = PalSurface->pixels ;
478+ do {
479+ DrawCutsceneForeground ();
480+ if (DiabloUiSurface () == PalSurface)
481+ BltFast (nullptr , nullptr );
482+ RenderPresent ();
483+ } while (PalSurface->pixels != initialPixels);
484+ }
485+
486+ // The loading thread sets `orig_palette`, so we make sure to use
487+ // our own palette for the fade-out.
488+ PaletteFadeOut (8 , ProgressEventHandlerState.palette );
454489 }
455-
456- PaletteFadeOut (8 );
457- orig_palette = prevPalette;
458- ApplyGamma (logical_palette, orig_palette, 256 );
459490 }
460491
461492 [[maybe_unused]] EventHandler prevHandler = SetEventHandler (ProgressEventHandlerState.prevHandler );
@@ -465,7 +496,7 @@ void ProgressEventHandler(const SDL_Event &event, uint16_t modState)
465496
466497 Player &myPlayer = *MyPlayer;
467498 NetSendCmdLocParam2 (true , CMD_PLAYER_JOINLEVEL, myPlayer.position .tile , myPlayer.plrlevel , myPlayer.plrIsOnSetLevel ? 1 : 0 );
468- DelayPlrMessages (SDL_GetTicks () - ProgressEventHandlerState.delayStart );
499+ DelayPlrMessages (SDL_GetTicks () - ProgressEventHandlerState.loadStartedAt );
469500
470501 if (gbSomebodyWonGameKludge && myPlayer.isOnLevel (16 )) {
471502 PrepDoEnding ();
@@ -552,9 +583,11 @@ void ShowProgress(interface_mode uMsg)
552583 IsProgress = true ;
553584 gbSomebodyWonGameKludge = false ;
554585
555- ProgressEventHandlerState.delayStart = SDL_GetTicks ();
586+ ProgressEventHandlerState.loadStartedAt = SDL_GetTicks ();
556587 ProgressEventHandlerState.prevHandler = SetEventHandler (ProgressEventHandler);
588+ ProgressEventHandlerState.skipRendering = true ;
557589 ProgressEventHandlerState.done = false ;
590+ ProgressEventHandlerState.drawnProgress = 0 ;
558591
559592#ifndef USE_SDL1
560593 DeactivateVirtualGamepad ();
@@ -573,42 +606,30 @@ void ShowProgress(interface_mode uMsg)
573606
574607 BlackPalette ();
575608
576- // Blit the background once and then free it.
609+ // Always load the background (even if we end up skipping rendering it).
610+ // This is because the MPQ archive can only be read by a single thread at a time.
577611 LoadCutsceneBackground (uMsg);
578- DrawCutsceneBackground ();
612+
613+ // Save the palette at this point because the loading process may replace it.
579614 ProgressEventHandlerState.palette = orig_palette;
580- if (RenderDirectlyToOutputSurface && PalSurface != nullptr ) {
581- // Render into all the backbuffers if there are multiple.
582- const void *initialPixels = PalSurface->pixels ;
583- if (DiabloUiSurface () == PalSurface)
584- BltFast (nullptr , nullptr );
585- RenderPresent ();
586- while (PalSurface->pixels != initialPixels) {
587- DrawCutsceneBackground ();
588- if (DiabloUiSurface () == PalSurface)
589- BltFast (nullptr , nullptr );
590- RenderPresent ();
591- }
592- }
593- FreeCutsceneBackground ();
594615 }
595616
596617 // Begin loading
597618 static interface_mode loadTarget;
598619 loadTarget = uMsg;
599620 SdlThread loadThread = SdlThread ([]() {
621+ const uint32_t start = SDL_GetTicks ();
600622 DoLoad (loadTarget);
623+ LogVerbose (" Load thread finished in {}ms" , SDL_GetTicks () - start);
601624 });
602625
603- if (!HeadlessMode) {
604- PaletteFadeIn (8 );
605- }
606-
607626 while (true ) {
627+ CheckShouldSkipRendering ();
608628 SDL_Event event;
609629 // We use the real `SDL_PollEvent` here instead of `FetchEvent`
610630 // to process real events rather than the recorded ones in demo mode.
611631 while (SDL_PollEvent (&event)) {
632+ CheckShouldSkipRendering ();
612633 if (event.type != SDL_QUIT) {
613634 HandleMessage (event, SDL_GetModState ());
614635 }
0 commit comments