diff options
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 @@ -if (YUZU_ENABLE_BOXCAT) - set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h) -else() - set(BCAT_BOXCAT_ADDITIONAL_SOURCES) -endif() - add_library(core STATIC arm/arm_interface.h arm/arm_interface.cpp @@ -303,7 +297,6 @@ add_library(core STATIC hle/service/audio/hwopus.h hle/service/bcat/backend/backend.cpp hle/service/bcat/backend/backend.h - ${BCAT_BOXCAT_ADDITIONAL_SOURCES} hle/service/bcat/bcat.cpp hle/service/bcat/bcat.h hle/service/bcat/module.cpp @@ -608,6 +601,13 @@ add_library(core STATIC tools/freezer.h ) +if (YUZU_ENABLE_BOXCAT) + target_sources(core PRIVATE + hle/service/bcat/backend/boxcat.cpp + hle/service/bcat/backend/boxcat.h + ) +endif() + if (MSVC) target_compile_options(core PRIVATE # '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 @@ #include <bitset> #include <functional> #include <memory> -#include <mutex> #include <thread> #include <unordered_map> #include <utility> @@ -107,7 +106,11 @@ struct KernelCore::Impl { cores.clear(); exclusive_monitor.reset(); - host_thread_ids.clear(); + + num_host_threads = 0; + std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(), + std::thread::id{}); + std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0); } void InitializePhysicalCores() { @@ -177,54 +180,56 @@ struct KernelCore::Impl { void MakeCurrentProcess(Process* process) { current_process = process; - if (process == nullptr) { return; } - - u32 core_id = GetCurrentHostThreadID(); + const u32 core_id = GetCurrentHostThreadID(); if (core_id < Core::Hardware::NUM_CPU_CORES) { system.Memory().SetCurrentPageTable(*process, core_id); } } void RegisterCoreThread(std::size_t core_id) { - std::unique_lock lock{register_thread_mutex}; + const std::thread::id this_id = std::this_thread::get_id(); if (!is_multicore) { - single_core_thread_id = std::this_thread::get_id(); + single_core_thread_id = this_id; } - const std::thread::id this_id = std::this_thread::get_id(); - const auto it = host_thread_ids.find(this_id); + const auto end = register_host_thread_keys.begin() + num_host_threads; + const auto it = std::find(register_host_thread_keys.begin(), end, this_id); ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); - ASSERT(it == host_thread_ids.end()); + ASSERT(it == end); ASSERT(!registered_core_threads[core_id]); - host_thread_ids[this_id] = static_cast<u32>(core_id); + InsertHostThread(static_cast<u32>(core_id)); registered_core_threads.set(core_id); } void RegisterHostThread() { - std::unique_lock lock{register_thread_mutex}; const std::thread::id this_id = std::this_thread::get_id(); - const auto it = host_thread_ids.find(this_id); - if (it != host_thread_ids.end()) { - return; + const auto end = register_host_thread_keys.begin() + num_host_threads; + const auto it = std::find(register_host_thread_keys.begin(), end, this_id); + if (it == end) { + InsertHostThread(registered_thread_ids++); } - host_thread_ids[this_id] = registered_thread_ids++; } - u32 GetCurrentHostThreadID() const { + void InsertHostThread(u32 value) { + const size_t index = num_host_threads++; + ASSERT_MSG(index < NUM_REGISTRABLE_HOST_THREADS, "Too many host threads"); + register_host_thread_values[index] = value; + register_host_thread_keys[index] = std::this_thread::get_id(); + } + + [[nodiscard]] u32 GetCurrentHostThreadID() const { const std::thread::id this_id = std::this_thread::get_id(); - if (!is_multicore) { - if (single_core_thread_id == this_id) { - return static_cast<u32>(system.GetCpuManager().CurrentCore()); - } + if (!is_multicore && single_core_thread_id == this_id) { + return static_cast<u32>(system.GetCpuManager().CurrentCore()); } - std::unique_lock lock{register_thread_mutex}; - const auto it = host_thread_ids.find(this_id); - if (it == host_thread_ids.end()) { + const auto end = register_host_thread_keys.begin() + num_host_threads; + const auto it = std::find(register_host_thread_keys.begin(), end, this_id); + if (it == end) { return Core::INVALID_HOST_THREAD_ID; } - return it->second; + return register_host_thread_values[std::distance(register_host_thread_keys.begin(), it)]; } Core::EmuThreadHandle GetCurrentEmuThreadID() const { @@ -322,10 +327,15 @@ struct KernelCore::Impl { std::vector<Kernel::PhysicalCore> cores; // 0-3 IDs represent core threads, >3 represent others - std::unordered_map<std::thread::id, u32> host_thread_ids; - u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; + std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads; - mutable std::mutex register_thread_mutex; + + // Number of host threads is a relatively high number to avoid overflowing + static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64; + std::atomic<size_t> num_host_threads{0}; + std::array<std::atomic<std::thread::id>, NUM_REGISTRABLE_HOST_THREADS> + register_host_thread_keys{}; + std::array<std::atomic<u32>, NUM_REGISTRABLE_HOST_THREADS> register_host_thread_values{}; // Kernel memory management 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, {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, }; + if (!client.is_valid()) { + LOG_ERROR(Service_BCAT, "Client is invalid, going offline!"); + return StatusResult::Offline; + } + + if (!client.is_socket_open()) { + LOG_ERROR(Service_BCAT, "Failed to open socket, going offline!"); + return StatusResult::Offline; + } + const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers); if (response == nullptr) 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 } auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); - if (dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { + if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { return FileSys::ERROR_PATH_NOT_FOUND; } if (!dir->DeleteFile(Common::FS::GetFilename(path))) { @@ -93,8 +93,9 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const { std::string path(Common::FS::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); - if (dir == nullptr && Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) + if (dir == nullptr || Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) { dir = backing; + } auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path)); if (new_dir == nullptr) { // 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> T GetRandomValue(T min, T max) { std::random_device device; std::mt19937 gen(device()); - std::uniform_int_distribution<u64> distribution(0, static_cast<u64>(max)); + std::uniform_int_distribution<u64> distribution(static_cast<u64>(min), static_cast<u64>(max)); return static_cast<T>(distribution(gen)); } 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: return GetVARegions(input, output); case IoctlCommand::IocUnmapBufferCommand: return UnmapBuffer(input, output); + case IoctlCommand::IocFreeSpaceCommand: + return FreeSpace(input, output); default: break; } @@ -91,6 +93,20 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& return result; } +u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { + IoctlFreeSpace params{}; + std::memcpy(¶ms, input.data(), input.size()); + + LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset, + params.pages, params.page_size); + + system.GPU().MemoryManager().Unmap(params.offset, + static_cast<std::size_t>(params.pages) * params.page_size); + + std::memcpy(output.data(), ¶ms, output.size()); + return NvErrCodes::Success; +} + u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { const auto num_entries = input.size() / sizeof(IoctlRemapEntry); 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: IocBindChannelCommand = 0x40044101, IocGetVaRegionsCommand = 0xC0404108, IocUnmapBufferCommand = 0xC0084105, + IocFreeSpaceCommand = 0xC0104103, }; struct IoctlInitalizeEx { @@ -107,6 +108,13 @@ private: }; static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); + struct IoctlFreeSpace { + u64_le offset; + u32_le pages; + u32_le page_size; + }; + static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size"); + struct IoctlRemapEntry { u16_le flags; u16_le kind; @@ -162,6 +170,7 @@ private: u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); + u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output); u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); 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 } void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, - std::function<void()> success_callback, - std::function<void()> failure_callback) { + const std::function<void()>& success_callback, + const std::function<void()>& failure_callback) { std::thread([=] { Common::Event success_event; - SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {}, - [&](Response::PadData data) { success_event.Set(); }}; + SocketCallback callback{ + .version = [](Response::Version) {}, + .port_info = [](Response::PortInfo) {}, + .pad_data = [&](Response::PadData) { success_event.Set(); }, + }; Socket socket{host, port, pad_index, client_id, std::move(callback)}; std::thread worker_thread{SocketLoop, &socket}; - bool result = success_event.WaitFor(std::chrono::seconds(8)); + const bool result = success_event.WaitFor(std::chrono::seconds(8)); socket.Stop(); worker_thread.join(); 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: }; void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, - std::function<void()> success_callback, - std::function<void()> failure_callback); + const std::function<void()>& success_callback, + const std::function<void()>& failure_callback); } // 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 logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); logic_op.Assign(PackLogicOp(regs.logic_op.operation)); rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); + topology.Assign(regs.draw.topology); std::memcpy(&point_size, ®s.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast @@ -131,7 +132,6 @@ void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size } void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) { - const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); u32 packed_front_face = PackFrontFace(regs.front_face); if (regs.screen_y_control.triangle_rast_flip != 0) { // Flip front face @@ -161,7 +161,6 @@ void FixedPipelineState::DynamicState::Fill(const Maxwell& regs) { depth_test_enable.Assign(regs.depth_test_enable); front_face.Assign(packed_front_face); depth_test_func.Assign(PackComparisonOp(regs.depth_test_func)); - topology.Assign(topology_index); cull_face.Assign(PackCullFace(regs.cull_face)); cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0); 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 { }; union { u32 raw2; - BitField<0, 4, u32> topology; - BitField<4, 2, u32> cull_face; - BitField<6, 1, u32> cull_enable; + BitField<0, 2, u32> cull_face; + BitField<2, 1, u32> cull_enable; }; std::array<VertexBinding, Maxwell::NumVertexArrays> vertex_bindings; @@ -169,10 +168,6 @@ struct FixedPipelineState { Maxwell::FrontFace FrontFace() const noexcept { return UnpackFrontFace(front_face.Value()); } - - constexpr Maxwell::PrimitiveTopology Topology() const noexcept { - return static_cast<Maxwell::PrimitiveTopology>(topology.Value()); - } }; union { @@ -190,6 +185,7 @@ struct FixedPipelineState { BitField<18, 1, u32> logic_op_enable; BitField<19, 4, u32> logic_op; BitField<23, 1, u32> rasterize_enable; + BitField<24, 4, Maxwell::PrimitiveTopology> topology; }; u32 point_size; 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() { return library; } -vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatch& dld, - WindowSystemType window_type = WindowSystemType::Headless, - bool enable_layers = false) { +std::pair<vk::Instance, u32> CreateInstance( + Common::DynamicLibrary& library, vk::InstanceDispatch& dld, + WindowSystemType window_type = WindowSystemType::Headless, bool enable_layers = false) { if (!library.IsOpen()) { LOG_ERROR(Render_Vulkan, "Vulkan library not available"); return {}; @@ -180,7 +180,10 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc } } - vk::Instance instance = vk::Instance::Create(layers, extensions, dld); + // Limit the maximum version of Vulkan to avoid using untested version. + const u32 version = std::min(vk::AvailableVersion(dld), static_cast<u32>(VK_API_VERSION_1_1)); + + vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld); if (!instance) { LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); return {}; @@ -188,7 +191,7 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc if (!vk::Load(*instance, dld)) { LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); } - return instance; + return std::make_pair(std::move(instance), version); } std::string GetReadableVersion(u32 version) { @@ -285,8 +288,8 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { bool RendererVulkan::Init() { library = OpenVulkanLibrary(); - instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, - Settings::values.renderer_debug); + std::tie(instance, instance_version) = CreateInstance( + library, dld, render_window.GetWindowInfo().type, Settings::values.renderer_debug); if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { return false; } @@ -416,7 +419,8 @@ bool RendererVulkan::PickDevices() { return false; } - device = std::make_unique<VKDevice>(*instance, physical_device, *surface, dld); + device = + std::make_unique<VKDevice>(*instance, instance_version, physical_device, *surface, dld); return device->Create(); } @@ -426,7 +430,7 @@ void RendererVulkan::Report() const { const std::string driver_version = GetDriverVersion(*device); const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version); - const std::string api_version = GetReadableVersion(device->GetApiVersion()); + const std::string api_version = GetReadableVersion(device->ApiVersion()); const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions()); @@ -445,7 +449,7 @@ void RendererVulkan::Report() const { std::vector<std::string> RendererVulkan::EnumerateDevices() { vk::InstanceDispatch dld; Common::DynamicLibrary library = OpenVulkanLibrary(); - vk::Instance instance = CreateInstance(library, dld); + vk::Instance instance = CreateInstance(library, dld).first; if (!instance) { return {}; } 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: vk::InstanceDispatch dld; vk::Instance instance; + u32 instance_version{}; + vk::SurfaceKHR surface; 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{ constexpr std::array REQUIRED_EXTENSIONS{ VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_KHR_MAINTENANCE1_EXTENSION_NAME, + VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, + VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, VK_KHR_16BIT_STORAGE_EXTENSION_NAME, VK_KHR_8BIT_STORAGE_EXTENSION_NAME, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, @@ -187,10 +190,10 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( } // Anonymous namespace -VKDevice::VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, - const vk::InstanceDispatch& dld) - : dld{dld}, physical{physical}, properties{physical.GetProperties()}, - format_properties{GetFormatProperties(physical, dld)} { +VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_, + VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) + : dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, + instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} { SetupFamilies(surface); SetupFeatures(); } @@ -597,20 +600,6 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { std::vector<const char*> VKDevice::LoadExtensions() { std::vector<const char*> extensions; - const auto Test = [&](const VkExtensionProperties& extension, - std::optional<std::reference_wrapper<bool>> status, const char* name, - bool push) { - if (extension.extensionName != std::string_view(name)) { - return; - } - if (push) { - extensions.push_back(name); - } - if (status) { - status->get() = true; - } - }; - extensions.reserve(7 + REQUIRED_EXTENSIONS.size()); extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); @@ -619,28 +608,36 @@ std::vector<const char*> VKDevice::LoadExtensions() { bool has_ext_transform_feedback{}; bool has_ext_custom_border_color{}; bool has_ext_extended_dynamic_state{}; - for (const auto& extension : physical.EnumerateDeviceExtensionProperties()) { - Test(extension, nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true); - Test(extension, khr_uniform_buffer_standard_layout, + for (const VkExtensionProperties& extension : physical.EnumerateDeviceExtensionProperties()) { + const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name, + bool push) { + if (extension.extensionName != std::string_view(name)) { + return; + } + if (push) { + extensions.push_back(name); + } + if (status) { + status->get() = true; + } + }; + test(nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true); + test(khr_uniform_buffer_standard_layout, VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true); - Test(extension, has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, - false); - Test(extension, ext_depth_range_unrestricted, - VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); - Test(extension, ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); - Test(extension, ext_shader_viewport_index_layer, - VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, true); - Test(extension, has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, - false); - Test(extension, has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, - false); - Test(extension, has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, - false); - Test(extension, has_ext_extended_dynamic_state, - VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); + test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false); + test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); + test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); + test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, + true); + test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false); + test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); + test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); + if (instance_version >= VK_API_VERSION_1_1) { + test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false); + } if (Settings::values.renderer_debug) { - Test(extension, nv_device_diagnostics_config, - VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, true); + test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, + true); } } 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; /// Handles data specific to a physical device. class VKDevice final { public: - explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, - const vk::InstanceDispatch& dld); + explicit VKDevice(VkInstance instance, u32 instance_version, vk::PhysicalDevice physical, + VkSurfaceKHR surface, const vk::InstanceDispatch& dld); ~VKDevice(); /// Initializes the device. Returns true on success. @@ -82,8 +82,13 @@ public: return present_family; } + /// Returns the current instance Vulkan API version in Vulkan-formatted version numbers. + u32 InstanceApiVersion() const { + return instance_version; + } + /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers. - u32 GetApiVersion() const { + u32 ApiVersion() const { return properties.apiVersion; } @@ -239,6 +244,7 @@ private: vk::Device logical; ///< Logical device. vk::Queue graphics_queue; ///< Main graphics queue. vk::Queue present_queue; ///< Main present queue. + u32 instance_version{}; ///< Vulkan onstance version. u32 graphics_family{}; ///< Main graphics queue family index. u32 present_family{}; ///< Main present queue family index. 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 vertex_input_ci.pNext = &input_divisor_ci; } - const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()); + const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, state.topology); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, .pNext = nullptr, .flags = 0, - .topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()), + .topology = MaxwellToVK::PrimitiveTopology(device, state.topology), .primitiveRestartEnable = state.primitive_restart_enable != 0 && SupportsPrimitiveRestart(input_assembly_topology), }; @@ -400,7 +400,6 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa static constexpr std::array extended{ VK_DYNAMIC_STATE_CULL_MODE_EXT, VK_DYNAMIC_STATE_FRONT_FACE_EXT, - VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT, VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT, VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT, 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) { std::pair<SPIRVProgram, std::vector<VkDescriptorSetLayoutBinding>> VKPipelineCache::DecompileShaders(const FixedPipelineState& fixed_state) { Specialization specialization; - if (fixed_state.dynamic_state.Topology() == Maxwell::PrimitiveTopology::Points || - device.IsExtExtendedDynamicStateSupported()) { + if (fixed_state.topology == Maxwell::PrimitiveTopology::Points) { float point_size; std::memcpy(&point_size, &fixed_state.point_size, sizeof(float)); 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() { UpdateDepthWriteEnable(regs); UpdateDepthCompareOp(regs); UpdateFrontFace(regs); - UpdatePrimitiveTopology(regs); UpdateStencilOp(regs); UpdateStencilTestEnable(regs); } @@ -1418,16 +1417,6 @@ void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) { [front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); }); } -void RasterizerVulkan::UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs) { - const Maxwell::PrimitiveTopology primitive_topology = regs.draw.topology.Value(); - if (!state_tracker.ChangePrimitiveTopology(primitive_topology)) { - return; - } - scheduler.Record([this, primitive_topology](vk::CommandBuffer cmdbuf) { - cmdbuf.SetPrimitiveTopologyEXT(MaxwellToVK::PrimitiveTopology(device, primitive_topology)); - }); -} - void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) { if (!state_tracker.TouchStencilOp()) { 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: void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs); - void UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); 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) { return false; } +u32 ShaderVersion(const VKDevice& device) { + if (device.InstanceApiVersion() < VK_API_VERSION_1_1) { + return 0x00010000; + } + return 0x00010300; +} + class SPIRVDecompiler final : public Sirit::Module { public: explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage, const Registry& registry, const Specialization& specialization) - : Module(0x00010300), device{device}, ir{ir}, stage{stage}, header{ir.GetHeader()}, - registry{registry}, specialization{specialization} { + : Module(ShaderVersion(device)), device{device}, ir{ir}, stage{stage}, + header{ir.GetHeader()}, registry{registry}, specialization{specialization} { if (stage != ShaderType::Compute) { transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo()); } @@ -293,6 +300,7 @@ public: AddCapability(spv::Capability::DrawParameters); AddCapability(spv::Capability::SubgroupBallotKHR); AddCapability(spv::Capability::SubgroupVoteKHR); + AddExtension("SPV_KHR_16bit_storage"); AddExtension("SPV_KHR_shader_ballot"); AddExtension("SPV_KHR_subgroup_vote"); 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 @@ #include <vector> #include "common/common_types.h" +#include "common/logging/log.h" #include "video_core/renderer_vulkan/wrapper.h" @@ -415,18 +416,17 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe return VK_SUCCESS; } -Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions, +Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char*> extensions, InstanceDispatch& dld) noexcept { - static constexpr VkApplicationInfo application_info{ + const VkApplicationInfo application_info{ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pNext = nullptr, .pApplicationName = "yuzu Emulator", .applicationVersion = VK_MAKE_VERSION(0, 1, 0), .pEngineName = "yuzu Emulator", .engineVersion = VK_MAKE_VERSION(0, 1, 0), - .apiVersion = VK_API_VERSION_1_1, + .apiVersion = version, }; - const VkInstanceCreateInfo ci{ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = nullptr, @@ -818,6 +818,21 @@ VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noe return properties; } +u32 AvailableVersion(const InstanceDispatch& dld) noexcept { + PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; + if (!Proc(vkEnumerateInstanceVersion, dld, "vkEnumerateInstanceVersion")) { + // If the procedure is not found, Vulkan 1.0 is assumed + return VK_API_VERSION_1_0; + } + u32 version; + if (const VkResult result = vkEnumerateInstanceVersion(&version); result != VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "vkEnumerateInstanceVersion returned {}, assuming Vulkan 1.1", + ToString(result)); + return VK_API_VERSION_1_1; + } + return version; +} + std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( const InstanceDispatch& dld) { 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> { public: /// Creates a Vulkan instance. Use "operator bool" for error handling. - static Instance Create(Span<const char*> layers, Span<const char*> extensions, + static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions, InstanceDispatch& dld) noexcept; /// Enumerates physical devices. @@ -1090,6 +1090,8 @@ private: const DeviceDispatch* dld; }; +u32 AvailableVersion(const InstanceDispatch& dld) noexcept; + std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( const InstanceDispatch& dld); |