summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt2
m---------externals/Vulkan-Headers0
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/video_core/CMakeLists.txt10
-rw-r--r--src/video_core/renderer_vulkan/declarations.h45
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp231
-rw-r--r--src/video_core/renderer_vulkan/vk_device.h116
9 files changed, 409 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules
index a33a04167..2558a5ebc 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -37,3 +37,6 @@
37[submodule "discord-rpc"] 37[submodule "discord-rpc"]
38 path = externals/discord-rpc 38 path = externals/discord-rpc
39 url = https://github.com/discordapp/discord-rpc.git 39 url = https://github.com/discordapp/discord-rpc.git
40[submodule "Vulkan-Headers"]
41 path = externals/Vulkan-Headers
42 url = https://github.com/KhronosGroup/Vulkan-Headers.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 97d888762..32cfa8580 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,6 +23,8 @@ option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OF
23 23
24option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) 24option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
25 25
26option(ENABLE_VULKAN "Enables Vulkan backend" ON)
27
26option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) 28option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
27 29
28if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit) 30if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
diff --git a/externals/Vulkan-Headers b/externals/Vulkan-Headers
new file mode 160000
Subproject 7f02d9bb810f371de0fe833c80004c34f7ff8c5
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 12f6d0114..a5e031189 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -232,6 +232,7 @@ void DebuggerBackend::Write(const Entry& entry) {
232 CLS(Render) \ 232 CLS(Render) \
233 SUB(Render, Software) \ 233 SUB(Render, Software) \
234 SUB(Render, OpenGL) \ 234 SUB(Render, OpenGL) \
235 SUB(Render, Vulkan) \
235 CLS(Audio) \ 236 CLS(Audio) \
236 SUB(Audio, DSP) \ 237 SUB(Audio, DSP) \
237 SUB(Audio, Sink) \ 238 SUB(Audio, Sink) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index d4ec31ec3..8ed6d5050 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -112,6 +112,7 @@ enum class Class : ClassType {
112 Render, ///< Emulator video output and hardware acceleration 112 Render, ///< Emulator video output and hardware acceleration
113 Render_Software, ///< Software renderer backend 113 Render_Software, ///< Software renderer backend
114 Render_OpenGL, ///< OpenGL backend 114 Render_OpenGL, ///< OpenGL backend
115 Render_Vulkan, ///< Vulkan backend
115 Audio, ///< Audio emulation 116 Audio, ///< Audio emulation
116 Audio_DSP, ///< The HLE implementation of the DSP 117 Audio_DSP, ///< The HLE implementation of the DSP
117 Audio_Sink, ///< Emulator audio output backend 118 Audio_Sink, ///< Emulator audio output backend
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 1db0d031d..d35a738d5 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -101,6 +101,16 @@ add_library(video_core STATIC
101 video_core.h 101 video_core.h
102) 102)
103 103
104if (ENABLE_VULKAN)
105 target_sources(video_core PRIVATE
106 renderer_vulkan/declarations.h
107 renderer_vulkan/vk_device.cpp
108 renderer_vulkan/vk_device.h)
109
110 target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include)
111 target_compile_definitions(video_core PRIVATE HAS_VULKAN)
112endif()
113
104create_target_directory_groups(video_core) 114create_target_directory_groups(video_core)
105 115
106target_link_libraries(video_core PUBLIC common core) 116target_link_libraries(video_core PUBLIC common core)
diff --git a/src/video_core/renderer_vulkan/declarations.h b/src/video_core/renderer_vulkan/declarations.h
new file mode 100644
index 000000000..ba25b5bc7
--- /dev/null
+++ b/src/video_core/renderer_vulkan/declarations.h
@@ -0,0 +1,45 @@
1// Copyright 2019 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.hpp>
8
9namespace Vulkan {
10
11// vulkan.hpp unique handlers use DispatchLoaderStatic
12template <typename T>
13using UniqueHandle = vk::UniqueHandle<T, vk::DispatchLoaderDynamic>;
14
15using UniqueAccelerationStructureNV = UniqueHandle<vk::AccelerationStructureNV>;
16using UniqueBuffer = UniqueHandle<vk::Buffer>;
17using UniqueBufferView = UniqueHandle<vk::BufferView>;
18using UniqueCommandBuffer = UniqueHandle<vk::CommandBuffer>;
19using UniqueCommandPool = UniqueHandle<vk::CommandPool>;
20using UniqueDescriptorPool = UniqueHandle<vk::DescriptorPool>;
21using UniqueDescriptorSet = UniqueHandle<vk::DescriptorSet>;
22using UniqueDescriptorSetLayout = UniqueHandle<vk::DescriptorSetLayout>;
23using UniqueDescriptorUpdateTemplate = UniqueHandle<vk::DescriptorUpdateTemplate>;
24using UniqueDevice = UniqueHandle<vk::Device>;
25using UniqueDeviceMemory = UniqueHandle<vk::DeviceMemory>;
26using UniqueEvent = UniqueHandle<vk::Event>;
27using UniqueFence = UniqueHandle<vk::Fence>;
28using UniqueFramebuffer = UniqueHandle<vk::Framebuffer>;
29using UniqueImage = UniqueHandle<vk::Image>;
30using UniqueImageView = UniqueHandle<vk::ImageView>;
31using UniqueIndirectCommandsLayoutNVX = UniqueHandle<vk::IndirectCommandsLayoutNVX>;
32using UniqueObjectTableNVX = UniqueHandle<vk::ObjectTableNVX>;
33using UniquePipeline = UniqueHandle<vk::Pipeline>;
34using UniquePipelineCache = UniqueHandle<vk::PipelineCache>;
35using UniquePipelineLayout = UniqueHandle<vk::PipelineLayout>;
36using UniqueQueryPool = UniqueHandle<vk::QueryPool>;
37using UniqueRenderPass = UniqueHandle<vk::RenderPass>;
38using UniqueSampler = UniqueHandle<vk::Sampler>;
39using UniqueSamplerYcbcrConversion = UniqueHandle<vk::SamplerYcbcrConversion>;
40using UniqueSemaphore = UniqueHandle<vk::Semaphore>;
41using UniqueShaderModule = UniqueHandle<vk::ShaderModule>;
42using UniqueSwapchainKHR = UniqueHandle<vk::SwapchainKHR>;
43using UniqueValidationCacheEXT = UniqueHandle<vk::ValidationCacheEXT>;
44
45} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
new file mode 100644
index 000000000..78a4e5f0e
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -0,0 +1,231 @@
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 <map>
6#include <optional>
7#include <set>
8#include <vector>
9#include "common/assert.h"
10#include "video_core/renderer_vulkan/declarations.h"
11#include "video_core/renderer_vulkan/vk_device.h"
12
13namespace Vulkan {
14
15namespace Alternatives {
16
17constexpr std::array<vk::Format, 3> Depth24UnormS8Uint = {
18 vk::Format::eD32SfloatS8Uint, vk::Format::eD16UnormS8Uint, {}};
19constexpr std::array<vk::Format, 3> Depth16UnormS8Uint = {
20 vk::Format::eD24UnormS8Uint, vk::Format::eD32SfloatS8Uint, {}};
21
22} // namespace Alternatives
23
24constexpr const vk::Format* GetFormatAlternatives(vk::Format format) {
25 switch (format) {
26 case vk::Format::eD24UnormS8Uint:
27 return Alternatives::Depth24UnormS8Uint.data();
28 case vk::Format::eD16UnormS8Uint:
29 return Alternatives::Depth16UnormS8Uint.data();
30 default:
31 return nullptr;
32 }
33}
34
35constexpr vk::FormatFeatureFlags GetFormatFeatures(vk::FormatProperties properties,
36 FormatType format_type) {
37 switch (format_type) {
38 case FormatType::Linear:
39 return properties.linearTilingFeatures;
40 case FormatType::Optimal:
41 return properties.optimalTilingFeatures;
42 case FormatType::Buffer:
43 return properties.bufferFeatures;
44 default:
45 return {};
46 }
47}
48
49VKDevice::VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical,
50 vk::SurfaceKHR surface)
51 : physical{physical}, format_properties{GetFormatProperties(dldi, physical)} {
52 SetupFamilies(dldi, surface);
53 SetupProperties(dldi);
54}
55
56VKDevice::~VKDevice() = default;
57
58bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance) {
59 const auto queue_cis = GetDeviceQueueCreateInfos();
60 vk::PhysicalDeviceFeatures device_features{};
61
62 const std::vector<const char*> extensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
63 const vk::DeviceCreateInfo device_ci({}, static_cast<u32>(queue_cis.size()), queue_cis.data(),
64 0, nullptr, static_cast<u32>(extensions.size()),
65 extensions.data(), &device_features);
66 vk::Device dummy_logical;
67 if (physical.createDevice(&device_ci, nullptr, &dummy_logical, dldi) != vk::Result::eSuccess) {
68 LOG_CRITICAL(Render_Vulkan, "Logical device failed to be created!");
69 return false;
70 }
71
72 dld.init(instance, dldi.vkGetInstanceProcAddr, dummy_logical, dldi.vkGetDeviceProcAddr);
73 logical = UniqueDevice(
74 dummy_logical, vk::ObjectDestroy<vk::NoParent, vk::DispatchLoaderDynamic>(nullptr, dld));
75
76 graphics_queue = logical->getQueue(graphics_family, 0, dld);
77 present_queue = logical->getQueue(present_family, 0, dld);
78 return true;
79}
80
81vk::Format VKDevice::GetSupportedFormat(vk::Format wanted_format,
82 vk::FormatFeatureFlags wanted_usage,
83 FormatType format_type) const {
84 if (IsFormatSupported(wanted_format, wanted_usage, format_type)) {
85 return wanted_format;
86 }
87 // The wanted format is not supported by hardware, search for alternatives
88 const vk::Format* alternatives = GetFormatAlternatives(wanted_format);
89 if (alternatives == nullptr) {
90 LOG_CRITICAL(Render_Vulkan,
91 "Format={} with usage={} and type={} has no defined alternatives and host "
92 "hardware does not support it",
93 static_cast<u32>(wanted_format), static_cast<u32>(wanted_usage),
94 static_cast<u32>(format_type));
95 UNREACHABLE();
96 return wanted_format;
97 }
98
99 std::size_t i = 0;
100 for (vk::Format alternative = alternatives[0]; alternative != vk::Format{};
101 alternative = alternatives[++i]) {
102 if (!IsFormatSupported(alternative, wanted_usage, format_type))
103 continue;
104 LOG_WARNING(Render_Vulkan,
105 "Emulating format={} with alternative format={} with usage={} and type={}",
106 static_cast<u32>(wanted_format), static_cast<u32>(alternative),
107 static_cast<u32>(wanted_usage), static_cast<u32>(format_type));
108 return alternative;
109 }
110
111 // No alternatives found, panic
112 LOG_CRITICAL(Render_Vulkan,
113 "Format={} with usage={} and type={} is not supported by the host hardware and "
114 "doesn't support any of the alternatives",
115 static_cast<u32>(wanted_format), static_cast<u32>(wanted_usage),
116 static_cast<u32>(format_type));
117 UNREACHABLE();
118 return wanted_format;
119}
120
121bool VKDevice::IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage,
122 FormatType format_type) const {
123 const auto it = format_properties.find(wanted_format);
124 if (it == format_properties.end()) {
125 LOG_CRITICAL(Render_Vulkan, "Unimplemented format query={}",
126 static_cast<u32>(wanted_format));
127 UNREACHABLE();
128 return true;
129 }
130 const vk::FormatFeatureFlags supported_usage = GetFormatFeatures(it->second, format_type);
131 return (supported_usage & wanted_usage) == wanted_usage;
132}
133
134bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical,
135 vk::SurfaceKHR surface) {
136 const std::string swapchain_extension = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
137
138 bool has_swapchain{};
139 for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) {
140 has_swapchain |= prop.extensionName == swapchain_extension;
141 }
142 if (!has_swapchain) {
143 // The device doesn't support creating swapchains.
144 return false;
145 }
146
147 bool has_graphics{}, has_present{};
148 const auto queue_family_properties = physical.getQueueFamilyProperties(dldi);
149 for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
150 const auto& family = queue_family_properties[i];
151 if (family.queueCount == 0)
152 continue;
153
154 has_graphics |=
155 (family.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlagBits>(0);
156 has_present |= physical.getSurfaceSupportKHR(i, surface, dldi) != 0;
157 }
158 if (!has_graphics || !has_present) {
159 // The device doesn't have a graphics and present queue.
160 return false;
161 }
162
163 // TODO(Rodrigo): Check if the device matches all requeriments.
164 const vk::PhysicalDeviceProperties props = physical.getProperties(dldi);
165 if (props.limits.maxUniformBufferRange < 65536) {
166 return false;
167 }
168
169 // Device is suitable.
170 return true;
171}
172
173void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceKHR surface) {
174 std::optional<u32> graphics_family_, present_family_;
175
176 const auto queue_family_properties = physical.getQueueFamilyProperties(dldi);
177 for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
178 if (graphics_family_ && present_family_)
179 break;
180
181 const auto& queue_family = queue_family_properties[i];
182 if (queue_family.queueCount == 0)
183 continue;
184
185 if (queue_family.queueFlags & vk::QueueFlagBits::eGraphics)
186 graphics_family_ = i;
187 if (physical.getSurfaceSupportKHR(i, surface, dldi))
188 present_family_ = i;
189 }
190 ASSERT(graphics_family_ && present_family_);
191
192 graphics_family = *graphics_family_;
193 present_family = *present_family_;
194}
195
196void VKDevice::SetupProperties(const vk::DispatchLoaderDynamic& dldi) {
197 const vk::PhysicalDeviceProperties props = physical.getProperties(dldi);
198 device_type = props.deviceType;
199 uniform_buffer_alignment = static_cast<u64>(props.limits.minUniformBufferOffsetAlignment);
200}
201
202std::vector<vk::DeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const {
203 static const float QUEUE_PRIORITY = 1.f;
204
205 std::set<u32> unique_queue_families = {graphics_family, present_family};
206 std::vector<vk::DeviceQueueCreateInfo> queue_cis;
207
208 for (u32 queue_family : unique_queue_families)
209 queue_cis.push_back({{}, queue_family, 1, &QUEUE_PRIORITY});
210
211 return queue_cis;
212}
213
214std::map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperties(
215 const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical) {
216 std::map<vk::Format, vk::FormatProperties> format_properties;
217
218 const auto AddFormatQuery = [&format_properties, &dldi, physical](vk::Format format) {
219 format_properties.emplace(format, physical.getFormatProperties(format, dldi));
220 };
221 AddFormatQuery(vk::Format::eA8B8G8R8UnormPack32);
222 AddFormatQuery(vk::Format::eR5G6B5UnormPack16);
223 AddFormatQuery(vk::Format::eD32Sfloat);
224 AddFormatQuery(vk::Format::eD16UnormS8Uint);
225 AddFormatQuery(vk::Format::eD24UnormS8Uint);
226 AddFormatQuery(vk::Format::eD32SfloatS8Uint);
227
228 return format_properties;
229}
230
231} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h
new file mode 100644
index 000000000..e87c7a508
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_device.h
@@ -0,0 +1,116 @@
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 <map>
8#include <vector>
9#include "common/common_types.h"
10#include "video_core/renderer_vulkan/declarations.h"
11
12namespace Vulkan {
13
14/// Format usage descriptor
15enum class FormatType { Linear, Optimal, Buffer };
16
17/// Handles data specific to a physical device.
18class VKDevice final {
19public:
20 explicit VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical,
21 vk::SurfaceKHR surface);
22 ~VKDevice();
23
24 /// Initializes the device. Returns true on success.
25 bool Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance);
26
27 /**
28 * Returns a format supported by the device for the passed requeriments.
29 * @param wanted_format The ideal format to be returned. It may not be the returned format.
30 * @param wanted_usage The usage that must be fulfilled even if the format is not supported.
31 * @param format_type Format type usage.
32 * @returns A format supported by the device.
33 */
34 vk::Format GetSupportedFormat(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage,
35 FormatType format_type) const;
36
37 /// Returns the dispatch loader with direct function pointers of the device
38 const vk::DispatchLoaderDynamic& GetDispatchLoader() const {
39 return dld;
40 }
41
42 /// Returns the logical device
43 vk::Device GetLogical() const {
44 return logical.get();
45 }
46
47 /// Returns the physical device.
48 vk::PhysicalDevice GetPhysical() const {
49 return physical;
50 }
51
52 /// Returns the main graphics queue.
53 vk::Queue GetGraphicsQueue() const {
54 return graphics_queue;
55 }
56
57 /// Returns the main present queue.
58 vk::Queue GetPresentQueue() const {
59 return present_queue;
60 }
61
62 /// Returns main graphics queue family index.
63 u32 GetGraphicsFamily() const {
64 return graphics_family;
65 }
66
67 /// Returns main present queue family index.
68 u32 GetPresentFamily() const {
69 return present_family;
70 }
71
72 /// Returns if the device is integrated with the host CPU
73 bool IsIntegrated() const {
74 return device_type == vk::PhysicalDeviceType::eIntegratedGpu;
75 }
76
77 /// Returns uniform buffer alignment requeriment
78 u64 GetUniformBufferAlignment() const {
79 return uniform_buffer_alignment;
80 }
81
82 /// Checks if the physical device is suitable.
83 static bool IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical,
84 vk::SurfaceKHR surface);
85
86private:
87 /// Sets up queue families.
88 void SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceKHR surface);
89
90 /// Sets up device properties.
91 void SetupProperties(const vk::DispatchLoaderDynamic& dldi);
92
93 /// Returns a list of queue initialization descriptors.
94 std::vector<vk::DeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const;
95
96 /// Returns true if a format is supported.
97 bool IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlags wanted_usage,
98 FormatType format_type) const;
99
100 /// Returns the device properties for Vulkan formats.
101 static std::map<vk::Format, vk::FormatProperties> GetFormatProperties(
102 const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical);
103
104 const vk::PhysicalDevice physical; ///< Physical device
105 vk::DispatchLoaderDynamic dld; ///< Device function pointers
106 UniqueDevice logical; ///< Logical device
107 vk::Queue graphics_queue; ///< Main graphics queue
108 vk::Queue present_queue; ///< Main present queue
109 u32 graphics_family{}; ///< Main graphics queue family index
110 u32 present_family{}; ///< Main present queue family index
111 vk::PhysicalDeviceType device_type; ///< Physical device type
112 u64 uniform_buffer_alignment{}; ///< Uniform buffer alignment requeriment
113 std::map<vk::Format, vk::FormatProperties> format_properties; ///< Format properties dictionary
114};
115
116} // namespace Vulkan