Skip to content

Commit

Permalink
Get Vulkan going again with libretro. Rendering is the wrong size and…
Browse files Browse the repository at this point in the history
… crashes on exit, but it's a start.

Only tested on Windows.
  • Loading branch information
hrydgard committed Oct 11, 2020
1 parent ced83b4 commit dffc36b
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 42 deletions.
4 changes: 4 additions & 0 deletions Common/GPU/Vulkan/VulkanContext.cpp
Expand Up @@ -146,10 +146,14 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
}
}

// Temporary hack for libretro. For some reason, when we try to load the functions from this extension,
// we get null pointers when running libretro. Quite strange.
#if !defined(__LIBRETRO__)
if (IsInstanceExtensionAvailable(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
instance_extensions_enabled_.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
extensionsLookup_.KHR_get_physical_device_properties2 = true;
}
#endif

// Validate that all the instance extensions we ask for are actually available.
for (auto ext : instance_extensions_enabled_) {
Expand Down
65 changes: 35 additions & 30 deletions libretro/LibretroVulkanContext.cpp
Expand Up @@ -31,16 +31,15 @@ static bool create_device(retro_vulkan_context *context, VkInstance instance, Vk
init_glslang();

if (!VulkanLoad()) {
// TODO: In the context of RetroArch, someone has already loaded the functions -
// we shouldn't need to load them again. On the other hand, it can't really hurt, we're gonna
// get the same pointers.
// TODO: In the context of RetroArch, someone has already loaded the functions.
// But grabbing the pointers for ourselves can't really be a bad thing.
ERROR_LOG(G3D, "RetroArch called the Vulkan entry point without Vulkan available???");
return false;
}

vk = new VulkanContext();

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);
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);

// TODO: Here we'll inject the instance and all of the stuff into the VulkanContext.

Expand Down Expand Up @@ -69,10 +68,6 @@ static bool create_device(retro_vulkan_context *context, VkInstance instance, Vk
vk->InitSurface(WINDOWSYSTEM_WAYLAND, nullptr, nullptr);
#endif

if (!vk->InitSwapchain()) {
return false;
}

context->gpu = vk->GetPhysicalDevice(physical_device);
context->device = vk->GetDevice();
context->queue = vk->GetGraphicsQueue();
Expand Down Expand Up @@ -100,13 +95,44 @@ bool LibretroVulkanContext::Init() {
return false;
}

static const struct retro_hw_render_context_negotiation_interface_vulkan iface = { RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN, RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION, GetApplicationInfo, create_device, nullptr };
static const struct retro_hw_render_context_negotiation_interface_vulkan iface = {
RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN,
RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION,
GetApplicationInfo,
create_device, // Callback above.
nullptr,
};
Libretro::environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE, (void *)&iface);

g_Config.iGPUBackend = (int)GPUBackend::VULKAN;
return true;
}

void LibretroVulkanContext::ContextReset() {
retro_hw_render_interface *vulkan;
if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&vulkan) || !vulkan) {
ERROR_LOG(G3D, "Failed to get HW rendering interface!\n");
return;
}
if (vulkan->interface_version != RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION) {
ERROR_LOG(G3D, "HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION, vulkan->interface_version);
return;
}
vk_libretro_set_hwrender_interface(vulkan);

LibretroHWRenderContext::ContextReset();
}

void LibretroVulkanContext::CreateDrawContext() {
vk->ReinitSurface();

if (!vk->InitSwapchain()) {
return;
}

draw_ = Draw::T3DCreateVulkanContext(vk, false);
}

void LibretroVulkanContext::Shutdown() {
LibretroHWRenderContext::Shutdown();

Expand All @@ -128,24 +154,3 @@ void LibretroVulkanContext::Shutdown() {
}

void *LibretroVulkanContext::GetAPIContext() { return vk; }

void LibretroVulkanContext::CreateDrawContext() {
retro_hw_render_interface *vulkan;
if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&vulkan) || !vulkan) {
ERROR_LOG(G3D, "Failed to get HW rendering interface!\n");
return;
}
if (vulkan->interface_version != RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION) {
ERROR_LOG(G3D, "HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION, vulkan->interface_version);
return;
}
vk_libretro_set_hwrender_interface(vulkan);

vk->ReinitSurface();

if (!vk->InitSwapchain()) {
return;
}

draw_ = Draw::T3DCreateVulkanContext(vk, false);
}
3 changes: 3 additions & 0 deletions libretro/LibretroVulkanContext.h
Expand Up @@ -12,6 +12,9 @@ class LibretroVulkanContext : public LibretroHWRenderContext {

void *GetAPIContext() override;
void CreateDrawContext() override;

void ContextReset() override;

GPUCore GetGPUCore() override { return GPUCORE_VULKAN; }
const char *Ident() override { return "Vulkan"; }
};
8 changes: 8 additions & 0 deletions libretro/Makefile
Expand Up @@ -284,6 +284,10 @@ else ifneq (,$(findstring windows_msvc2017,$(platform)))
LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO
LIBS += WindowsApp.lib
endif

