Skip to content

Commit

Permalink
Merge pull request #6334 from stenzek/startup
Browse files Browse the repository at this point in the history
Video Backend Initialization/Core Boot Improvements
  • Loading branch information
Helios747 committed Feb 8, 2018
2 parents 4636230 + 505d30b commit 096131c
Show file tree
Hide file tree
Showing 24 changed files with 87 additions and 288 deletions.
124 changes: 31 additions & 93 deletions Source/Core/Core/Core.cpp
Expand Up @@ -241,7 +241,6 @@ bool Init(std::unique_ptr<BootParameters> boot)

// Start the emu thread
s_emu_thread = std::thread(EmuThread, std::move(boot));

return true;
}

Expand Down Expand Up @@ -311,9 +310,13 @@ void UndeclareAsCPUThread()
// For the CPU Thread only.
static void CPUSetInitialExecutionState()
{
QueueHostJob([] {
// The CPU starts in stepping state, and will wait until a new state is set before executing.
// SetState must be called on the host thread, so we defer it for later.
QueueHostJob([]() {
SetState(SConfig::GetInstance().bBootToPause ? State::Paused : State::Running);
Host_UpdateDisasmDialog();
Host_UpdateMainFrame();
Host_Message(WM_USER_CREATE);
});
}

Expand All @@ -323,24 +326,28 @@ static void CpuThread(const std::optional<std::string>& savestate_path, bool del
DeclareAsCPUThread();

const SConfig& _CoreParameter = SConfig::GetInstance();

if (_CoreParameter.bCPUThread)
{
Common::SetCurrentThreadName("CPU thread");
}
else
{
Common::SetCurrentThreadName("CPU-GPU thread");
g_video_backend->Video_Prepare();
Host_Message(WM_USER_CREATE);
}

// This needs to be delayed until after the video backend is ready.
DolphinAnalytics::Instance()->ReportGameStart();

if (_CoreParameter.bFastmem)
EMM::InstallExceptionHandler(); // Let's run under memory watch

#ifdef USE_MEMORYWATCHER
MemoryWatcher::Init();
#endif

if (savestate_path)
{
::State::LoadAs(*savestate_path);
if (delete_savestate)
File::Delete(*savestate_path);
}

s_is_started = true;
CPUSetInitialExecutionState();

Expand All @@ -361,25 +368,11 @@ static void CpuThread(const std::optional<std::string>& savestate_path, bool del
}
#endif

#ifdef USE_MEMORYWATCHER
MemoryWatcher::Init();
#endif

if (savestate_path)
{
::State::LoadAs(*savestate_path);
if (delete_savestate)
File::Delete(*savestate_path);
}

// Enter CPU run loop. When we leave it - we are done.
CPU::Run();

s_is_started = false;

if (!_CoreParameter.bCPUThread)
g_video_backend->Video_CleanupShared();

if (_CoreParameter.bFastmem)
EMM::UninstallExceptionHandler();
}
Expand All @@ -388,18 +381,12 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
bool delete_savestate)
{
DeclareAsCPUThread();
const SConfig& _CoreParameter = SConfig::GetInstance();

const SConfig& _CoreParameter = SConfig::GetInstance();
if (_CoreParameter.bCPUThread)
{
Common::SetCurrentThreadName("FIFO player thread");
}
else
{
g_video_backend->Video_Prepare();
Host_Message(WM_USER_CREATE);
Common::SetCurrentThreadName("FIFO-GPU thread");
}

// Enter CPU run loop. When we leave it - we are done.
if (auto cpu_core = FifoPlayer::GetInstance().GetCPUCore())
Expand All @@ -412,26 +399,15 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,

s_is_started = false;
PowerPC::InjectExternalCPUCore(nullptr);
FifoPlayer::GetInstance().Close();
}
FifoPlayer::GetInstance().Close();

// If we did not enter the CPU Run Loop above then run a fake one instead.
// We need to be IsRunningAndStarted() for DolphinWX to stop us.
if (CPU::GetState() != CPU::State::PowerDown)
else
{
s_is_started = true;
Host_Message(WM_USER_STOP);
while (CPU::GetState() != CPU::State::PowerDown)
{
if (!_CoreParameter.bCPUThread)
g_video_backend->PeekMessages();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
s_is_started = false;
// FIFO log does not contain any frames, cannot continue.
PanicAlert("FIFO file is invalid, cannot playback.");
FifoPlayer::GetInstance().Close();
return;
}

if (!_CoreParameter.bCPUThread)
g_video_backend->Video_CleanupShared();
}

// Initialize and create emulation thread
Expand All @@ -455,9 +431,6 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
INFO_LOG(CONSOLE, "Stop\t\t---- Shutdown complete ----");
}};

