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