Browse Source

dos: Load on main thread

I tried the interrupt handler approach but couldn't get it to work,
so for now we're back to loading and updating the progress bar
synchronously on DOS.
pull/8164/head
Gleb Mazovetskiy 7 months ago
parent
commit
469d57ce68
  1. 146
      Source/interfac.cpp

146
Source/interfac.cpp

@ -36,6 +36,10 @@
#include "controls/touch/renderers.h"
#endif
#ifdef __DJGPP__
#define LOAD_ON_MAIN_THREAD
#endif
namespace devilution {
namespace {
@ -235,6 +239,64 @@ void DrawCutsceneForeground()
RenderPresent();
}
struct {
uint32_t loadStartedAt;
EventHandler prevHandler;
bool skipRendering;
bool done;
uint32_t drawnProgress;
std::array<SDL_Color, 256> palette;
} ProgressEventHandlerState;
void InitRendering()
{
// Blit the background once and then free it.
DrawCutsceneBackground();
if (RenderDirectlyToOutputSurface && PalSurface != nullptr) {
// Render into all the backbuffers if there are multiple.
const void *initialPixels = PalSurface->pixels;
if (DiabloUiSurface() == PalSurface)
BltFast(nullptr, nullptr);
RenderPresent();
while (PalSurface->pixels != initialPixels) {
DrawCutsceneBackground();
if (DiabloUiSurface() == PalSurface)
BltFast(nullptr, nullptr);
RenderPresent();
}
}
FreeCutsceneBackground();
// The loading thread sets `logical_palette`, so we make sure to use
// our own palette for the fade-in.
PaletteFadeIn(8, ProgressEventHandlerState.palette);
}
void CheckShouldSkipRendering()
{
if (!ProgressEventHandlerState.skipRendering) return;
const bool shouldSkip = ProgressEventHandlerState.loadStartedAt + *GetOptions().Gameplay.skipLoadingScreenThresholdMs > SDL_GetTicks();
if (shouldSkip) return;
ProgressEventHandlerState.skipRendering = false;
if (!HeadlessMode) InitRendering();
}
bool HandleProgressBarUpdate()
{
CheckShouldSkipRendering();
SDL_Event event;
// We use the real `PollEvent` here instead of `FetchMessage`
// to process real events rather than the recorded ones in demo mode.
while (PollEvent(&event) != 0) {
CheckShouldSkipRendering();
if (event.type != SDL_QUIT) {
HandleMessage(event, SDL_GetModState());
}
if (ProgressEventHandlerState.done) return false;
}
return true;
}
void DoLoad(interface_mode uMsg)
{
IncProgress();
@ -401,6 +463,9 @@ void DoLoad(interface_mode uMsg)
LogError("Failed to send WM_ERROR {}", SDL_GetError());
SDL_ClearError();
}
#ifdef LOAD_ON_MAIN_THREAD
HandleProgressBarUpdate();
#endif
return;
}
@ -410,48 +475,9 @@ void DoLoad(interface_mode uMsg)
LogError("Failed to send WM_DONE {}", SDL_GetError());
SDL_ClearError();
}
}
struct {
uint32_t loadStartedAt;
EventHandler prevHandler;
bool skipRendering;
bool done;
uint32_t drawnProgress;
std::array<SDL_Color, 256> palette;
} ProgressEventHandlerState;
void InitRendering()
{
// Blit the background once and then free it.
DrawCutsceneBackground();
if (RenderDirectlyToOutputSurface && PalSurface != nullptr) {
// Render into all the backbuffers if there are multiple.
const void *initialPixels = PalSurface->pixels;
if (DiabloUiSurface() == PalSurface)
BltFast(nullptr, nullptr);
RenderPresent();
while (PalSurface->pixels != initialPixels) {
DrawCutsceneBackground();
if (DiabloUiSurface() == PalSurface)
BltFast(nullptr, nullptr);
RenderPresent();
}
}
FreeCutsceneBackground();
// The loading thread sets `logical_palette`, so we make sure to use
// our own palette for the fade-in.
PaletteFadeIn(8, ProgressEventHandlerState.palette);
}
void CheckShouldSkipRendering()
{
if (!ProgressEventHandlerState.skipRendering) return;
const bool shouldSkip = ProgressEventHandlerState.loadStartedAt + *GetOptions().Gameplay.skipLoadingScreenThresholdMs > SDL_GetTicks();
if (shouldSkip) return;
ProgressEventHandlerState.skipRendering = false;
if (!HeadlessMode) InitRendering();
#ifdef LOAD_ON_MAIN_THREAD
HandleProgressBarUpdate();
#endif
}
void ProgressEventHandler(const SDL_Event &event, uint16_t modState)
@ -525,6 +551,9 @@ void ProgressEventHandler(const SDL_Event &event, uint16_t modState)
app_fatal("Unknown progress mode");
break;
}
#ifdef LOAD_ON_MAIN_THREAD
HandleProgressBarUpdate();
#endif
}
} // namespace
@ -578,6 +607,9 @@ void IncProgress(uint32_t steps)
LogError("Failed to send WM_PROGRESS {}", SDL_GetError());
SDL_ClearError();
}
#ifdef LOAD_ON_MAIN_THREAD
HandleProgressBarUpdate();
#endif
}
}
@ -629,6 +661,11 @@ void ShowProgress(interface_mode uMsg)
}
// Begin loading
#ifdef LOAD_ON_MAIN_THREAD
const uint32_t start = SDL_GetTicks();
DoLoad(uMsg);
LogVerbose("Loading finished in {}ms", SDL_GetTicks() - start);
#else
static interface_mode loadTarget;
loadTarget = uMsg;
SdlThread loadThread = SdlThread([]() {
@ -636,28 +673,9 @@ void ShowProgress(interface_mode uMsg)
DoLoad(loadTarget);
LogVerbose("Load thread finished in {}ms", SDL_GetTicks() - start);
});
const auto processEvent = [&](const SDL_Event &event) {
CheckShouldSkipRendering();
if (event.type != SDL_QUIT) {
HandleMessage(event, SDL_GetModState());
}
if (ProgressEventHandlerState.done) {
loadThread.join();
return false;
}
return true;
};
while (true) {
CheckShouldSkipRendering();
SDL_Event event;
// We use the real `PollEvent` here instead of `FetchMessage`
// to process real events rather than the recorded ones in demo mode.
while (PollEvent(&event)) {
if (!processEvent(event)) return;
}
}
while (HandleProgressBarUpdate()) { }
loadThread.join();
#endif
}
} // namespace devilution

Loading…
Cancel
Save