summaryrefslogtreecommitdiff
path: root/src/yuzu_cmd/emu_window
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu_cmd/emu_window')
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp4
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h3
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp7
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h4
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp162
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h39
6 files changed, 219 insertions, 0 deletions
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index b1c512db1..e96139885 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -89,6 +89,10 @@ bool EmuWindow_SDL2::IsOpen() const {
89 return is_open; 89 return is_open;
90} 90}
91 91
92bool EmuWindow_SDL2::IsShown() const {
93 return is_shown;
94}
95
92void EmuWindow_SDL2::OnResize() { 96void EmuWindow_SDL2::OnResize() {
93 int width, height; 97 int width, height;
94 SDL_GetWindowSize(render_window, &width, &height); 98 SDL_GetWindowSize(render_window, &width, &height);
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index eaa971f77..b38f56661 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -21,6 +21,9 @@ public:
21 /// Whether the window is still open, and a close request hasn't yet been sent 21 /// Whether the window is still open, and a close request hasn't yet been sent
22 bool IsOpen() const; 22 bool IsOpen() const;
23 23
24 /// Returns if window is shown (not minimized)
25 bool IsShown() const override;
26
24protected: 27protected:
25 /// Called by PollEvents when a key is pressed or released. 28 /// Called by PollEvents when a key is pressed or released.
26 void OnKeyEvent(int key, u8 state); 29 void OnKeyEvent(int key, u8 state);
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
index 6fde694a2..7ffa0ac09 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -9,6 +9,7 @@
9#include <SDL.h> 9#include <SDL.h>
10#include <fmt/format.h> 10#include <fmt/format.h>
11#include <glad/glad.h> 11#include <glad/glad.h>
12#include "common/assert.h"
12#include "common/logging/log.h" 13#include "common/logging/log.h"
13#include "common/scm_rev.h" 14#include "common/scm_rev.h"
14#include "common/string_util.h" 15#include "common/string_util.h"
@@ -151,6 +152,12 @@ void EmuWindow_SDL2_GL::DoneCurrent() {
151 SDL_GL_MakeCurrent(render_window, nullptr); 152 SDL_GL_MakeCurrent(render_window, nullptr);
152} 153}
153 154
155void EmuWindow_SDL2_GL::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance,
156 void* surface) const {
157 // Should not have been called from OpenGL
158 UNREACHABLE();
159}
160
154std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const { 161std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const {
155 return std::make_unique<SDLGLContext>(); 162 return std::make_unique<SDLGLContext>();
156} 163}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
index 630deba93..c753085a8 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h
@@ -22,6 +22,10 @@ public:
22 /// Releases the GL context from the caller thread 22 /// Releases the GL context from the caller thread
23 void DoneCurrent() override; 23 void DoneCurrent() override;
24 24
25 /// Ignored in OpenGL
26 void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance,
27 void* surface) const override;
28
25 std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; 29 std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
26 30
27private: 31private:
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
new file mode 100644
index 000000000..a203f0da9
--- /dev/null
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp
@@ -0,0 +1,162 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <string>
7#include <vector>
8#include <SDL.h>
9#include <SDL_vulkan.h>
10#include <fmt/format.h>
11#include <vulkan/vulkan.h>
12#include "common/assert.h"
13#include "common/logging/log.h"
14#include "common/scm_rev.h"
15#include "core/settings.h"
16#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
17
18EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(bool fullscreen) : EmuWindow_SDL2(fullscreen) {
19 if (SDL_Vulkan_LoadLibrary(nullptr) != 0) {
20 LOG_CRITICAL(Frontend, "SDL failed to load the Vulkan library: {}", SDL_GetError());
21 exit(EXIT_FAILURE);
22 }
23
24 vkGetInstanceProcAddr =
25 reinterpret_cast<PFN_vkGetInstanceProcAddr>(SDL_Vulkan_GetVkGetInstanceProcAddr());
26 if (vkGetInstanceProcAddr == nullptr) {
27 LOG_CRITICAL(Frontend, "Failed to retrieve Vulkan function pointer!");
28 exit(EXIT_FAILURE);
29 }
30
31 const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name,
32 Common::g_scm_branch, Common::g_scm_desc);
33 render_window =
34 SDL_CreateWindow(window_title.c_str(),
35 SDL_WINDOWPOS_UNDEFINED, // x position
36 SDL_WINDOWPOS_UNDEFINED, // y position
37 Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height,
38 SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_VULKAN);
39
40 const bool use_standard_layers = UseStandardLayers(vkGetInstanceProcAddr);
41
42 u32 extra_ext_count{};
43 if (!SDL_Vulkan_GetInstanceExtensions(render_window, &extra_ext_count, NULL)) {
44 LOG_CRITICAL(Frontend, "Failed to query Vulkan extensions count from SDL! {}",
45 SDL_GetError());
46 exit(1);
47 }
48
49 auto extra_ext_names = std::make_unique<const char* []>(extra_ext_count);
50 if (!SDL_Vulkan_GetInstanceExtensions(render_window, &extra_ext_count, extra_ext_names.get())) {
51 LOG_CRITICAL(Frontend, "Failed to query Vulkan extensions from SDL! {}", SDL_GetError());
52 exit(1);
53 }
54 std::vector<const char*> enabled_extensions;
55 enabled_extensions.insert(enabled_extensions.begin(), extra_ext_names.get(),
56 extra_ext_names.get() + extra_ext_count);
57
58 std::vector<const char*> enabled_layers;
59 if (use_standard_layers) {
60 enabled_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
61 enabled_layers.push_back("VK_LAYER_LUNARG_standard_validation");
62 }
63
64 VkApplicationInfo app_info{};
65 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
66 app_info.apiVersion = VK_API_VERSION_1_1;
67 app_info.applicationVersion = VK_MAKE_VERSION(0, 1, 0);
68 app_info.pApplicationName = "yuzu-emu";
69 app_info.engineVersion = VK_MAKE_VERSION(0, 1, 0);
70 app_info.pEngineName = "yuzu-emu";
71
72 VkInstanceCreateInfo instance_ci{};
73 instance_ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
74 instance_ci.pApplicationInfo = &app_info;
75 instance_ci.enabledExtensionCount = static_cast<u32>(enabled_extensions.size());
76 instance_ci.ppEnabledExtensionNames = enabled_extensions.data();
77 if (Settings::values.renderer_debug) {
78 instance_ci.enabledLayerCount = static_cast<u32>(enabled_layers.size());
79 instance_ci.ppEnabledLayerNames = enabled_layers.data();
80 }
81
82 const auto vkCreateInstance =
83 reinterpret_cast<PFN_vkCreateInstance>(vkGetInstanceProcAddr(nullptr, "vkCreateInstance"));
84 if (vkCreateInstance == nullptr ||
85 vkCreateInstance(&instance_ci, nullptr, &vk_instance) != VK_SUCCESS) {
86 LOG_CRITICAL(Frontend, "Failed to create Vulkan instance!");
87 exit(EXIT_FAILURE);
88 }
89
90 vkDestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(
91 vkGetInstanceProcAddr(vk_instance, "vkDestroyInstance"));
92 if (vkDestroyInstance == nullptr) {
93 LOG_CRITICAL(Frontend, "Failed to retrieve Vulkan function pointer!");
94 exit(EXIT_FAILURE);
95 }
96
97 if (!SDL_Vulkan_CreateSurface(render_window, vk_instance, &vk_surface)) {
98 LOG_CRITICAL(Frontend, "Failed to create Vulkan surface! {}", SDL_GetError());
99 exit(EXIT_FAILURE);
100 }
101
102 OnResize();
103 OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
104 SDL_PumpEvents();
105 LOG_INFO(Frontend, "yuzu Version: {} | {}-{} (Vulkan)", Common::g_build_name,
106 Common::g_scm_branch, Common::g_scm_desc);
107}
108
109EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() {
110 vkDestroyInstance(vk_instance, nullptr);
111}
112
113void EmuWindow_SDL2_VK::SwapBuffers() {}
114
115void EmuWindow_SDL2_VK::MakeCurrent() {
116 // Unused on Vulkan
117}
118
119void EmuWindow_SDL2_VK::DoneCurrent() {
120 // Unused on Vulkan
121}
122
123void EmuWindow_SDL2_VK::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance,
124 void* surface) const {
125 const auto instance_proc_addr = vkGetInstanceProcAddr;
126 std::memcpy(get_instance_proc_addr, &instance_proc_addr, sizeof(instance_proc_addr));
127 std::memcpy(instance, &vk_instance, sizeof(vk_instance));
128 std::memcpy(surface, &vk_surface, sizeof(vk_surface));
129}
130
131std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const {
132 return nullptr;
133}
134
135bool EmuWindow_SDL2_VK::UseStandardLayers(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr) const {
136 if (!Settings::values.renderer_debug) {
137 return false;
138 }
139
140 const auto vkEnumerateInstanceLayerProperties =
141 reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
142 vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceLayerProperties"));
143 if (vkEnumerateInstanceLayerProperties == nullptr) {
144 LOG_CRITICAL(Frontend, "Failed to retrieve Vulkan function pointer!");
145 return false;
146 }
147
148 u32 available_layers_count{};
149 if (vkEnumerateInstanceLayerProperties(&available_layers_count, nullptr) != VK_SUCCESS) {
150 LOG_CRITICAL(Frontend, "Failed to enumerate Vulkan validation layers!");
151 return false;
152 }
153 std::vector<VkLayerProperties> layers(available_layers_count);
154 if (vkEnumerateInstanceLayerProperties(&available_layers_count, layers.data()) != VK_SUCCESS) {
155 LOG_CRITICAL(Frontend, "Failed to enumerate Vulkan validation layers!");
156 return false;
157 }
158
159 return std::find_if(layers.begin(), layers.end(), [&](const auto& layer) {
160 return layer.layerName == std::string("VK_LAYER_LUNARG_standard_validation");
161 }) != layers.end();
162}
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
new file mode 100644
index 000000000..2a7c06a24
--- /dev/null
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h
@@ -0,0 +1,39 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vulkan/vulkan.h>
8#include "core/frontend/emu_window.h"
9#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
10
11class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
12public:
13 explicit EmuWindow_SDL2_VK(bool fullscreen);
14 ~EmuWindow_SDL2_VK();
15
16 /// Swap buffers to display the next frame
17 void SwapBuffers() override;
18
19 /// Makes the graphics context current for the caller thread
20 void MakeCurrent() override;
21
22 /// Releases the GL context from the caller thread
23 void DoneCurrent() override;
24
25 /// Retrieves Vulkan specific handlers from the window
26 void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance,
27 void* surface) const override;
28
29 std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
30
31private:
32 bool UseStandardLayers(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr) const;
33
34 VkInstance vk_instance{};
35 VkSurfaceKHR vk_surface{};
36
37 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr{};
38 PFN_vkDestroyInstance vkDestroyInstance{};
39};