// Prevent the UI from getting stuck whenever an error occurs.
Common::ScopeGuard stop_message_guard{[] { Host_Message(WM_USER_STOP); }};

Common::SetCurrentThreadName("Emuthread - Starting");

// For a time this acts as the CPU thread...
Expand Down Expand Up @@ -493,8 +466,6 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
}
Common::ScopeGuard video_guard{[] { g_video_backend->Shutdown(); }};

OSD::AddMessage("Dolphin " + g_video_backend->GetName() + " Video Backend.", 5000);

if (cpu_info.HTT)
SConfig::GetInstance().bDSPThread = cpu_info.num_cores > 4;
else
Expand Down Expand Up @@ -574,9 +545,6 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
// This adds the SyncGPU handler to CoreTiming, so now CoreTiming::Advance might block.
Fifo::Prepare();

// Thread is no longer acting as CPU Thread
UndeclareAsCPUThread();

// Setup our core, but can't use dynarec if we are compare server
if (core_parameter.iCPUCore != PowerPC::CORE_INTERPRETER &&
(!core_parameter.bRunCompareServer || core_parameter.bRunCompareClient))
Expand All @@ -588,68 +556,38 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
}

// Update the window again because all stuff is initialized
Host_UpdateDisasmDialog();
Host_UpdateMainFrame();

// ENTER THE VIDEO THREAD LOOP
if (core_parameter.bCPUThread)
{
// This thread, after creating the EmuWindow, spawns a CPU
// thread, and then takes over and becomes the video thread
Common::SetCurrentThreadName("Video thread");
UndeclareAsCPUThread();

g_video_backend->Video_Prepare();
Host_Message(WM_USER_CREATE);

// Spawn the CPU thread
// Spawn the CPU thread. The CPU thread will signal the event that boot is complete.
s_cpu_thread = std::thread(cpuThreadFunc, savestate_path, delete_savestate);

// become the GPU thread
Fifo::RunGpuLoop();

// We have now exited the Video Loop
INFO_LOG(CONSOLE, "%s", StopMessage(false, "Video Loop Ended").c_str());

// Join with the CPU thread.
s_cpu_thread.join();
INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str());
}
else // SingleCore mode
{
// The spawned CPU Thread also does the graphics.
// The EmuThread is thus an idle thread, which sleeps while
// waiting for the program to terminate. Without this extra
// thread, the video backend window hangs in single core mode
// because no one is pumping messages.
Common::SetCurrentThreadName("Emuthread - Idle");

// Spawn the CPU+GPU thread
s_cpu_thread = std::thread(cpuThreadFunc, savestate_path, delete_savestate);

while (CPU::GetState() != CPU::State::PowerDown)
{
g_video_backend->PeekMessages();
Common::SleepCurrentThread(20);
}
// Become the CPU thread
cpuThreadFunc(savestate_path, delete_savestate);
}

INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping Emu thread ...").c_str());

// Wait for s_cpu_thread to exit
INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str());

#ifdef USE_GDBSTUB
INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping GDB ...").c_str());
gdb_deinit();
INFO_LOG(CONSOLE, "%s", StopMessage(true, "GDB stopped.").c_str());
#endif

s_cpu_thread.join();

INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str());

if (core_parameter.bCPUThread)
g_video_backend->Video_CleanupShared();

// If we shut down normally, the stop message does not need to be triggered.
stop_message_guard.Dismiss();
}

