Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/SDL/SDLVulkanGraphicsContext.cpp
5659 views
1
#include "ppsspp_config.h"
2
#include "Core/Config.h"
3
#include "Core/ConfigValues.h"
4
#include "Common/System/System.h"
5
#include "Common/System/NativeApp.h"
6
#include "Common/System/Display.h"
7
#include "Common/GPU/thin3d.h"
8
#include "Common/GPU/thin3d_create.h"
9
#include "Common/GPU/Vulkan/VulkanRenderManager.h"
10
#include "Common/Data/Text/Parsers.h"
11
#include "GPU/Vulkan/VulkanUtil.h"
12
13
#include "Core/System.h"
14
#if PPSSPP_PLATFORM(MAC)
15
#include "SDL2/SDL_vulkan.h"
16
#else
17
#include "SDL_vulkan.h"
18
#endif
19
#include "SDLVulkanGraphicsContext.h"
20
21
#if defined(VK_USE_PLATFORM_METAL_EXT)
22
#include "SDLCocoaMetalLayer.h"
23
#endif
24
25
#ifdef _DEBUG
26
static const bool g_Validate = true;
27
#else
28
static const bool g_Validate = false;
29
#endif
30
31
bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int w, int h, int mode, std::string *error_message) {
32
window = SDL_CreateWindow("Initializing Vulkan...", x, y, w, h, mode);
33
if (!window) {
34
fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError());
35
exit(1);
36
}
37
38
init_glslang();
39
40
g_LogOptions.breakOnError = true;
41
g_LogOptions.breakOnWarning = true;
42
g_LogOptions.msgBoxOnError = false;
43
44
Version gitVer(PPSSPP_GIT_VERSION);
45
46
std::string errorStr;
47
if (!VulkanLoad(&errorStr)) {
48
*error_message = "Failed to load Vulkan driver library: ";
49
(*error_message) += errorStr;
50
return false;
51
}
52
53
vulkan_ = new VulkanContext();
54
55
VulkanContext::CreateInfo info{};
56
InitVulkanCreateInfoFromConfig(&info);
57
if (VK_SUCCESS != vulkan_->CreateInstance(info)) {
58
*error_message = vulkan_->InitError();
59
delete vulkan_;
60
vulkan_ = nullptr;
61
return false;
62
}
63
64
int deviceNum = vulkan_->GetPhysicalDeviceByName(g_Config.sVulkanDevice);
65
if (deviceNum < 0) {
66
deviceNum = vulkan_->GetBestPhysicalDevice();
67
if (!g_Config.sVulkanDevice.empty())
68
g_Config.sVulkanDevice = vulkan_->GetPhysicalDeviceProperties(deviceNum).properties.deviceName;
69
}
70
71
if (vulkan_->CreateDevice(deviceNum) != VK_SUCCESS) {
72
*error_message = vulkan_->InitError();
73
delete vulkan_;
74
vulkan_ = nullptr;
75
return false;
76
}
77
78
vulkan_->SetCbGetDrawSize([window]() {
79
int w=1,h=1;
80
SDL_Vulkan_GetDrawableSize(window, &w, &h);
81
return VkExtent2D {(uint32_t)w, (uint32_t)h};
82
});
83
84
SDL_SysWMinfo sys_info{};
85
SDL_VERSION(&sys_info.version); //Set SDL version
86
if (!SDL_GetWindowWMInfo(window, &sys_info)) {
87
fprintf(stderr, "Error getting SDL window wm info: %s\n", SDL_GetError());
88
exit(1);
89
}
90
switch (sys_info.subsystem) {
91
case SDL_SYSWM_X11:
92
#if defined(VK_USE_PLATFORM_XLIB_KHR)
93
vulkan_->InitSurface(WINDOWSYSTEM_XLIB, (void*)sys_info.info.x11.display,
94
(void *)(intptr_t)sys_info.info.x11.window);
95
#elif defined(VK_USE_PLATFORM_XCB_KHR)
96
vulkan_->InitSurface(WINDOWSYSTEM_XCB, (void*)XGetXCBConnection(sys_info.info.x11.display),
97
(void *)(intptr_t)sys_info.info.x11.window);
98
#endif
99
break;
100
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
101
case SDL_SYSWM_WAYLAND:
102
vulkan_->InitSurface(WINDOWSYSTEM_WAYLAND, (void*)sys_info.info.wl.display, (void *)sys_info.info.wl.surface);
103
break;
104
#endif
105
#if defined(VK_USE_PLATFORM_METAL_EXT)
106
#if PPSSPP_PLATFORM(MAC)
107
case SDL_SYSWM_COCOA:
108
vulkan_->InitSurface(WINDOWSYSTEM_METAL_EXT, makeWindowMetalCompatible(sys_info.info.cocoa.window), nullptr);
109
break;
110
#else
111
case SDL_SYSWM_UIKIT:
112
vulkan_->InitSurface(WINDOWSYSTEM_METAL_EXT, makeWindowMetalCompatible(sys_info.info.uikit.window), nullptr);
113
break;
114
#endif
115
#endif
116
#if defined(VK_USE_PLATFORM_DISPLAY_KHR)
117
case SDL_SYSWM_KMSDRM:
118
/*
119
There is no problem passing null for the next two arguments, and reinit will be called later
120
huangzihan china
121
*/
122
vulkan_->InitSurface(WINDOWSYSTEM_DISPLAY, nullptr, nullptr);
123
break;
124
#endif
125
default:
126
fprintf(stderr, "Vulkan subsystem %d not supported\n", sys_info.subsystem);
127
exit(1);
128
break;
129
}
130
131
bool useMultiThreading = g_Config.bRenderMultiThreading;
132
if (g_Config.iInflightFrames == 1) {
133
useMultiThreading = false;
134
}
135
draw_ = Draw::T3DCreateVulkanContext(vulkan_, useMultiThreading);
136
137
VkPresentModeKHR presentMode = ConfigPresentModeToVulkan(draw_);
138
if (!vulkan_->InitSwapchain(presentMode)) {
139
*error_message = vulkan_->InitError();
140
Shutdown();
141
return false;
142
}
143
144
SetGPUBackend(GPUBackend::VULKAN);
145
bool success = draw_->CreatePresets();
146
_assert_(success);
147
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
148
149
renderManager_ = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
150
renderManager_->SetInflightFrames(g_Config.iInflightFrames);
151
return true;
152
}
153
154
void SDLVulkanGraphicsContext::Shutdown() {
155
if (draw_)
156
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
157
delete draw_;
158
draw_ = nullptr;
159
vulkan_->WaitUntilQueueIdle();
160
vulkan_->DestroySwapchain();
161
vulkan_->DestroySurface();
162
vulkan_->DestroyDevice();
163
vulkan_->DestroyInstance();
164
delete vulkan_;
165
vulkan_ = nullptr;
166
finalize_glslang();
167
}
168
169
void SDLVulkanGraphicsContext::Resize() {
170
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
171
// NOTE: Removing DestroySwapchain here causes a double re-create on MacOS with MoltenVK, for some reason.
172
// It's like passing on oldSwapchain doesn't really work as expected.
173
vulkan_->DestroySwapchain();
174
VkPresentModeKHR presentMode = ConfigPresentModeToVulkan(draw_);
175
vulkan_->InitSwapchain(presentMode);
176
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
177
}
178
179
void SDLVulkanGraphicsContext::Poll() {
180
// Check for existing swapchain to avoid issues during shutdown.
181
if (vulkan_->GetSwapchain() && renderManager_->NeedsSwapchainRecreate()) {
182
Resize();
183
}
184
}
185
186