mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-20 17:59:08 +02:00
Merge pull request #21944 from hrydgard/more-headless-fixes
More headless fixes, and an adhoc crash fix
This commit is contained in:
18 files changed
+104
-85
No files matched your search
@@ -433,7 +433,7 @@ void VulkanRenderManager::StopThreads() {
|
||||
// Not sure this is a sensible check - should be ok even if not.
|
||||
// _dbg_assert_(steps_.empty());
|
||||
|
||||
_dbg_assert_(renderThread_.joinable());
|
||||
_dbg_assert_(!useRenderThread_ || renderThread_.joinable());
|
||||
if (useRenderThread_ && renderThread_.joinable()) {
|
||||
// Tell the render thread to quit when it's done.
|
||||
VKRRenderThreadTask *task = new VKRRenderThreadTask(VKRRunType::EXIT);
|
||||
|
||||
@@ -59,6 +59,5 @@ public:
|
||||
sleep_ms(5, "exit poll");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
@@ -250,6 +250,7 @@ enum SystemProperty {
|
||||
SYSPROP_INSTALLER_NAME, // Useful on Android to check if we were installed from the play store.
|
||||
};
|
||||
|
||||
// NOTE: Unlike requests or UIMessage, these are synchronous!
|
||||
enum class SystemNotification {
|
||||
UI,
|
||||
MEM_VIEW,
|
||||
@@ -273,6 +274,8 @@ enum class SystemNotification {
|
||||
AUDIO_MODE_CHANGED,
|
||||
APP_SWITCH_MODE_CHANGED,
|
||||
PAD_STATE_CHANGED,
|
||||
CONFIG_LOADED,
|
||||
BEFORE_CONFIG_SAVE_ON_EXIT,
|
||||
};
|
||||
|
||||
// I guess it's not super great architecturally to centralize this, since it's not general - but same with a lot of
|
||||
|
||||
@@ -1784,7 +1784,7 @@ static int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbufle
|
||||
getLocalMac(&localmac);
|
||||
|
||||
// Clear Memory
|
||||
context = {};
|
||||
*context = {};
|
||||
|
||||
// Allocate Receive Buffer
|
||||
context->rxbuf = (uint8_t*)malloc(rxbuflen);
|
||||
|
||||
@@ -2792,7 +2792,7 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt
|
||||
}
|
||||
}
|
||||
|
||||
// Check early for the degenerate case from Tactics Ogre.
|
||||
// Check early for the degenerate case from Tactics Ogre (EN version, japanese is worse!).
|
||||
if (pure3D && plan.levelsToLoad == 2 && gstate.getTextureAddress(0) == gstate.getTextureAddress(1)) {
|
||||
// Simply treat it as a regular 2D texture, no fake mipmaps or anything.
|
||||
// levelsToLoad/Create gets set to 1 on the way out from the surrounding if.
|
||||
|
||||
@@ -515,8 +515,12 @@ bool TextureCacheVulkan::RunMultipassCompute(VulkanContext *vulkan, VkCommandBuf
|
||||
stage.useFinalOutputSize ? dstWidth : srcWidth * stage.dstWidthScale,
|
||||
stage.useFinalOutputSize ? dstHeight : srcHeight * stage.dstHeightScale,
|
||||
};
|
||||
VkPipeline pipeline = computeShaderManager_.GetPipeline(multipassCS_[stage.shaderIndex], "Multipass Compute Shader");
|
||||
if (!pipeline) {
|
||||
return false;
|
||||
}
|
||||
VkDescriptorSet stageSet = computeShaderManager_.GetDescriptorSet(outputView, inputBuffer, inputOffset, inputRange, VK_NULL_HANDLE, 0, 0, inputImage, textureScaleCBuffer_.Buffer(), textureScaleCBuffer_.Size());
|
||||
vkCmdBindPipeline(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipeline(multipassCS_[stage.shaderIndex]));
|
||||
vkCmdBindPipeline(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
|
||||
vkCmdBindDescriptorSets(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipelineLayout(), 0, 1, &stageSet, 0, nullptr);
|
||||
vkCmdPushConstants(cmdInit, computeShaderManager_.GetPipelineLayout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(params), ¶ms);
|
||||
vkCmdDispatch(cmdInit, (params.dstWidth + 7) / 8, (params.dstHeight + 7) / 8, 1);
|
||||
@@ -542,7 +546,11 @@ bool TextureCacheVulkan::ScaleBufferToImage(VulkanContext *vulkan, VkCommandBuff
|
||||
}
|
||||
VkDescriptorSet descSet = computeShaderManager_.GetDescriptorSet(dstView, texBuf, bufferOffset, srcSize, VK_NULL_HANDLE, 0, 0, VK_NULL_HANDLE, textureScaleCBuffer_.Buffer(), textureScaleCBuffer_.Size());
|
||||
struct Params { int x; int y; } params{ srcWidth, srcHeight };
|
||||
vkCmdBindPipeline(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipeline(singlePassCS_));
|
||||
VkPipeline pipeline = computeShaderManager_.GetPipeline(singlePassCS_, "Single Pass Compute Shader");
|
||||
if (!pipeline) {
|
||||
return false;
|
||||
}
|
||||
vkCmdBindPipeline(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
|
||||
vkCmdBindDescriptorSets(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipelineLayout(), 0, 1, &descSet, 0, nullptr);
|
||||
vkCmdPushConstants(cmdInit, computeShaderManager_.GetPipelineLayout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(params), ¶ms);
|
||||
vkCmdDispatch(cmdInit, (srcWidth + 7) / 8, (srcHeight + 7) / 8, 1);
|
||||
|
||||
@@ -262,7 +262,7 @@ VkDescriptorSet VulkanComputeShaderManager::GetDescriptorSet(VkImageView image,
|
||||
return desc;
|
||||
}
|
||||
|
||||
VkPipeline VulkanComputeShaderManager::GetPipeline(VkShaderModule cs) {
|
||||
VkPipeline VulkanComputeShaderManager::GetPipeline(VkShaderModule cs, const char *tag) {
|
||||
PipelineKey key{ cs };
|
||||
VkPipeline pipeline;
|
||||
if (pipelines_.Get(key, &pipeline)) {
|
||||
@@ -278,7 +278,11 @@ VkPipeline VulkanComputeShaderManager::GetPipeline(VkShaderModule cs) {
|
||||
pci.flags = 0;
|
||||
|
||||
VkResult res = vkCreateComputePipelines(vulkan_->GetDevice(), pipelineCache_, 1, &pci, nullptr, &pipeline);
|
||||
_assert_(res == VK_SUCCESS);
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(Log::G3D, "Failed to create compute pipeline from shader module (%s)", tag);
|
||||
pipelines_.Insert(key, VK_NULL_HANDLE);
|
||||
}
|
||||
_dbg_assert_msg_(res == VK_SUCCESS, "Failed to create compute pipeline from shader module (%s)", tag);
|
||||
|
||||
pipelines_.Insert(key, pipeline);
|
||||
return pipeline;
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
VkDescriptorSet GetDescriptorSet(VkImageView image, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, VkBuffer buffer2, VkDeviceSize offset2, VkDeviceSize range2, VkImageView image2, VkBuffer cbuffer, VkDeviceSize cbufferSize);
|
||||
|
||||
// This of course caches though.
|
||||
VkPipeline GetPipeline(VkShaderModule cs);
|
||||
VkPipeline GetPipeline(VkShaderModule cs, const char *tag);
|
||||
VkPipelineLayout GetPipelineLayout() const { return pipelineLayout_; }
|
||||
void ClearPipelines();
|
||||
|
||||
|
||||
@@ -575,6 +575,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
// Note that if we don't have storage permission here, loading the config will
|
||||
// fail and it will be set to the default. Later, we load again when we get permission.
|
||||
g_Config.Load();
|
||||
System_Notify(SystemNotification::CONFIG_LOADED);
|
||||
#endif
|
||||
|
||||
const char *fileToLog = nullptr;
|
||||
@@ -1708,6 +1709,8 @@ void NativeShutdown() {
|
||||
g_screenManager = nullptr;
|
||||
}
|
||||
|
||||
System_Notify(SystemNotification::BEFORE_CONFIG_SAVE_ON_EXIT);
|
||||
|
||||
g_Config.Save("NativeShutdown");
|
||||
|
||||
g_i18nrepo.LogMissingKeys();
|
||||
|
||||
+21
-49
@@ -11,15 +11,12 @@
|
||||
#include "Common/Log.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/GraphicsContext.h"
|
||||
#include "Common/TimeUtil.h"
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
|
||||
#include "Windows/EmuThread.h"
|
||||
#include "Windows/W32Util/Misc.h"
|
||||
#include "Windows/MainWindow.h"
|
||||
#include "Windows/resource.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/Config.h"
|
||||
@@ -43,23 +40,28 @@ static std::thread emuThread;
|
||||
static std::atomic<EmuThreadState> g_emuThreadState(EmuThreadState::DISABLED);
|
||||
|
||||
static std::thread mainThread;
|
||||
static bool useEmuThread;
|
||||
static std::string g_error_message;
|
||||
static bool g_inLoop;
|
||||
|
||||
static const char** g_argv;
|
||||
static int g_argc;
|
||||
|
||||
extern std::vector<std::wstring> GetWideCmdLine();
|
||||
|
||||
class GraphicsContext;
|
||||
static GraphicsContext *g_graphicsContext;
|
||||
|
||||
void MainThreadFunc();
|
||||
void MainThreadFunc(int argc, const char *argv[]);
|
||||
|
||||
// On most other platforms, we let the "main" thread become the render thread and
|
||||
// start a separate emu thread from that, if needed. Should probably switch to that
|
||||
// to make it the same on all platforms.
|
||||
void MainThread_Start(bool separateEmuThread) {
|
||||
useEmuThread = separateEmuThread;
|
||||
mainThread = std::thread(&MainThreadFunc);
|
||||
void MainThread_Start(int argc, const char *argv[]) {
|
||||
// This is just to survive WM_USER_RESTART_EMUTHREAD.
|
||||
if (g_argc == 0) {
|
||||
g_argc = argc;
|
||||
g_argv = argv;
|
||||
}
|
||||
mainThread = std::thread([]() {
|
||||
MainThreadFunc(g_argc, g_argv);
|
||||
});
|
||||
}
|
||||
|
||||
void MainThread_Stop() {
|
||||
@@ -70,6 +72,9 @@ void MainThread_Stop() {
|
||||
}
|
||||
|
||||
bool MainThread_Ready() {
|
||||
if (g_inLoop) {
|
||||
_dbg_assert_(mainThread.joinable());
|
||||
}
|
||||
return g_inLoop;
|
||||
}
|
||||
|
||||
@@ -148,41 +153,15 @@ bool CreateGraphicsBackend(std::string *error_message, GraphicsContext **ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
void MainThreadFunc() {
|
||||
// We'll start up a separate thread we'll call Emu
|
||||
SetCurrentThreadName(useEmuThread ? "RenderThread" : "EmuThread");
|
||||
void MainThreadFunc(int argc, const char *argv[]) {
|
||||
const bool useEmuThread = g_Config.iGPUBackend == (int)GPUBackend::OPENGL;
|
||||
|
||||
const HWND console = GetConsoleWindow();
|
||||
if (console && g_Config.iConsoleWindowX != -1 && g_Config.iConsoleWindowY != -1) {
|
||||
SetWindowPos(console, NULL, g_Config.iConsoleWindowX, g_Config.iConsoleWindowY, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
||||
}
|
||||
SetCurrentThreadName(useEmuThread ? "RenderThread" : "EmuThread");
|
||||
|
||||
System_SetWindowTitle("");
|
||||
|
||||
// We convert command line arguments to UTF-8 immediately.
|
||||
std::vector<std::wstring> wideArgs = GetWideCmdLine();
|
||||
std::vector<std::string> argsUTF8;
|
||||
for (auto& string : wideArgs) {
|
||||
argsUTF8.push_back(ConvertWStringToUTF8(string));
|
||||
}
|
||||
std::vector<const char *> args;
|
||||
for (auto& string : argsUTF8) {
|
||||
args.push_back(string.c_str());
|
||||
}
|
||||
bool performingRestart = NativeIsRestarting();
|
||||
NativeInit(static_cast<int>(args.size()), &args[0], "", "", nullptr);
|
||||
|
||||
if (g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
|
||||
if (!useEmuThread) {
|
||||
// Okay, we must've switched to OpenGL. Let's flip the emu thread on.
|
||||
useEmuThread = true;
|
||||
SetCurrentThreadName("Render");
|
||||
}
|
||||
} else if (useEmuThread) {
|
||||
// We must've failed over from OpenGL, flip the emu thread off.
|
||||
useEmuThread = false;
|
||||
SetCurrentThreadName("EmuThread");
|
||||
}
|
||||
const bool performingRestart = NativeIsRestarting();
|
||||
NativeInit(argc, argv, "", "", nullptr);
|
||||
|
||||
if (g_Config.sFailedGPUBackends.find("ALL") != std::string::npos) {
|
||||
Reporting::ReportMessage("Graphics init error: %s", "ALL");
|
||||
@@ -313,18 +292,11 @@ void MainThreadFunc() {
|
||||
|
||||
g_graphicsContext->ThreadEnd();
|
||||
g_graphicsContext->ShutdownFromRenderThread();
|
||||
|
||||
g_graphicsContext->Shutdown();
|
||||
|
||||
delete g_graphicsContext;
|
||||
g_graphicsContext = nullptr;
|
||||
|
||||
RECT rc;
|
||||
if (console && GetWindowRect(console, &rc) && !IsIconic(console)) {
|
||||
g_Config.iConsoleWindowX = rc.left;
|
||||
g_Config.iConsoleWindowY = rc.top;
|
||||
}
|
||||
|
||||
NativeShutdown();
|
||||
|
||||
PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_UPDATE_UI, 0, 0);
|
||||
|
||||
+3
-1
@@ -17,6 +17,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
void MainThread_Start(bool separateRenderThread);
|
||||
void MainThread_Start(int argc, const char *argv[]);
|
||||
void MainThread_Stop();
|
||||
bool MainThread_Ready();
|
||||
|
||||
void MainThreadFunc(int argc, const char *argv[]);
|
||||
@@ -1102,7 +1102,7 @@ namespace MainWindow {
|
||||
g_InputManager.StopPolling();
|
||||
MainThread_Stop();
|
||||
UpdateUIState(UISTATE_MENU);
|
||||
MainThread_Start(g_Config.iGPUBackend == (int)GPUBackend::OPENGL);
|
||||
MainThread_Start(0, nullptr);
|
||||
g_InputManager.BeginPolling();
|
||||
break;
|
||||
|
||||
|
||||
+35
-5
@@ -594,6 +594,21 @@ void System_Notify(SystemNotification notification) {
|
||||
case SystemNotification::APP_SWITCH_MODE_CHANGED:
|
||||
case SystemNotification::UI_STATE_CHANGED:
|
||||
break;
|
||||
case SystemNotification::CONFIG_LOADED:
|
||||
{
|
||||
// This is too early to move the console into position - hasn't been allocated yet.
|
||||
break;
|
||||
}
|
||||
case SystemNotification::BEFORE_CONFIG_SAVE_ON_EXIT:
|
||||
{
|
||||
RECT rc{};
|
||||
const HWND console = GetConsoleWindow();
|
||||
if (console && GetWindowRect(console, &rc) && !IsIconic(console)) {
|
||||
g_Config.iConsoleWindowX = rc.left;
|
||||
g_Config.iConsoleWindowY = rc.top;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -893,7 +908,6 @@ static bool DetectVulkanInExternalProcess() {
|
||||
std::vector<std::wstring> GetWideCmdLine() {
|
||||
wchar_t **wargv;
|
||||
int wargc = -1;
|
||||
// This is used for the WM_USER_RESTART_EMUTHREAD path.
|
||||
if (!restartArgs.empty()) {
|
||||
std::wstring wargs = ConvertUTF8ToWString("PPSSPP " + restartArgs);
|
||||
wargv = CommandLineToArgvW(wargs.c_str(), &wargc);
|
||||
@@ -904,7 +918,6 @@ std::vector<std::wstring> GetWideCmdLine() {
|
||||
|
||||
std::vector<std::wstring> wideArgs(wargv, wargv + wargc);
|
||||
LocalFree(wargv);
|
||||
|
||||
return wideArgs;
|
||||
}
|
||||
|
||||
@@ -1008,7 +1021,7 @@ static void WinMainCleanup() {
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) {
|
||||
std::vector<std::wstring> wideArgs = GetWideCmdLine();
|
||||
const std::vector<std::wstring> wideArgs = GetWideCmdLine();
|
||||
|
||||
// Check for the Vulkan workaround before any serious init.
|
||||
for (size_t i = 1; i < wideArgs.size(); ++i) {
|
||||
@@ -1029,7 +1042,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
||||
SetCurrentThreadName("Main");
|
||||
|
||||
TimeInit();
|
||||
|
||||
WinMainInit();
|
||||
|
||||
#ifndef _DEBUG
|
||||
@@ -1088,6 +1100,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
||||
// if it's not loaded here first.
|
||||
g_Config.SetSearchPath(GetSysDirectory(DIRECTORY_SYSTEM));
|
||||
g_Config.Load(configFilename.c_str(), controlsConfigFilename.c_str());
|
||||
System_Notify(SystemNotification::CONFIG_LOADED);
|
||||
|
||||
bool debugLogLevel = false;
|
||||
|
||||
@@ -1170,6 +1183,12 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
||||
// - It should be possible to log to a file without showing the console.
|
||||
g_logManager.GetConsoleListener()->Init(showLog, 150, 120);
|
||||
|
||||
// Move the console into position.
|
||||
const HWND console = GetConsoleWindow();
|
||||
if (console && g_Config.iConsoleWindowX != -1 && g_Config.iConsoleWindowY != -1) {
|
||||
SetWindowPos(console, NULL, g_Config.iConsoleWindowX, g_Config.iConsoleWindowY, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
if (debugLogLevel) {
|
||||
g_logManager.SetAllLogLevels(LogLevel::LDEBUG);
|
||||
}
|
||||
@@ -1208,7 +1227,18 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
||||
// Emu thread (and render thread, if any) is always running!
|
||||
// Only OpenGL uses an externally managed render thread (due to GL's single-threaded context design). Vulkan
|
||||
// manages its own render thread.
|
||||
MainThread_Start(g_Config.iGPUBackend == (int)GPUBackend::OPENGL);
|
||||
|
||||
// We convert command line arguments to UTF-8.
|
||||
std::vector<std::string> argsUTF8;
|
||||
for (const auto &string : wideArgs) {
|
||||
argsUTF8.push_back(ConvertWStringToUTF8(string));
|
||||
}
|
||||
std::vector<const char *> args;
|
||||
for (const auto &string : argsUTF8) {
|
||||
args.push_back(string.c_str());
|
||||
}
|
||||
|
||||
MainThread_Start((int)args.size(), args.data());
|
||||
|
||||
g_InputManager.BeginPolling();
|
||||
|
||||
|
||||
@@ -317,7 +317,7 @@ std::vector<u32> TranslateDebugBufferToCompare(const GPUDebugBuffer *buffer, u32
|
||||
outStride = -outStride;
|
||||
}
|
||||
|
||||
// Skip the bottom of the image in the buffer was smaller. Remember, we're flipped.
|
||||
// Skip the bottom of the image if the buffer was smaller. Remember, we're flipped.
|
||||
u32 *dst = &data[0];
|
||||
if (safeH < h) {
|
||||
dst += (h - safeH) * stride;
|
||||
|
||||
@@ -262,7 +262,7 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, const
|
||||
}
|
||||
|
||||
if (draw) {
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "Backbuffer");
|
||||
draw->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "BackBuffer");
|
||||
// Vulkan may get angry if we don't do a final present.
|
||||
if (gpu) {
|
||||
gpu->SetCurFramebufferDirty(true);
|
||||
|
||||
@@ -180,11 +180,7 @@ bool SDLHeadlessHost::InitGraphics(std::string *error_message, GraphicsContext *
|
||||
gfx_->ThreadStart();
|
||||
threadState_ = RenderThreadState::STARTED;
|
||||
|
||||
while (threadState_ != RenderThreadState::STOP_REQUESTED) {
|
||||
if (!gfx_->ThreadFrame(true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
gfx_->ThreadFrameUntilCondition([this] { return threadState_ == RenderThreadState::STOP_REQUESTED; });
|
||||
|
||||
threadState_ = RenderThreadState::STOPPING;
|
||||
gfx_->ThreadEnd();
|
||||
@@ -201,6 +197,7 @@ bool SDLHeadlessHost::InitGraphics(std::string *error_message, GraphicsContext *
|
||||
}
|
||||
|
||||
void SDLHeadlessHost::ShutdownGraphics() {
|
||||
threadState_ = RenderThreadState::STOP_REQUESTED;
|
||||
while (threadState_ != RenderThreadState::STOPPED && threadState_ != RenderThreadState::START_FAILED)
|
||||
sleep_ms(1, "sdl-stop-poll");
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "Common/Log.h"
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/TimeUtil.h"
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
|
||||
#include "Core/CoreParameter.h"
|
||||
#include "Core/System.h"
|
||||
@@ -81,13 +82,11 @@ bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsConte
|
||||
}
|
||||
|
||||
WindowsGraphicsContext *graphicsContext = nullptr;
|
||||
bool needRenderThread = false;
|
||||
switch (gpuCore_) {
|
||||
case GPUCORE_GLES:
|
||||
#if PPSSPP_API(ANY_GL)
|
||||
case GPUCORE_SOFTWARE:
|
||||
graphicsContext = new WindowsGLContext();
|
||||
needRenderThread = true;
|
||||
break;
|
||||
#endif
|
||||
case GPUCORE_DIRECTX11:
|
||||
@@ -112,8 +111,11 @@ bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsConte
|
||||
return false;
|
||||
}
|
||||
|
||||
bool needRenderThread = gpuCore_ == GPUCORE_GLES;
|
||||
|
||||
if (needRenderThread) {
|
||||
std::thread th([&]{
|
||||
renderThread_ = std::thread([this]{
|
||||
SetCurrentThreadName("RenderThread");
|
||||
while (threadState_ == RenderThreadState::IDLE)
|
||||
sleep_ms(1, "render-thread-idle-poll");
|
||||
threadState_ = RenderThreadState::STARTING;
|
||||
@@ -126,18 +128,13 @@ bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsConte
|
||||
gfx_->ThreadStart();
|
||||
threadState_ = RenderThreadState::STARTED;
|
||||
|
||||
while (threadState_ != RenderThreadState::STOP_REQUESTED) {
|
||||
if (!gfx_->ThreadFrame(true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
gfx_->ThreadFrameUntilCondition([this] { return threadState_ == RenderThreadState::STOP_REQUESTED; });
|
||||
|
||||
threadState_ = RenderThreadState::STOPPING;
|
||||
gfx_->ThreadEnd();
|
||||
gfx_->ShutdownFromRenderThread();
|
||||
threadState_ = RenderThreadState::STOPPED;
|
||||
});
|
||||
th.detach();
|
||||
}
|
||||
|
||||
if (needRenderThread) {
|
||||
@@ -152,8 +149,12 @@ bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsConte
|
||||
}
|
||||
|
||||
void WindowsHeadlessHost::ShutdownGraphics() {
|
||||
while (threadState_ != RenderThreadState::STOPPED && threadState_ != RenderThreadState::IDLE)
|
||||
sleep_ms(1, "render-thread-stop-poll");
|
||||
if (renderThread_.joinable()) {
|
||||
threadState_ = RenderThreadState::STOP_REQUESTED;
|
||||
while (threadState_ != RenderThreadState::STOPPED && threadState_ != RenderThreadState::IDLE)
|
||||
sleep_ms(1, "render-thread-stop-poll");
|
||||
renderThread_.join();
|
||||
}
|
||||
|
||||
gfx_->Shutdown();
|
||||
delete gfx_;
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
|
||||
#include "Common/CommonWindows.h"
|
||||
|
||||
class WindowsHeadlessHost : public HeadlessHost
|
||||
{
|
||||
class WindowsHeadlessHost : public HeadlessHost {
|
||||
public:
|
||||
bool InitGraphics(std::string *error_message, GraphicsContext **ctx, GPUCore core) override;
|
||||
void ShutdownGraphics() override;
|
||||
@@ -51,4 +50,5 @@ protected:
|
||||
HDC hDC;
|
||||
HGLRC hRC;
|
||||
volatile RenderThreadState threadState_ = RenderThreadState::IDLE;
|
||||
std::thread renderThread_;
|
||||
};
|
||||
Reference in new issue
Block a user