// Set or get the running state
Expand Down
3 changes: 1 addition & 2 deletions Source/Core/DolphinNoGUI/MainNoGUI.cpp
Expand Up @@ -83,10 +83,9 @@ static Common::Event updateMainFrameEvent;
void Host_Message(int Id)
{
if (Id == WM_USER_STOP)
{
s_running.Clear();
if (Id == WM_USER_JOB_DISPATCH || Id == WM_USER_STOP)
updateMainFrameEvent.Set();
}
}

static void* s_window_handle = nullptr;
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DolphinWX/Frame.cpp
Expand Up @@ -761,6 +761,8 @@ void CFrame::OnHostMessage(wxCommandEvent& event)
case WM_USER_CREATE:
if (SConfig::GetInstance().bHideCursor)
m_render_parent->SetCursor(wxCURSOR_BLANK);
if (SConfig::GetInstance().bFullscreen)
DoFullscreen(true);
break;

case IDM_PANIC:
Expand Down
6 changes: 1 addition & 5 deletions Source/Core/DolphinWX/FrameTools.cpp
Expand Up @@ -717,22 +717,18 @@ void CFrame::StartGame(std::unique_ptr<BootParameters> boot)
m_render_parent = new wxPanel(m_render_frame, IDM_MPANEL, wxDefaultPosition, wxDefaultSize, 0);
#endif
m_render_frame->Show();
m_render_frame->Raise();
}

#if defined(__APPLE__)
m_render_frame->EnableFullScreenView(true);
#endif

wxBusyCursor hourglass;

DoFullscreen(SConfig::GetInstance().bFullscreen);

SetDebuggerStartupParameters();

if (!BootManager::BootCore(std::move(boot)))
{
DoFullscreen(false);

// Destroy the renderer frame when not rendering to main
if (!SConfig::GetInstance().bRenderToMain)
m_render_frame->Destroy();
Expand Down
7 changes: 0 additions & 7 deletions Source/Core/VideoBackends/D3D/VideoBackend.h
Expand Up @@ -17,13 +17,6 @@ class VideoBackend : public VideoBackendBase
std::string GetName() const override;
std::string GetDisplayName() const override;

void Video_Prepare() override;
void Video_Cleanup() override;

void InitBackendInfo() override;

unsigned int PeekMessages() override;

void* m_window_handle;
};
}
38 changes: 9 additions & 29 deletions Source/Core/VideoBackends/D3D/main.cpp
Expand Up @@ -26,19 +26,6 @@

namespace DX11
{
unsigned int VideoBackend::PeekMessages()
{
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
return FALSE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;
}

std::string VideoBackend::GetName() const
{
return "D3D";
Expand Down Expand Up @@ -145,32 +132,30 @@ bool VideoBackend::Initialize(void* window_handle)
InitBackendInfo();
InitializeShared();

m_window_handle = window_handle;

return true;
}

void VideoBackend::Video_Prepare()
{
if (FAILED(D3D::Create(reinterpret_cast<HWND>(m_window_handle))))
if (FAILED(D3D::Create(reinterpret_cast<HWND>(window_handle))))
{
PanicAlert("Failed to create D3D device.");
return false;
}

// internal interfaces
g_renderer = std::make_unique<Renderer>();
g_texture_cache = std::make_unique<TextureCache>();
g_vertex_manager = std::make_unique<VertexManager>();
g_perf_query = std::make_unique<PerfQuery>();

VertexShaderCache::Init();
PixelShaderCache::Init();
GeometryShaderCache::Init();
VertexShaderCache::WaitForBackgroundCompilesToComplete();
D3D::InitUtils();
BBox::Init();
return true;
}

void VideoBackend::Shutdown()
{
// TODO: should be in Video_Cleanup
g_renderer->Shutdown();

D3D::ShutdownUtils();
PixelShaderCache::Shutdown();
VertexShaderCache::Shutdown();
Expand All @@ -182,13 +167,8 @@ void VideoBackend::Shutdown()
g_texture_cache.reset();
g_renderer.reset();

D3D::Close();

ShutdownShared();
}

void VideoBackend::Video_Cleanup()
{
CleanupShared();
D3D::Close();
}
}

0 comments on commit 096131c

Please sign in to comment.