CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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