emu_window_sdl2_vk.cpp 6.4 KB

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