ifeq ($(DEBUG), 1)
MSVC2017CompileFlags += -DEBUG
endif

CFLAGS += $(MSVC2017CompileFlags) -nologo
CXXFLAGS += $(MSVC2017CompileFlags) -nologo -EHsc
Expand Down Expand Up @@ -392,6 +396,10 @@ else ifneq (,$(findstring windows_msvc2019,$(platform)))
LIBS += WindowsApp.lib
endif

ifeq ($(DEBUG), 1)
MSVC2019CompileFlags += -DEBUG
endif

CFLAGS += $(MSVC2019CompileFlags) -nologo
CXXFLAGS += $(MSVC2019CompileFlags) -nologo -EHsc

Expand Down
10 changes: 8 additions & 2 deletions libretro/README_WINDOWS.txt
Expand Up @@ -13,8 +13,7 @@ pacman -S make
Then use the following in msys:

cd libretro

make platform=windows_msvc2019_desktop_x64 -j32 && cp ppsspp_libretro.* /d/retroarch/cores
make platform=windows_msvc2019_desktop_x64 -j32 && cp ppsspp_libretro.* /d/retroarch/cores && rm nul

Note that the latter part copies the DLL/PDB into wherever retroarch reads it from. Might need to adjust the path,
and adjust -j32 depending on your number of logical CPUs - might not need that many threads (or you might need more...).
Expand All @@ -24,6 +23,13 @@ and adjust -j32 depending on your number of logical CPUs - might not need that m
To debug from within MSVC, open retroarch.exe (or retroarch_debug.exe) as a Project/Solution, then open a few of the cpp files,
set some breakpoints and just launch using F5.

If you get

```
../git-version.cpp(3): error C2374: 'PPSSPP_GIT_VERSION': redefinition; multiple initialization
../git-version.cpp(1): note: see declaration of 'PPSSPP_GIT_VERSION'
```
just do `rm ../git-version.cpp`.


Useful libretro/vulkan sample code:
Expand Down
33 changes: 23 additions & 10 deletions libretro/libretro_vulkan.cpp
@@ -1,10 +1,19 @@
// Debugging notes
// The crash happens when we try to call vkGetPhysicalDeviceProperties2KHR which seems to be null.
//
// Apparently we don't manage to specify the extensions we want. Still something reports that this one
// is present?
// Failed to load : vkGetPhysicalDeviceProperties2KHR
// Failed to load : vkGetPhysicalDeviceFeatures2KHR

#include <cstring>
#include <cassert>
#include <vector>
#include <mutex>
#include <condition_variable>

#include "Common/Log.h"

#define VK_NO_PROTOTYPES
#include "libretro/libretro_vulkan.h"

Expand Down Expand Up @@ -49,6 +58,7 @@ struct VkSwapchainKHR_T {
static VkSwapchainKHR_T chain;

#define LIBRETRO_VK_WARP_LIST() \
LIBRETRO_VK_WARP_FUNC(vkCreateInstance); \
LIBRETRO_VK_WARP_FUNC(vkDestroyInstance); \
LIBRETRO_VK_WARP_FUNC(vkCreateDevice); \
LIBRETRO_VK_WARP_FUNC(vkDestroyDevice); \
Expand Down Expand Up @@ -332,13 +342,11 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass_libretro(VkDevice device, cons
}

#undef LIBRETRO_VK_WARP_FUNC
#define LIBRETRO_VK_WARP_FUNC(x) \
do { \
if (!strcmp(pName, #x)) { \
x##_org = (PFN_##x)fptr; \
return (PFN_vkVoidFunction)x##_libretro; \
} \
} while (0)
#define LIBRETRO_VK_WARP_FUNC(x) \
if (!strcmp(pName, #x)) { \
x##_org = (PFN_##x)fptr; \
return (PFN_vkVoidFunction)x##_libretro; \
}

VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr_libretro(VkInstance instance, const char *pName) {
if (false
Expand All @@ -362,8 +370,10 @@ VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr_libretro(VkInstan
}

PFN_vkVoidFunction fptr = vkGetInstanceProcAddr_org(instance, pName);
if (!fptr)
return fptr;
if (!fptr) {
ERROR_LOG(G3D, "Failed to load VK instance function: %s", pName);
return fptr;
}

LIBRETRO_VK_WARP_LIST();

Expand Down Expand Up @@ -400,7 +410,10 @@ void vk_libretro_init(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR su
vkCreateInstance = vkCreateInstance_libretro;
}

void vk_libretro_set_hwrender_interface(retro_hw_render_interface *hw_render_interface) { vulkan = (retro_hw_render_interface_vulkan *)hw_render_interface; }
void vk_libretro_set_hwrender_interface(retro_hw_render_interface *hw_render_interface) {
vulkan = (retro_hw_render_interface_vulkan *)hw_render_interface;
}

void vk_libretro_shutdown() {
memset(&vk_init_info, 0x00, sizeof(vk_init_info));
vulkan = NULL;
Expand Down

0 comments on commit dffc36b

Please sign in to comment.