emu_window_sdl2_vk.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <string>
  6. #include <vector>
  7. #include <SDL.h>
  8. #include <SDL_vulkan.h>
  9. #include <fmt/format.h>
  10. #include <vulkan/vulkan.h>
  11. #include "common/assert.h"
  12. #include "common/logging/log.h"
  13. #include "common/scm_rev.h"
  14. #include "core/settings.h"
  15. #include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
  16. EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen)
  17. : EmuWindow_SDL2{system, fullscreen} {
  18. if (SDL_Vulkan_LoadLibrary(nullptr) != 0) {
  19. LOG_CRITICAL(Frontend, "SDL failed to load the Vulkan library: {}", SDL_GetError());
  20. exit(EXIT_FAILURE);
  21. }
  22. vkGetInstanceProcAddr =
  23. reinterpret_cast<PFN_vkGetInstanceProcAddr>(SDL_Vulkan_GetVkGetInstanceProcAddr());
  24. if (vkGetInstanceProcAddr == nullptr) {
  25. LOG_CRITICAL(Frontend, "Failed to retrieve Vulkan function pointer!");
  26. exit(EXIT_FAILURE);
  27. }
  28. const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name,
  29. Common::g_scm_branch, Common::g_scm_desc);
  30. render_window =
  31. SDL_CreateWindow(window_title.c_str(),
  32. SDL_WINDOWPOS_UNDEFINED, // x position
  33. SDL_WINDOWPOS_UNDEFINED, // y position
  34. Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height,
  35. SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_VULKAN);
  36. const bool use_standard_layers = UseStandardLayers(vkGetInstanceProcAddr);
  37. u32 extra_ext_count{};
  38. if (!SDL_Vulkan_GetInstanceExtensions(render_window, &extra_ext_count, NULL)) {
  39. LOG_CRITICAL(Frontend, "Failed to query Vulkan extensions count from SDL! {}",
  40. SDL_GetError());
  41. exit(1);
  42. }
  43. auto extra_ext_names = std::make_unique<const char* []>(extra_ext_count);
  44. if (!SDL_Vulkan_GetInstanceExtensions(render_window, &extra_ext_count, extra_ext_names.get())) {
  45. LOG_CRITICAL(Frontend, "Failed to query Vulkan extensions from SDL! {}", SDL_GetError());
  46. exit(1);
  47. }
  48. std::vector<const char*> enabled_extensions;
  49. enabled_extensions.insert(enabled_extensions.begin(), extra_ext_names.get(),
  50. extra_ext_names.get() + extra_ext_count);
  51. std::vector<const char*> enabled_layers;
  52. if (use_standard_layers) {
  53. enabled_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
  54. enabled_layers.push_back("VK_LAYER_LUNARG_standard_validation");
  55. }
  56. VkApplicationInfo app_info{};
  57. app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  58. app_info.apiVersion = VK_API_VERSION_1_1;
  59. app_info.applicationVersion = VK_MAKE_VERSION(0, 1, 0);
  60. app_info.pApplicationName = "yuzu-emu";
  61. app_info.engineVersion = VK_MAKE_VERSION(0, 1, 0);
  62. app_info.pEngineName = "yuzu-emu";
  63. VkInstanceCreateInfo instance_ci{};
  64. instance_ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  65. instance_ci.pApplicationInfo = &app_info;
  66. instance_ci.enabledExtensionCount = static_cast<u32>(enabled_extensions.size());
  67. instance_ci.ppEnabledExtensionNames = enabled_extensions.data();
  68. if (Settings::values.renderer_debug) {
  69. instance_ci.enabledLayerCount = static_cast<u32>(enabled_layers.size());
  70. instance_ci.ppEnabledLayerNames = enabled_layers.data();
  71. }
  72. const auto vkCreateInstance =
  73. reinterpret_cast<PFN_vkCreateInstance>(vkGetInstanceProcAddr(nullptr, "vkCreateInstance"));
  74. if (vkCreateInstance == nullptr ||
  75. vkCreateInstance(&instance_ci, nullptr, &vk_instance) != VK_SUCCESS) {
  76. LOG_CRITICAL(Frontend, "Failed to create Vulkan instance!");
  77. exit(EXIT_FAILURE);
  78. }
  79. vkDestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(
  80. vkGetInstanceProcAddr(vk_instance, "vkDestroyInstance"));
  81. if (vkDestroyInstance == nullptr) {
  82. LOG_CRITICAL(Frontend, "Failed to retrieve Vulkan function pointer!");
  83. exit(EXIT_FAILURE);
  84. }
  85. if (!SDL_Vulkan_CreateSurface(render_window, vk_instance, &vk_surface)) {
  86. LOG_CRITICAL(Frontend, "Failed to create Vulkan surface! {}", SDL_GetError());
  87. exit(EXIT_FAILURE);
  88. }
  89. OnResize();
  90. OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
  91. SDL_PumpEvents();
  92. LOG_INFO(Frontend, "yuzu Version: {} | {}-{} (Vulkan)", Common::g_build_name,
  93. Common::g_scm_branch, Common::g_scm_desc);
  94. }
  95. EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() {
  96. vkDestroyInstance(vk_instance, nullptr);
  97. }
  98. void EmuWindow_SDL2_VK::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance,
  99. void* surface) const {
  100. const auto instance_proc_addr = vkGetInstanceProcAddr;
  101. std::memcpy(get_instance_proc_addr, &instance_proc_addr, sizeof(instance_proc_addr));
  102. std::memcpy(instance, &vk_instance, sizeof(vk_instance));
  103. std::memcpy(surface, &vk_surface, sizeof(vk_surface));
  104. }
  105. std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const {
  106. return nullptr;
  107. }
  108. bool EmuWindow_SDL2_VK::UseStandardLayers(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr) const {
  109. if (!Settings::values.renderer_debug) {
  110. return false;
  111. }
  112. const auto vkEnumerateInstanceLayerProperties =
  113. reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
  114. vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceLayerProperties"));
  115. if (vkEnumerateInstanceLayerProperties == nullptr) {
  116. LOG_CRITICAL(Frontend, "Failed to retrieve Vulkan function pointer!");
  117. return false;
  118. }
  119. u32 available_layers_count{};
  120. if (vkEnumerateInstanceLayerProperties(&available_layers_count, nullptr) != VK_SUCCESS) {
  121. LOG_CRITICAL(Frontend, "Failed to enumerate Vulkan validation layers!");
  122. return false;
  123. }
  124. std::vector<VkLayerProperties> layers(available_layers_count);
  125. if (vkEnumerateInstanceLayerProperties(&available_layers_count, layers.data()) != VK_SUCCESS) {
  126. LOG_CRITICAL(Frontend, "Failed to enumerate Vulkan validation layers!");
  127. return false;
  128. }
  129. return std::find_if(layers.begin(), layers.end(), [&](const auto& layer) {
  130. return layer.layerName == std::string("VK_LAYER_LUNARG_standard_validation");
  131. }) != layers.end();
  132. }
  133. void EmuWindow_SDL2_VK::Present() {
  134. // TODO (bunnei): ImplementMe
  135. }