summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt14
-rw-r--r--src/core/hle/kernel/kernel.cpp66
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp10
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp5
-rw-r--r--src/core/hle/service/mii/manager.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h9
-rw-r--r--src/input_common/udp/client.cpp13
-rw-r--r--src/input_common/udp/client.h4
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp3
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.h10
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp24
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp73
-rw-r--r--src/video_core/renderer_vulkan/vk_device.h12
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp12
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp23
-rw-r--r--src/video_core/renderer_vulkan/wrapper.h4
22 files changed, 193 insertions, 129 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9760be4e4..b6dc25f6b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -1,9 +1,3 @@
1if (YUZU_ENABLE_BOXCAT)
2 set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h)
3else()
4 set(BCAT_BOXCAT_ADDITIONAL_SOURCES)
5endif()
6
7add_library(core STATIC 1add_library(core STATIC
8 arm/arm_interface.h 2 arm/arm_interface.h
9 arm/arm_interface.cpp 3 arm/arm_interface.cpp
@@ -303,7 +297,6 @@ add_library(core STATIC
303 hle/service/audio/hwopus.h 297 hle/service/audio/hwopus.h
304 hle/service/bcat/backend/backend.cpp 298 hle/service/bcat/backend/backend.cpp
305 hle/service/bcat/backend/backend.h 299 hle/service/bcat/backend/backend.h
306 ${BCAT_BOXCAT_ADDITIONAL_SOURCES}
307 hle/service/bcat/bcat.cpp 300 hle/service/bcat/bcat.cpp
308 hle/service/bcat/bcat.h 301 hle/service/bcat/bcat.h
309 hle/service/bcat/module.cpp 302 hle/service/bcat/module.cpp
@@ -608,6 +601,13 @@ add_library(core STATIC
608 tools/freezer.h 601 tools/freezer.h
609) 602)
610 603
604if (YUZU_ENABLE_BOXCAT)
605 target_sources(core PRIVATE
606 hle/service/bcat/backend/boxcat.cpp
607 hle/service/bcat/backend/boxcat.h
608 )
609endif()
610
611if (MSVC) 611if (MSVC)
612 target_compile_options(core PRIVATE 612 target_compile_options(core PRIVATE
613 # 'expression' : signed/unsigned mismatch 613 # 'expression' : signed/unsigned mismatch
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index f2b0fe2fd..96ca01194 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -7,7 +7,6 @@
7#include <bitset> 7#include <bitset>
8#include <functional> 8#include <functional>
9#include <memory> 9#include <memory>
10#include <mutex>
11#include <thread> 10#include <thread>
12#include <unordered_map> 11#include <unordered_map>
13#include <utility> 12#include <utility>
@@ -107,7 +106,11 @@ struct KernelCore::Impl {
107 cores.clear(); 106 cores.clear();
108 107
109 exclusive_monitor.reset(); 108 exclusive_monitor.reset();
110 host_thread_ids.clear(); 109
110 num_host_threads = 0;
111 std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
112 std::thread::id{});
113 std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
111 } 114 }
112 115
113 void InitializePhysicalCores() { 116 void InitializePhysicalCores() {
@@ -177,54 +180,56 @@ struct KernelCore::Impl {
177 180
178 void MakeCurrentProcess(Process* process) { 181 void MakeCurrentProcess(Process* process) {
179 current_process = process; 182 current_process = process;
180
181 if (process == nullptr) { 183 if (process == nullptr) {
182 return; 184 return;
183 } 185 }
184 186 const u32 core_id = GetCurrentHostThreadID();
185 u32 core_id = GetCurrentHostThreadID();
186 if (core_id < Core::Hardware::NUM_CPU_CORES) { 187 if (core_id < Core::Hardware::NUM_CPU_CORES) {
187 system.Memory().SetCurrentPageTable(*process, core_id); 188 system.Memory().SetCurrentPageTable(*process, core_id);
188 } 189 }
189 } 190 }
190 191
191 void RegisterCoreThread(std::size_t core_id) { 192 void RegisterCoreThread(std::size_t core_id) {
192 std::unique_lock lock{register_thread_mutex}; 193 const std::thread::id this_id = std::this_thread::get_id();
193 if (!is_multicore) { 194 if (!is_multicore) {
194 single_core_thread_id = std::this_thread::get_id(); 195 single_core_thread_id = this_id;
195 } 196 }
196 const std::thread::id this_id = std::this_thread::get_id(); 197 const auto end = register_host_thread_keys.begin() + num_host_threads;
197 const auto it = host_thread_ids.find(this_id); 198 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
198 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); 199 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
199 ASSERT(it == host_thread_ids.end()); 200 ASSERT(it == end);
200 ASSERT(!registered_core_threads[core_id]); 201 ASSERT(!registered_core_threads[core_id]);
201 host_thread_ids[this_id] = static_cast<u32>(core_id); 202 InsertHostThread(static_cast<u32>(core_id));
202 registered_core_threads.set(core_id); 203 registered_core_threads.set(core_id);
203 } 204 }
204 205
205 void RegisterHostThread() { 206 void RegisterHostThread() {
206 std::unique_lock lock{register_thread_mutex};
207 const std::thread::id this_id = std::this_thread::get_id(); 207 const std::thread::id this_id = std::this_thread::get_id();
208 const auto it = host_thread_ids.find(this_id); 208 const auto end = register_host_thread_keys.begin() + num_host_threads;
209 if (it != host_thread_ids.end()) { 209 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
210 return; 210 if (it == end) {
211 InsertHostThread(registered_thread_ids++);
211 } 212 }
212 host_thread_ids[this_id] = registered_thread_ids++;
213 } 213 }
214 214
215 u32 GetCurrentHostThreadID() const { 215 void InsertHostThread(u32 value) {
216 const size_t index = num_host_threads++;
217 ASSERT_MSG(index < NUM_REGISTRABLE_HOST_THREADS, "Too many host threads");
218 register_host_thread_values[index] = value;
219 register_host_thread_keys[index] = std::this_thread::get_id();
220 }
221
222 [[nodiscard]] u32 GetCurrentHostThreadID() const {
216 const std::thread::id this_id = std::this_thread::get_id(); 223 const std::thread::id this_id = std::this_thread::get_id();
217 if (!is_multicore) { 224 if (!is_multicore && single_core_thread_id == this_id) {
218 if (single_core_thread_id == this_id) { 225 return static_cast<u32>(system.GetCpuManager().CurrentCore());
219 return static_cast<u32>(system.GetCpuManager().CurrentCore());
220 }
221 } 226 }
222 std::unique_lock lock{register_thread_mutex}; 227 const auto end = register_host_thread_keys.begin() + num_host_threads;
223 const auto it = host_thread_ids.find(this_id); 228 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
224 if (it == host_thread_ids.end()) { 229 if (it == end) {
225 return Core::INVALID_HOST_THREAD_ID; 230 return Core::INVALID_HOST_THREAD_ID;
226 } 231 }
227 return it->second; 232 return register_host_thread_values[std::distance(register_host_thread_keys.begin(), it)];
228 } 233 }
229 234
230 Core::EmuThreadHandle GetCurrentEmuThreadID() const { 235 Core::EmuThreadHandle GetCurrentEmuThreadID() const {
@@ -322,10 +327,15 @@ struct KernelCore::Impl {
322 std::vector<Kernel::PhysicalCore> cores; 327 std::vector<Kernel::PhysicalCore> cores;
323 328
324 // 0-3 IDs represent core threads, >3 represent others 329 // 0-3 IDs represent core threads, >3 represent others
325 std::unordered_map<std::thread::id, u32> host_thread_ids; 330 std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
326 u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
327 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads; 331 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
328 mutable std::mutex register_thread_mutex; 332
333 // Number of host threads is a relatively high number to avoid overflowing
334 static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64;
335 std::atomic<size_t> num_host_threads{0};
336 std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS>
337 register_host_thread_keys{};
338 std::array<std::atomic<u32>, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_values{};
329 339
330 // Kernel memory management 340 // Kernel memory management
331 std::unique_ptr<Memory::MemoryManager> memory_manager; 341 std::unique_ptr<Memory::MemoryManager> memory_manager;
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index 589e288df..3b6f7498e 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -454,6 +454,16 @@ Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global,
454 {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, 454 {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)},
455 }; 455 };
456 456
457 if (!client.is_valid()) {
458 LOG_ERROR(Service_BCAT, "Client is invalid, going offline!");
459 return StatusResult::Offline;
460 }
461
462 if (!client.is_socket_open()) {
463 LOG_ERROR(Service_BCAT, "Failed to open socket, going offline!");
464 return StatusResult::Offline;
465 }
466
457 const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers); 467 const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers);
458 if (response == nullptr) 468 if (response == nullptr)
459 return StatusResult::Offline; 469 return StatusResult::Offline;
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 54a5fb84b..3cdef4888 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -79,7 +79,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
79 } 79 }
80 80
81 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 81 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
82 if (dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { 82 if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
83 return FileSys::ERROR_PATH_NOT_FOUND; 83 return FileSys::ERROR_PATH_NOT_FOUND;
84 } 84 }
85 if (!dir->DeleteFile(Common::FS::GetFilename(path))) { 85 if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
@@ -93,8 +93,9 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
93ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const { 93ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
94 std::string path(Common::FS::SanitizePath(path_)); 94 std::string path(Common::FS::SanitizePath(path_));
95 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 95 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
96 if (dir == nullptr && Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) 96 if (dir == nullptr || Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) {
97 dir = backing; 97 dir = backing;
98 }
98 auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path)); 99 auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path));
99 if (new_dir == nullptr) { 100 if (new_dir == nullptr) {
100 // TODO(DarkLordZach): Find a better error code for this 101 // TODO(DarkLordZach): Find a better error code for this
diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp
index 8e433eb41..d73b90015 100644
--- a/src/core/hle/service/mii/manager.cpp
+++ b/src/core/hle/service/mii/manager.cpp
@@ -131,7 +131,7 @@ template <typename T>
131T GetRandomValue(T min, T max) { 131T GetRandomValue(T min, T max) {
132 std::random_device device; 132 std::random_device device;
133 std::mt19937 gen(device()); 133 std::mt19937 gen(device());
134 std::uniform_int_distribution<u64> distribution(0, static_cast<u64>(max)); 134 std::uniform_int_distribution<u64> distribution(static_cast<u64>(min), static_cast<u64>(max));
135 return static_cast<T>(distribution(gen)); 135 return static_cast<T>(distribution(gen));
136} 136}
137 137
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 39bd2a45b..f2529a12e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -46,6 +46,8 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std:
46 return GetVARegions(input, output); 46 return GetVARegions(input, output);
47 case IoctlCommand::IocUnmapBufferCommand: 47 case IoctlCommand::IocUnmapBufferCommand:
48 return UnmapBuffer(input, output); 48 return UnmapBuffer(input, output);
49 case IoctlCommand::IocFreeSpaceCommand:
50 return FreeSpace(input, output);
49 default: 51 default:
50 break; 52 break;
51 } 53 }
@@ -91,6 +93,20 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
91 return result; 93 return result;
92} 94}
93 95
96u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
97 IoctlFreeSpace params{};
98 std::memcpy(&params, input.data(), input.size());
99
100 LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset,
101 params.pages, params.page_size);
102
103 system.GPU().MemoryManager().Unmap(params.offset,
104 static_cast<std::size_t>(params.pages) * params.page_size);
105
106 std::memcpy(output.data(), &params, output.size());
107 return NvErrCodes::Success;
108}
109
94u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { 110u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
95 const auto num_entries = input.size() / sizeof(IoctlRemapEntry); 111 const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
96 112
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 9a0cdff0c..fcdb40d93 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -82,6 +82,7 @@ private:
82 IocBindChannelCommand = 0x40044101, 82 IocBindChannelCommand = 0x40044101,
83 IocGetVaRegionsCommand = 0xC0404108, 83 IocGetVaRegionsCommand = 0xC0404108,
84 IocUnmapBufferCommand = 0xC0084105, 84 IocUnmapBufferCommand = 0xC0084105,
85 IocFreeSpaceCommand = 0xC0104103,
85 }; 86 };
86 87
87 struct IoctlInitalizeEx { 88 struct IoctlInitalizeEx {
@@ -107,6 +108,13 @@ private:
107 }; 108 };
108 static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); 109 static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
109 110
111 struct IoctlFreeSpace {
112 u64_le offset;
113 u32_le pages;
114 u32_le page_size;
115 };
116 static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");
117
110 struct IoctlRemapEntry { 118 struct IoctlRemapEntry {
111 u16_le flags; 119 u16_le flags;
112 u16_le kind; 120 u16_le kind;
@@ -162,6 +170,7 @@ private:
162 u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); 170 u32 Remap(const std::vector<u8>& input, std::vector<u8>& output);
163 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); 171 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
164 u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); 172 u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
173 u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
165 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); 174 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
166 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); 175 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
167 176
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index bb109562c..7039d6fc3 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -333,15 +333,18 @@ const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() cons
333} 333}
334 334
335void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, 335void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id,
336 std::function<void()> success_callback, 336 const std::function<void()>& success_callback,
337 std::function<void()> failure_callback) { 337 const std::function<void()>& failure_callback) {
338 std::thread([=] { 338 std::thread([=] {
339 Common::Event success_event; 339 Common::Event success_event;
340 SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {}, 340 SocketCallback callback{
341 [&](Response::PadData data) { success_event.Set(); }}; 341 .version = [](Response::Version) {},
342 .port_info = [](Response::PortInfo) {},
343 .pad_data = [&](Response::PadData) { success_event.Set(); },
344 };
342 Socket socket{host, port, pad_index, client_id, std::move(callback)}; 345 Socket socket{host, port, pad_index, client_id, std::move(callback)};
343 std::thread worker_thread{SocketLoop, &socket}; 346 std::thread worker_thread{SocketLoop, &socket};
344 bool result = success_event.WaitFor(std::chrono::seconds(8)); 347 const bool result = success_event.WaitFor(std::chrono::seconds(8));
345 socket.Stop(); 348 socket.Stop();
346 worker_thread.join(); 349 worker_thread.join();
347 if (result) { 350 if (result) {
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index 2491a03a2..747e0c0a2 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -150,7 +150,7 @@ private:
150}; 150};
151 151
152void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, 152void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id,
153 std::function<void()> success_callback, 153 const std::function<void()>& success_callback,
154 std::function<void()> failure_callback); 154 const std::function<void()>& failure_callback);
155 155
156} // namespace InputCommon::CemuhookUDP 156} // namespace InputCommon::CemuhookUDP
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index 81a39a3b8..da5c550ea 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -58,6 +58,7 @@ void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_sta
58 logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); 58 logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0);
59 logic_op.Assign(PackLogicOp(regs.logic_op.operation)); 59 logic_op.Assign(PackLogicOp(regs.logic_op.operation));
60 rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); 60 rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0);
61 topology.Assign(regs.draw.topology);
61 62
62 std::memcpy(&point_size, &regs.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast 63 std::memcpy(&point_size, &regs.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast
63 64
@@ -131,7 +132,6 @@ void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size
131} 132}
132 133
133void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) { 134void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) {
134 const u32 topology_index = static_cast<u32>(regs.draw.topology.Value());
135 u32 packed_front_face = PackFrontFace(regs.front_face); 135 u32 packed_front_face = PackFrontFace(regs.front_face);
136 if (regs.screen_y_control.triangle_rast_flip != 0) { 136 if (regs.screen_y_control.triangle_rast_flip != 0) {
137 // Flip front face 137 // Flip front face
@@ -161,7 +161,6 @@ void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) {
161 depth_test_enable.Assign(regs.depth_test_enable); 161 depth_test_enable.Assign(regs.depth_test_enable);
162 front_face.Assign(packed_front_face); 162 front_face.Assign(packed_front_face);
163 depth_test_func.Assign(PackComparisonOp(regs.depth_test_func)); 163 depth_test_func.Assign(PackComparisonOp(regs.depth_test_func));
164 topology.Assign(topology_index);
165 cull_face.Assign(PackCullFace(regs.cull_face)); 164 cull_face.Assign(PackCullFace(regs.cull_face));
166 cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0); 165 cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0);
167 166
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
index cdcbb65f5..2c18eeaae 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h
@@ -150,9 +150,8 @@ struct FixedPipelineState {
150 }; 150 };
151 union { 151 union {
152 u32 raw2; 152 u32 raw2;
153 BitField<0, 4, u32> topology; 153 BitField<0, 2, u32> cull_face;
154 BitField<4, 2, u32> cull_face; 154 BitField<2, 1, u32> cull_enable;
155 BitField<6, 1, u32> cull_enable;
156 }; 155 };
157 std::array<VertexBinding, Maxwell::NumVertexArrays> vertex_bindings; 156 std::array<VertexBinding, Maxwell::NumVertexArrays> vertex_bindings;
158 157
@@ -169,10 +168,6 @@ struct FixedPipelineState {
169 Maxwell::FrontFace FrontFace() const noexcept { 168 Maxwell::FrontFace FrontFace() const noexcept {
170 return UnpackFrontFace(front_face.Value()); 169 return UnpackFrontFace(front_face.Value());
171 } 170 }
172
173 constexpr Maxwell::PrimitiveTopology Topology() const noexcept {
174 return static_cast<Maxwell::PrimitiveTopology>(topology.Value());
175 }
176 }; 171 };
177 172
178 union { 173 union {
@@ -190,6 +185,7 @@ struct FixedPipelineState {
190 BitField<18, 1, u32> logic_op_enable; 185 BitField<18, 1, u32> logic_op_enable;
191 BitField<19, 4, u32> logic_op; 186 BitField<19, 4, u32> logic_op;
192 BitField<23, 1, u32> rasterize_enable; 187 BitField<23, 1, u32> rasterize_enable;
188 BitField<24, 4, Maxwell::PrimitiveTopology> topology;
193 }; 189 };
194 u32 point_size; 190 u32 point_size;
195 std::array<u32, Maxwell::NumVertexArrays> binding_divisors; 191 std::array<u32, Maxwell::NumVertexArrays> binding_divisors;
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 715182b3b..f2610868e 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -92,9 +92,9 @@ Common::DynamicLibrary OpenVulkanLibrary() {
92 return library; 92 return library;
93} 93}
94 94
95vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatch& dld, 95std::pair<vk::Instance, u32> CreateInstance(
96 WindowSystemType window_type = WindowSystemType::Headless, 96 Common::DynamicLibrary& library, vk::InstanceDispatch& dld,
97 bool enable_layers = false) { 97 WindowSystemType window_type = WindowSystemType::Headless, bool enable_layers = false) {
98 if (!library.IsOpen()) { 98 if (!library.IsOpen()) {
99 LOG_ERROR(Render_Vulkan, "Vulkan library not available"); 99 LOG_ERROR(Render_Vulkan, "Vulkan library not available");
100 return {}; 100 return {};
@@ -180,7 +180,10 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc
180 } 180 }
181 } 181 }
182 182
183 vk::Instance instance = vk::Instance::Create(layers, extensions, dld); 183 // Limit the maximum version of Vulkan to avoid using untested version.
184 const u32 version = std::min(vk::AvailableVersion(dld), static_cast<u32>(VK_API_VERSION_1_1));
185
186 vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld);
184 if (!instance) { 187 if (!instance) {
185 LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); 188 LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance");
186 return {}; 189 return {};
@@ -188,7 +191,7 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc
188 if (!vk::Load(*instance, dld)) { 191 if (!vk::Load(*instance, dld)) {
189 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); 192 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
190 } 193 }
191 return instance; 194 return std::make_pair(std::move(instance), version);
192} 195}
193 196
194std::string GetReadableVersion(u32 version) { 197std::string GetReadableVersion(u32 version) {
@@ -285,8 +288,8 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
285 288
286bool RendererVulkan::Init() { 289bool RendererVulkan::Init() {
287 library = OpenVulkanLibrary(); 290 library = OpenVulkanLibrary();
288 instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, 291 std::tie(instance, instance_version) = CreateInstance(
289 Settings::values.renderer_debug); 292 library, dld, render_window.GetWindowInfo().type, Settings::values.renderer_debug);
290 if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { 293 if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) {
291 return false; 294 return false;
292 } 295 }
@@ -416,7 +419,8 @@ bool RendererVulkan::PickDevices() {
416 return false; 419 return false;
417 } 420 }
418 421
419 device = std::make_unique<VKDevice>(*instance, physical_device, *surface, dld); 422 device =
423 std::make_unique<VKDevice>(*instance, instance_version, physical_device, *surface, dld);
420 return device->Create(); 424 return device->Create();
421} 425}
422 426
@@ -426,7 +430,7 @@ void RendererVulkan::Report() const {
426 const std::string driver_version = GetDriverVersion(*device); 430 const std::string driver_version = GetDriverVersion(*device);
427 const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version); 431 const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version);
428 432
429 const std::string api_version = GetReadableVersion(device->GetApiVersion()); 433 const std::string api_version = GetReadableVersion(device->ApiVersion());
430 434
431 const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions()); 435 const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions());
432 436
@@ -445,7 +449,7 @@ void RendererVulkan::Report() const {
445std::vector<std::string> RendererVulkan::EnumerateDevices() { 449std::vector<std::string> RendererVulkan::EnumerateDevices() {
446 vk::InstanceDispatch dld; 450 vk::InstanceDispatch dld;
447 Common::DynamicLibrary library = OpenVulkanLibrary(); 451 Common::DynamicLibrary library = OpenVulkanLibrary();
448 vk::Instance instance = CreateInstance(library, dld); 452 vk::Instance instance = CreateInstance(library, dld).first;
449 if (!instance) { 453 if (!instance) {
450 return {}; 454 return {};
451 } 455 }
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index 49a4141ec..1044ca124 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -73,6 +73,8 @@ private:
73 vk::InstanceDispatch dld; 73 vk::InstanceDispatch dld;
74 74
75 vk::Instance instance; 75 vk::Instance instance;
76 u32 instance_version{};
77
76 vk::SurfaceKHR surface; 78 vk::SurfaceKHR surface;
77 79
78 VKScreenInfo screen_info; 80 VKScreenInfo screen_info;
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 1f057b43b..e1217ca83 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -38,6 +38,9 @@ constexpr std::array Depth16UnormS8_UINT{
38 38
39constexpr std::array REQUIRED_EXTENSIONS{ 39constexpr std::array REQUIRED_EXTENSIONS{
40 VK_KHR_SWAPCHAIN_EXTENSION_NAME, 40 VK_KHR_SWAPCHAIN_EXTENSION_NAME,
41 VK_KHR_MAINTENANCE1_EXTENSION_NAME,
42 VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME,
43 VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
41 VK_KHR_16BIT_STORAGE_EXTENSION_NAME, 44 VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
42 VK_KHR_8BIT_STORAGE_EXTENSION_NAME, 45 VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
43 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, 46 VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
@@ -187,10 +190,10 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
187 190
188} // Anonymous namespace 191} // Anonymous namespace
189 192
190VKDevice::VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, 193VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_,
191 const vk::InstanceDispatch& dld) 194 VkSurfaceKHR surface, const vk::InstanceDispatch& dld_)
192 : dld{dld}, physical{physical}, properties{physical.GetProperties()}, 195 : dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
193 format_properties{GetFormatProperties(physical, dld)} { 196 instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} {
194 SetupFamilies(surface); 197 SetupFamilies(surface);
195 SetupFeatures(); 198 SetupFeatures();
196} 199}
@@ -597,20 +600,6 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
597 600
598std::vector<const char*> VKDevice::LoadExtensions() { 601std::vector<const char*> VKDevice::LoadExtensions() {
599 std::vector<const char*> extensions; 602 std::vector<const char*> extensions;
600 const auto Test = [&](const VkExtensionProperties& extension,
601 std::optional<std::reference_wrapper<bool>> status, const char* name,
602 bool push) {
603 if (extension.extensionName != std::string_view(name)) {
604 return;
605 }
606 if (push) {
607 extensions.push_back(name);
608 }
609 if (status) {
610 status->get() = true;
611 }
612 };
613
614 extensions.reserve(7 + REQUIRED_EXTENSIONS.size()); 603 extensions.reserve(7 + REQUIRED_EXTENSIONS.size());
615 extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); 604 extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end());
616 605
@@ -619,28 +608,36 @@ std::vector<const char*> VKDevice::LoadExtensions() {
619 bool has_ext_transform_feedback{}; 608 bool has_ext_transform_feedback{};
620 bool has_ext_custom_border_color{}; 609 bool has_ext_custom_border_color{};
621 bool has_ext_extended_dynamic_state{}; 610 bool has_ext_extended_dynamic_state{};
622 for (const auto& extension : physical.EnumerateDeviceExtensionProperties()) { 611 for (const VkExtensionProperties& extension : physical.EnumerateDeviceExtensionProperties()) {
623 Test(extension, nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true); 612 const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name,
624 Test(extension, khr_uniform_buffer_standard_layout, 613 bool push) {
614 if (extension.extensionName != std::string_view(name)) {
615 return;
616 }
617 if (push) {
618 extensions.push_back(name);
619 }
620 if (status) {
621 status->get() = true;
622 }
623 };
624 test(nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true);
625 test(khr_uniform_buffer_standard_layout,
625 VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true); 626 VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true);
626 Test(extension, has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, 627 test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
627 false); 628 test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true);
628 Test(extension, ext_depth_range_unrestricted, 629 test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
629 VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); 630 test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME,
630 Test(extension, ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); 631 true);
631 Test(extension, ext_shader_viewport_index_layer, 632 test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false);
632 VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, true); 633 test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false);
633 Test(extension, has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, 634 test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
634 false); 635 if (instance_version >= VK_API_VERSION_1_1) {
635 Test(extension, has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, 636 test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
636 false); 637 }
637 Test(extension, has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME,
638 false);
639 Test(extension, has_ext_extended_dynamic_state,
640 VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
641 if (Settings::values.renderer_debug) { 638 if (Settings::values.renderer_debug) {
642 Test(extension, nv_device_diagnostics_config, 639 test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
643 VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, true); 640 true);
644 } 641 }
645 } 642 }
646 643
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h
index 26a233db1..4286673d9 100644
--- a/src/video_core/renderer_vulkan/vk_device.h
+++ b/src/video_core/renderer_vulkan/vk_device.h
@@ -24,8 +24,8 @@ const u32 GuestWarpSize = 32;
24/// Handles data specific to a physical device. 24/// Handles data specific to a physical device.
25class VKDevice final { 25class VKDevice final {
26public: 26public:
27 explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, 27 explicit VKDevice(VkInstance instance, u32 instance_version, vk::PhysicalDevice physical,
28 const vk::InstanceDispatch& dld); 28 VkSurfaceKHR surface, const vk::InstanceDispatch& dld);
29 ~VKDevice(); 29 ~VKDevice();
30 30
31 /// Initializes the device. Returns true on success. 31 /// Initializes the device. Returns true on success.
@@ -82,8 +82,13 @@ public:
82 return present_family; 82 return present_family;
83 } 83 }
84 84
85 /// Returns the current instance Vulkan API version in Vulkan-formatted version numbers.
86 u32 InstanceApiVersion() const {
87 return instance_version;
88 }
89
85 /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers. 90 /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers.
86 u32 GetApiVersion() const { 91 u32 ApiVersion() const {
87 return properties.apiVersion; 92 return properties.apiVersion;
88 } 93 }
89 94
@@ -239,6 +244,7 @@ private:
239 vk::Device logical; ///< Logical device. 244 vk::Device logical; ///< Logical device.
240 vk::Queue graphics_queue; ///< Main graphics queue. 245 vk::Queue graphics_queue; ///< Main graphics queue.
241 vk::Queue present_queue; ///< Main present queue. 246 vk::Queue present_queue; ///< Main present queue.
247 u32 instance_version{}; ///< Vulkan onstance version.
242 u32 graphics_family{}; ///< Main graphics queue family index. 248 u32 graphics_family{}; ///< Main graphics queue family index.
243 u32 present_family{}; ///< Main present queue family index. 249 u32 present_family{}; ///< Main present queue family index.
244 VkDriverIdKHR driver_id{}; ///< Driver ID. 250 VkDriverIdKHR driver_id{}; ///< Driver ID.
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index a4b9e7ef5..696eaeb5f 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -261,12 +261,12 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
261 vertex_input_ci.pNext = &input_divisor_ci; 261 vertex_input_ci.pNext = &input_divisor_ci;
262 } 262 }
263 263
264 const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()); 264 const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, state.topology);
265 const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ 265 const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
266 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 266 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
267 .pNext = nullptr, 267 .pNext = nullptr,
268 .flags = 0, 268 .flags = 0,
269 .topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()), 269 .topology = MaxwellToVK::PrimitiveTopology(device, state.topology),
270 .primitiveRestartEnable = state.primitive_restart_enable != 0 && 270 .primitiveRestartEnable = state.primitive_restart_enable != 0 &&
271 SupportsPrimitiveRestart(input_assembly_topology), 271 SupportsPrimitiveRestart(input_assembly_topology),
272 }; 272 };
@@ -400,7 +400,6 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
400 static constexpr std::array extended{ 400 static constexpr std::array extended{
401 VK_DYNAMIC_STATE_CULL_MODE_EXT, 401 VK_DYNAMIC_STATE_CULL_MODE_EXT,
402 VK_DYNAMIC_STATE_FRONT_FACE_EXT, 402 VK_DYNAMIC_STATE_FRONT_FACE_EXT,
403 VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,
404 VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT, 403 VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT,
405 VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT, 404 VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
406 VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT, 405 VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 5c038f4bc..dedc9c466 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -331,8 +331,7 @@ void VKPipelineCache::OnShaderRemoval(Shader* shader) {
331std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> 331std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>>
332VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { 332VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) {
333 Specialization specialization; 333 Specialization specialization;
334 if (fixed_state.dynamic_state.Topology() == Maxwell::PrimitiveTopology::Points || 334 if (fixed_state.topology == Maxwell::PrimitiveTopology::Points) {
335 device.IsExtExtendedDynamicStateSupported()) {
336 float point_size; 335 float point_size;
337 std::memcpy(&point_size, &fixed_state.point_size, sizeof(float)); 336 std::memcpy(&point_size, &fixed_state.point_size, sizeof(float));
338 specialization.point_size = point_size; 337 specialization.point_size = point_size;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index f3c2483c8..e0fb8693f 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -948,7 +948,6 @@ void RasterizerVulkan::UpdateDynamicStates() {
948 UpdateDepthWriteEnable(regs); 948 UpdateDepthWriteEnable(regs);
949 UpdateDepthCompareOp(regs); 949 UpdateDepthCompareOp(regs);
950 UpdateFrontFace(regs); 950 UpdateFrontFace(regs);
951 UpdatePrimitiveTopology(regs);
952 UpdateStencilOp(regs); 951 UpdateStencilOp(regs);
953 UpdateStencilTestEnable(regs); 952 UpdateStencilTestEnable(regs);
954 } 953 }
@@ -1418,16 +1417,6 @@ void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) {
1418 [front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); }); 1417 [front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); });
1419} 1418}
1420 1419
1421void RasterizerVulkan::UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs) {
1422 const Maxwell::PrimitiveTopology primitive_topology = regs.draw.topology.Value();
1423 if (!state_tracker.ChangePrimitiveTopology(primitive_topology)) {
1424 return;
1425 }
1426 scheduler.Record([this, primitive_topology](vk::CommandBuffer cmdbuf) {
1427 cmdbuf.SetPrimitiveTopologyEXT(MaxwellToVK::PrimitiveTopology(device, primitive_topology));
1428 });
1429}
1430
1431void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) { 1420void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) {
1432 if (!state_tracker.TouchStencilOp()) { 1421 if (!state_tracker.TouchStencilOp()) {
1433 return; 1422 return;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index b47c8fc13..237e51fa4 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -259,7 +259,6 @@ private:
259 void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs); 259 void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs);
260 void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs); 260 void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
261 void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs); 261 void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs);
262 void UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs);
263 void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); 262 void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs);
264 void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); 263 void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
265 264
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index cd7d7a4e4..a20452b87 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -272,12 +272,19 @@ bool IsPrecise(Operation operand) {
272 return false; 272 return false;
273} 273}
274 274
275u32 ShaderVersion(const VKDevice& device) {
276 if (device.InstanceApiVersion() < VK_API_VERSION_1_1) {
277 return 0x00010000;
278 }
279 return 0x00010300;
280}
281
275class SPIRVDecompiler final : public Sirit::Module { 282class SPIRVDecompiler final : public Sirit::Module {
276public: 283public:
277 explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage, 284 explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage,
278 const Registry& registry, const Specialization& specialization) 285 const Registry& registry, const Specialization& specialization)
279 : Module(0x00010300), device{device}, ir{ir}, stage{stage}, header{ir.GetHeader()}, 286 : Module(ShaderVersion(device)), device{device}, ir{ir}, stage{stage},
280 registry{registry}, specialization{specialization} { 287 header{ir.GetHeader()}, registry{registry}, specialization{specialization} {
281 if (stage != ShaderType::Compute) { 288 if (stage != ShaderType::Compute) {
282 transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo()); 289 transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo());
283 } 290 }
@@ -293,6 +300,7 @@ public:
293 AddCapability(spv::Capability::DrawParameters); 300 AddCapability(spv::Capability::DrawParameters);
294 AddCapability(spv::Capability::SubgroupBallotKHR); 301 AddCapability(spv::Capability::SubgroupBallotKHR);
295 AddCapability(spv::Capability::SubgroupVoteKHR); 302 AddCapability(spv::Capability::SubgroupVoteKHR);
303 AddExtension("SPV_KHR_16bit_storage");
296 AddExtension("SPV_KHR_shader_ballot"); 304 AddExtension("SPV_KHR_shader_ballot");
297 AddExtension("SPV_KHR_subgroup_vote"); 305 AddExtension("SPV_KHR_subgroup_vote");
298 AddExtension("SPV_KHR_storage_buffer_storage_class"); 306 AddExtension("SPV_KHR_storage_buffer_storage_class");
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index 2598440fb..c034558a3 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -11,6 +11,7 @@
11#include <vector> 11#include <vector>
12 12
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/logging/log.h"
14 15
15#include "video_core/renderer_vulkan/wrapper.h" 16#include "video_core/renderer_vulkan/wrapper.h"
16 17
@@ -415,18 +416,17 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe
415 return VK_SUCCESS; 416 return VK_SUCCESS;
416} 417}
417 418
418Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions, 419Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
419 InstanceDispatch& dld) noexcept { 420 InstanceDispatch& dld) noexcept {
420 static constexpr VkApplicationInfo application_info{ 421 const VkApplicationInfo application_info{
421 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 422 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
422 .pNext = nullptr, 423 .pNext = nullptr,
423 .pApplicationName = "yuzu Emulator", 424 .pApplicationName = "yuzu Emulator",
424 .applicationVersion = VK_MAKE_VERSION(0, 1, 0), 425 .applicationVersion = VK_MAKE_VERSION(0, 1, 0),
425 .pEngineName = "yuzu Emulator", 426 .pEngineName = "yuzu Emulator",
426 .engineVersion = VK_MAKE_VERSION(0, 1, 0), 427 .engineVersion = VK_MAKE_VERSION(0, 1, 0),
427 .apiVersion = VK_API_VERSION_1_1, 428 .apiVersion = version,
428 }; 429 };
429
430 const VkInstanceCreateInfo ci{ 430 const VkInstanceCreateInfo ci{
431 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 431 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
432 .pNext = nullptr, 432 .pNext = nullptr,
@@ -818,6 +818,21 @@ VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noe
818 return properties; 818 return properties;
819} 819}
820 820
821u32 AvailableVersion(const InstanceDispatch& dld) noexcept {
822 PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion;
823 if (!Proc(vkEnumerateInstanceVersion, dld, "vkEnumerateInstanceVersion")) {
824 // If the procedure is not found, Vulkan 1.0 is assumed
825 return VK_API_VERSION_1_0;
826 }
827 u32 version;
828 if (const VkResult result = vkEnumerateInstanceVersion(&version); result != VK_SUCCESS) {
829 LOG_ERROR(Render_Vulkan, "vkEnumerateInstanceVersion returned {}, assuming Vulkan 1.1",
830 ToString(result));
831 return VK_API_VERSION_1_1;
832 }
833 return version;
834}
835
821std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( 836std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
822 const InstanceDispatch& dld) { 837 const InstanceDispatch& dld) {
823 u32 num; 838 u32 num;
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
index 234e01693..f64919623 100644
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ b/src/video_core/renderer_vulkan/wrapper.h
@@ -564,7 +564,7 @@ class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
564 564
565public: 565public:
566 /// Creates a Vulkan instance. Use "operator bool" for error handling. 566 /// Creates a Vulkan instance. Use "operator bool" for error handling.
567 static Instance Create(Span<const char*> layers, Span<const char*> extensions, 567 static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
568 InstanceDispatch& dld) noexcept; 568 InstanceDispatch& dld) noexcept;
569 569
570 /// Enumerates physical devices. 570 /// Enumerates physical devices.
@@ -1090,6 +1090,8 @@ private:
1090 const DeviceDispatch* dld; 1090 const DeviceDispatch* dld;
1091}; 1091};
1092 1092
1093u32 AvailableVersion(const InstanceDispatch& dld) noexcept;
1094
1093std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( 1095std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
1094 const InstanceDispatch& dld); 1096 const InstanceDispatch& dld);
1095 1097