mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Headless: Make all GPU backends work correctly on Windows
This commit is contained in:
1 parent
25cf52176f
commit
551e4cd0ab
11 files changed
+85
-62
No files matched your search
@@ -668,7 +668,10 @@ bool CreateDir(const Path &path, bool quiet) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG(Log::IO, "CreateDir('%s')", path.c_str());
|
if (!quiet) {
|
||||||
|
DEBUG_LOG(Log::IO, "CreateDir('%s')", path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBRETRO_VFS
|
#ifdef HAVE_LIBRETRO_VFS
|
||||||
switch (LibretroMkdir(path.ToString().c_str())) {
|
switch (LibretroMkdir(path.ToString().c_str())) {
|
||||||
case -2:
|
case -2:
|
||||||
|
|||||||
@@ -6,6 +6,16 @@
|
|||||||
#include "Common/GPU/thin3d.h"
|
#include "Common/GPU/thin3d.h"
|
||||||
#include "Common/TimeUtil.h"
|
#include "Common/TimeUtil.h"
|
||||||
|
|
||||||
|
struct WindowDesc {
|
||||||
|
WindowSystem winsys{};
|
||||||
|
void *data1 = nullptr;
|
||||||
|
void *data2 = nullptr;
|
||||||
|
|
||||||
|
bool Valid() const {
|
||||||
|
return winsys != WindowSystem::WINDOWSYSTEM_UNINITIALIZED && data2; // Not all platforms use data1, so don't check it.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Init is done differently on each platform, and done close to the creation, so it's
|
// Init is done differently on each platform, and done close to the creation, so it's
|
||||||
// expected to be implemented by subclasses.
|
// expected to be implemented by subclasses.
|
||||||
class GraphicsContext {
|
class GraphicsContext {
|
||||||
|
|||||||
@@ -6,11 +6,6 @@ class GraphicsContext;
|
|||||||
|
|
||||||
class Application {
|
class Application {
|
||||||
public:
|
public:
|
||||||
WindowSystem windowSystem;
|
|
||||||
void *windowData1 = nullptr;
|
|
||||||
void *windowData2 = nullptr; // This should be the window, if there is one.
|
|
||||||
|
|
||||||
void *Window() const { return windowData2; }
|
|
||||||
virtual ~Application() = default;
|
virtual ~Application() = default;
|
||||||
virtual bool InitGraphics(GraphicsContext *graphicsContext) = 0;
|
virtual bool InitGraphics(GraphicsContext *graphicsContext) = 0;
|
||||||
virtual void ShutdownGraphics(GraphicsContext *graphicsContext) = 0;
|
virtual void ShutdownGraphics(GraphicsContext *graphicsContext) = 0;
|
||||||
|
|||||||
+3
-3
@@ -396,10 +396,10 @@ CommandLineParseResult CommandLineOptions::Parse(int argc, const char *argv[], C
|
|||||||
gpuBackend = GPUBackend::OPENGL;
|
gpuBackend = GPUBackend::OPENGL;
|
||||||
softwareRendering = true;
|
softwareRendering = true;
|
||||||
} else if (sscanf(restOfOption.c_str(), "gles%lg", &glVersionTemp) == 1 || sscanf(restOfOption.c_str(), "opengl%lg", &glVersionTemp) == 1) {
|
} else if (sscanf(restOfOption.c_str(), "gles%lg", &glVersionTemp) == 1 || sscanf(restOfOption.c_str(), "opengl%lg", &glVersionTemp) == 1) {
|
||||||
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
|
gpuBackend = GPUBackend::OPENGL;
|
||||||
g_Config.bSoftwareRendering = false;
|
softwareRendering = false;
|
||||||
force_gl_version = int(10.0 * glVersionTemp + 0.5);
|
force_gl_version = int(10.0 * glVersionTemp + 0.5);
|
||||||
} else if (restOfOption == "gles") {
|
} else if (restOfOption == "gles" || restOfOption == "opengl") {
|
||||||
gpuBackend = GPUBackend::OPENGL;
|
gpuBackend = GPUBackend::OPENGL;
|
||||||
softwareRendering = false;
|
softwareRendering = false;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+2
-8
@@ -100,8 +100,6 @@ bool RunMainLoop(GraphicsContext *graphicsContext, Application *application, std
|
|||||||
|
|
||||||
application->InitGraphics(graphicsContext);
|
application->InitGraphics(graphicsContext);
|
||||||
|
|
||||||
DEBUG_LOG(Log::Boot, "Done.");
|
|
||||||
|
|
||||||
g_inLoop = true;
|
g_inLoop = true;
|
||||||
|
|
||||||
while (frame(graphicsContext)) {
|
while (frame(graphicsContext)) {
|
||||||
@@ -114,7 +112,6 @@ bool RunMainLoop(GraphicsContext *graphicsContext, Application *application, std
|
|||||||
|
|
||||||
// Process the shutdown. Without this, non-GL delays 800ms on shutdown. TODO: is this still an issue?
|
// Process the shutdown. Without this, non-GL delays 800ms on shutdown. TODO: is this still an issue?
|
||||||
Core_StateProcessed();
|
Core_StateProcessed();
|
||||||
frame(graphicsContext);
|
|
||||||
|
|
||||||
g_inLoop = false;
|
g_inLoop = false;
|
||||||
|
|
||||||
@@ -124,20 +121,17 @@ bool RunMainLoop(GraphicsContext *graphicsContext, Application *application, std
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call InitAPI and ShutdownAPI outside this!
|
// Call InitAPI and ShutdownAPI outside this!
|
||||||
bool MainThreadFunc(GraphicsContext *graphicsContext, Application *application, WindowSystem windowSystem, void *windowData1, void *windowData2, std::function<bool(GraphicsContext *)> frame) {
|
bool MainThreadFunc(GraphicsContext *graphicsContext, Application *application, const WindowDesc &windowDesc, std::function<bool(GraphicsContext *)> frame) {
|
||||||
// This is now the render thread, and will spawn the emu thread below.
|
// This is now the render thread, and will spawn the emu thread below.
|
||||||
std::string error_string;
|
std::string error_string;
|
||||||
bool success = graphicsContext->InitSurface(windowSystem, windowData1, windowData2, &error_string);
|
bool success = graphicsContext->InitSurface(windowDesc.winsys, windowDesc.data1, windowDesc.data2, &error_string);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string errorMessage;
|
std::string errorMessage;
|
||||||
if (graphicsContext->NeedsSeparateEmuThread()) {
|
if (graphicsContext->NeedsSeparateEmuThread()) {
|
||||||
SetCurrentThreadName("RenderThread");
|
SetCurrentThreadName("RenderThread");
|
||||||
|
|
||||||
DEBUG_LOG(Log::Boot, "Done.");
|
|
||||||
|
|
||||||
g_inLoop = true;
|
g_inLoop = true;
|
||||||
std::thread emuThread = EmuThread_Start(graphicsContext, application, frame);
|
std::thread emuThread = EmuThread_Start(graphicsContext, application, frame);
|
||||||
graphicsContext->ThreadStart();
|
graphicsContext->ThreadStart();
|
||||||
|
|||||||
+2
-1
@@ -26,12 +26,13 @@
|
|||||||
bool MainThread_Ready();
|
bool MainThread_Ready();
|
||||||
|
|
||||||
class GraphicsContext;
|
class GraphicsContext;
|
||||||
|
struct WindowDesc;
|
||||||
|
|
||||||
// Doesn't take ownership of the graphicsContext, you have to delete it.
|
// Doesn't take ownership of the graphicsContext, you have to delete it.
|
||||||
// This should be used by platforms that launch a separate thread and doesn't
|
// This should be used by platforms that launch a separate thread and doesn't
|
||||||
// need to run a polling loop in it.
|
// need to run a polling loop in it.
|
||||||
// NOTE: Does take ownership over Application (which is just a wrapper for NativeInitGraphics/NativeShutdownGraphics/NativeFrame).
|
// NOTE: Does take ownership over Application (which is just a wrapper for NativeInitGraphics/NativeShutdownGraphics/NativeFrame).
|
||||||
bool MainThreadFunc(GraphicsContext * graphicsContext, Application *application, WindowSystem windowSystem, void *windowData1, void *windowData2, std::function<bool(GraphicsContext *)> frame);
|
bool MainThreadFunc(GraphicsContext * graphicsContext, Application *application, const WindowDesc &windowDesc, std::function<bool(GraphicsContext *)> frame);
|
||||||
|
|
||||||
// If you're not using MainThreadFunc, you can at least use these to manage a spinning EmuThread (that calls NativeFrame),
|
// If you're not using MainThreadFunc, you can at least use these to manage a spinning EmuThread (that calls NativeFrame),
|
||||||
// whether your graphics context requires multithreading or not. Then use RunMainLoop to implement your main loop for
|
// whether your graphics context requires multithreading or not. Then use RunMainLoop to implement your main loop for
|
||||||
|
|||||||
+7
-2
@@ -1236,7 +1236,12 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
|||||||
System_SetWindowTitle("");
|
System_SetWindowTitle("");
|
||||||
System_Notify(SystemNotification::UI);
|
System_Notify(SystemNotification::UI);
|
||||||
|
|
||||||
std::thread mainThread = std::thread([]() {
|
WindowDesc desc;
|
||||||
|
desc.winsys = WINDOWSYSTEM_WIN32;
|
||||||
|
desc.data1 = MainWindow::GetHInstance();
|
||||||
|
desc.data2 = MainWindow::GetHWND();
|
||||||
|
|
||||||
|
std::thread mainThread = std::thread([desc]() {
|
||||||
// TODO: We can really merge all of this into MainThreadFunc
|
// TODO: We can really merge all of this into MainThreadFunc
|
||||||
std::string errorMessage;
|
std::string errorMessage;
|
||||||
std::string *deviceNameSetting;
|
std::string *deviceNameSetting;
|
||||||
@@ -1245,7 +1250,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
|||||||
HandleGraphicsFailure(errorMessage);
|
HandleGraphicsFailure(errorMessage);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!MainThreadFunc(graphicsContext.get(), new NativeApplication(), WINDOWSYSTEM_WIN32, MainWindow::GetHInstance(), MainWindow::GetHWND(),
|
if (!MainThreadFunc(graphicsContext.get(), new NativeApplication(), desc,
|
||||||
[](GraphicsContext *graphicsContext) {
|
[](GraphicsContext *graphicsContext) {
|
||||||
NativeFrame(graphicsContext);
|
NativeFrame(graphicsContext);
|
||||||
return GetUIState() != UISTATE_EXIT;
|
return GetUIState() != UISTATE_EXIT;
|
||||||
|
|||||||
+35
-30
@@ -233,14 +233,12 @@ void System_SendDebugScreenshot(const uint8_t *data, int width, int height) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GraphicsContext *CreateGraphicsContext(GPUCore gpuCore, std::string **deviceSetting, WindowSystem *winsys) {
|
static GraphicsContext *CreateGraphicsContext(GPUCore gpuCore, std::string **deviceSetting) {
|
||||||
#ifdef SDL
|
#ifdef SDL
|
||||||
*deviceSetting = nullptr;
|
*deviceSetting = nullptr;
|
||||||
*winsys = WindowSystem::WINDOWSYSTEM_SDL;
|
|
||||||
return new SDLHeadlessGLGraphicsContext();
|
return new SDLHeadlessGLGraphicsContext();
|
||||||
#elif PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
#elif PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||||
GraphicsContext *graphicsContext = nullptr;
|
GraphicsContext *graphicsContext = nullptr;
|
||||||
*winsys = WINDOWSYSTEM_WIN32;
|
|
||||||
switch (gpuCore) {
|
switch (gpuCore) {
|
||||||
case GPUCORE_GLES:
|
case GPUCORE_GLES:
|
||||||
*deviceSetting = nullptr;
|
*deviceSetting = nullptr;
|
||||||
@@ -353,12 +351,11 @@ static bool RunAutoTest(GraphicsContext *graphicsContext, CoreParameter &corePar
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (draw) {
|
if (draw) {
|
||||||
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.
|
// Vulkan may get angry if we don't do a final present.
|
||||||
if (gpu) {
|
if (gpu) {
|
||||||
gpu->SetCurFramebufferDirty(true);
|
gpu->SetCurFramebufferDirty(true);
|
||||||
gpu->PrepareCopyDisplayToOutput(g_Config.GetDisplayLayoutConfig(DeviceOrientation::Landscape));
|
gpu->PrepareCopyDisplayToOutput(g_Config.GetDisplayLayoutConfig(DeviceOrientation::Landscape));
|
||||||
draw->BindFramebufferAsRenderTarget(nullptr, {RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR}, "BackBuffer");
|
draw->BindFramebufferAsRenderTarget(nullptr, {RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE}, "BackBuffer");
|
||||||
gpu->CopyDisplayToOutput(g_Config.GetDisplayLayoutConfig(DeviceOrientation::Landscape));
|
gpu->CopyDisplayToOutput(g_Config.GetDisplayLayoutConfig(DeviceOrientation::Landscape));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,8 +494,6 @@ public:
|
|||||||
void ShutdownGraphics(GraphicsContext *graphicsContext) override {
|
void ShutdownGraphics(GraphicsContext *graphicsContext) override {
|
||||||
graphicsContext->NotifyEmuThreadExit();
|
graphicsContext->NotifyEmuThreadExit();
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
std::function<void()> frameCallback_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
@@ -656,7 +651,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
g_Config.iInternalResolution = cmdLineOptions.resolutionScale.value_or(1);
|
g_Config.iInternalResolution = cmdLineOptions.resolutionScale.value_or(1);
|
||||||
g_Config.bEnableLogging = (fullLog || outputDebugStringLog);
|
g_Config.bEnableLogging = (fullLog || outputDebugStringLog);
|
||||||
g_Config.bVertexDecoderJit = true;
|
g_Config.bVertexDecoderJit = true;
|
||||||
g_Config.bSoftwareRendering = gpuCore == GPUCORE_SOFTWARE;
|
g_Config.bSoftwareRendering = cmdLineOptions.softwareRendering.value_or(false);
|
||||||
g_Config.bSoftwareRenderingJit = true;
|
g_Config.bSoftwareRenderingJit = true;
|
||||||
g_Config.iSplineBezierQuality = 2;
|
g_Config.iSplineBezierQuality = 2;
|
||||||
g_Config.bHighQualityDepth = true;
|
g_Config.bHighQualityDepth = true;
|
||||||
@@ -676,19 +671,33 @@ int main(int argc, const char* argv[]) {
|
|||||||
// overrides above, so a matching command line flag always wins.
|
// overrides above, so a matching command line flag always wins.
|
||||||
cmdLineOptions.ApplyToConfig();
|
cmdLineOptions.ApplyToConfig();
|
||||||
|
|
||||||
// TODO: Will we need a larger window for higher resolutions? Well, not if we use buffered rendering.
|
// Translate backend to core. We probably should consider merging these enums.
|
||||||
void *window = nullptr;
|
if (!g_Config.bSoftwareRendering && cmdLineOptions.gpuBackend.has_value()) {
|
||||||
|
switch (cmdLineOptions.gpuBackend.value()) {
|
||||||
|
case GPUBackend::OPENGL:
|
||||||
|
gpuCore = GPUCORE_GLES;
|
||||||
|
break;
|
||||||
|
case GPUBackend::DIRECT3D11:
|
||||||
|
gpuCore = GPUCORE_DIRECTX11;
|
||||||
|
break;
|
||||||
|
case GPUBackend::VULKAN:
|
||||||
|
gpuCore = GPUCORE_VULKAN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Time to set up graphics
|
// Time to set up graphics
|
||||||
GraphicsContext *graphicsContext = nullptr;
|
GraphicsContext *graphicsContext = nullptr;
|
||||||
std::string *deviceSetting = nullptr;
|
std::string *deviceSetting = nullptr;
|
||||||
WindowSystem winsys = WindowSystem::WINDOWSYSTEM_NONE;
|
WindowDesc windowDesc;
|
||||||
if (g_Config.bSoftwareRendering) {
|
if (g_Config.bSoftwareRendering) {
|
||||||
// For software rendering, we just create a dummy graphics context (to share as much code as possible).
|
// For software rendering, we just create a dummy graphics context (to share as much code as possible).
|
||||||
|
// We don't bother with a window.
|
||||||
graphicsContext = new NullGraphicsContext();
|
graphicsContext = new NullGraphicsContext();
|
||||||
} else {
|
} else {
|
||||||
window = CreateHiddenWindow(480, 272);
|
// TODO: Will we need a larger window for higher resolutions? Well, not if we use buffered rendering.
|
||||||
graphicsContext = CreateGraphicsContext(gpuCore, &deviceSetting, &winsys);
|
windowDesc = CreateHiddenWindow(480, 272);
|
||||||
|
graphicsContext = CreateGraphicsContext(gpuCore, &deviceSetting);
|
||||||
if (!graphicsContext) {
|
if (!graphicsContext) {
|
||||||
// If we don't get the desired context, we DO NOT fall back.
|
// If we don't get the desired context, we DO NOT fall back.
|
||||||
fprintf(stderr, "Failed to create a graphics context for GPU core");
|
fprintf(stderr, "Failed to create a graphics context for GPU core");
|
||||||
@@ -785,31 +794,27 @@ int main(int argc, const char* argv[]) {
|
|||||||
SaveState::Load(Path(stateToLoad), -1);
|
SaveState::Load(Path(stateToLoad), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string errorMessage;
|
||||||
Application *app = new HeadlessApplication([&]() {
|
if (!graphicsContext->InitAPI(windowDesc.data2, deviceSetting, &errorMessage)) {
|
||||||
// This is called from the main thread, so we can run the emulation here if we don't need a separate thread.
|
// No fallbacks in headless - if we can't run it, we can't. Let's not get confusing.
|
||||||
if (!graphicsContext->NeedsSeparateEmuThread()) {
|
fprintf(stderr, "Failed to initialize graphics API: %s\n", errorMessage.c_str());
|
||||||
RunTests(graphicsContext, coreParameter, testOptions, testFilenames);
|
return 1;
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (graphicsContext->NeedsSeparateEmuThread()) {
|
|
||||||
std::thread emuThread = EmuThread_Start(graphicsContext, app, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
emuThread.join();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int retval = 0;
|
||||||
|
MainThreadFunc(graphicsContext, new HeadlessApplication(), windowDesc, [&retval, &coreParameter, &testOptions, &testFilenames](GraphicsContext *graphicsContext) {
|
||||||
|
retval = RunTests(graphicsContext, coreParameter, testOptions, testFilenames);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
// Run the tests (or frame dumps), one after another.
|
graphicsContext->ShutdownAPI();
|
||||||
const int retval = RunTests(graphicsContext, coreParameter, testOptions, testFilenames);
|
|
||||||
|
|
||||||
if (cmdLineOptions.debuggerPort.has_value()) {
|
if (cmdLineOptions.debuggerPort.has_value()) {
|
||||||
ShutdownWebServer();
|
ShutdownWebServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window) {
|
if (windowDesc.Valid()) {
|
||||||
DestroyHiddenWindow(window);
|
DestroyHiddenWindow(windowDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_VFS.Clear();
|
g_VFS.Clear();
|
||||||
|
|||||||
@@ -37,17 +37,20 @@
|
|||||||
|
|
||||||
const bool WINDOW_VISIBLE = false;
|
const bool WINDOW_VISIBLE = false;
|
||||||
|
|
||||||
void *CreateHiddenWindow(int w, int h) {
|
WindowDesc CreateHiddenWindow(int w, int h) {
|
||||||
Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS;
|
Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS;
|
||||||
if (!WINDOW_VISIBLE) {
|
if (!WINDOW_VISIBLE) {
|
||||||
flags |= SDL_WINDOW_HIDDEN;
|
flags |= SDL_WINDOW_HIDDEN;
|
||||||
}
|
}
|
||||||
return SDL_CreateWindow("PPSSPPHeadless", w, h, flags);
|
WindowDesc desc;
|
||||||
|
desc.data2 = SDL_CreateWindow("PPSSPPHeadless", w, h, flags);
|
||||||
|
desc.winsys = WindowSystem::WINDOWSYSTEM_SDL;
|
||||||
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyHiddenWindow(void *window) {
|
void DestroyHiddenWindow(WindowDesc window) {
|
||||||
if (window) {
|
if (window.data2) {
|
||||||
SDL_DestroyWindow(static_cast<SDL_Window *>(window));
|
SDL_DestroyWindow(static_cast<SDL_Window *>(window.data2));
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,11 @@
|
|||||||
#include "headless/WindowsHeadlessHost.h"
|
#include "headless/WindowsHeadlessHost.h"
|
||||||
|
|
||||||
#include "Common/CommonWindows.h"
|
#include "Common/CommonWindows.h"
|
||||||
|
#include "Common/GPU/GraphicsContext.h"
|
||||||
|
|
||||||
const bool WINDOW_VISIBLE = false;
|
const bool WINDOW_VISIBLE = false;
|
||||||
|
|
||||||
void *CreateHiddenWindow(int w, int h) {
|
WindowDesc CreateHiddenWindow(int w, int h) {
|
||||||
static WNDCLASSEX wndClass = {
|
static WNDCLASSEX wndClass = {
|
||||||
sizeof(WNDCLASSEX),
|
sizeof(WNDCLASSEX),
|
||||||
CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||||
@@ -46,11 +47,15 @@ void *CreateHiddenWindow(int w, int h) {
|
|||||||
ShowWindow(wnd, TRUE);
|
ShowWindow(wnd, TRUE);
|
||||||
SetFocus(wnd);
|
SetFocus(wnd);
|
||||||
}
|
}
|
||||||
return static_cast<void *>(wnd);
|
WindowDesc desc;
|
||||||
|
desc.data1 = GetModuleHandle(NULL);
|
||||||
|
desc.data2 = wnd;
|
||||||
|
desc.winsys = WindowSystem::WINDOWSYSTEM_WIN32;
|
||||||
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyHiddenWindow(void *window) {
|
void DestroyHiddenWindow(WindowDesc window) {
|
||||||
if (window) {
|
if (window.data2) {
|
||||||
DestroyWindow(static_cast<HWND>(window));
|
DestroyWindow(static_cast<HWND>(window.data2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
struct WindowDesc;
|
||||||
|
|
||||||
// Same API as for SDL
|
// Same API as for SDL
|
||||||
void *CreateHiddenWindow(int w, int h);
|
WindowDesc CreateHiddenWindow(int w, int h);
|
||||||
void DestroyHiddenWindow(void *window);
|
void DestroyHiddenWindow(WindowDesc window);
|
||||||
Reference in new issue
Block a user