1
2 #include "Common/GPU/Vulkan/VulkanLoader.h"
3 #include "Common/GPU/Vulkan/VulkanContext.h"
4 #include "Common/GPU/Vulkan/VulkanDebug.h"
5 #include "Common/Log.h"
6 #include "Core/Config.h"
7 #include "Core/ConfigValues.h"
8 #include "Core/System.h"
9 #include "GPU/GPUInterface.h"
10 #include "Common/Data/Text/Parsers.h"
11
12 #include "libretro/LibretroVulkanContext.h"
13 #include "libretro/libretro_vulkan.h"
14 #include <GPU/Vulkan/VulkanRenderManager.h>
15
16 static VulkanContext *vk;
17
18 void vk_libretro_init(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface, PFN_vkGetInstanceProcAddr get_instance_proc_addr, const char **required_device_extensions, unsigned num_required_device_extensions, const char **required_device_layers, unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features);
19 void vk_libretro_shutdown();
20 void vk_libretro_set_hwrender_interface(retro_hw_render_interface *hw_render_interface);
21 void vk_libretro_wait_for_presentation();
22
LibretroVulkanContext()23 LibretroVulkanContext::LibretroVulkanContext()
24 : LibretroHWRenderContext(RETRO_HW_CONTEXT_VULKAN, VK_MAKE_VERSION(1, 0, 18)) {}
25
SwapBuffers()26 void LibretroVulkanContext::SwapBuffers() {
27 vk_libretro_wait_for_presentation();
28 LibretroHWRenderContext::SwapBuffers();
29 }
30
create_device(retro_vulkan_context * context,VkInstance instance,VkPhysicalDevice gpu,VkSurfaceKHR surface,PFN_vkGetInstanceProcAddr get_instance_proc_addr,const char ** required_device_extensions,unsigned num_required_device_extensions,const char ** required_device_layers,unsigned num_required_device_layers,const VkPhysicalDeviceFeatures * required_features)31 static bool create_device(retro_vulkan_context *context, VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface, PFN_vkGetInstanceProcAddr get_instance_proc_addr, const char **required_device_extensions, unsigned num_required_device_extensions, const char **required_device_layers, unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features) {
32 init_glslang();
33
34 if (!VulkanLoad()) {
35 // TODO: In the context of RetroArch, someone has already loaded the functions.
36 // But grabbing the pointers for ourselves can't really be a bad thing.
37 ERROR_LOG(G3D, "RetroArch called the Vulkan entry point without Vulkan available???");
38 return false;
39 }
40
41 vk = new VulkanContext();
42
43 vk_libretro_init(instance, gpu, surface, get_instance_proc_addr, required_device_extensions, num_required_device_extensions, required_device_layers, num_required_device_layers, required_features);
44
45 // TODO: Here we'll inject the instance and all of the stuff into the VulkanContext.
46
47 vk->CreateInstance({});
48
49 int physical_device = 0;
50 while (gpu && vk->GetPhysicalDevice(physical_device) != gpu) {
51 physical_device++;
52 }
53
54 if (!gpu) {
55 physical_device = vk->GetBestPhysicalDevice();
56 }
57
58 vk->ChooseDevice(physical_device);
59 vk->CreateDevice();
60 #ifdef _WIN32
61 vk->InitSurface(WINDOWSYSTEM_WIN32, nullptr, nullptr);
62 #elif defined(__ANDROID__)
63 vk->InitSurface(WINDOWSYSTEM_ANDROID, nullptr, nullptr);
64 #elif defined(VK_USE_PLATFORM_XLIB_KHR)
65 vk->InitSurface(WINDOWSYSTEM_XLIB, nullptr, nullptr);
66 #elif defined(VK_USE_PLATFORM_XCB_KHR)
67 vk->InitSurface(WINDOWSYSTEM_XCB, nullptr, nullptr);
68 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
69 vk->InitSurface(WINDOWSYSTEM_WAYLAND, nullptr, nullptr);
70 #elif defined(VK_USE_PLATFORM_DISPLAY_KHR)
71 vk->InitSurface(WINDOWSYSTEM_DISPLAY, nullptr, nullptr);
72 #endif
73
74 context->gpu = vk->GetPhysicalDevice(physical_device);
75 context->device = vk->GetDevice();
76 context->queue = vk->GetGraphicsQueue();
77 context->queue_family_index = vk->GetGraphicsQueueFamilyIndex();
78 context->presentation_queue = context->queue;
79 context->presentation_queue_family_index = context->queue_family_index;
80 #ifdef _DEBUG
81 fflush(stdout);
82 #endif
83 return true;
84 }
85
GetApplicationInfo(void)86 static const VkApplicationInfo *GetApplicationInfo(void) {
87 static VkApplicationInfo app_info{ VK_STRUCTURE_TYPE_APPLICATION_INFO };
88 app_info.pApplicationName = "PPSSPP";
89 app_info.applicationVersion = Version(PPSSPP_GIT_VERSION).ToInteger();
90 app_info.pEngineName = "PPSSPP";
91 app_info.engineVersion = 2;
92 app_info.apiVersion = VK_API_VERSION_1_0;
93 return &app_info;
94 }
95
Init()96 bool LibretroVulkanContext::Init() {
97 if (!LibretroHWRenderContext::Init(false)) {
98 return false;
99 }
100
101 static const struct retro_hw_render_context_negotiation_interface_vulkan iface = {
102 RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN,
103 RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION,
104 GetApplicationInfo,
105 create_device, // Callback above.
106 nullptr,
107 };
108 Libretro::environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE, (void *)&iface);
109
110 g_Config.iGPUBackend = (int)GPUBackend::VULKAN;
111 return true;
112 }
113
ContextReset()114 void LibretroVulkanContext::ContextReset() {
115 retro_hw_render_interface *vulkan;
116 if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&vulkan) || !vulkan) {
117 ERROR_LOG(G3D, "Failed to get HW rendering interface!\n");
118 return;
119 }
120 if (vulkan->interface_version != RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION) {
121 ERROR_LOG(G3D, "HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION, vulkan->interface_version);
122 return;
123 }
124 vk_libretro_set_hwrender_interface(vulkan);
125
126 LibretroHWRenderContext::ContextReset();
127 }
128
ContextDestroy()129 void LibretroVulkanContext::ContextDestroy() {
130 INFO_LOG(G3D, "LibretroVulkanContext::ContextDestroy()");
131
132 LostBackbuffer();
133 gpu->DeviceLost();
134 }
135
CreateDrawContext()136 void LibretroVulkanContext::CreateDrawContext() {
137 vk->ReinitSurface();
138
139 if (!vk->InitSwapchain()) {
140 return;
141 }
142
143 draw_ = Draw::T3DCreateVulkanContext(vk, false);
144 ((VulkanRenderManager*)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER))->SetInflightFrames(g_Config.iInflightFrames);
145 SetGPUBackend(GPUBackend::VULKAN);
146 }
147
Shutdown()148 void LibretroVulkanContext::Shutdown() {
149 LibretroHWRenderContext::Shutdown();
150
151 if (!vk) {
152 return;
153 }
154
155 vk->WaitUntilQueueIdle();
156
157 vk->DestroySwapchain();
158 vk->DestroySurface();
159 vk->DestroyDevice();
160 vk->DestroyInstance();
161 delete vk;
162 vk = nullptr;
163
164 finalize_glslang();
165 vk_libretro_shutdown();
166 }
167
GetAPIContext()168 void *LibretroVulkanContext::GetAPIContext() { return vk; }
169