diff options
72 files changed, 1246 insertions, 643 deletions
diff --git a/.gitmodules b/.gitmodules index 89f2ad924..5a8169b44 100644 --- a/.gitmodules +++ b/.gitmodules | |||
| @@ -55,3 +55,6 @@ | |||
| 55 | [submodule "tzdb_to_nx"] | 55 | [submodule "tzdb_to_nx"] |
| 56 | path = externals/nx_tzdb/tzdb_to_nx | 56 | path = externals/nx_tzdb/tzdb_to_nx |
| 57 | url = https://github.com/lat9nq/tzdb_to_nx.git | 57 | url = https://github.com/lat9nq/tzdb_to_nx.git |
| 58 | [submodule "VulkanMemoryAllocator"] | ||
| 59 | path = externals/vma/VulkanMemoryAllocator | ||
| 60 | url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator | ||
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 7cce27d51..0184289eb 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt | |||
| @@ -143,6 +143,11 @@ endif() | |||
| 143 | # TZDB (Time Zone Database) | 143 | # TZDB (Time Zone Database) |
| 144 | add_subdirectory(nx_tzdb) | 144 | add_subdirectory(nx_tzdb) |
| 145 | 145 | ||
| 146 | # VMA | ||
| 147 | add_library(vma vma/vma.cpp) | ||
| 148 | target_include_directories(vma PUBLIC ./vma/VulkanMemoryAllocator/include) | ||
| 149 | target_link_libraries(vma PRIVATE Vulkan::Headers) | ||
| 150 | |||
| 146 | if (NOT TARGET LLVM::Demangle) | 151 | if (NOT TARGET LLVM::Demangle) |
| 147 | add_library(demangle demangle/ItaniumDemangle.cpp) | 152 | add_library(demangle demangle/ItaniumDemangle.cpp) |
| 148 | target_include_directories(demangle PUBLIC ./demangle) | 153 | target_include_directories(demangle PUBLIC ./demangle) |
diff --git a/externals/SDL b/externals/SDL | |||
| Subproject c27f3ead7c37bcbef608f385baa9fce7232efc6 | Subproject 491fba1d06a4810645092b2559b9cc94abeb23b | ||
diff --git a/externals/nx_tzdb/tzdb_to_nx b/externals/nx_tzdb/tzdb_to_nx | |||
| Subproject 8c272f21d19c6e821345fd055f41b9640f9189d | Subproject 212afa2394a74226dcf1b7996a570aae17debb6 | ||
diff --git a/externals/vma/VulkanMemoryAllocator b/externals/vma/VulkanMemoryAllocator new file mode 160000 | |||
| Subproject 0aa3989b8f382f185fdf646cc83a1d16fa31d6a | |||
diff --git a/externals/vma/vma.cpp b/externals/vma/vma.cpp new file mode 100644 index 000000000..1fe2cf52b --- /dev/null +++ b/externals/vma/vma.cpp | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #define VMA_IMPLEMENTATION | ||
| 5 | #define VMA_STATIC_VULKAN_FUNCTIONS 0 | ||
| 6 | #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 | ||
| 7 | |||
| 8 | #include <vk_mem_alloc.h> \ No newline at end of file | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt index dd6c895fd..f54dccc69 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt | |||
| @@ -29,7 +29,6 @@ import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager | |||
| 29 | import org.yuzu.yuzu_emu.model.Game | 29 | import org.yuzu.yuzu_emu.model.Game |
| 30 | import org.yuzu.yuzu_emu.model.GamesViewModel | 30 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 31 | import org.yuzu.yuzu_emu.model.HomeViewModel | 31 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 32 | import org.yuzu.yuzu_emu.utils.FileUtil | ||
| 33 | 32 | ||
| 34 | class SearchFragment : Fragment() { | 33 | class SearchFragment : Fragment() { |
| 35 | private var _binding: FragmentSearchBinding? = null | 34 | private var _binding: FragmentSearchBinding? = null |
| @@ -128,10 +127,7 @@ class SearchFragment : Fragment() { | |||
| 128 | 127 | ||
| 129 | R.id.chip_homebrew -> baseList.filter { it.isHomebrew } | 128 | R.id.chip_homebrew -> baseList.filter { it.isHomebrew } |
| 130 | 129 | ||
| 131 | R.id.chip_retail -> baseList.filter { | 130 | R.id.chip_retail -> baseList.filter { !it.isHomebrew } |
| 132 | FileUtil.hasExtension(it.path, "xci") || | ||
| 133 | FileUtil.hasExtension(it.path, "nsp") | ||
| 134 | } | ||
| 135 | 131 | ||
| 136 | else -> baseList | 132 | else -> baseList |
| 137 | } | 133 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt index 6a048e39f..6527c64ab 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt | |||
| @@ -43,7 +43,7 @@ class Game( | |||
| 43 | 43 | ||
| 44 | companion object { | 44 | companion object { |
| 45 | val extensions: Set<String> = HashSet( | 45 | val extensions: Set<String> = HashSet( |
| 46 | listOf(".xci", ".nsp", ".nca", ".nro") | 46 | listOf("xci", "nsp", "nca", "nro") |
| 47 | ) | 47 | ) |
| 48 | } | 48 | } |
| 49 | } | 49 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 3086cfad3..f7d7aed1e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt | |||
| @@ -296,7 +296,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 296 | return@registerForActivityResult | 296 | return@registerForActivityResult |
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | if (!FileUtil.hasExtension(result, "keys")) { | 299 | if (FileUtil.getExtension(result) != "keys") { |
| 300 | MessageDialogFragment.newInstance( | 300 | MessageDialogFragment.newInstance( |
| 301 | R.string.reading_keys_failure, | 301 | R.string.reading_keys_failure, |
| 302 | R.string.install_prod_keys_failure_extension_description | 302 | R.string.install_prod_keys_failure_extension_description |
| @@ -393,7 +393,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 393 | return@registerForActivityResult | 393 | return@registerForActivityResult |
| 394 | } | 394 | } |
| 395 | 395 | ||
| 396 | if (!FileUtil.hasExtension(result, "bin")) { | 396 | if (FileUtil.getExtension(result) != "bin") { |
| 397 | MessageDialogFragment.newInstance( | 397 | MessageDialogFragment.newInstance( |
| 398 | R.string.reading_keys_failure, | 398 | R.string.reading_keys_failure, |
| 399 | R.string.install_amiibo_keys_failure_extension_description | 399 | R.string.install_amiibo_keys_failure_extension_description |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt index 9f3bbe56f..142af5f26 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt | |||
| @@ -7,7 +7,6 @@ import android.content.Context | |||
| 7 | import android.database.Cursor | 7 | import android.database.Cursor |
| 8 | import android.net.Uri | 8 | import android.net.Uri |
| 9 | import android.provider.DocumentsContract | 9 | import android.provider.DocumentsContract |
| 10 | import android.provider.OpenableColumns | ||
| 11 | import androidx.documentfile.provider.DocumentFile | 10 | import androidx.documentfile.provider.DocumentFile |
| 12 | import java.io.BufferedInputStream | 11 | import java.io.BufferedInputStream |
| 13 | import java.io.File | 12 | import java.io.File |
| @@ -185,19 +184,18 @@ object FileUtil { | |||
| 185 | 184 | ||
| 186 | /** | 185 | /** |
| 187 | * Get file display name from given path | 186 | * Get file display name from given path |
| 188 | * @param path content uri path | 187 | * @param uri content uri |
| 189 | * @return String display name | 188 | * @return String display name |
| 190 | */ | 189 | */ |
| 191 | fun getFilename(context: Context, path: String): String { | 190 | fun getFilename(uri: Uri): String { |
| 192 | val resolver = context.contentResolver | 191 | val resolver = YuzuApplication.appContext.contentResolver |
| 193 | val columns = arrayOf( | 192 | val columns = arrayOf( |
| 194 | DocumentsContract.Document.COLUMN_DISPLAY_NAME | 193 | DocumentsContract.Document.COLUMN_DISPLAY_NAME |
| 195 | ) | 194 | ) |
| 196 | var filename = "" | 195 | var filename = "" |
| 197 | var c: Cursor? = null | 196 | var c: Cursor? = null |
| 198 | try { | 197 | try { |
| 199 | val mUri = Uri.parse(path) | 198 | c = resolver.query(uri, columns, null, null, null) |
| 200 | c = resolver.query(mUri, columns, null, null, null) | ||
| 201 | c!!.moveToNext() | 199 | c!!.moveToNext() |
| 202 | filename = c.getString(0) | 200 | filename = c.getString(0) |
| 203 | } catch (e: Exception) { | 201 | } catch (e: Exception) { |
| @@ -326,25 +324,9 @@ object FileUtil { | |||
| 326 | } | 324 | } |
| 327 | } | 325 | } |
| 328 | 326 | ||
| 329 | fun hasExtension(path: String, extension: String): Boolean = | 327 | fun getExtension(uri: Uri): String { |
| 330 | path.substring(path.lastIndexOf(".") + 1).contains(extension) | 328 | val fileName = getFilename(uri) |
| 331 | 329 | return fileName.substring(fileName.lastIndexOf(".") + 1) | |
| 332 | fun hasExtension(uri: Uri, extension: String): Boolean { | 330 | .lowercase() |
| 333 | val fileName: String? | ||
| 334 | val cursor = YuzuApplication.appContext.contentResolver.query(uri, null, null, null, null) | ||
| 335 | val nameIndex = cursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME) | ||
| 336 | cursor?.moveToFirst() | ||
| 337 | |||
| 338 | if (nameIndex == null) { | ||
| 339 | return false | ||
| 340 | } | ||
| 341 | |||
| 342 | fileName = cursor.getString(nameIndex) | ||
| 343 | cursor.close() | ||
| 344 | |||
| 345 | if (fileName == null) { | ||
| 346 | return false | ||
| 347 | } | ||
| 348 | return fileName.substring(fileName.lastIndexOf(".") + 1).contains(extension) | ||
| 349 | } | 331 | } |
| 350 | } | 332 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt index ee9f3e570..f8e7eeca7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt | |||
| @@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.utils | |||
| 6 | import android.content.SharedPreferences | 6 | import android.content.SharedPreferences |
| 7 | import android.net.Uri | 7 | import android.net.Uri |
| 8 | import androidx.preference.PreferenceManager | 8 | import androidx.preference.PreferenceManager |
| 9 | import java.util.* | ||
| 10 | import kotlinx.serialization.encodeToString | 9 | import kotlinx.serialization.encodeToString |
| 11 | import kotlinx.serialization.json.Json | 10 | import kotlinx.serialization.json.Json |
| 12 | import org.yuzu.yuzu_emu.NativeLibrary | 11 | import org.yuzu.yuzu_emu.NativeLibrary |
| @@ -33,15 +32,9 @@ object GameHelper { | |||
| 33 | val children = FileUtil.listFiles(context, gamesUri) | 32 | val children = FileUtil.listFiles(context, gamesUri) |
| 34 | for (file in children) { | 33 | for (file in children) { |
| 35 | if (!file.isDirectory) { | 34 | if (!file.isDirectory) { |
| 36 | val filename = file.uri.toString() | 35 | // Check that the file has an extension we care about before trying to read out of it. |
| 37 | val extensionStart = filename.lastIndexOf('.') | 36 | if (Game.extensions.contains(FileUtil.getExtension(file.uri))) { |
| 38 | if (extensionStart > 0) { | 37 | games.add(getGame(file.uri)) |
| 39 | val fileExtension = filename.substring(extensionStart) | ||
| 40 | |||
| 41 | // Check that the file has an extension we care about before trying to read out of it. | ||
| 42 | if (Game.extensions.contains(fileExtension.lowercase(Locale.getDefault()))) { | ||
| 43 | games.add(getGame(filename)) | ||
| 44 | } | ||
| 45 | } | 38 | } |
| 46 | } | 39 | } |
| 47 | } | 40 | } |
| @@ -59,21 +52,19 @@ object GameHelper { | |||
| 59 | return games.toList() | 52 | return games.toList() |
| 60 | } | 53 | } |
| 61 | 54 | ||
| 62 | private fun getGame(filePath: String): Game { | 55 | private fun getGame(uri: Uri): Game { |
| 56 | val filePath = uri.toString() | ||
| 63 | var name = NativeLibrary.getTitle(filePath) | 57 | var name = NativeLibrary.getTitle(filePath) |
| 64 | 58 | ||
| 65 | // If the game's title field is empty, use the filename. | 59 | // If the game's title field is empty, use the filename. |
| 66 | if (name.isEmpty()) { | 60 | if (name.isEmpty()) { |
| 67 | name = filePath.substring(filePath.lastIndexOf("/") + 1) | 61 | name = FileUtil.getFilename(uri) |
| 68 | } | 62 | } |
| 69 | var gameId = NativeLibrary.getGameId(filePath) | 63 | var gameId = NativeLibrary.getGameId(filePath) |
| 70 | 64 | ||
| 71 | // If the game's ID field is empty, use the filename without extension. | 65 | // If the game's ID field is empty, use the filename without extension. |
| 72 | if (gameId.isEmpty()) { | 66 | if (gameId.isEmpty()) { |
| 73 | gameId = filePath.substring( | 67 | gameId = name.substring(0, name.lastIndexOf(".")) |
| 74 | filePath.lastIndexOf("/") + 1, | ||
| 75 | filePath.lastIndexOf(".") | ||
| 76 | ) | ||
| 77 | } | 68 | } |
| 78 | 69 | ||
| 79 | val newGame = Game( | 70 | val newGame = Game( |
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index d576aac50..8bc6a4a04 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -60,6 +60,9 @@ | |||
| 60 | #include "video_core/rasterizer_interface.h" | 60 | #include "video_core/rasterizer_interface.h" |
| 61 | #include "video_core/renderer_base.h" | 61 | #include "video_core/renderer_base.h" |
| 62 | 62 | ||
| 63 | #define jconst [[maybe_unused]] const auto | ||
| 64 | #define jauto [[maybe_unused]] auto | ||
| 65 | |||
| 63 | namespace { | 66 | namespace { |
| 64 | 67 | ||
| 65 | class EmulationSession final { | 68 | class EmulationSession final { |
| @@ -99,8 +102,8 @@ public: | |||
| 99 | } | 102 | } |
| 100 | 103 | ||
| 101 | int InstallFileToNand(std::string filename) { | 104 | int InstallFileToNand(std::string filename) { |
| 102 | const auto copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, | 105 | jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, |
| 103 | std::size_t block_size) { | 106 | std::size_t block_size) { |
| 104 | if (src == nullptr || dest == nullptr) { | 107 | if (src == nullptr || dest == nullptr) { |
| 105 | return false; | 108 | return false; |
| 106 | } | 109 | } |
| @@ -109,10 +112,10 @@ public: | |||
| 109 | } | 112 | } |
| 110 | 113 | ||
| 111 | using namespace Common::Literals; | 114 | using namespace Common::Literals; |
| 112 | std::vector<u8> buffer(1_MiB); | 115 | [[maybe_unused]] std::vector<u8> buffer(1_MiB); |
| 113 | 116 | ||
| 114 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { | 117 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { |
| 115 | const auto read = src->Read(buffer.data(), buffer.size(), i); | 118 | jconst read = src->Read(buffer.data(), buffer.size(), i); |
| 116 | dest->Write(buffer.data(), read, i); | 119 | dest->Write(buffer.data(), read, i); |
| 117 | } | 120 | } |
| 118 | return true; | 121 | return true; |
| @@ -129,14 +132,14 @@ public: | |||
| 129 | m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); | 132 | m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); |
| 130 | m_system.GetFileSystemController().CreateFactories(*m_vfs); | 133 | m_system.GetFileSystemController().CreateFactories(*m_vfs); |
| 131 | 134 | ||
| 132 | std::shared_ptr<FileSys::NSP> nsp; | 135 | [[maybe_unused]] std::shared_ptr<FileSys::NSP> nsp; |
| 133 | if (filename.ends_with("nsp")) { | 136 | if (filename.ends_with("nsp")) { |
| 134 | nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read)); | 137 | nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read)); |
| 135 | if (nsp->IsExtractedType()) { | 138 | if (nsp->IsExtractedType()) { |
| 136 | return InstallError; | 139 | return InstallError; |
| 137 | } | 140 | } |
| 138 | } else if (filename.ends_with("xci")) { | 141 | } else if (filename.ends_with("xci")) { |
| 139 | const auto xci = | 142 | jconst xci = |
| 140 | std::make_shared<FileSys::XCI>(m_vfs->OpenFile(filename, FileSys::Mode::Read)); | 143 | std::make_shared<FileSys::XCI>(m_vfs->OpenFile(filename, FileSys::Mode::Read)); |
| 141 | nsp = xci->GetSecurePartitionNSP(); | 144 | nsp = xci->GetSecurePartitionNSP(); |
| 142 | } else { | 145 | } else { |
| @@ -151,7 +154,7 @@ public: | |||
| 151 | return InstallError; | 154 | return InstallError; |
| 152 | } | 155 | } |
| 153 | 156 | ||
| 154 | const auto res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry( | 157 | jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry( |
| 155 | *nsp, true, copy_func); | 158 | *nsp, true, copy_func); |
| 156 | 159 | ||
| 157 | switch (res) { | 160 | switch (res) { |
| @@ -234,7 +237,7 @@ public: | |||
| 234 | m_system.SetFilesystem(m_vfs); | 237 | m_system.SetFilesystem(m_vfs); |
| 235 | 238 | ||
| 236 | // Initialize system. | 239 | // Initialize system. |
| 237 | auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>(); | 240 | jauto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>(); |
| 238 | m_software_keyboard = android_keyboard.get(); | 241 | m_software_keyboard = android_keyboard.get(); |
| 239 | m_system.SetShuttingDown(false); | 242 | m_system.SetShuttingDown(false); |
| 240 | m_system.ApplySettings(); | 243 | m_system.ApplySettings(); |
| @@ -332,7 +335,7 @@ public: | |||
| 332 | 335 | ||
| 333 | while (true) { | 336 | while (true) { |
| 334 | { | 337 | { |
| 335 | std::unique_lock lock(m_mutex); | 338 | [[maybe_unused]] std::unique_lock lock(m_mutex); |
| 336 | if (m_cv.wait_for(lock, std::chrono::milliseconds(800), | 339 | if (m_cv.wait_for(lock, std::chrono::milliseconds(800), |
| 337 | [&]() { return !m_is_running; })) { | 340 | [&]() { return !m_is_running; })) { |
| 338 | // Emulation halted. | 341 | // Emulation halted. |
| @@ -364,7 +367,7 @@ public: | |||
| 364 | } | 367 | } |
| 365 | 368 | ||
| 366 | bool IsHandheldOnly() { | 369 | bool IsHandheldOnly() { |
| 367 | const auto npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); | 370 | jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); |
| 368 | 371 | ||
| 369 | if (npad_style_set.fullkey == 1) { | 372 | if (npad_style_set.fullkey == 1) { |
| 370 | return false; | 373 | return false; |
| @@ -377,17 +380,17 @@ public: | |||
| 377 | return !Settings::values.use_docked_mode.GetValue(); | 380 | return !Settings::values.use_docked_mode.GetValue(); |
| 378 | } | 381 | } |
| 379 | 382 | ||
| 380 | void SetDeviceType(int index, int type) { | 383 | void SetDeviceType([[maybe_unused]] int index, int type) { |
| 381 | auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); | 384 | jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); |
| 382 | controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type)); | 385 | controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type)); |
| 383 | } | 386 | } |
| 384 | 387 | ||
| 385 | void OnGamepadConnectEvent(int index) { | 388 | void OnGamepadConnectEvent([[maybe_unused]] int index) { |
| 386 | auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); | 389 | jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); |
| 387 | 390 | ||
| 388 | // Ensure that player1 is configured correctly and handheld disconnected | 391 | // Ensure that player1 is configured correctly and handheld disconnected |
| 389 | if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) { | 392 | if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) { |
| 390 | auto handheld = | 393 | jauto handheld = |
| 391 | m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); | 394 | m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); |
| 392 | 395 | ||
| 393 | if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { | 396 | if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { |
| @@ -399,7 +402,8 @@ public: | |||
| 399 | 402 | ||
| 400 | // Ensure that handheld is configured correctly and player 1 disconnected | 403 | // Ensure that handheld is configured correctly and player 1 disconnected |
| 401 | if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) { | 404 | if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) { |
| 402 | auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); | 405 | jauto player1 = |
| 406 | m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); | ||
| 403 | 407 | ||
| 404 | if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) { | 408 | if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) { |
| 405 | player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); | 409 | player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); |
| @@ -413,8 +417,8 @@ public: | |||
| 413 | } | 417 | } |
| 414 | } | 418 | } |
| 415 | 419 | ||
| 416 | void OnGamepadDisconnectEvent(int index) { | 420 | void OnGamepadDisconnectEvent([[maybe_unused]] int index) { |
| 417 | auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); | 421 | jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); |
| 418 | controller->Disconnect(); | 422 | controller->Disconnect(); |
| 419 | } | 423 | } |
| 420 | 424 | ||
| @@ -430,7 +434,7 @@ private: | |||
| 430 | }; | 434 | }; |
| 431 | 435 | ||
| 432 | RomMetadata GetRomMetadata(const std::string& path) { | 436 | RomMetadata GetRomMetadata(const std::string& path) { |
| 433 | if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) { | 437 | if (jauto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) { |
| 434 | return search->second; | 438 | return search->second; |
| 435 | } | 439 | } |
| 436 | 440 | ||
| @@ -438,14 +442,14 @@ private: | |||
| 438 | } | 442 | } |
| 439 | 443 | ||
| 440 | RomMetadata CacheRomMetadata(const std::string& path) { | 444 | RomMetadata CacheRomMetadata(const std::string& path) { |
| 441 | const auto file = Core::GetGameFileFromPath(m_vfs, path); | 445 | jconst file = Core::GetGameFileFromPath(m_vfs, path); |
| 442 | auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); | 446 | jauto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); |
| 443 | 447 | ||
| 444 | RomMetadata entry; | 448 | RomMetadata entry; |
| 445 | loader->ReadTitle(entry.title); | 449 | loader->ReadTitle(entry.title); |
| 446 | loader->ReadIcon(entry.icon); | 450 | loader->ReadIcon(entry.icon); |
| 447 | if (loader->GetFileType() == Loader::FileType::NRO) { | 451 | if (loader->GetFileType() == Loader::FileType::NRO) { |
| 448 | auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get()); | 452 | jauto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get()); |
| 449 | entry.isHomebrew = loader_nro->IsHomebrew(); | 453 | entry.isHomebrew = loader_nro->IsHomebrew(); |
| 450 | } else { | 454 | } else { |
| 451 | entry.isHomebrew = false; | 455 | entry.isHomebrew = false; |
| @@ -516,7 +520,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) { | |||
| 516 | 520 | ||
| 517 | SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); | 521 | SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); |
| 518 | 522 | ||
| 519 | const auto result = EmulationSession::GetInstance().InitializeEmulation(filepath); | 523 | jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath); |
| 520 | if (result != Core::SystemResultStatus::Success) { | 524 | if (result != Core::SystemResultStatus::Success) { |
| 521 | return result; | 525 | return result; |
| 522 | } | 526 | } |
| @@ -528,24 +532,25 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) { | |||
| 528 | 532 | ||
| 529 | extern "C" { | 533 | extern "C" { |
| 530 | 534 | ||
| 531 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jclass clazz, jobject surf) { | 535 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject instance, |
| 536 | [[maybe_unused]] jobject surf) { | ||
| 532 | EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf)); | 537 | EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf)); |
| 533 | EmulationSession::GetInstance().SurfaceChanged(); | 538 | EmulationSession::GetInstance().SurfaceChanged(); |
| 534 | } | 539 | } |
| 535 | 540 | ||
| 536 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jclass clazz) { | 541 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jobject instance) { |
| 537 | ANativeWindow_release(EmulationSession::GetInstance().NativeWindow()); | 542 | ANativeWindow_release(EmulationSession::GetInstance().NativeWindow()); |
| 538 | EmulationSession::GetInstance().SetNativeWindow(nullptr); | 543 | EmulationSession::GetInstance().SetNativeWindow(nullptr); |
| 539 | EmulationSession::GetInstance().SurfaceChanged(); | 544 | EmulationSession::GetInstance().SurfaceChanged(); |
| 540 | } | 545 | } |
| 541 | 546 | ||
| 542 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jclass clazz, | 547 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance, |
| 543 | jstring j_directory) { | 548 | [[maybe_unused]] jstring j_directory) { |
| 544 | Common::FS::SetAppDirectory(GetJString(env, j_directory)); | 549 | Common::FS::SetAppDirectory(GetJString(env, j_directory)); |
| 545 | } | 550 | } |
| 546 | 551 | ||
| 547 | int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jclass clazz, | 552 | int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance, |
| 548 | jstring j_file) { | 553 | [[maybe_unused]] jstring j_file) { |
| 549 | return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file)); | 554 | return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file)); |
| 550 | } | 555 | } |
| 551 | 556 | ||
| @@ -570,7 +575,7 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* e | |||
| 570 | } | 575 | } |
| 571 | 576 | ||
| 572 | jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading( | 577 | jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading( |
| 573 | JNIEnv* env, [[maybe_unused]] jobject instance) { | 578 | JNIEnv* env, jobject instance) { |
| 574 | #ifdef ARCHITECTURE_arm64 | 579 | #ifdef ARCHITECTURE_arm64 |
| 575 | // If the KGSL device exists custom drivers can be loaded using adrenotools | 580 | // If the KGSL device exists custom drivers can be loaded using adrenotools |
| 576 | return SupportsCustomDriver(); | 581 | return SupportsCustomDriver(); |
| @@ -648,8 +653,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(JNIEnv* | |||
| 648 | return static_cast<jboolean>(true); | 653 | return static_cast<jboolean>(true); |
| 649 | } | 654 | } |
| 650 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent(JNIEnv* env, jclass clazz, | 655 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent(JNIEnv* env, jclass clazz, |
| 651 | [[maybe_unused]] jint j_device, | 656 | jint j_device, jint j_button, |
| 652 | jint j_button, jint action) { | 657 | jint action) { |
| 653 | if (EmulationSession::GetInstance().IsRunning()) { | 658 | if (EmulationSession::GetInstance().IsRunning()) { |
| 654 | // Ensure gamepad is connected | 659 | // Ensure gamepad is connected |
| 655 | EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); | 660 | EmulationSession::GetInstance().OnGamepadConnectEvent(j_device); |
| @@ -718,8 +723,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c | |||
| 718 | } | 723 | } |
| 719 | 724 | ||
| 720 | jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass clazz, | 725 | jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass clazz, |
| 721 | [[maybe_unused]] jstring j_filename) { | 726 | jstring j_filename) { |
| 722 | auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename)); | 727 | jauto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename)); |
| 723 | jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size())); | 728 | jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size())); |
| 724 | env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon), | 729 | env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon), |
| 725 | reinterpret_cast<jbyte*>(icon_data.data())); | 730 | reinterpret_cast<jbyte*>(icon_data.data())); |
| @@ -727,8 +732,8 @@ jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass cla | |||
| 727 | } | 732 | } |
| 728 | 733 | ||
| 729 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle(JNIEnv* env, jclass clazz, | 734 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle(JNIEnv* env, jclass clazz, |
| 730 | [[maybe_unused]] jstring j_filename) { | 735 | jstring j_filename) { |
| 731 | auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename)); | 736 | jauto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename)); |
| 732 | return env->NewStringUTF(title.c_str()); | 737 | return env->NewStringUTF(title.c_str()); |
| 733 | } | 738 | } |
| 734 | 739 | ||
| @@ -743,22 +748,21 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId(JNIEnv* env, jclass claz | |||
| 743 | } | 748 | } |
| 744 | 749 | ||
| 745 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions(JNIEnv* env, jclass clazz, | 750 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions(JNIEnv* env, jclass clazz, |
| 746 | [[maybe_unused]] jstring j_filename) { | 751 | jstring j_filename) { |
| 747 | return env->NewStringUTF(""); | 752 | return env->NewStringUTF(""); |
| 748 | } | 753 | } |
| 749 | 754 | ||
| 750 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany(JNIEnv* env, jclass clazz, | 755 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany(JNIEnv* env, jclass clazz, |
| 751 | [[maybe_unused]] jstring j_filename) { | 756 | jstring j_filename) { |
| 752 | return env->NewStringUTF(""); | 757 | return env->NewStringUTF(""); |
| 753 | } | 758 | } |
| 754 | 759 | ||
| 755 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew(JNIEnv* env, jclass clazz, | 760 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew(JNIEnv* env, jclass clazz, |
| 756 | [[maybe_unused]] jstring j_filename) { | 761 | jstring j_filename) { |
| 757 | return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename)); | 762 | return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename)); |
| 758 | } | 763 | } |
| 759 | 764 | ||
| 760 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation | 765 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation(JNIEnv* env, jclass clazz) { |
| 761 | [[maybe_unused]] (JNIEnv* env, jclass clazz) { | ||
| 762 | // Create the default config.ini. | 766 | // Create the default config.ini. |
| 763 | Config{}; | 767 | Config{}; |
| 764 | // Initialize the emulated system. | 768 | // Initialize the emulated system. |
| @@ -770,8 +774,7 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass cl | |||
| 770 | } | 774 | } |
| 771 | 775 | ||
| 772 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( | 776 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( |
| 773 | JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_file, | 777 | JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {} |
| 774 | [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {} | ||
| 775 | 778 | ||
| 776 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) { | 779 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) { |
| 777 | Config{}; | 780 | Config{}; |
| @@ -816,7 +819,7 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jcl | |||
| 816 | jdoubleArray j_stats = env->NewDoubleArray(4); | 819 | jdoubleArray j_stats = env->NewDoubleArray(4); |
| 817 | 820 | ||
| 818 | if (EmulationSession::GetInstance().IsRunning()) { | 821 | if (EmulationSession::GetInstance().IsRunning()) { |
| 819 | const auto results = EmulationSession::GetInstance().PerfStats(); | 822 | jconst results = EmulationSession::GetInstance().PerfStats(); |
| 820 | 823 | ||
| 821 | // Converting the structure into an array makes it easier to pass it to the frontend | 824 | // Converting the structure into an array makes it easier to pass it to the frontend |
| 822 | double stats[4] = {results.system_fps, results.average_game_fps, results.frametime, | 825 | double stats[4] = {results.system_fps, results.average_game_fps, results.frametime, |
diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp index 1baf6d746..36e67c145 100644 --- a/src/common/fs/fs.cpp +++ b/src/common/fs/fs.cpp | |||
| @@ -605,6 +605,12 @@ fs::file_type GetEntryType(const fs::path& path) { | |||
| 605 | } | 605 | } |
| 606 | 606 | ||
| 607 | u64 GetSize(const fs::path& path) { | 607 | u64 GetSize(const fs::path& path) { |
| 608 | #ifdef ANDROID | ||
| 609 | if (Android::IsContentUri(path)) { | ||
| 610 | return Android::GetSize(path); | ||
| 611 | } | ||
| 612 | #endif | ||
| 613 | |||
| 608 | std::error_code ec; | 614 | std::error_code ec; |
| 609 | 615 | ||
| 610 | const auto file_size = fs::file_size(path, ec); | 616 | const auto file_size = fs::file_size(path, ec); |
diff --git a/src/common/settings.h b/src/common/settings.h index 3aedf3850..ae5ed93d8 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -525,9 +525,16 @@ struct Values { | |||
| 525 | Setting<bool> tas_loop{false, "tas_loop"}; | 525 | Setting<bool> tas_loop{false, "tas_loop"}; |
| 526 | 526 | ||
| 527 | Setting<bool> mouse_panning{false, "mouse_panning"}; | 527 | Setting<bool> mouse_panning{false, "mouse_panning"}; |
| 528 | Setting<u8, true> mouse_panning_sensitivity{50, 1, 100, "mouse_panning_sensitivity"}; | 528 | Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"}; |
| 529 | Setting<bool> mouse_enabled{false, "mouse_enabled"}; | 529 | Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"}; |
| 530 | Setting<u8, true> mouse_panning_deadzone_x_counterweight{ | ||
| 531 | 0, 0, 100, "mouse_panning_deadzone_x_counterweight"}; | ||
| 532 | Setting<u8, true> mouse_panning_deadzone_y_counterweight{ | ||
| 533 | 0, 0, 100, "mouse_panning_deadzone_y_counterweight"}; | ||
| 534 | Setting<u8, true> mouse_panning_decay_strength{22, 0, 100, "mouse_panning_decay_strength"}; | ||
| 535 | Setting<u8, true> mouse_panning_min_decay{5, 0, 100, "mouse_panning_min_decay"}; | ||
| 530 | 536 | ||
| 537 | Setting<bool> mouse_enabled{false, "mouse_enabled"}; | ||
| 531 | Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; | 538 | Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; |
| 532 | Setting<bool> keyboard_enabled{false, "keyboard_enabled"}; | 539 | Setting<bool> keyboard_enabled{false, "keyboard_enabled"}; |
| 533 | 540 | ||
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index c937495f9..1ebc32c1e 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -1250,6 +1250,11 @@ Common::Input::DriverResult EmulatedController::SetPollingMode( | |||
| 1250 | const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode); | 1250 | const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode); |
| 1251 | const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode); | 1251 | const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode); |
| 1252 | 1252 | ||
| 1253 | // Restore previous state | ||
| 1254 | if (mapped_nfc_result != Common::Input::DriverResult::Success) { | ||
| 1255 | right_output_device->SetPollingMode(Common::Input::PollingMode::Active); | ||
| 1256 | } | ||
| 1257 | |||
| 1253 | if (virtual_nfc_result == Common::Input::DriverResult::Success) { | 1258 | if (virtual_nfc_result == Common::Input::DriverResult::Success) { |
| 1254 | return virtual_nfc_result; | 1259 | return virtual_nfc_result; |
| 1255 | } | 1260 | } |
| @@ -1329,16 +1334,22 @@ bool EmulatedController::StartNfcPolling() { | |||
| 1329 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1334 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1330 | auto& nfc_virtual_output_device = output_devices[3]; | 1335 | auto& nfc_virtual_output_device = output_devices[3]; |
| 1331 | 1336 | ||
| 1332 | return nfc_output_device->StartNfcPolling() == Common::Input::NfcState::Success || | 1337 | const auto device_result = nfc_output_device->StartNfcPolling(); |
| 1333 | nfc_virtual_output_device->StartNfcPolling() == Common::Input::NfcState::Success; | 1338 | const auto virtual_device_result = nfc_virtual_output_device->StartNfcPolling(); |
| 1339 | |||
| 1340 | return device_result == Common::Input::NfcState::Success || | ||
| 1341 | virtual_device_result == Common::Input::NfcState::Success; | ||
| 1334 | } | 1342 | } |
| 1335 | 1343 | ||
| 1336 | bool EmulatedController::StopNfcPolling() { | 1344 | bool EmulatedController::StopNfcPolling() { |
| 1337 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1345 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1338 | auto& nfc_virtual_output_device = output_devices[3]; | 1346 | auto& nfc_virtual_output_device = output_devices[3]; |
| 1339 | 1347 | ||
| 1340 | return nfc_output_device->StopNfcPolling() == Common::Input::NfcState::Success || | 1348 | const auto device_result = nfc_output_device->StopNfcPolling(); |
| 1341 | nfc_virtual_output_device->StopNfcPolling() == Common::Input::NfcState::Success; | 1349 | const auto virtual_device_result = nfc_virtual_output_device->StopNfcPolling(); |
| 1350 | |||
| 1351 | return device_result == Common::Input::NfcState::Success || | ||
| 1352 | virtual_device_result == Common::Input::NfcState::Success; | ||
| 1342 | } | 1353 | } |
| 1343 | 1354 | ||
| 1344 | bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { | 1355 | bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { |
diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 0c9f642bb..f07cf8a0e 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp | |||
| @@ -76,9 +76,6 @@ void Mouse::UpdateThread(std::stop_token stop_token) { | |||
| 76 | UpdateStickInput(); | 76 | UpdateStickInput(); |
| 77 | UpdateMotionInput(); | 77 | UpdateMotionInput(); |
| 78 | 78 | ||
| 79 | if (mouse_panning_timeout++ > 20) { | ||
| 80 | StopPanning(); | ||
| 81 | } | ||
| 82 | std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); | 79 | std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); |
| 83 | } | 80 | } |
| 84 | } | 81 | } |
| @@ -88,18 +85,45 @@ void Mouse::UpdateStickInput() { | |||
| 88 | return; | 85 | return; |
| 89 | } | 86 | } |
| 90 | 87 | ||
| 91 | const float sensitivity = | 88 | const float length = last_mouse_change.Length(); |
| 92 | Settings::values.mouse_panning_sensitivity.GetValue() * default_stick_sensitivity; | ||
| 93 | 89 | ||
| 94 | // Slow movement by 4% | 90 | // Prevent input from exceeding the max range (1.0f) too much, |
| 95 | last_mouse_change *= 0.96f; | 91 | // but allow some room to make it easier to sustain |
| 96 | SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity); | 92 | if (length > 1.2f) { |
| 97 | SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); | 93 | last_mouse_change /= length; |
| 94 | last_mouse_change *= 1.2f; | ||
| 95 | } | ||
| 96 | |||
| 97 | auto mouse_change = last_mouse_change; | ||
| 98 | |||
| 99 | // Bind the mouse change to [0 <= deadzone_counterweight <= 1,1] | ||
| 100 | if (length < 1.0f) { | ||
| 101 | const float deadzone_h_counterweight = | ||
| 102 | Settings::values.mouse_panning_deadzone_x_counterweight.GetValue(); | ||
| 103 | const float deadzone_v_counterweight = | ||
| 104 | Settings::values.mouse_panning_deadzone_y_counterweight.GetValue(); | ||
| 105 | mouse_change /= length; | ||
| 106 | mouse_change.x *= length + (1 - length) * deadzone_h_counterweight * 0.01f; | ||
| 107 | mouse_change.y *= length + (1 - length) * deadzone_v_counterweight * 0.01f; | ||
| 108 | } | ||
| 109 | |||
| 110 | SetAxis(identifier, mouse_axis_x, mouse_change.x); | ||
| 111 | SetAxis(identifier, mouse_axis_y, -mouse_change.y); | ||
| 112 | |||
| 113 | // Decay input over time | ||
| 114 | const float clamped_length = std::min(1.0f, length); | ||
| 115 | const float decay_strength = Settings::values.mouse_panning_decay_strength.GetValue(); | ||
| 116 | const float decay = 1 - clamped_length * clamped_length * decay_strength * 0.01f; | ||
| 117 | const float min_decay = Settings::values.mouse_panning_min_decay.GetValue(); | ||
| 118 | const float clamped_decay = std::min(1 - min_decay / 100.0f, decay); | ||
| 119 | last_mouse_change *= clamped_decay; | ||
| 98 | } | 120 | } |
| 99 | 121 | ||
| 100 | void Mouse::UpdateMotionInput() { | 122 | void Mouse::UpdateMotionInput() { |
| 101 | const float sensitivity = | 123 | // This may need its own sensitivity instead of using the average |
| 102 | Settings::values.mouse_panning_sensitivity.GetValue() * default_motion_sensitivity; | 124 | const float sensitivity = (Settings::values.mouse_panning_x_sensitivity.GetValue() + |
| 125 | Settings::values.mouse_panning_y_sensitivity.GetValue()) / | ||
| 126 | 2.0f * default_motion_sensitivity; | ||
| 103 | 127 | ||
| 104 | const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x + | 128 | const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x + |
| 105 | last_motion_change.y * last_motion_change.y); | 129 | last_motion_change.y * last_motion_change.y); |
| @@ -131,49 +155,28 @@ void Mouse::UpdateMotionInput() { | |||
| 131 | 155 | ||
| 132 | void Mouse::Move(int x, int y, int center_x, int center_y) { | 156 | void Mouse::Move(int x, int y, int center_x, int center_y) { |
| 133 | if (Settings::values.mouse_panning) { | 157 | if (Settings::values.mouse_panning) { |
| 134 | mouse_panning_timeout = 0; | 158 | const auto mouse_change = |
| 135 | |||
| 136 | auto mouse_change = | ||
| 137 | (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>(); | 159 | (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>(); |
| 138 | last_motion_change += {-mouse_change.y, -mouse_change.x, 0}; | 160 | const float x_sensitivity = |
| 139 | 161 | Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity; | |
| 140 | const auto move_distance = mouse_change.Length(); | 162 | const float y_sensitivity = |
| 141 | if (move_distance == 0) { | 163 | Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity; |
| 142 | return; | ||
| 143 | } | ||
| 144 | 164 | ||
| 145 | // Make slow movements at least 3 units on length | 165 | last_motion_change += {-mouse_change.y, -mouse_change.x, 0}; |
| 146 | if (move_distance < 3.0f) { | 166 | last_mouse_change.x += mouse_change.x * x_sensitivity * 0.09f; |
| 147 | // Normalize value | 167 | last_mouse_change.y += mouse_change.y * y_sensitivity * 0.09f; |
| 148 | mouse_change /= move_distance; | ||
| 149 | mouse_change *= 3.0f; | ||
| 150 | } | ||
| 151 | |||
| 152 | // Average mouse movements | ||
| 153 | last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f); | ||
| 154 | |||
| 155 | const auto last_move_distance = last_mouse_change.Length(); | ||
| 156 | |||
| 157 | // Make fast movements clamp to 8 units on length | ||
| 158 | if (last_move_distance > 8.0f) { | ||
| 159 | // Normalize value | ||
| 160 | last_mouse_change /= last_move_distance; | ||
| 161 | last_mouse_change *= 8.0f; | ||
| 162 | } | ||
| 163 | |||
| 164 | // Ignore average if it's less than 1 unit and use current movement value | ||
| 165 | if (last_move_distance < 1.0f) { | ||
| 166 | last_mouse_change = mouse_change / mouse_change.Length(); | ||
| 167 | } | ||
| 168 | 168 | ||
| 169 | return; | 169 | return; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | if (button_pressed) { | 172 | if (button_pressed) { |
| 173 | const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin; | 173 | const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin; |
| 174 | const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; | 174 | const float x_sensitivity = Settings::values.mouse_panning_x_sensitivity.GetValue(); |
| 175 | SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * sensitivity); | 175 | const float y_sensitivity = Settings::values.mouse_panning_y_sensitivity.GetValue(); |
| 176 | SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * sensitivity); | 176 | SetAxis(identifier, mouse_axis_x, |
| 177 | static_cast<float>(mouse_move.x) * x_sensitivity * 0.0012f); | ||
| 178 | SetAxis(identifier, mouse_axis_y, | ||
| 179 | static_cast<float>(-mouse_move.y) * y_sensitivity * 0.0012f); | ||
| 177 | 180 | ||
| 178 | last_motion_change = { | 181 | last_motion_change = { |
| 179 | static_cast<float>(-mouse_move.y) / 50.0f, | 182 | static_cast<float>(-mouse_move.y) / 50.0f, |
| @@ -241,10 +244,6 @@ void Mouse::ReleaseAllButtons() { | |||
| 241 | button_pressed = false; | 244 | button_pressed = false; |
| 242 | } | 245 | } |
| 243 | 246 | ||
| 244 | void Mouse::StopPanning() { | ||
| 245 | last_mouse_change = {}; | ||
| 246 | } | ||
| 247 | |||
| 248 | std::vector<Common::ParamPackage> Mouse::GetInputDevices() const { | 247 | std::vector<Common::ParamPackage> Mouse::GetInputDevices() const { |
| 249 | std::vector<Common::ParamPackage> devices; | 248 | std::vector<Common::ParamPackage> devices; |
| 250 | devices.emplace_back(Common::ParamPackage{ | 249 | devices.emplace_back(Common::ParamPackage{ |
diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index b872c7a0f..0e8edcce1 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h | |||
| @@ -98,7 +98,6 @@ private: | |||
| 98 | void UpdateThread(std::stop_token stop_token); | 98 | void UpdateThread(std::stop_token stop_token); |
| 99 | void UpdateStickInput(); | 99 | void UpdateStickInput(); |
| 100 | void UpdateMotionInput(); | 100 | void UpdateMotionInput(); |
| 101 | void StopPanning(); | ||
| 102 | 101 | ||
| 103 | Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; | 102 | Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; |
| 104 | 103 | ||
| @@ -108,7 +107,6 @@ private: | |||
| 108 | Common::Vec3<float> last_motion_change; | 107 | Common::Vec3<float> last_motion_change; |
| 109 | Common::Vec2<int> wheel_position; | 108 | Common::Vec2<int> wheel_position; |
| 110 | bool button_pressed; | 109 | bool button_pressed; |
| 111 | int mouse_panning_timeout{}; | ||
| 112 | std::jthread update_thread; | 110 | std::jthread update_thread; |
| 113 | }; | 111 | }; |
| 114 | 112 | ||
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 9a0439bb5..9f26392b1 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp | |||
| @@ -150,6 +150,8 @@ public: | |||
| 150 | if (sdl_controller) { | 150 | if (sdl_controller) { |
| 151 | const auto type = SDL_GameControllerGetType(sdl_controller.get()); | 151 | const auto type = SDL_GameControllerGetType(sdl_controller.get()); |
| 152 | return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || | 152 | return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || |
| 153 | (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) || | ||
| 154 | (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) || | ||
| 153 | (type == SDL_CONTROLLER_TYPE_PS5); | 155 | (type == SDL_CONTROLLER_TYPE_PS5); |
| 154 | } | 156 | } |
| 155 | return false; | 157 | return false; |
| @@ -228,9 +230,8 @@ public: | |||
| 228 | return false; | 230 | return false; |
| 229 | } | 231 | } |
| 230 | 232 | ||
| 231 | Common::Input::BatteryLevel GetBatteryLevel() { | 233 | Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) { |
| 232 | const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); | 234 | switch (battery_level) { |
| 233 | switch (level) { | ||
| 234 | case SDL_JOYSTICK_POWER_EMPTY: | 235 | case SDL_JOYSTICK_POWER_EMPTY: |
| 235 | return Common::Input::BatteryLevel::Empty; | 236 | return Common::Input::BatteryLevel::Empty; |
| 236 | case SDL_JOYSTICK_POWER_LOW: | 237 | case SDL_JOYSTICK_POWER_LOW: |
| @@ -378,7 +379,6 @@ void SDLDriver::InitJoystick(int joystick_index) { | |||
| 378 | if (joystick_map.find(guid) == joystick_map.end()) { | 379 | if (joystick_map.find(guid) == joystick_map.end()) { |
| 379 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); | 380 | auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); |
| 380 | PreSetController(joystick->GetPadIdentifier()); | 381 | PreSetController(joystick->GetPadIdentifier()); |
| 381 | SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); | ||
| 382 | joystick->EnableMotion(); | 382 | joystick->EnableMotion(); |
| 383 | joystick_map[guid].emplace_back(std::move(joystick)); | 383 | joystick_map[guid].emplace_back(std::move(joystick)); |
| 384 | return; | 384 | return; |
| @@ -398,7 +398,6 @@ void SDLDriver::InitJoystick(int joystick_index) { | |||
| 398 | const int port = static_cast<int>(joystick_guid_list.size()); | 398 | const int port = static_cast<int>(joystick_guid_list.size()); |
| 399 | auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); | 399 | auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); |
| 400 | PreSetController(joystick->GetPadIdentifier()); | 400 | PreSetController(joystick->GetPadIdentifier()); |
| 401 | SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); | ||
| 402 | joystick->EnableMotion(); | 401 | joystick->EnableMotion(); |
| 403 | joystick_guid_list.emplace_back(std::move(joystick)); | 402 | joystick_guid_list.emplace_back(std::move(joystick)); |
| 404 | } | 403 | } |
| @@ -438,8 +437,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { | |||
| 438 | if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { | 437 | if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { |
| 439 | const PadIdentifier identifier = joystick->GetPadIdentifier(); | 438 | const PadIdentifier identifier = joystick->GetPadIdentifier(); |
| 440 | SetButton(identifier, event.jbutton.button, true); | 439 | SetButton(identifier, event.jbutton.button, true); |
| 441 | // Battery doesn't trigger an event so just update every button press | ||
| 442 | SetBattery(identifier, joystick->GetBatteryLevel()); | ||
| 443 | } | 440 | } |
| 444 | break; | 441 | break; |
| 445 | } | 442 | } |
| @@ -466,6 +463,13 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { | |||
| 466 | } | 463 | } |
| 467 | break; | 464 | break; |
| 468 | } | 465 | } |
| 466 | case SDL_JOYBATTERYUPDATED: { | ||
| 467 | if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) { | ||
| 468 | const PadIdentifier identifier = joystick->GetPadIdentifier(); | ||
| 469 | SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level)); | ||
| 470 | } | ||
| 471 | break; | ||
| 472 | } | ||
| 469 | case SDL_JOYDEVICEREMOVED: | 473 | case SDL_JOYDEVICEREMOVED: |
| 470 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); | 474 | LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); |
| 471 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); | 475 | CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); |
| @@ -483,6 +487,10 @@ void SDLDriver::CloseJoysticks() { | |||
| 483 | } | 487 | } |
| 484 | 488 | ||
| 485 | SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { | 489 | SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { |
| 490 | // Set our application name. Currently passed to DBus by SDL and visible to the user through | ||
| 491 | // their desktop environment. | ||
| 492 | SDL_SetHint(SDL_HINT_APP_NAME, "yuzu"); | ||
| 493 | |||
| 486 | if (!Settings::values.enable_raw_input) { | 494 | if (!Settings::values.enable_raw_input) { |
| 487 | // Disable raw input. When enabled this setting causes SDL to die when a web applet opens | 495 | // Disable raw input. When enabled this setting causes SDL to die when a web applet opens |
| 488 | SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); | 496 | SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); |
| @@ -501,6 +509,9 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en | |||
| 501 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0"); | 509 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0"); |
| 502 | } else { | 510 | } else { |
| 503 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); | 511 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); |
| 512 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED, "0"); | ||
| 513 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0"); | ||
| 514 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1"); | ||
| 504 | } | 515 | } |
| 505 | 516 | ||
| 506 | // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled | 517 | // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled |
| @@ -508,8 +519,11 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en | |||
| 508 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0"); | 519 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0"); |
| 509 | } else { | 520 | } else { |
| 510 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); | 521 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); |
| 522 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); | ||
| 511 | } | 523 | } |
| 512 | 524 | ||
| 525 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1"); | ||
| 526 | |||
| 513 | // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native | 527 | // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native |
| 514 | // driver on Linux. | 528 | // driver on Linux. |
| 515 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); | 529 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); |
| @@ -789,7 +803,9 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p | |||
| 789 | // This list also excludes Screenshot since there's not really a mapping for that | 803 | // This list also excludes Screenshot since there's not really a mapping for that |
| 790 | ButtonBindings switch_to_sdl_button; | 804 | ButtonBindings switch_to_sdl_button; |
| 791 | 805 | ||
| 792 | if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { | 806 | if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO || |
| 807 | SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT || | ||
| 808 | SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) { | ||
| 793 | switch_to_sdl_button = GetNintendoButtonBinding(joystick); | 809 | switch_to_sdl_button = GetNintendoButtonBinding(joystick); |
| 794 | } else { | 810 | } else { |
| 795 | switch_to_sdl_button = GetDefaultButtonBinding(); | 811 | switch_to_sdl_button = GetDefaultButtonBinding(); |
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 2c8c66951..ec984a647 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp | |||
| @@ -72,6 +72,7 @@ DriverResult JoyconDriver::InitializeDevice() { | |||
| 72 | nfc_enabled = false; | 72 | nfc_enabled = false; |
| 73 | passive_enabled = false; | 73 | passive_enabled = false; |
| 74 | irs_enabled = false; | 74 | irs_enabled = false; |
| 75 | input_only_device = false; | ||
| 75 | gyro_sensitivity = Joycon::GyroSensitivity::DPS2000; | 76 | gyro_sensitivity = Joycon::GyroSensitivity::DPS2000; |
| 76 | gyro_performance = Joycon::GyroPerformance::HZ833; | 77 | gyro_performance = Joycon::GyroPerformance::HZ833; |
| 77 | accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8; | 78 | accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8; |
| @@ -86,16 +87,23 @@ DriverResult JoyconDriver::InitializeDevice() { | |||
| 86 | rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle); | 87 | rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle); |
| 87 | 88 | ||
| 88 | // Get fixed joycon info | 89 | // Get fixed joycon info |
| 89 | generic_protocol->GetVersionNumber(version); | 90 | if (generic_protocol->GetVersionNumber(version) != DriverResult::Success) { |
| 90 | generic_protocol->SetLowPowerMode(false); | 91 | // If this command fails the device doesn't accept configuration commands |
| 91 | generic_protocol->GetColor(color); | 92 | input_only_device = true; |
| 92 | if (handle_device_type == ControllerType::Pro) { | ||
| 93 | // Some 3rd party controllers aren't pro controllers | ||
| 94 | generic_protocol->GetControllerType(device_type); | ||
| 95 | } else { | ||
| 96 | device_type = handle_device_type; | ||
| 97 | } | 93 | } |
| 98 | generic_protocol->GetSerialNumber(serial_number); | 94 | |
| 95 | if (!input_only_device) { | ||
| 96 | generic_protocol->SetLowPowerMode(false); | ||
| 97 | generic_protocol->GetColor(color); | ||
| 98 | if (handle_device_type == ControllerType::Pro) { | ||
| 99 | // Some 3rd party controllers aren't pro controllers | ||
| 100 | generic_protocol->GetControllerType(device_type); | ||
| 101 | } else { | ||
| 102 | device_type = handle_device_type; | ||
| 103 | } | ||
| 104 | generic_protocol->GetSerialNumber(serial_number); | ||
| 105 | } | ||
| 106 | |||
| 99 | supported_features = GetSupportedFeatures(); | 107 | supported_features = GetSupportedFeatures(); |
| 100 | 108 | ||
| 101 | // Get Calibration data | 109 | // Get Calibration data |
| @@ -261,6 +269,10 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 261 | generic_protocol->EnableImu(false); | 269 | generic_protocol->EnableImu(false); |
| 262 | } | 270 | } |
| 263 | 271 | ||
| 272 | if (input_only_device) { | ||
| 273 | return DriverResult::NotSupported; | ||
| 274 | } | ||
| 275 | |||
| 264 | if (irs_protocol->IsEnabled()) { | 276 | if (irs_protocol->IsEnabled()) { |
| 265 | irs_protocol->DisableIrs(); | 277 | irs_protocol->DisableIrs(); |
| 266 | } | 278 | } |
| @@ -282,6 +294,7 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 282 | } | 294 | } |
| 283 | irs_protocol->DisableIrs(); | 295 | irs_protocol->DisableIrs(); |
| 284 | LOG_ERROR(Input, "Error enabling IRS"); | 296 | LOG_ERROR(Input, "Error enabling IRS"); |
| 297 | return result; | ||
| 285 | } | 298 | } |
| 286 | 299 | ||
| 287 | if (nfc_enabled && supported_features.nfc) { | 300 | if (nfc_enabled && supported_features.nfc) { |
| @@ -291,6 +304,7 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 291 | } | 304 | } |
| 292 | nfc_protocol->DisableNfc(); | 305 | nfc_protocol->DisableNfc(); |
| 293 | LOG_ERROR(Input, "Error enabling NFC"); | 306 | LOG_ERROR(Input, "Error enabling NFC"); |
| 307 | return result; | ||
| 294 | } | 308 | } |
| 295 | 309 | ||
| 296 | if (hidbus_enabled && supported_features.hidbus) { | 310 | if (hidbus_enabled && supported_features.hidbus) { |
| @@ -305,6 +319,7 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 305 | ring_connected = false; | 319 | ring_connected = false; |
| 306 | ring_protocol->DisableRingCon(); | 320 | ring_protocol->DisableRingCon(); |
| 307 | LOG_ERROR(Input, "Error enabling Ringcon"); | 321 | LOG_ERROR(Input, "Error enabling Ringcon"); |
| 322 | return result; | ||
| 308 | } | 323 | } |
| 309 | 324 | ||
| 310 | if (passive_enabled && supported_features.passive) { | 325 | if (passive_enabled && supported_features.passive) { |
| @@ -333,6 +348,10 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() { | |||
| 333 | .vibration = true, | 348 | .vibration = true, |
| 334 | }; | 349 | }; |
| 335 | 350 | ||
| 351 | if (input_only_device) { | ||
| 352 | return features; | ||
| 353 | } | ||
| 354 | |||
| 336 | if (device_type == ControllerType::Right) { | 355 | if (device_type == ControllerType::Right) { |
| 337 | features.nfc = true; | 356 | features.nfc = true; |
| 338 | features.irs = true; | 357 | features.irs = true; |
| @@ -517,6 +536,11 @@ DriverResult JoyconDriver::StopNfcPolling() { | |||
| 517 | const auto result = nfc_protocol->StopNFCPollingMode(); | 536 | const auto result = nfc_protocol->StopNFCPollingMode(); |
| 518 | disable_input_thread = false; | 537 | disable_input_thread = false; |
| 519 | 538 | ||
| 539 | if (amiibo_detected) { | ||
| 540 | amiibo_detected = false; | ||
| 541 | joycon_poller->UpdateAmiibo({}); | ||
| 542 | } | ||
| 543 | |||
| 520 | return result; | 544 | return result; |
| 521 | } | 545 | } |
| 522 | 546 | ||
diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index bc7025a21..45b32d2f8 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h | |||
| @@ -120,6 +120,7 @@ private: | |||
| 120 | // Hardware configuration | 120 | // Hardware configuration |
| 121 | u8 leds{}; | 121 | u8 leds{}; |
| 122 | ReportMode mode{}; | 122 | ReportMode mode{}; |
| 123 | bool input_only_device{}; | ||
| 123 | bool passive_enabled{}; // Low power mode, Ideal for multiple controllers at the same time | 124 | bool passive_enabled{}; // Low power mode, Ideal for multiple controllers at the same time |
| 124 | bool hidbus_enabled{}; // External device support | 125 | bool hidbus_enabled{}; // External device support |
| 125 | bool irs_enabled{}; // Infrared camera input | 126 | bool irs_enabled{}; // Infrared camera input |
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 51669261a..88f4cec1c 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp | |||
| @@ -73,7 +73,7 @@ DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) { | |||
| 73 | DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, | 73 | DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, |
| 74 | SubCommandResponse& output) { | 74 | SubCommandResponse& output) { |
| 75 | constexpr int timeout_mili = 66; | 75 | constexpr int timeout_mili = 66; |
| 76 | constexpr int MaxTries = 15; | 76 | constexpr int MaxTries = 3; |
| 77 | int tries = 0; | 77 | int tries = 0; |
| 78 | 78 | ||
| 79 | do { | 79 | do { |
| @@ -113,9 +113,7 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const | |||
| 113 | return result; | 113 | return result; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | result = GetSubCommandResponse(sc, output); | 116 | return GetSubCommandResponse(sc, output); |
| 117 | |||
| 118 | return DriverResult::Success; | ||
| 119 | } | 117 | } |
| 120 | 118 | ||
| 121 | DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { | 119 | DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { |
| @@ -158,7 +156,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe | |||
| 158 | 156 | ||
| 159 | DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { | 157 | DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) { |
| 160 | constexpr std::size_t HeaderSize = 5; | 158 | constexpr std::size_t HeaderSize = 5; |
| 161 | constexpr std::size_t MaxTries = 10; | 159 | constexpr std::size_t MaxTries = 5; |
| 162 | std::size_t tries = 0; | 160 | std::size_t tries = 0; |
| 163 | SubCommandResponse response{}; | 161 | SubCommandResponse response{}; |
| 164 | std::array<u8, sizeof(ReadSpiPacket)> buffer{}; | 162 | std::array<u8, sizeof(ReadSpiPacket)> buffer{}; |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index fd4a61a4d..b795c0179 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp | |||
| @@ -461,7 +461,7 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I | |||
| 461 | header += fmt::format("R{},", index); | 461 | header += fmt::format("R{},", index); |
| 462 | } | 462 | } |
| 463 | if (program.local_memory_size > 0) { | 463 | if (program.local_memory_size > 0) { |
| 464 | header += fmt::format("lmem[{}],", program.local_memory_size); | 464 | header += fmt::format("lmem[{}],", Common::DivCeil(program.local_memory_size, 4U)); |
| 465 | } | 465 | } |
| 466 | if (program.info.uses_fswzadd) { | 466 | if (program.info.uses_fswzadd) { |
| 467 | header += "FSWZA[4],FSWZB[4],"; | 467 | header += "FSWZA[4],FSWZB[4],"; |
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 5a4195217..70292686f 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -424,6 +424,10 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 424 | info.used_constant_buffer_types |= IR::Type::U32 | IR::Type::U32x2; | 424 | info.used_constant_buffer_types |= IR::Type::U32 | IR::Type::U32x2; |
| 425 | info.used_storage_buffer_types |= IR::Type::U32 | IR::Type::U32x2 | IR::Type::U32x4; | 425 | info.used_storage_buffer_types |= IR::Type::U32 | IR::Type::U32x2 | IR::Type::U32x4; |
| 426 | break; | 426 | break; |
| 427 | case IR::Opcode::LoadLocal: | ||
| 428 | case IR::Opcode::WriteLocal: | ||
| 429 | info.uses_local_memory = true; | ||
| 430 | break; | ||
| 427 | default: | 431 | default: |
| 428 | break; | 432 | break; |
| 429 | } | 433 | } |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index d308db942..b4b4afd37 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -172,6 +172,7 @@ struct Info { | |||
| 172 | bool stores_indexed_attributes{}; | 172 | bool stores_indexed_attributes{}; |
| 173 | 173 | ||
| 174 | bool stores_global_memory{}; | 174 | bool stores_global_memory{}; |
| 175 | bool uses_local_memory{}; | ||
| 175 | 176 | ||
| 176 | bool uses_fp16{}; | 177 | bool uses_fp16{}; |
| 177 | bool uses_fp64{}; | 178 | bool uses_fp64{}; |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index bf6439530..e9e6f278d 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -291,7 +291,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS}) | |||
| 291 | 291 | ||
| 292 | add_dependencies(video_core host_shaders) | 292 | add_dependencies(video_core host_shaders) |
| 293 | target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) | 293 | target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) |
| 294 | target_link_libraries(video_core PRIVATE sirit Vulkan::Headers) | 294 | target_link_libraries(video_core PRIVATE sirit Vulkan::Headers vma) |
| 295 | 295 | ||
| 296 | if (ENABLE_NSIGHT_AFTERMATH) | 296 | if (ENABLE_NSIGHT_AFTERMATH) |
| 297 | if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) | 297 | if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) |
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 2442c3c29..e61d9af80 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt | |||
| @@ -33,6 +33,7 @@ set(SHADER_FILES | |||
| 33 | opengl_fidelityfx_fsr.frag | 33 | opengl_fidelityfx_fsr.frag |
| 34 | opengl_fidelityfx_fsr_easu.frag | 34 | opengl_fidelityfx_fsr_easu.frag |
| 35 | opengl_fidelityfx_fsr_rcas.frag | 35 | opengl_fidelityfx_fsr_rcas.frag |
| 36 | opengl_lmem_warmup.comp | ||
| 36 | opengl_present.frag | 37 | opengl_present.frag |
| 37 | opengl_present.vert | 38 | opengl_present.vert |
| 38 | opengl_present_scaleforce.frag | 39 | opengl_present_scaleforce.frag |
diff --git a/src/video_core/host_shaders/opengl_lmem_warmup.comp b/src/video_core/host_shaders/opengl_lmem_warmup.comp new file mode 100644 index 000000000..518268477 --- /dev/null +++ b/src/video_core/host_shaders/opengl_lmem_warmup.comp | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | // This shader is a workaround for a quirk in NVIDIA OpenGL drivers | ||
| 5 | // Shaders using local memory see a great performance benefit if a shader that was dispatched | ||
| 6 | // before it had more local memory allocated. | ||
| 7 | // This shader allocates the maximum local memory allowed on NVIDIA drivers to ensure that | ||
| 8 | // subsequent shaders see the performance boost. | ||
| 9 | |||
| 10 | // NOTE: This shader does no actual meaningful work and returns immediately, | ||
| 11 | // it is simply a means to have the driver expect a shader using lots of local memory. | ||
| 12 | |||
| 13 | #version 450 | ||
| 14 | |||
| 15 | layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; | ||
| 16 | |||
| 17 | layout(location = 0) uniform uint uniform_data; | ||
| 18 | |||
| 19 | layout(binding = 0, rgba8) uniform writeonly restrict image2DArray dest_image; | ||
| 20 | |||
| 21 | #define MAX_LMEM_SIZE 4080 // Size chosen to avoid errors in Nvidia's GLSL compiler | ||
| 22 | #define NUM_LMEM_CONSTANTS 1 | ||
| 23 | #define ARRAY_SIZE MAX_LMEM_SIZE - NUM_LMEM_CONSTANTS | ||
| 24 | |||
| 25 | uint lmem_0[ARRAY_SIZE]; | ||
| 26 | const uvec4 constant_values[NUM_LMEM_CONSTANTS] = uvec4[](uvec4(0)); | ||
| 27 | |||
| 28 | void main() { | ||
| 29 | const uint global_id = gl_GlobalInvocationID.x; | ||
| 30 | if (global_id <= 128) { | ||
| 31 | // Since the shader is called with a dispatch of 1x1x1 | ||
| 32 | // This should always be the case, and this shader will not actually execute | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | for (uint t = 0; t < uniform_data; t++) { | ||
| 36 | const uint offset = (t * uniform_data); | ||
| 37 | lmem_0[offset] = t; | ||
| 38 | } | ||
| 39 | const uint offset = (gl_GlobalInvocationID.y * uniform_data + gl_GlobalInvocationID.x); | ||
| 40 | const uint value = lmem_0[offset]; | ||
| 41 | const uint const_value = constant_values[offset / 4][offset % 4]; | ||
| 42 | const uvec4 color = uvec4(value + const_value); | ||
| 43 | |||
| 44 | // A "side-effect" is needed so the variables don't get optimized out, | ||
| 45 | // but this should never execute so there should be no clobbering of previously bound state. | ||
| 46 | imageStore(dest_image, ivec3(gl_GlobalInvocationID), color); | ||
| 47 | } | ||
diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp index 3151c0db8..f9ca55c36 100644 --- a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp | |||
| @@ -63,6 +63,7 @@ ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cac | |||
| 63 | writes_global_memory = !use_storage_buffers && | 63 | writes_global_memory = !use_storage_buffers && |
| 64 | std::ranges::any_of(info.storage_buffers_descriptors, | 64 | std::ranges::any_of(info.storage_buffers_descriptors, |
| 65 | [](const auto& desc) { return desc.is_written; }); | 65 | [](const auto& desc) { return desc.is_written; }); |
| 66 | uses_local_memory = info.uses_local_memory; | ||
| 66 | if (force_context_flush) { | 67 | if (force_context_flush) { |
| 67 | std::scoped_lock lock{built_mutex}; | 68 | std::scoped_lock lock{built_mutex}; |
| 68 | built_fence.Create(); | 69 | built_fence.Create(); |
diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.h b/src/video_core/renderer_opengl/gl_compute_pipeline.h index 9bcc72b59..c26b4fa5e 100644 --- a/src/video_core/renderer_opengl/gl_compute_pipeline.h +++ b/src/video_core/renderer_opengl/gl_compute_pipeline.h | |||
| @@ -59,6 +59,10 @@ public: | |||
| 59 | return writes_global_memory; | 59 | return writes_global_memory; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | [[nodiscard]] bool UsesLocalMemory() const noexcept { | ||
| 63 | return uses_local_memory; | ||
| 64 | } | ||
| 65 | |||
| 62 | void SetEngine(Tegra::Engines::KeplerCompute* kepler_compute_, | 66 | void SetEngine(Tegra::Engines::KeplerCompute* kepler_compute_, |
| 63 | Tegra::MemoryManager* gpu_memory_) { | 67 | Tegra::MemoryManager* gpu_memory_) { |
| 64 | kepler_compute = kepler_compute_; | 68 | kepler_compute = kepler_compute_; |
| @@ -84,6 +88,7 @@ private: | |||
| 84 | 88 | ||
| 85 | bool use_storage_buffers{}; | 89 | bool use_storage_buffers{}; |
| 86 | bool writes_global_memory{}; | 90 | bool writes_global_memory{}; |
| 91 | bool uses_local_memory{}; | ||
| 87 | 92 | ||
| 88 | std::mutex built_mutex; | 93 | std::mutex built_mutex; |
| 89 | std::condition_variable built_condvar; | 94 | std::condition_variable built_condvar; |
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 03d234f2f..33e63c17d 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -194,6 +194,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) { | |||
| 194 | has_bool_ref_bug = true; | 194 | has_bool_ref_bug = true; |
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| 197 | has_lmem_perf_bug = is_nvidia; | ||
| 197 | 198 | ||
| 198 | strict_context_required = emu_window.StrictContextRequired(); | 199 | strict_context_required = emu_window.StrictContextRequired(); |
| 199 | // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation. | 200 | // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation. |
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index ad27264e5..a5a6bbbba 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h | |||
| @@ -192,6 +192,10 @@ public: | |||
| 192 | return supports_conditional_barriers; | 192 | return supports_conditional_barriers; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | bool HasLmemPerfBug() const { | ||
| 196 | return has_lmem_perf_bug; | ||
| 197 | } | ||
| 198 | |||
| 195 | private: | 199 | private: |
| 196 | static bool TestVariableAoffi(); | 200 | static bool TestVariableAoffi(); |
| 197 | static bool TestPreciseBug(); | 201 | static bool TestPreciseBug(); |
| @@ -238,6 +242,7 @@ private: | |||
| 238 | bool can_report_memory{}; | 242 | bool can_report_memory{}; |
| 239 | bool strict_context_required{}; | 243 | bool strict_context_required{}; |
| 240 | bool supports_conditional_barriers{}; | 244 | bool supports_conditional_barriers{}; |
| 245 | bool has_lmem_perf_bug{}; | ||
| 241 | 246 | ||
| 242 | std::string vendor_name; | 247 | std::string vendor_name; |
| 243 | }; | 248 | }; |
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp index c58f760b8..23a48c6fe 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp | |||
| @@ -215,6 +215,7 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c | |||
| 215 | 215 | ||
| 216 | writes_global_memory |= std::ranges::any_of( | 216 | writes_global_memory |= std::ranges::any_of( |
| 217 | info.storage_buffers_descriptors, [](const auto& desc) { return desc.is_written; }); | 217 | info.storage_buffers_descriptors, [](const auto& desc) { return desc.is_written; }); |
| 218 | uses_local_memory |= info.uses_local_memory; | ||
| 218 | } | 219 | } |
| 219 | ASSERT(num_textures <= MAX_TEXTURES); | 220 | ASSERT(num_textures <= MAX_TEXTURES); |
| 220 | ASSERT(num_images <= MAX_IMAGES); | 221 | ASSERT(num_images <= MAX_IMAGES); |
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.h b/src/video_core/renderer_opengl/gl_graphics_pipeline.h index 7bab3be0a..7b3d7eae8 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.h +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.h | |||
| @@ -98,6 +98,10 @@ public: | |||
| 98 | return writes_global_memory; | 98 | return writes_global_memory; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | [[nodiscard]] bool UsesLocalMemory() const noexcept { | ||
| 102 | return uses_local_memory; | ||
| 103 | } | ||
| 104 | |||
| 101 | [[nodiscard]] bool IsBuilt() noexcept; | 105 | [[nodiscard]] bool IsBuilt() noexcept; |
| 102 | 106 | ||
| 103 | template <typename Spec> | 107 | template <typename Spec> |
| @@ -146,6 +150,7 @@ private: | |||
| 146 | 150 | ||
| 147 | bool use_storage_buffers{}; | 151 | bool use_storage_buffers{}; |
| 148 | bool writes_global_memory{}; | 152 | bool writes_global_memory{}; |
| 153 | bool uses_local_memory{}; | ||
| 149 | 154 | ||
| 150 | static constexpr std::size_t XFB_ENTRY_STRIDE = 3; | 155 | static constexpr std::size_t XFB_ENTRY_STRIDE = 3; |
| 151 | GLsizei num_xfb_attribs{}; | 156 | GLsizei num_xfb_attribs{}; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index fc711c44a..edf527f2d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -222,6 +222,9 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { | |||
| 222 | gpu.TickWork(); | 222 | gpu.TickWork(); |
| 223 | 223 | ||
| 224 | std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; | 224 | std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; |
| 225 | if (pipeline->UsesLocalMemory()) { | ||
| 226 | program_manager.LocalMemoryWarmup(); | ||
| 227 | } | ||
| 225 | pipeline->SetEngine(maxwell3d, gpu_memory); | 228 | pipeline->SetEngine(maxwell3d, gpu_memory); |
| 226 | pipeline->Configure(is_indexed); | 229 | pipeline->Configure(is_indexed); |
| 227 | 230 | ||
| @@ -371,6 +374,9 @@ void RasterizerOpenGL::DispatchCompute() { | |||
| 371 | if (!pipeline) { | 374 | if (!pipeline) { |
| 372 | return; | 375 | return; |
| 373 | } | 376 | } |
| 377 | if (pipeline->UsesLocalMemory()) { | ||
| 378 | program_manager.LocalMemoryWarmup(); | ||
| 379 | } | ||
| 374 | pipeline->SetEngine(kepler_compute, gpu_memory); | 380 | pipeline->SetEngine(kepler_compute, gpu_memory); |
| 375 | pipeline->Configure(); | 381 | pipeline->Configure(); |
| 376 | const auto& qmd{kepler_compute->launch_description}; | 382 | const auto& qmd{kepler_compute->launch_description}; |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 98841ae65..03d4b9d06 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp | |||
| @@ -3,7 +3,9 @@ | |||
| 3 | 3 | ||
| 4 | #include <glad/glad.h> | 4 | #include <glad/glad.h> |
| 5 | 5 | ||
| 6 | #include "video_core/host_shaders/opengl_lmem_warmup_comp.h" | ||
| 6 | #include "video_core/renderer_opengl/gl_shader_manager.h" | 7 | #include "video_core/renderer_opengl/gl_shader_manager.h" |
| 8 | #include "video_core/renderer_opengl/gl_shader_util.h" | ||
| 7 | 9 | ||
| 8 | namespace OpenGL { | 10 | namespace OpenGL { |
| 9 | 11 | ||
| @@ -17,6 +19,10 @@ ProgramManager::ProgramManager(const Device& device) { | |||
| 17 | if (device.UseAssemblyShaders()) { | 19 | if (device.UseAssemblyShaders()) { |
| 18 | glEnable(GL_COMPUTE_PROGRAM_NV); | 20 | glEnable(GL_COMPUTE_PROGRAM_NV); |
| 19 | } | 21 | } |
| 22 | if (device.HasLmemPerfBug()) { | ||
| 23 | lmem_warmup_program = | ||
| 24 | CreateProgram(HostShaders::OPENGL_LMEM_WARMUP_COMP, GL_COMPUTE_SHADER); | ||
| 25 | } | ||
| 20 | } | 26 | } |
| 21 | 27 | ||
| 22 | void ProgramManager::BindComputeProgram(GLuint program) { | 28 | void ProgramManager::BindComputeProgram(GLuint program) { |
| @@ -98,6 +104,13 @@ void ProgramManager::BindAssemblyPrograms(std::span<const OGLAssemblyProgram, NU | |||
| 98 | 104 | ||
| 99 | void ProgramManager::RestoreGuestCompute() {} | 105 | void ProgramManager::RestoreGuestCompute() {} |
| 100 | 106 | ||
| 107 | void ProgramManager::LocalMemoryWarmup() { | ||
| 108 | if (lmem_warmup_program.handle != 0) { | ||
| 109 | BindComputeProgram(lmem_warmup_program.handle); | ||
| 110 | glDispatchCompute(1, 1, 1); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 101 | void ProgramManager::BindPipeline() { | 114 | void ProgramManager::BindPipeline() { |
| 102 | if (!is_pipeline_bound) { | 115 | if (!is_pipeline_bound) { |
| 103 | is_pipeline_bound = true; | 116 | is_pipeline_bound = true; |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 07ffab77f..852d8c88e 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h | |||
| @@ -30,6 +30,8 @@ public: | |||
| 30 | 30 | ||
| 31 | void RestoreGuestCompute(); | 31 | void RestoreGuestCompute(); |
| 32 | 32 | ||
| 33 | void LocalMemoryWarmup(); | ||
| 34 | |||
| 33 | private: | 35 | private: |
| 34 | void BindPipeline(); | 36 | void BindPipeline(); |
| 35 | 37 | ||
| @@ -44,6 +46,7 @@ private: | |||
| 44 | u32 current_stage_mask = 0; | 46 | u32 current_stage_mask = 0; |
| 45 | std::array<GLuint, NUM_STAGES> current_programs{}; | 47 | std::array<GLuint, NUM_STAGES> current_programs{}; |
| 46 | GLuint current_assembly_compute_program = 0; | 48 | GLuint current_assembly_compute_program = 0; |
| 49 | OGLProgram lmem_warmup_program; | ||
| 47 | }; | 50 | }; |
| 48 | 51 | ||
| 49 | } // namespace OpenGL | 52 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 77128c6e2..ddf28ca28 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -89,8 +89,8 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, | |||
| 89 | Settings::values.renderer_debug.GetValue())), | 89 | Settings::values.renderer_debug.GetValue())), |
| 90 | debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), | 90 | debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), |
| 91 | surface(CreateSurface(instance, render_window.GetWindowInfo())), | 91 | surface(CreateSurface(instance, render_window.GetWindowInfo())), |
| 92 | device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), | 92 | device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), |
| 93 | state_tracker(), scheduler(device, state_tracker), | 93 | scheduler(device, state_tracker), |
| 94 | swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, | 94 | swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, |
| 95 | render_window.GetFramebufferLayout().height, false), | 95 | render_window.GetFramebufferLayout().height, false), |
| 96 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, | 96 | present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, |
| @@ -173,7 +173,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 173 | return; | 173 | return; |
| 174 | } | 174 | } |
| 175 | const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; | 175 | const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; |
| 176 | vk::Image staging_image = device.GetLogical().CreateImage(VkImageCreateInfo{ | 176 | vk::Image staging_image = memory_allocator.CreateImage(VkImageCreateInfo{ |
| 177 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 177 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 178 | .pNext = nullptr, | 178 | .pNext = nullptr, |
| 179 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, | 179 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, |
| @@ -196,7 +196,6 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 196 | .pQueueFamilyIndices = nullptr, | 196 | .pQueueFamilyIndices = nullptr, |
| 197 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 197 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 198 | }); | 198 | }); |
| 199 | const auto image_commit = memory_allocator.Commit(staging_image, MemoryUsage::DeviceLocal); | ||
| 200 | 199 | ||
| 201 | const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 200 | const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 202 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 201 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| @@ -234,8 +233,8 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 234 | .queueFamilyIndexCount = 0, | 233 | .queueFamilyIndexCount = 0, |
| 235 | .pQueueFamilyIndices = nullptr, | 234 | .pQueueFamilyIndices = nullptr, |
| 236 | }; | 235 | }; |
| 237 | const vk::Buffer dst_buffer = device.GetLogical().CreateBuffer(dst_buffer_info); | 236 | const vk::Buffer dst_buffer = |
| 238 | MemoryCommit dst_buffer_memory = memory_allocator.Commit(dst_buffer, MemoryUsage::Download); | 237 | memory_allocator.CreateBuffer(dst_buffer_info, MemoryUsage::Download); |
| 239 | 238 | ||
| 240 | scheduler.RequestOutsideRenderPassOperationContext(); | 239 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 241 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { | 240 | scheduler.Record([&](vk::CommandBuffer cmdbuf) { |
| @@ -309,8 +308,9 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr | |||
| 309 | scheduler.Finish(); | 308 | scheduler.Finish(); |
| 310 | 309 | ||
| 311 | // Copy backing image data to the QImage screenshot buffer | 310 | // Copy backing image data to the QImage screenshot buffer |
| 312 | const auto dst_memory_map = dst_buffer_memory.Map(); | 311 | dst_buffer.Invalidate(); |
| 313 | std::memcpy(renderer_settings.screenshot_bits, dst_memory_map.data(), dst_memory_map.size()); | 312 | std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(), |
| 313 | dst_buffer.Mapped().size()); | ||
| 314 | renderer_settings.screenshot_complete_callback(false); | 314 | renderer_settings.screenshot_complete_callback(false); |
| 315 | renderer_settings.screenshot_requested = false; | 315 | renderer_settings.screenshot_requested = false; |
| 316 | } | 316 | } |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index acb143fc7..ad3b29f0e 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -162,7 +162,7 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, | |||
| 162 | SetUniformData(data, layout); | 162 | SetUniformData(data, layout); |
| 163 | SetVertexData(data, framebuffer, layout); | 163 | SetVertexData(data, framebuffer, layout); |
| 164 | 164 | ||
| 165 | const std::span<u8> mapped_span = buffer_commit.Map(); | 165 | const std::span<u8> mapped_span = buffer.Mapped(); |
| 166 | std::memcpy(mapped_span.data(), &data, sizeof(data)); | 166 | std::memcpy(mapped_span.data(), &data, sizeof(data)); |
| 167 | 167 | ||
| 168 | if (!use_accelerated) { | 168 | if (!use_accelerated) { |
| @@ -1071,14 +1071,9 @@ void BlitScreen::ReleaseRawImages() { | |||
| 1071 | scheduler.Wait(tick); | 1071 | scheduler.Wait(tick); |
| 1072 | } | 1072 | } |
| 1073 | raw_images.clear(); | 1073 | raw_images.clear(); |
| 1074 | raw_buffer_commits.clear(); | ||
| 1075 | |||
| 1076 | aa_image_view.reset(); | 1074 | aa_image_view.reset(); |
| 1077 | aa_image.reset(); | 1075 | aa_image.reset(); |
| 1078 | aa_commit = MemoryCommit{}; | ||
| 1079 | |||
| 1080 | buffer.reset(); | 1076 | buffer.reset(); |
| 1081 | buffer_commit = MemoryCommit{}; | ||
| 1082 | } | 1077 | } |
| 1083 | 1078 | ||
| 1084 | void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { | 1079 | void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { |
| @@ -1094,20 +1089,18 @@ void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer | |||
| 1094 | .pQueueFamilyIndices = nullptr, | 1089 | .pQueueFamilyIndices = nullptr, |
| 1095 | }; | 1090 | }; |
| 1096 | 1091 | ||
| 1097 | buffer = device.GetLogical().CreateBuffer(ci); | 1092 | buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload); |
| 1098 | buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload); | ||
| 1099 | } | 1093 | } |
| 1100 | 1094 | ||
| 1101 | void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | 1095 | void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { |
| 1102 | raw_images.resize(image_count); | 1096 | raw_images.resize(image_count); |
| 1103 | raw_image_views.resize(image_count); | 1097 | raw_image_views.resize(image_count); |
| 1104 | raw_buffer_commits.resize(image_count); | ||
| 1105 | 1098 | ||
| 1106 | const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1, | 1099 | const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1, |
| 1107 | u32 down_shift = 0) { | 1100 | u32 down_shift = 0) { |
| 1108 | u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 1101 | u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
| 1109 | : VK_IMAGE_USAGE_TRANSFER_DST_BIT; | 1102 | : VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
| 1110 | return device.GetLogical().CreateImage(VkImageCreateInfo{ | 1103 | return memory_allocator.CreateImage(VkImageCreateInfo{ |
| 1111 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 1104 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 1112 | .pNext = nullptr, | 1105 | .pNext = nullptr, |
| 1113 | .flags = 0, | 1106 | .flags = 0, |
| @@ -1130,9 +1123,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1130 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 1123 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 1131 | }); | 1124 | }); |
| 1132 | }; | 1125 | }; |
| 1133 | const auto create_commit = [&](vk::Image& image) { | ||
| 1134 | return memory_allocator.Commit(image, MemoryUsage::DeviceLocal); | ||
| 1135 | }; | ||
| 1136 | const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) { | 1126 | const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) { |
| 1137 | return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 1127 | return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 1138 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 1128 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| @@ -1161,7 +1151,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1161 | 1151 | ||
| 1162 | for (size_t i = 0; i < image_count; ++i) { | 1152 | for (size_t i = 0; i < image_count; ++i) { |
| 1163 | raw_images[i] = create_image(); | 1153 | raw_images[i] = create_image(); |
| 1164 | raw_buffer_commits[i] = create_commit(raw_images[i]); | ||
| 1165 | raw_image_views[i] = create_image_view(raw_images[i]); | 1154 | raw_image_views[i] = create_image_view(raw_images[i]); |
| 1166 | } | 1155 | } |
| 1167 | 1156 | ||
| @@ -1169,7 +1158,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1169 | const u32 up_scale = Settings::values.resolution_info.up_scale; | 1158 | const u32 up_scale = Settings::values.resolution_info.up_scale; |
| 1170 | const u32 down_shift = Settings::values.resolution_info.down_shift; | 1159 | const u32 down_shift = Settings::values.resolution_info.down_shift; |
| 1171 | aa_image = create_image(true, up_scale, down_shift); | 1160 | aa_image = create_image(true, up_scale, down_shift); |
| 1172 | aa_commit = create_commit(aa_image); | ||
| 1173 | aa_image_view = create_image_view(aa_image, true); | 1161 | aa_image_view = create_image_view(aa_image, true); |
| 1174 | VkExtent2D size{ | 1162 | VkExtent2D size{ |
| 1175 | .width = (up_scale * framebuffer.width) >> down_shift, | 1163 | .width = (up_scale * framebuffer.width) >> down_shift, |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 68ec20253..8365b5668 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h | |||
| @@ -142,13 +142,11 @@ private: | |||
| 142 | vk::Sampler sampler; | 142 | vk::Sampler sampler; |
| 143 | 143 | ||
| 144 | vk::Buffer buffer; | 144 | vk::Buffer buffer; |
| 145 | MemoryCommit buffer_commit; | ||
| 146 | 145 | ||
| 147 | std::vector<u64> resource_ticks; | 146 | std::vector<u64> resource_ticks; |
| 148 | 147 | ||
| 149 | std::vector<vk::Image> raw_images; | 148 | std::vector<vk::Image> raw_images; |
| 150 | std::vector<vk::ImageView> raw_image_views; | 149 | std::vector<vk::ImageView> raw_image_views; |
| 151 | std::vector<MemoryCommit> raw_buffer_commits; | ||
| 152 | 150 | ||
| 153 | vk::DescriptorPool aa_descriptor_pool; | 151 | vk::DescriptorPool aa_descriptor_pool; |
| 154 | vk::DescriptorSetLayout aa_descriptor_set_layout; | 152 | vk::DescriptorSetLayout aa_descriptor_set_layout; |
| @@ -159,7 +157,6 @@ private: | |||
| 159 | vk::DescriptorSets aa_descriptor_sets; | 157 | vk::DescriptorSets aa_descriptor_sets; |
| 160 | vk::Image aa_image; | 158 | vk::Image aa_image; |
| 161 | vk::ImageView aa_image_view; | 159 | vk::ImageView aa_image_view; |
| 162 | MemoryCommit aa_commit; | ||
| 163 | 160 | ||
| 164 | u32 raw_width = 0; | 161 | u32 raw_width = 0; |
| 165 | u32 raw_height = 0; | 162 | u32 raw_height = 0; |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index f47301ad5..660f7c9ff 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -50,7 +50,7 @@ size_t BytesPerIndex(VkIndexType index_type) { | |||
| 50 | } | 50 | } |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | vk::Buffer CreateBuffer(const Device& device, u64 size) { | 53 | vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allocator, u64 size) { |
| 54 | VkBufferUsageFlags flags = | 54 | VkBufferUsageFlags flags = |
| 55 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | 55 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 56 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | | 56 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | |
| @@ -60,7 +60,7 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) { | |||
| 60 | if (device.IsExtTransformFeedbackSupported()) { | 60 | if (device.IsExtTransformFeedbackSupported()) { |
| 61 | flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; | 61 | flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; |
| 62 | } | 62 | } |
| 63 | return device.GetLogical().CreateBuffer({ | 63 | const VkBufferCreateInfo buffer_ci = { |
| 64 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 64 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 65 | .pNext = nullptr, | 65 | .pNext = nullptr, |
| 66 | .flags = 0, | 66 | .flags = 0, |
| @@ -69,7 +69,8 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) { | |||
| 69 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 69 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 70 | .queueFamilyIndexCount = 0, | 70 | .queueFamilyIndexCount = 0, |
| 71 | .pQueueFamilyIndices = nullptr, | 71 | .pQueueFamilyIndices = nullptr, |
| 72 | }); | 72 | }; |
| 73 | return memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); | ||
| 73 | } | 74 | } |
| 74 | } // Anonymous namespace | 75 | } // Anonymous namespace |
| 75 | 76 | ||
| @@ -79,8 +80,8 @@ Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params) | |||
| 79 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, | 80 | Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, |
| 80 | VAddr cpu_addr_, u64 size_bytes_) | 81 | VAddr cpu_addr_, u64 size_bytes_) |
| 81 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_), | 82 | : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_), |
| 82 | device{&runtime.device}, buffer{CreateBuffer(*device, SizeBytes())}, | 83 | device{&runtime.device}, buffer{ |
| 83 | commit{runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal)} { | 84 | CreateBuffer(*device, runtime.memory_allocator, SizeBytes())} { |
| 84 | if (runtime.device.HasDebuggingToolAttached()) { | 85 | if (runtime.device.HasDebuggingToolAttached()) { |
| 85 | buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); | 86 | buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str()); |
| 86 | } | 87 | } |
| @@ -138,7 +139,7 @@ public: | |||
| 138 | const u32 num_first_offset_copies = 4; | 139 | const u32 num_first_offset_copies = 4; |
| 139 | const size_t bytes_per_index = BytesPerIndex(index_type); | 140 | const size_t bytes_per_index = BytesPerIndex(index_type); |
| 140 | const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies; | 141 | const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies; |
| 141 | buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ | 142 | const VkBufferCreateInfo buffer_ci = { |
| 142 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 143 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 143 | .pNext = nullptr, | 144 | .pNext = nullptr, |
| 144 | .flags = 0, | 145 | .flags = 0, |
| @@ -147,14 +148,21 @@ public: | |||
| 147 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 148 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 148 | .queueFamilyIndexCount = 0, | 149 | .queueFamilyIndexCount = 0, |
| 149 | .pQueueFamilyIndices = nullptr, | 150 | .pQueueFamilyIndices = nullptr, |
| 150 | }); | 151 | }; |
| 152 | buffer = memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); | ||
| 151 | if (device.HasDebuggingToolAttached()) { | 153 | if (device.HasDebuggingToolAttached()) { |
| 152 | buffer.SetObjectNameEXT("Quad LUT"); | 154 | buffer.SetObjectNameEXT("Quad LUT"); |
| 153 | } | 155 | } |
| 154 | memory_commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); | ||
| 155 | 156 | ||
| 156 | const StagingBufferRef staging = staging_pool.Request(size_bytes, MemoryUsage::Upload); | 157 | const bool host_visible = buffer.IsHostVisible(); |
| 157 | u8* staging_data = staging.mapped_span.data(); | 158 | const StagingBufferRef staging = [&] { |
| 159 | if (host_visible) { | ||
| 160 | return StagingBufferRef{}; | ||
| 161 | } | ||
| 162 | return staging_pool.Request(size_bytes, MemoryUsage::Upload); | ||
| 163 | }(); | ||
| 164 | |||
| 165 | u8* staging_data = host_visible ? buffer.Mapped().data() : staging.mapped_span.data(); | ||
| 158 | const size_t quad_size = bytes_per_index * 6; | 166 | const size_t quad_size = bytes_per_index * 6; |
| 159 | 167 | ||
| 160 | for (u32 first = 0; first < num_first_offset_copies; ++first) { | 168 | for (u32 first = 0; first < num_first_offset_copies; ++first) { |
| @@ -164,29 +172,33 @@ public: | |||
| 164 | } | 172 | } |
| 165 | } | 173 | } |
| 166 | 174 | ||
| 167 | scheduler.RequestOutsideRenderPassOperationContext(); | 175 | if (!host_visible) { |
| 168 | scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset, | 176 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 169 | dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) { | 177 | scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset, |
| 170 | const VkBufferCopy copy{ | 178 | dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) { |
| 171 | .srcOffset = src_offset, | 179 | const VkBufferCopy copy{ |
| 172 | .dstOffset = 0, | 180 | .srcOffset = src_offset, |
| 173 | .size = size_bytes, | 181 | .dstOffset = 0, |
| 174 | }; | 182 | .size = size_bytes, |
| 175 | const VkBufferMemoryBarrier write_barrier{ | 183 | }; |
| 176 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | 184 | const VkBufferMemoryBarrier write_barrier{ |
| 177 | .pNext = nullptr, | 185 | .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, |
| 178 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | 186 | .pNext = nullptr, |
| 179 | .dstAccessMask = VK_ACCESS_INDEX_READ_BIT, | 187 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, |
| 180 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 188 | .dstAccessMask = VK_ACCESS_INDEX_READ_BIT, |
| 181 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | 189 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 182 | .buffer = dst_buffer, | 190 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, |
| 183 | .offset = 0, | 191 | .buffer = dst_buffer, |
| 184 | .size = size_bytes, | 192 | .offset = 0, |
| 185 | }; | 193 | .size = size_bytes, |
| 186 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); | 194 | }; |
| 187 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, | 195 | cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy); |
| 188 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier); | 196 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, |
| 189 | }); | 197 | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier); |
| 198 | }); | ||
| 199 | } else { | ||
| 200 | buffer.Flush(); | ||
| 201 | } | ||
| 190 | } | 202 | } |
| 191 | 203 | ||
| 192 | void BindBuffer(u32 first) { | 204 | void BindBuffer(u32 first) { |
| @@ -587,11 +599,10 @@ void BufferCacheRuntime::ReserveNullBuffer() { | |||
| 587 | create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; | 599 | create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; |
| 588 | } | 600 | } |
| 589 | create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; | 601 | create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; |
| 590 | null_buffer = device.GetLogical().CreateBuffer(create_info); | 602 | null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal); |
| 591 | if (device.HasDebuggingToolAttached()) { | 603 | if (device.HasDebuggingToolAttached()) { |
| 592 | null_buffer.SetObjectNameEXT("Null buffer"); | 604 | null_buffer.SetObjectNameEXT("Null buffer"); |
| 593 | } | 605 | } |
| 594 | null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal); | ||
| 595 | 606 | ||
| 596 | scheduler.RequestOutsideRenderPassOperationContext(); | 607 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 597 | scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) { | 608 | scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) { |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index cdeef8846..95446c732 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -48,7 +48,6 @@ private: | |||
| 48 | 48 | ||
| 49 | const Device* device{}; | 49 | const Device* device{}; |
| 50 | vk::Buffer buffer; | 50 | vk::Buffer buffer; |
| 51 | MemoryCommit commit; | ||
| 52 | std::vector<BufferView> views; | 51 | std::vector<BufferView> views; |
| 53 | }; | 52 | }; |
| 54 | 53 | ||
| @@ -142,7 +141,6 @@ private: | |||
| 142 | std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer; | 141 | std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer; |
| 143 | 142 | ||
| 144 | vk::Buffer null_buffer; | 143 | vk::Buffer null_buffer; |
| 145 | MemoryCommit null_buffer_commit; | ||
| 146 | 144 | ||
| 147 | std::unique_ptr<Uint8Pass> uint8_pass; | 145 | std::unique_ptr<Uint8Pass> uint8_pass; |
| 148 | QuadIndexedPass quad_index_pass; | 146 | QuadIndexedPass quad_index_pass; |
diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp index df972cd54..9bcdca2fb 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.cpp +++ b/src/video_core/renderer_vulkan/vk_fsr.cpp | |||
| @@ -205,10 +205,9 @@ void FSR::CreateDescriptorSets() { | |||
| 205 | void FSR::CreateImages() { | 205 | void FSR::CreateImages() { |
| 206 | images.resize(image_count * 2); | 206 | images.resize(image_count * 2); |
| 207 | image_views.resize(image_count * 2); | 207 | image_views.resize(image_count * 2); |
| 208 | buffer_commits.resize(image_count * 2); | ||
| 209 | 208 | ||
| 210 | for (size_t i = 0; i < image_count * 2; ++i) { | 209 | for (size_t i = 0; i < image_count * 2; ++i) { |
| 211 | images[i] = device.GetLogical().CreateImage(VkImageCreateInfo{ | 210 | images[i] = memory_allocator.CreateImage(VkImageCreateInfo{ |
| 212 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 211 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 213 | .pNext = nullptr, | 212 | .pNext = nullptr, |
| 214 | .flags = 0, | 213 | .flags = 0, |
| @@ -231,7 +230,6 @@ void FSR::CreateImages() { | |||
| 231 | .pQueueFamilyIndices = nullptr, | 230 | .pQueueFamilyIndices = nullptr, |
| 232 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 231 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 233 | }); | 232 | }); |
| 234 | buffer_commits[i] = memory_allocator.Commit(images[i], MemoryUsage::DeviceLocal); | ||
| 235 | image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 233 | image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 236 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 234 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 237 | .pNext = nullptr, | 235 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_fsr.h b/src/video_core/renderer_vulkan/vk_fsr.h index 5d872861f..8bb9fc23a 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.h +++ b/src/video_core/renderer_vulkan/vk_fsr.h | |||
| @@ -47,7 +47,6 @@ private: | |||
| 47 | vk::Sampler sampler; | 47 | vk::Sampler sampler; |
| 48 | std::vector<vk::Image> images; | 48 | std::vector<vk::Image> images; |
| 49 | std::vector<vk::ImageView> image_views; | 49 | std::vector<vk::ImageView> image_views; |
| 50 | std::vector<MemoryCommit> buffer_commits; | ||
| 51 | }; | 50 | }; |
| 52 | 51 | ||
| 53 | } // namespace Vulkan | 52 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 10ace0420..d681bd22a 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp | |||
| @@ -181,7 +181,7 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_ | |||
| 181 | frame->height = height; | 181 | frame->height = height; |
| 182 | frame->is_srgb = is_srgb; | 182 | frame->is_srgb = is_srgb; |
| 183 | 183 | ||
| 184 | frame->image = dld.CreateImage({ | 184 | frame->image = memory_allocator.CreateImage({ |
| 185 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 185 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 186 | .pNext = nullptr, | 186 | .pNext = nullptr, |
| 187 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, | 187 | .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, |
| @@ -204,8 +204,6 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_ | |||
| 204 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 204 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 205 | }); | 205 | }); |
| 206 | 206 | ||
| 207 | frame->image_commit = memory_allocator.Commit(frame->image, MemoryUsage::DeviceLocal); | ||
| 208 | |||
| 209 | frame->image_view = dld.CreateImageView({ | 207 | frame->image_view = dld.CreateImageView({ |
| 210 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 208 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 211 | .pNext = nullptr, | 209 | .pNext = nullptr, |
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index 4ac2e2395..83e859416 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h | |||
| @@ -29,7 +29,6 @@ struct Frame { | |||
| 29 | vk::Image image; | 29 | vk::Image image; |
| 30 | vk::ImageView image_view; | 30 | vk::ImageView image_view; |
| 31 | vk::Framebuffer framebuffer; | 31 | vk::Framebuffer framebuffer; |
| 32 | MemoryCommit image_commit; | ||
| 33 | vk::CommandBuffer cmdbuf; | 32 | vk::CommandBuffer cmdbuf; |
| 34 | vk::Semaphore render_ready; | 33 | vk::Semaphore render_ready; |
| 35 | vk::Fence present_done; | 34 | vk::Fence present_done; |
diff --git a/src/video_core/renderer_vulkan/vk_smaa.cpp b/src/video_core/renderer_vulkan/vk_smaa.cpp index f8735189d..5efd7d66e 100644 --- a/src/video_core/renderer_vulkan/vk_smaa.cpp +++ b/src/video_core/renderer_vulkan/vk_smaa.cpp | |||
| @@ -25,9 +25,7 @@ namespace { | |||
| 25 | 25 | ||
| 26 | #define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0]))) | 26 | #define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0]))) |
| 27 | 27 | ||
| 28 | std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device, | 28 | vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format) { |
| 29 | MemoryAllocator& allocator, | ||
| 30 | VkExtent2D dimensions, VkFormat format) { | ||
| 31 | const VkImageCreateInfo image_ci{ | 29 | const VkImageCreateInfo image_ci{ |
| 32 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 30 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 33 | .pNext = nullptr, | 31 | .pNext = nullptr, |
| @@ -46,11 +44,7 @@ std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device, | |||
| 46 | .pQueueFamilyIndices = nullptr, | 44 | .pQueueFamilyIndices = nullptr, |
| 47 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 45 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 48 | }; | 46 | }; |
| 49 | 47 | return allocator.CreateImage(image_ci); | |
| 50 | auto image = device.GetLogical().CreateImage(image_ci); | ||
| 51 | auto commit = allocator.Commit(image, Vulkan::MemoryUsage::DeviceLocal); | ||
| 52 | |||
| 53 | return std::make_pair(std::move(image), std::move(commit)); | ||
| 54 | } | 48 | } |
| 55 | 49 | ||
| 56 | void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, | 50 | void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout, |
| @@ -82,7 +76,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo | |||
| 82 | void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, | 76 | void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler, |
| 83 | vk::Image& image, VkExtent2D dimensions, VkFormat format, | 77 | vk::Image& image, VkExtent2D dimensions, VkFormat format, |
| 84 | std::span<const u8> initial_contents = {}) { | 78 | std::span<const u8> initial_contents = {}) { |
| 85 | auto upload_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ | 79 | const VkBufferCreateInfo upload_ci = { |
| 86 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 80 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 87 | .pNext = nullptr, | 81 | .pNext = nullptr, |
| 88 | .flags = 0, | 82 | .flags = 0, |
| @@ -91,9 +85,10 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc | |||
| 91 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 85 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 92 | .queueFamilyIndexCount = 0, | 86 | .queueFamilyIndexCount = 0, |
| 93 | .pQueueFamilyIndices = nullptr, | 87 | .pQueueFamilyIndices = nullptr, |
| 94 | }); | 88 | }; |
| 95 | auto upload_commit = allocator.Commit(upload_buffer, MemoryUsage::Upload); | 89 | auto upload_buffer = allocator.CreateBuffer(upload_ci, MemoryUsage::Upload); |
| 96 | std::ranges::copy(initial_contents, upload_commit.Map().begin()); | 90 | std::ranges::copy(initial_contents, upload_buffer.Mapped().begin()); |
| 91 | upload_buffer.Flush(); | ||
| 97 | 92 | ||
| 98 | const std::array<VkBufferImageCopy, 1> regions{{{ | 93 | const std::array<VkBufferImageCopy, 1> regions{{{ |
| 99 | .bufferOffset = 0, | 94 | .bufferOffset = 0, |
| @@ -117,9 +112,6 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc | |||
| 117 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | 112 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); |
| 118 | }); | 113 | }); |
| 119 | scheduler.Finish(); | 114 | scheduler.Finish(); |
| 120 | |||
| 121 | // This should go out of scope before the commit | ||
| 122 | auto upload_buffer2 = std::move(upload_buffer); | ||
| 123 | } | 115 | } |
| 124 | 116 | ||
| 125 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { | 117 | vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) { |
| @@ -531,10 +523,8 @@ void SMAA::CreateImages() { | |||
| 531 | static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT}; | 523 | static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT}; |
| 532 | static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT}; | 524 | static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT}; |
| 533 | 525 | ||
| 534 | std::tie(m_static_images[Area], m_static_buffer_commits[Area]) = | 526 | m_static_images[Area] = CreateWrappedImage(m_allocator, area_extent, VK_FORMAT_R8G8_UNORM); |
| 535 | CreateWrappedImage(m_device, m_allocator, area_extent, VK_FORMAT_R8G8_UNORM); | 527 | m_static_images[Search] = CreateWrappedImage(m_allocator, search_extent, VK_FORMAT_R8_UNORM); |
| 536 | std::tie(m_static_images[Search], m_static_buffer_commits[Search]) = | ||
| 537 | CreateWrappedImage(m_device, m_allocator, search_extent, VK_FORMAT_R8_UNORM); | ||
| 538 | 528 | ||
| 539 | m_static_image_views[Area] = | 529 | m_static_image_views[Area] = |
| 540 | CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM); | 530 | CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM); |
| @@ -544,12 +534,11 @@ void SMAA::CreateImages() { | |||
| 544 | for (u32 i = 0; i < m_image_count; i++) { | 534 | for (u32 i = 0; i < m_image_count; i++) { |
| 545 | Images& images = m_dynamic_images.emplace_back(); | 535 | Images& images = m_dynamic_images.emplace_back(); |
| 546 | 536 | ||
| 547 | std::tie(images.images[Blend], images.buffer_commits[Blend]) = | 537 | images.images[Blend] = |
| 548 | CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); | 538 | CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); |
| 549 | std::tie(images.images[Edges], images.buffer_commits[Edges]) = | 539 | images.images[Edges] = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT); |
| 550 | CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT); | 540 | images.images[Output] = |
| 551 | std::tie(images.images[Output], images.buffer_commits[Output]) = | 541 | CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); |
| 552 | CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT); | ||
| 553 | 542 | ||
| 554 | images.image_views[Blend] = | 543 | images.image_views[Blend] = |
| 555 | CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT); | 544 | CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT); |
diff --git a/src/video_core/renderer_vulkan/vk_smaa.h b/src/video_core/renderer_vulkan/vk_smaa.h index 99a369148..0e214258a 100644 --- a/src/video_core/renderer_vulkan/vk_smaa.h +++ b/src/video_core/renderer_vulkan/vk_smaa.h | |||
| @@ -66,13 +66,11 @@ private: | |||
| 66 | std::array<vk::Pipeline, MaxSMAAStage> m_pipelines{}; | 66 | std::array<vk::Pipeline, MaxSMAAStage> m_pipelines{}; |
| 67 | std::array<vk::RenderPass, MaxSMAAStage> m_renderpasses{}; | 67 | std::array<vk::RenderPass, MaxSMAAStage> m_renderpasses{}; |
| 68 | 68 | ||
| 69 | std::array<MemoryCommit, MaxStaticImage> m_static_buffer_commits; | ||
| 70 | std::array<vk::Image, MaxStaticImage> m_static_images{}; | 69 | std::array<vk::Image, MaxStaticImage> m_static_images{}; |
| 71 | std::array<vk::ImageView, MaxStaticImage> m_static_image_views{}; | 70 | std::array<vk::ImageView, MaxStaticImage> m_static_image_views{}; |
| 72 | 71 | ||
| 73 | struct Images { | 72 | struct Images { |
| 74 | vk::DescriptorSets descriptor_sets{}; | 73 | vk::DescriptorSets descriptor_sets{}; |
| 75 | std::array<MemoryCommit, MaxDynamicImage> buffer_commits; | ||
| 76 | std::array<vk::Image, MaxDynamicImage> images{}; | 74 | std::array<vk::Image, MaxDynamicImage> images{}; |
| 77 | std::array<vk::ImageView, MaxDynamicImage> image_views{}; | 75 | std::array<vk::ImageView, MaxDynamicImage> image_views{}; |
| 78 | std::array<vk::Framebuffer, MaxSMAAStage> framebuffers{}; | 76 | std::array<vk::Framebuffer, MaxSMAAStage> framebuffers{}; |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 74ca77216..62b251a9b 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp | |||
| @@ -30,55 +30,6 @@ constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB; | |||
| 30 | constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB; | 30 | constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB; |
| 31 | constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS; | 31 | constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS; |
| 32 | 32 | ||
| 33 | constexpr VkMemoryPropertyFlags HOST_FLAGS = | ||
| 34 | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 35 | constexpr VkMemoryPropertyFlags STREAM_FLAGS = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | HOST_FLAGS; | ||
| 36 | |||
| 37 | bool IsStreamHeap(VkMemoryHeap heap) noexcept { | ||
| 38 | return STREAM_BUFFER_SIZE < (heap.size * 2) / 3; | ||
| 39 | } | ||
| 40 | |||
| 41 | std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask, | ||
| 42 | VkMemoryPropertyFlags flags) noexcept { | ||
| 43 | for (u32 type_index = 0; type_index < props.memoryTypeCount; ++type_index) { | ||
| 44 | if (((type_mask >> type_index) & 1) == 0) { | ||
| 45 | // Memory type is incompatible | ||
| 46 | continue; | ||
| 47 | } | ||
| 48 | const VkMemoryType& memory_type = props.memoryTypes[type_index]; | ||
| 49 | if ((memory_type.propertyFlags & flags) != flags) { | ||
| 50 | // Memory type doesn't have the flags we want | ||
| 51 | continue; | ||
| 52 | } | ||
| 53 | if (!IsStreamHeap(props.memoryHeaps[memory_type.heapIndex])) { | ||
| 54 | // Memory heap is not suitable for streaming | ||
| 55 | continue; | ||
| 56 | } | ||
| 57 | // Success! | ||
| 58 | return type_index; | ||
| 59 | } | ||
| 60 | return std::nullopt; | ||
| 61 | } | ||
| 62 | |||
| 63 | u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask, | ||
| 64 | bool try_device_local) { | ||
| 65 | std::optional<u32> type; | ||
| 66 | if (try_device_local) { | ||
| 67 | // Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this | ||
| 68 | type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS); | ||
| 69 | if (type) { | ||
| 70 | return *type; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | // Otherwise try without the DEVICE_LOCAL_BIT | ||
| 74 | type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS); | ||
| 75 | if (type) { | ||
| 76 | return *type; | ||
| 77 | } | ||
| 78 | // This should never happen, and in case it does, signal it as an out of memory situation | ||
| 79 | throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); | ||
| 80 | } | ||
| 81 | |||
| 82 | size_t Region(size_t iterator) noexcept { | 33 | size_t Region(size_t iterator) noexcept { |
| 83 | return iterator / REGION_SIZE; | 34 | return iterator / REGION_SIZE; |
| 84 | } | 35 | } |
| @@ -87,8 +38,7 @@ size_t Region(size_t iterator) noexcept { | |||
| 87 | StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, | 38 | StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, |
| 88 | Scheduler& scheduler_) | 39 | Scheduler& scheduler_) |
| 89 | : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { | 40 | : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { |
| 90 | const vk::Device& dev = device.GetLogical(); | 41 | const VkBufferCreateInfo stream_ci = { |
| 91 | stream_buffer = dev.CreateBuffer(VkBufferCreateInfo{ | ||
| 92 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 42 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 93 | .pNext = nullptr, | 43 | .pNext = nullptr, |
| 94 | .flags = 0, | 44 | .flags = 0, |
| @@ -99,46 +49,13 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem | |||
| 99 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 49 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 100 | .queueFamilyIndexCount = 0, | 50 | .queueFamilyIndexCount = 0, |
| 101 | .pQueueFamilyIndices = nullptr, | 51 | .pQueueFamilyIndices = nullptr, |
| 102 | }); | ||
| 103 | if (device.HasDebuggingToolAttached()) { | ||
| 104 | stream_buffer.SetObjectNameEXT("Stream Buffer"); | ||
| 105 | } | ||
| 106 | VkMemoryDedicatedRequirements dedicated_reqs{ | ||
| 107 | .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, | ||
| 108 | .pNext = nullptr, | ||
| 109 | .prefersDedicatedAllocation = VK_FALSE, | ||
| 110 | .requiresDedicatedAllocation = VK_FALSE, | ||
| 111 | }; | ||
| 112 | const auto requirements = dev.GetBufferMemoryRequirements(*stream_buffer, &dedicated_reqs); | ||
| 113 | const bool make_dedicated = dedicated_reqs.prefersDedicatedAllocation == VK_TRUE || | ||
| 114 | dedicated_reqs.requiresDedicatedAllocation == VK_TRUE; | ||
| 115 | const VkMemoryDedicatedAllocateInfo dedicated_info{ | ||
| 116 | .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, | ||
| 117 | .pNext = nullptr, | ||
| 118 | .image = nullptr, | ||
| 119 | .buffer = *stream_buffer, | ||
| 120 | }; | 52 | }; |
| 121 | const auto memory_properties = device.GetPhysical().GetMemoryProperties().memoryProperties; | 53 | stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream); |
| 122 | VkMemoryAllocateInfo stream_memory_info{ | ||
| 123 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | ||
| 124 | .pNext = make_dedicated ? &dedicated_info : nullptr, | ||
| 125 | .allocationSize = requirements.size, | ||
| 126 | .memoryTypeIndex = | ||
| 127 | FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true), | ||
| 128 | }; | ||
| 129 | stream_memory = dev.TryAllocateMemory(stream_memory_info); | ||
| 130 | if (!stream_memory) { | ||
| 131 | LOG_INFO(Render_Vulkan, "Dynamic memory allocation failed, trying with system memory"); | ||
| 132 | stream_memory_info.memoryTypeIndex = | ||
| 133 | FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, false); | ||
| 134 | stream_memory = dev.AllocateMemory(stream_memory_info); | ||
| 135 | } | ||
| 136 | |||
| 137 | if (device.HasDebuggingToolAttached()) { | 54 | if (device.HasDebuggingToolAttached()) { |
| 138 | stream_memory.SetObjectNameEXT("Stream Buffer Memory"); | 55 | stream_buffer.SetObjectNameEXT("Stream Buffer"); |
| 139 | } | 56 | } |
| 140 | stream_buffer.BindMemory(*stream_memory, 0); | 57 | stream_pointer = stream_buffer.Mapped(); |
| 141 | stream_pointer = stream_memory.Map(0, STREAM_BUFFER_SIZE); | 58 | ASSERT_MSG(!stream_pointer.empty(), "Stream buffer must be host visible!"); |
| 142 | } | 59 | } |
| 143 | 60 | ||
| 144 | StagingBufferPool::~StagingBufferPool() = default; | 61 | StagingBufferPool::~StagingBufferPool() = default; |
| @@ -199,7 +116,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) { | |||
| 199 | return StagingBufferRef{ | 116 | return StagingBufferRef{ |
| 200 | .buffer = *stream_buffer, | 117 | .buffer = *stream_buffer, |
| 201 | .offset = static_cast<VkDeviceSize>(offset), | 118 | .offset = static_cast<VkDeviceSize>(offset), |
| 202 | .mapped_span = std::span<u8>(stream_pointer + offset, size), | 119 | .mapped_span = stream_pointer.subspan(offset, size), |
| 203 | .usage{}, | 120 | .usage{}, |
| 204 | .log2_level{}, | 121 | .log2_level{}, |
| 205 | .index{}, | 122 | .index{}, |
| @@ -247,7 +164,7 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s | |||
| 247 | StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, | 164 | StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, |
| 248 | bool deferred) { | 165 | bool deferred) { |
| 249 | const u32 log2 = Common::Log2Ceil64(size); | 166 | const u32 log2 = Common::Log2Ceil64(size); |
| 250 | vk::Buffer buffer = device.GetLogical().CreateBuffer({ | 167 | const VkBufferCreateInfo buffer_ci = { |
| 251 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 168 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 252 | .pNext = nullptr, | 169 | .pNext = nullptr, |
| 253 | .flags = 0, | 170 | .flags = 0, |
| @@ -259,17 +176,15 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage | |||
| 259 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 176 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 260 | .queueFamilyIndexCount = 0, | 177 | .queueFamilyIndexCount = 0, |
| 261 | .pQueueFamilyIndices = nullptr, | 178 | .pQueueFamilyIndices = nullptr, |
| 262 | }); | 179 | }; |
| 180 | vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage); | ||
| 263 | if (device.HasDebuggingToolAttached()) { | 181 | if (device.HasDebuggingToolAttached()) { |
| 264 | ++buffer_index; | 182 | ++buffer_index; |
| 265 | buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); | 183 | buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); |
| 266 | } | 184 | } |
| 267 | MemoryCommit commit = memory_allocator.Commit(buffer, usage); | 185 | const std::span<u8> mapped_span = buffer.Mapped(); |
| 268 | const std::span<u8> mapped_span = IsHostVisible(usage) ? commit.Map() : std::span<u8>{}; | ||
| 269 | |||
| 270 | StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ | 186 | StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ |
| 271 | .buffer = std::move(buffer), | 187 | .buffer = std::move(buffer), |
| 272 | .commit = std::move(commit), | ||
| 273 | .mapped_span = mapped_span, | 188 | .mapped_span = mapped_span, |
| 274 | .usage = usage, | 189 | .usage = usage, |
| 275 | .log2_level = log2, | 190 | .log2_level = log2, |
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 4fd15f11a..5f69f08b1 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h | |||
| @@ -46,7 +46,6 @@ private: | |||
| 46 | 46 | ||
| 47 | struct StagingBuffer { | 47 | struct StagingBuffer { |
| 48 | vk::Buffer buffer; | 48 | vk::Buffer buffer; |
| 49 | MemoryCommit commit; | ||
| 50 | std::span<u8> mapped_span; | 49 | std::span<u8> mapped_span; |
| 51 | MemoryUsage usage; | 50 | MemoryUsage usage; |
| 52 | u32 log2_level; | 51 | u32 log2_level; |
| @@ -97,8 +96,7 @@ private: | |||
| 97 | Scheduler& scheduler; | 96 | Scheduler& scheduler; |
| 98 | 97 | ||
| 99 | vk::Buffer stream_buffer; | 98 | vk::Buffer stream_buffer; |
| 100 | vk::DeviceMemory stream_memory; | 99 | std::span<u8> stream_pointer; |
| 101 | u8* stream_pointer = nullptr; | ||
| 102 | 100 | ||
| 103 | size_t iterator = 0; | 101 | size_t iterator = 0; |
| 104 | size_t used_iterator = 0; | 102 | size_t used_iterator = 0; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index f3cef09dd..ce6acc30c 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | #include "video_core/renderer_vulkan/blit_image.h" | 15 | #include "video_core/renderer_vulkan/blit_image.h" |
| 16 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 16 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 17 | #include "video_core/renderer_vulkan/vk_compute_pass.h" | 17 | #include "video_core/renderer_vulkan/vk_compute_pass.h" |
| 18 | #include "video_core/renderer_vulkan/vk_rasterizer.h" | ||
| 19 | #include "video_core/renderer_vulkan/vk_render_pass_cache.h" | 18 | #include "video_core/renderer_vulkan/vk_render_pass_cache.h" |
| 20 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 19 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 21 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" | 20 | #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" |
| @@ -163,11 +162,12 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 163 | }; | 162 | }; |
| 164 | } | 163 | } |
| 165 | 164 | ||
| 166 | [[nodiscard]] vk::Image MakeImage(const Device& device, const ImageInfo& info) { | 165 | [[nodiscard]] vk::Image MakeImage(const Device& device, const MemoryAllocator& allocator, |
| 166 | const ImageInfo& info) { | ||
| 167 | if (info.type == ImageType::Buffer) { | 167 | if (info.type == ImageType::Buffer) { |
| 168 | return vk::Image{}; | 168 | return vk::Image{}; |
| 169 | } | 169 | } |
| 170 | return device.GetLogical().CreateImage(MakeImageCreateInfo(device, info)); | 170 | return allocator.CreateImage(MakeImageCreateInfo(device, info)); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | [[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { | 173 | [[nodiscard]] VkImageAspectFlags ImageAspectMask(PixelFormat format) { |
| @@ -839,14 +839,14 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) { | |||
| 839 | 839 | ||
| 840 | VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { | 840 | VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { |
| 841 | const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); | 841 | const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL); |
| 842 | if (buffer_commits[level]) { | 842 | if (buffers[level]) { |
| 843 | return *buffers[level]; | 843 | return *buffers[level]; |
| 844 | } | 844 | } |
| 845 | const auto new_size = Common::NextPow2(needed_size); | 845 | const auto new_size = Common::NextPow2(needed_size); |
| 846 | static constexpr VkBufferUsageFlags flags = | 846 | static constexpr VkBufferUsageFlags flags = |
| 847 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | 847 | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 848 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; | 848 | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; |
| 849 | buffers[level] = device.GetLogical().CreateBuffer({ | 849 | const VkBufferCreateInfo temp_ci = { |
| 850 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 850 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 851 | .pNext = nullptr, | 851 | .pNext = nullptr, |
| 852 | .flags = 0, | 852 | .flags = 0, |
| @@ -855,9 +855,8 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { | |||
| 855 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 855 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 856 | .queueFamilyIndexCount = 0, | 856 | .queueFamilyIndexCount = 0, |
| 857 | .pQueueFamilyIndices = nullptr, | 857 | .pQueueFamilyIndices = nullptr, |
| 858 | }); | 858 | }; |
| 859 | buffer_commits[level] = std::make_unique<MemoryCommit>( | 859 | buffers[level] = memory_allocator.CreateBuffer(temp_ci, MemoryUsage::DeviceLocal); |
| 860 | memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal)); | ||
| 861 | return *buffers[level]; | 860 | return *buffers[level]; |
| 862 | } | 861 | } |
| 863 | 862 | ||
| @@ -1266,8 +1265,8 @@ void TextureCacheRuntime::TickFrame() {} | |||
| 1266 | Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_, | 1265 | Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_, |
| 1267 | VAddr cpu_addr_) | 1266 | VAddr cpu_addr_) |
| 1268 | : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler}, | 1267 | : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler}, |
| 1269 | runtime{&runtime_}, original_image(MakeImage(runtime_.device, info)), | 1268 | runtime{&runtime_}, |
| 1270 | commit(runtime_.memory_allocator.Commit(original_image, MemoryUsage::DeviceLocal)), | 1269 | original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info)), |
| 1271 | aspect_mask(ImageAspectMask(info.format)) { | 1270 | aspect_mask(ImageAspectMask(info.format)) { |
| 1272 | if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) { | 1271 | if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) { |
| 1273 | if (Settings::values.async_astc.GetValue()) { | 1272 | if (Settings::values.async_astc.GetValue()) { |
| @@ -1468,9 +1467,7 @@ bool Image::ScaleUp(bool ignore) { | |||
| 1468 | auto scaled_info = info; | 1467 | auto scaled_info = info; |
| 1469 | scaled_info.size.width = scaled_width; | 1468 | scaled_info.size.width = scaled_width; |
| 1470 | scaled_info.size.height = scaled_height; | 1469 | scaled_info.size.height = scaled_height; |
| 1471 | scaled_image = MakeImage(runtime->device, scaled_info); | 1470 | scaled_image = MakeImage(runtime->device, runtime->memory_allocator, scaled_info); |
| 1472 | auto& allocator = runtime->memory_allocator; | ||
| 1473 | scaled_commit = MemoryCommit(allocator.Commit(scaled_image, MemoryUsage::DeviceLocal)); | ||
| 1474 | ignore = false; | 1471 | ignore = false; |
| 1475 | } | 1472 | } |
| 1476 | current_image = *scaled_image; | 1473 | current_image = *scaled_image; |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index f14525dcb..220943116 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h | |||
| @@ -116,7 +116,6 @@ public: | |||
| 116 | 116 | ||
| 117 | static constexpr size_t indexing_slots = 8 * sizeof(size_t); | 117 | static constexpr size_t indexing_slots = 8 * sizeof(size_t); |
| 118 | std::array<vk::Buffer, indexing_slots> buffers{}; | 118 | std::array<vk::Buffer, indexing_slots> buffers{}; |
| 119 | std::array<std::unique_ptr<MemoryCommit>, indexing_slots> buffer_commits{}; | ||
| 120 | }; | 119 | }; |
| 121 | 120 | ||
| 122 | class Image : public VideoCommon::ImageBase { | 121 | class Image : public VideoCommon::ImageBase { |
| @@ -180,12 +179,10 @@ private: | |||
| 180 | TextureCacheRuntime* runtime{}; | 179 | TextureCacheRuntime* runtime{}; |
| 181 | 180 | ||
| 182 | vk::Image original_image; | 181 | vk::Image original_image; |
| 183 | MemoryCommit commit; | ||
| 184 | std::vector<vk::ImageView> storage_image_views; | 182 | std::vector<vk::ImageView> storage_image_views; |
| 185 | VkImageAspectFlags aspect_mask = 0; | 183 | VkImageAspectFlags aspect_mask = 0; |
| 186 | bool initialized = false; | 184 | bool initialized = false; |
| 187 | vk::Image scaled_image{}; | 185 | vk::Image scaled_image{}; |
| 188 | MemoryCommit scaled_commit{}; | ||
| 189 | VkImage current_image{}; | 186 | VkImage current_image{}; |
| 190 | 187 | ||
| 191 | std::unique_ptr<Framebuffer> scale_framebuffer; | 188 | std::unique_ptr<Framebuffer> scale_framebuffer; |
diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp index a802d3c49..460d8d59d 100644 --- a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp +++ b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp | |||
| @@ -18,7 +18,7 @@ using namespace Common::Literals; | |||
| 18 | 18 | ||
| 19 | TurboMode::TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld) | 19 | TurboMode::TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld) |
| 20 | #ifndef ANDROID | 20 | #ifndef ANDROID |
| 21 | : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device, false} | 21 | : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device} |
| 22 | #endif | 22 | #endif |
| 23 | { | 23 | { |
| 24 | { | 24 | { |
| @@ -41,7 +41,7 @@ void TurboMode::Run(std::stop_token stop_token) { | |||
| 41 | auto& dld = m_device.GetLogical(); | 41 | auto& dld = m_device.GetLogical(); |
| 42 | 42 | ||
| 43 | // Allocate buffer. 2MiB should be sufficient. | 43 | // Allocate buffer. 2MiB should be sufficient. |
| 44 | auto buffer = dld.CreateBuffer(VkBufferCreateInfo{ | 44 | const VkBufferCreateInfo buffer_ci = { |
| 45 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 45 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 46 | .pNext = nullptr, | 46 | .pNext = nullptr, |
| 47 | .flags = 0, | 47 | .flags = 0, |
| @@ -50,10 +50,8 @@ void TurboMode::Run(std::stop_token stop_token) { | |||
| 50 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 50 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 51 | .queueFamilyIndexCount = 0, | 51 | .queueFamilyIndexCount = 0, |
| 52 | .pQueueFamilyIndices = nullptr, | 52 | .pQueueFamilyIndices = nullptr, |
| 53 | }); | 53 | }; |
| 54 | 54 | vk::Buffer buffer = m_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal); | |
| 55 | // Commit some device local memory for the buffer. | ||
| 56 | auto commit = m_allocator.Commit(buffer, MemoryUsage::DeviceLocal); | ||
| 57 | 55 | ||
| 58 | // Create the descriptor pool to contain our descriptor. | 56 | // Create the descriptor pool to contain our descriptor. |
| 59 | static constexpr VkDescriptorPoolSize pool_size{ | 57 | static constexpr VkDescriptorPoolSize pool_size{ |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index b11abe311..e4ca65b58 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -22,6 +22,8 @@ | |||
| 22 | #include <adrenotools/bcenabler.h> | 22 | #include <adrenotools/bcenabler.h> |
| 23 | #endif | 23 | #endif |
| 24 | 24 | ||
| 25 | #include <vk_mem_alloc.h> | ||
| 26 | |||
| 25 | namespace Vulkan { | 27 | namespace Vulkan { |
| 26 | using namespace Common::Literals; | 28 | using namespace Common::Literals; |
| 27 | namespace { | 29 | namespace { |
| @@ -596,9 +598,31 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 596 | 598 | ||
| 597 | graphics_queue = logical.GetQueue(graphics_family); | 599 | graphics_queue = logical.GetQueue(graphics_family); |
| 598 | present_queue = logical.GetQueue(present_family); | 600 | present_queue = logical.GetQueue(present_family); |
| 601 | |||
| 602 | VmaVulkanFunctions functions{}; | ||
| 603 | functions.vkGetInstanceProcAddr = dld.vkGetInstanceProcAddr; | ||
| 604 | functions.vkGetDeviceProcAddr = dld.vkGetDeviceProcAddr; | ||
| 605 | |||
| 606 | const VmaAllocatorCreateInfo allocator_info = { | ||
| 607 | .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, | ||
| 608 | .physicalDevice = physical, | ||
| 609 | .device = *logical, | ||
| 610 | .preferredLargeHeapBlockSize = 0, | ||
| 611 | .pAllocationCallbacks = nullptr, | ||
| 612 | .pDeviceMemoryCallbacks = nullptr, | ||
| 613 | .pHeapSizeLimit = nullptr, | ||
| 614 | .pVulkanFunctions = &functions, | ||
| 615 | .instance = instance, | ||
| 616 | .vulkanApiVersion = VK_API_VERSION_1_1, | ||
| 617 | .pTypeExternalMemoryHandleTypes = nullptr, | ||
| 618 | }; | ||
| 619 | |||
| 620 | vk::Check(vmaCreateAllocator(&allocator_info, &allocator)); | ||
| 599 | } | 621 | } |
| 600 | 622 | ||
| 601 | Device::~Device() = default; | 623 | Device::~Device() { |
| 624 | vmaDestroyAllocator(allocator); | ||
| 625 | } | ||
| 602 | 626 | ||
| 603 | VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, | 627 | VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, |
| 604 | FormatType format_type) const { | 628 | FormatType format_type) const { |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 0b634a876..b84af3dfb 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | #include "common/settings.h" | 14 | #include "common/settings.h" |
| 15 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 15 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 16 | 16 | ||
| 17 | VK_DEFINE_HANDLE(VmaAllocator) | ||
| 18 | |||
| 17 | // Define all features which may be used by the implementation here. | 19 | // Define all features which may be used by the implementation here. |
| 18 | // Vulkan version in the macro describes the minimum version required for feature availability. | 20 | // Vulkan version in the macro describes the minimum version required for feature availability. |
| 19 | // If the Vulkan version is lower than the required version, the named extension is required. | 21 | // If the Vulkan version is lower than the required version, the named extension is required. |
| @@ -199,6 +201,11 @@ public: | |||
| 199 | return dld; | 201 | return dld; |
| 200 | } | 202 | } |
| 201 | 203 | ||
| 204 | /// Returns the VMA allocator. | ||
| 205 | VmaAllocator GetAllocator() const { | ||
| 206 | return allocator; | ||
| 207 | } | ||
| 208 | |||
| 202 | /// Returns the logical device. | 209 | /// Returns the logical device. |
| 203 | const vk::Device& GetLogical() const { | 210 | const vk::Device& GetLogical() const { |
| 204 | return logical; | 211 | return logical; |
| @@ -630,6 +637,7 @@ private: | |||
| 630 | 637 | ||
| 631 | private: | 638 | private: |
| 632 | VkInstance instance; ///< Vulkan instance. | 639 | VkInstance instance; ///< Vulkan instance. |
| 640 | VmaAllocator allocator; ///< VMA allocator. | ||
| 633 | vk::DeviceDispatch dld; ///< Device function pointers. | 641 | vk::DeviceDispatch dld; ///< Device function pointers. |
| 634 | vk::PhysicalDevice physical; ///< Physical device. | 642 | vk::PhysicalDevice physical; ///< Physical device. |
| 635 | vk::Device logical; ///< Logical device. | 643 | vk::Device logical; ///< Logical device. |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index e28a556f8..a2ef0efa4 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | #include <optional> | 6 | #include <optional> |
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | 8 | ||
| 9 | #include <glad/glad.h> | ||
| 10 | |||
| 11 | #include "common/alignment.h" | 9 | #include "common/alignment.h" |
| 12 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 13 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| @@ -17,6 +15,8 @@ | |||
| 17 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | 15 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" |
| 18 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 19 | 17 | ||
| 18 | #include <vk_mem_alloc.h> | ||
| 19 | |||
| 20 | namespace Vulkan { | 20 | namespace Vulkan { |
| 21 | namespace { | 21 | namespace { |
| 22 | struct Range { | 22 | struct Range { |
| @@ -49,22 +49,45 @@ struct Range { | |||
| 49 | case MemoryUsage::Download: | 49 | case MemoryUsage::Download: |
| 50 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | | 50 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | |
| 51 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; | 51 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; |
| 52 | case MemoryUsage::Stream: | ||
| 53 | return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | | ||
| 54 | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 52 | } | 55 | } |
| 53 | ASSERT_MSG(false, "Invalid memory usage={}", usage); | 56 | ASSERT_MSG(false, "Invalid memory usage={}", usage); |
| 54 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | 57 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; |
| 55 | } | 58 | } |
| 56 | 59 | ||
| 57 | constexpr VkExportMemoryAllocateInfo EXPORT_ALLOCATE_INFO{ | 60 | [[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferedVmaFlags(MemoryUsage usage) { |
| 58 | .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, | 61 | return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
| 59 | .pNext = nullptr, | 62 | : VkMemoryPropertyFlagBits{}; |
| 60 | #ifdef _WIN32 | 63 | } |
| 61 | .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, | 64 | |
| 62 | #elif __unix__ | 65 | [[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) { |
| 63 | .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, | 66 | switch (usage) { |
| 64 | #else | 67 | case MemoryUsage::Upload: |
| 65 | .handleTypes = 0, | 68 | case MemoryUsage::Stream: |
| 66 | #endif | 69 | return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; |
| 67 | }; | 70 | case MemoryUsage::Download: |
| 71 | return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; | ||
| 72 | case MemoryUsage::DeviceLocal: | ||
| 73 | return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | | ||
| 74 | VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT; | ||
| 75 | } | ||
| 76 | return {}; | ||
| 77 | } | ||
| 78 | |||
| 79 | [[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) { | ||
| 80 | switch (usage) { | ||
| 81 | case MemoryUsage::DeviceLocal: | ||
| 82 | case MemoryUsage::Stream: | ||
| 83 | return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; | ||
| 84 | case MemoryUsage::Upload: | ||
| 85 | case MemoryUsage::Download: | ||
| 86 | return VMA_MEMORY_USAGE_AUTO_PREFER_HOST; | ||
| 87 | } | ||
| 88 | return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; | ||
| 89 | } | ||
| 90 | |||
| 68 | } // Anonymous namespace | 91 | } // Anonymous namespace |
| 69 | 92 | ||
| 70 | class MemoryAllocation { | 93 | class MemoryAllocation { |
| @@ -74,14 +97,6 @@ public: | |||
| 74 | : allocator{allocator_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, | 97 | : allocator{allocator_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, |
| 75 | property_flags{properties}, shifted_memory_type{1U << type} {} | 98 | property_flags{properties}, shifted_memory_type{1U << type} {} |
| 76 | 99 | ||
| 77 | #if defined(_WIN32) || defined(__unix__) | ||
| 78 | ~MemoryAllocation() { | ||
| 79 | if (owning_opengl_handle != 0) { | ||
| 80 | glDeleteMemoryObjectsEXT(1, &owning_opengl_handle); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | #endif | ||
| 84 | |||
| 85 | MemoryAllocation& operator=(const MemoryAllocation&) = delete; | 100 | MemoryAllocation& operator=(const MemoryAllocation&) = delete; |
| 86 | MemoryAllocation(const MemoryAllocation&) = delete; | 101 | MemoryAllocation(const MemoryAllocation&) = delete; |
| 87 | 102 | ||
| @@ -120,31 +135,6 @@ public: | |||
| 120 | return memory_mapped_span; | 135 | return memory_mapped_span; |
| 121 | } | 136 | } |
| 122 | 137 | ||
| 123 | #ifdef _WIN32 | ||
| 124 | [[nodiscard]] u32 ExportOpenGLHandle() { | ||
| 125 | if (!owning_opengl_handle) { | ||
| 126 | glCreateMemoryObjectsEXT(1, &owning_opengl_handle); | ||
| 127 | glImportMemoryWin32HandleEXT(owning_opengl_handle, allocation_size, | ||
| 128 | GL_HANDLE_TYPE_OPAQUE_WIN32_EXT, | ||
| 129 | memory.GetMemoryWin32HandleKHR()); | ||
| 130 | } | ||
| 131 | return owning_opengl_handle; | ||
| 132 | } | ||
| 133 | #elif __unix__ | ||
| 134 | [[nodiscard]] u32 ExportOpenGLHandle() { | ||
| 135 | if (!owning_opengl_handle) { | ||
| 136 | glCreateMemoryObjectsEXT(1, &owning_opengl_handle); | ||
| 137 | glImportMemoryFdEXT(owning_opengl_handle, allocation_size, GL_HANDLE_TYPE_OPAQUE_FD_EXT, | ||
| 138 | memory.GetMemoryFdKHR()); | ||
| 139 | } | ||
| 140 | return owning_opengl_handle; | ||
| 141 | } | ||
| 142 | #else | ||
| 143 | [[nodiscard]] u32 ExportOpenGLHandle() { | ||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | #endif | ||
| 147 | |||
| 148 | /// Returns whether this allocation is compatible with the arguments. | 138 | /// Returns whether this allocation is compatible with the arguments. |
| 149 | [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { | 139 | [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { |
| 150 | return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0; | 140 | return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0; |
| @@ -182,9 +172,6 @@ private: | |||
| 182 | const u32 shifted_memory_type; ///< Shifted Vulkan memory type. | 172 | const u32 shifted_memory_type; ///< Shifted Vulkan memory type. |
| 183 | std::vector<Range> commits; ///< All commit ranges done from this allocation. | 173 | std::vector<Range> commits; ///< All commit ranges done from this allocation. |
| 184 | std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. | 174 | std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. |
| 185 | #if defined(_WIN32) || defined(__unix__) | ||
| 186 | u32 owning_opengl_handle{}; ///< Owning OpenGL memory object handle. | ||
| 187 | #endif | ||
| 188 | }; | 175 | }; |
| 189 | 176 | ||
| 190 | MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, | 177 | MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, |
| @@ -216,24 +203,70 @@ std::span<u8> MemoryCommit::Map() { | |||
| 216 | return span; | 203 | return span; |
| 217 | } | 204 | } |
| 218 | 205 | ||
| 219 | u32 MemoryCommit::ExportOpenGLHandle() const { | ||
| 220 | return allocation->ExportOpenGLHandle(); | ||
| 221 | } | ||
| 222 | |||
| 223 | void MemoryCommit::Release() { | 206 | void MemoryCommit::Release() { |
| 224 | if (allocation) { | 207 | if (allocation) { |
| 225 | allocation->Free(begin); | 208 | allocation->Free(begin); |
| 226 | } | 209 | } |
| 227 | } | 210 | } |
| 228 | 211 | ||
| 229 | MemoryAllocator::MemoryAllocator(const Device& device_, bool export_allocations_) | 212 | MemoryAllocator::MemoryAllocator(const Device& device_) |
| 230 | : device{device_}, properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, | 213 | : device{device_}, allocator{device.GetAllocator()}, |
| 231 | export_allocations{export_allocations_}, | 214 | properties{device_.GetPhysical().GetMemoryProperties().memoryProperties}, |
| 232 | buffer_image_granularity{ | 215 | buffer_image_granularity{ |
| 233 | device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} | 216 | device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {} |
| 234 | 217 | ||
| 235 | MemoryAllocator::~MemoryAllocator() = default; | 218 | MemoryAllocator::~MemoryAllocator() = default; |
| 236 | 219 | ||
| 220 | vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const { | ||
| 221 | const VmaAllocationCreateInfo alloc_ci = { | ||
| 222 | .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT, | ||
| 223 | .usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, | ||
| 224 | .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, | ||
| 225 | .preferredFlags = 0, | ||
| 226 | .memoryTypeBits = 0, | ||
| 227 | .pool = VK_NULL_HANDLE, | ||
| 228 | .pUserData = nullptr, | ||
| 229 | .priority = 0.f, | ||
| 230 | }; | ||
| 231 | |||
| 232 | VkImage handle{}; | ||
| 233 | VmaAllocation allocation{}; | ||
| 234 | |||
| 235 | vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr)); | ||
| 236 | |||
| 237 | return vk::Image(handle, *device.GetLogical(), allocator, allocation, | ||
| 238 | device.GetDispatchLoader()); | ||
| 239 | } | ||
| 240 | |||
| 241 | vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const { | ||
| 242 | const VmaAllocationCreateInfo alloc_ci = { | ||
| 243 | .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT | | ||
| 244 | MemoryUsageVmaFlags(usage), | ||
| 245 | .usage = MemoryUsageVma(usage), | ||
| 246 | .requiredFlags = 0, | ||
| 247 | .preferredFlags = MemoryUsagePreferedVmaFlags(usage), | ||
| 248 | .memoryTypeBits = 0, | ||
| 249 | .pool = VK_NULL_HANDLE, | ||
| 250 | .pUserData = nullptr, | ||
| 251 | .priority = 0.f, | ||
| 252 | }; | ||
| 253 | |||
| 254 | VkBuffer handle{}; | ||
| 255 | VmaAllocationInfo alloc_info{}; | ||
| 256 | VmaAllocation allocation{}; | ||
| 257 | VkMemoryPropertyFlags property_flags{}; | ||
| 258 | |||
| 259 | vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info)); | ||
| 260 | vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags); | ||
| 261 | |||
| 262 | u8* data = reinterpret_cast<u8*>(alloc_info.pMappedData); | ||
| 263 | const std::span<u8> mapped_data = data ? std::span<u8>{data, ci.size} : std::span<u8>{}; | ||
| 264 | const bool is_coherent = property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||
| 265 | |||
| 266 | return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data, is_coherent, | ||
| 267 | device.GetDispatchLoader()); | ||
| 268 | } | ||
| 269 | |||
| 237 | MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { | 270 | MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { |
| 238 | // Find the fastest memory flags we can afford with the current requirements | 271 | // Find the fastest memory flags we can afford with the current requirements |
| 239 | const u32 type_mask = requirements.memoryTypeBits; | 272 | const u32 type_mask = requirements.memoryTypeBits; |
| @@ -253,25 +286,11 @@ MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, M | |||
| 253 | return TryCommit(requirements, flags).value(); | 286 | return TryCommit(requirements, flags).value(); |
| 254 | } | 287 | } |
| 255 | 288 | ||
| 256 | MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) { | ||
| 257 | auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage); | ||
| 258 | buffer.BindMemory(commit.Memory(), commit.Offset()); | ||
| 259 | return commit; | ||
| 260 | } | ||
| 261 | |||
| 262 | MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) { | ||
| 263 | VkMemoryRequirements requirements = device.GetLogical().GetImageMemoryRequirements(*image); | ||
| 264 | requirements.size = Common::AlignUp(requirements.size, buffer_image_granularity); | ||
| 265 | auto commit = Commit(requirements, usage); | ||
| 266 | image.BindMemory(commit.Memory(), commit.Offset()); | ||
| 267 | return commit; | ||
| 268 | } | ||
| 269 | |||
| 270 | bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { | 289 | bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { |
| 271 | const u32 type = FindType(flags, type_mask).value(); | 290 | const u32 type = FindType(flags, type_mask).value(); |
| 272 | vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ | 291 | vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ |
| 273 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | 292 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, |
| 274 | .pNext = export_allocations ? &EXPORT_ALLOCATE_INFO : nullptr, | 293 | .pNext = nullptr, |
| 275 | .allocationSize = size, | 294 | .allocationSize = size, |
| 276 | .memoryTypeIndex = type, | 295 | .memoryTypeIndex = type, |
| 277 | }); | 296 | }); |
| @@ -342,16 +361,4 @@ std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 ty | |||
| 342 | return std::nullopt; | 361 | return std::nullopt; |
| 343 | } | 362 | } |
| 344 | 363 | ||
| 345 | bool IsHostVisible(MemoryUsage usage) noexcept { | ||
| 346 | switch (usage) { | ||
| 347 | case MemoryUsage::DeviceLocal: | ||
| 348 | return false; | ||
| 349 | case MemoryUsage::Upload: | ||
| 350 | case MemoryUsage::Download: | ||
| 351 | return true; | ||
| 352 | } | ||
| 353 | ASSERT_MSG(false, "Invalid memory usage={}", usage); | ||
| 354 | return false; | ||
| 355 | } | ||
| 356 | |||
| 357 | } // namespace Vulkan | 364 | } // namespace Vulkan |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index a5bff03fe..f449bc8d0 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 10 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 11 | 11 | ||
| 12 | VK_DEFINE_HANDLE(VmaAllocator) | ||
| 13 | |||
| 12 | namespace Vulkan { | 14 | namespace Vulkan { |
| 13 | 15 | ||
| 14 | class Device; | 16 | class Device; |
| @@ -17,9 +19,11 @@ class MemoryAllocation; | |||
| 17 | 19 | ||
| 18 | /// Hints and requirements for the backing memory type of a commit | 20 | /// Hints and requirements for the backing memory type of a commit |
| 19 | enum class MemoryUsage { | 21 | enum class MemoryUsage { |
| 20 | DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU | 22 | DeviceLocal, ///< Requests device local host visible buffer, falling back to device local |
| 23 | ///< memory. | ||
| 21 | Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads | 24 | Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads |
| 22 | Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks | 25 | Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks |
| 26 | Stream, ///< Requests device local host visible buffer, falling back host memory. | ||
| 23 | }; | 27 | }; |
| 24 | 28 | ||
| 25 | /// Ownership handle of a memory commitment. | 29 | /// Ownership handle of a memory commitment. |
| @@ -41,9 +45,6 @@ public: | |||
| 41 | /// It will map the backing allocation if it hasn't been mapped before. | 45 | /// It will map the backing allocation if it hasn't been mapped before. |
| 42 | std::span<u8> Map(); | 46 | std::span<u8> Map(); |
| 43 | 47 | ||
| 44 | /// Returns an non-owning OpenGL handle, creating one if it doesn't exist. | ||
| 45 | u32 ExportOpenGLHandle() const; | ||
| 46 | |||
| 47 | /// Returns the Vulkan memory handler. | 48 | /// Returns the Vulkan memory handler. |
| 48 | VkDeviceMemory Memory() const { | 49 | VkDeviceMemory Memory() const { |
| 49 | return memory; | 50 | return memory; |
| @@ -74,16 +75,19 @@ public: | |||
| 74 | * Construct memory allocator | 75 | * Construct memory allocator |
| 75 | * | 76 | * |
| 76 | * @param device_ Device to allocate from | 77 | * @param device_ Device to allocate from |
| 77 | * @param export_allocations_ True when allocations have to be exported | ||
| 78 | * | 78 | * |
| 79 | * @throw vk::Exception on failure | 79 | * @throw vk::Exception on failure |
| 80 | */ | 80 | */ |
| 81 | explicit MemoryAllocator(const Device& device_, bool export_allocations_); | 81 | explicit MemoryAllocator(const Device& device_); |
| 82 | ~MemoryAllocator(); | 82 | ~MemoryAllocator(); |
| 83 | 83 | ||
| 84 | MemoryAllocator& operator=(const MemoryAllocator&) = delete; | 84 | MemoryAllocator& operator=(const MemoryAllocator&) = delete; |
| 85 | MemoryAllocator(const MemoryAllocator&) = delete; | 85 | MemoryAllocator(const MemoryAllocator&) = delete; |
| 86 | 86 | ||
| 87 | vk::Image CreateImage(const VkImageCreateInfo& ci) const; | ||
| 88 | |||
| 89 | vk::Buffer CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const; | ||
| 90 | |||
| 87 | /** | 91 | /** |
| 88 | * Commits a memory with the specified requirements. | 92 | * Commits a memory with the specified requirements. |
| 89 | * | 93 | * |
| @@ -97,9 +101,6 @@ public: | |||
| 97 | /// Commits memory required by the buffer and binds it. | 101 | /// Commits memory required by the buffer and binds it. |
| 98 | MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); | 102 | MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); |
| 99 | 103 | ||
| 100 | /// Commits memory required by the image and binds it. | ||
| 101 | MemoryCommit Commit(const vk::Image& image, MemoryUsage usage); | ||
| 102 | |||
| 103 | private: | 104 | private: |
| 104 | /// Tries to allocate a chunk of memory. | 105 | /// Tries to allocate a chunk of memory. |
| 105 | bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); | 106 | bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); |
| @@ -117,15 +118,12 @@ private: | |||
| 117 | /// Returns index to the fastest memory type compatible with the passed requirements. | 118 | /// Returns index to the fastest memory type compatible with the passed requirements. |
| 118 | std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; | 119 | std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; |
| 119 | 120 | ||
| 120 | const Device& device; ///< Device handle. | 121 | const Device& device; ///< Device handle. |
| 121 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. | 122 | VmaAllocator allocator; ///< Vma allocator. |
| 122 | const bool export_allocations; ///< True when memory allocations have to be exported. | 123 | const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. |
| 123 | std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. | 124 | std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. |
| 124 | VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers | 125 | VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers |
| 125 | // and optimal images | 126 | // and optimal images |
| 126 | }; | 127 | }; |
| 127 | 128 | ||
| 128 | /// Returns true when a memory usage is guaranteed to be host visible. | ||
| 129 | bool IsHostVisible(MemoryUsage usage) noexcept; | ||
| 130 | |||
| 131 | } // namespace Vulkan | 129 | } // namespace Vulkan |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 336f53700..28fcb21a0 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | 12 | ||
| 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 14 | 14 | ||
| 15 | #include <vk_mem_alloc.h> | ||
| 16 | |||
| 15 | namespace Vulkan::vk { | 17 | namespace Vulkan::vk { |
| 16 | 18 | ||
| 17 | namespace { | 19 | namespace { |
| @@ -547,24 +549,40 @@ DebugUtilsMessenger Instance::CreateDebugUtilsMessenger( | |||
| 547 | return DebugUtilsMessenger(object, handle, *dld); | 549 | return DebugUtilsMessenger(object, handle, *dld); |
| 548 | } | 550 | } |
| 549 | 551 | ||
| 550 | void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { | 552 | void Image::SetObjectNameEXT(const char* name) const { |
| 551 | Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); | 553 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); |
| 552 | } | 554 | } |
| 553 | 555 | ||
| 554 | void Buffer::SetObjectNameEXT(const char* name) const { | 556 | void Image::Release() const noexcept { |
| 555 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); | 557 | if (handle) { |
| 558 | vmaDestroyImage(allocator, handle, allocation); | ||
| 559 | } | ||
| 556 | } | 560 | } |
| 557 | 561 | ||
| 558 | void BufferView::SetObjectNameEXT(const char* name) const { | 562 | void Buffer::Flush() const { |
| 559 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); | 563 | if (!is_coherent) { |
| 564 | vmaFlushAllocation(allocator, allocation, 0, VK_WHOLE_SIZE); | ||
| 565 | } | ||
| 560 | } | 566 | } |
| 561 | 567 | ||
| 562 | void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { | 568 | void Buffer::Invalidate() const { |
| 563 | Check(dld->vkBindImageMemory(owner, handle, memory, offset)); | 569 | if (!is_coherent) { |
| 570 | vmaInvalidateAllocation(allocator, allocation, 0, VK_WHOLE_SIZE); | ||
| 571 | } | ||
| 564 | } | 572 | } |
| 565 | 573 | ||
| 566 | void Image::SetObjectNameEXT(const char* name) const { | 574 | void Buffer::SetObjectNameEXT(const char* name) const { |
| 567 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); | 575 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); |
| 576 | } | ||
| 577 | |||
| 578 | void Buffer::Release() const noexcept { | ||
| 579 | if (handle) { | ||
| 580 | vmaDestroyBuffer(allocator, handle, allocation); | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | void BufferView::SetObjectNameEXT(const char* name) const { | ||
| 585 | SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); | ||
| 568 | } | 586 | } |
| 569 | 587 | ||
| 570 | void ImageView::SetObjectNameEXT(const char* name) const { | 588 | void ImageView::SetObjectNameEXT(const char* name) const { |
| @@ -701,24 +719,12 @@ Queue Device::GetQueue(u32 family_index) const noexcept { | |||
| 701 | return Queue(queue, *dld); | 719 | return Queue(queue, *dld); |
| 702 | } | 720 | } |
| 703 | 721 | ||
| 704 | Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const { | ||
| 705 | VkBuffer object; | ||
| 706 | Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object)); | ||
| 707 | return Buffer(object, handle, *dld); | ||
| 708 | } | ||
| 709 | |||
| 710 | BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { | 722 | BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { |
| 711 | VkBufferView object; | 723 | VkBufferView object; |
| 712 | Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); | 724 | Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); |
| 713 | return BufferView(object, handle, *dld); | 725 | return BufferView(object, handle, *dld); |
| 714 | } | 726 | } |
| 715 | 727 | ||
| 716 | Image Device::CreateImage(const VkImageCreateInfo& ci) const { | ||
| 717 | VkImage object; | ||
| 718 | Check(dld->vkCreateImage(handle, &ci, nullptr, &object)); | ||
| 719 | return Image(object, handle, *dld); | ||
| 720 | } | ||
| 721 | |||
| 722 | ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const { | 728 | ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const { |
| 723 | VkImageView object; | 729 | VkImageView object; |
| 724 | Check(dld->vkCreateImageView(handle, &ci, nullptr, &object)); | 730 | Check(dld->vkCreateImageView(handle, &ci, nullptr, &object)); |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 4ff328a21..44fce47a5 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h | |||
| @@ -32,6 +32,9 @@ | |||
| 32 | #pragma warning(disable : 26812) // Disable prefer enum class over enum | 32 | #pragma warning(disable : 26812) // Disable prefer enum class over enum |
| 33 | #endif | 33 | #endif |
| 34 | 34 | ||
| 35 | VK_DEFINE_HANDLE(VmaAllocator) | ||
| 36 | VK_DEFINE_HANDLE(VmaAllocation) | ||
| 37 | |||
| 35 | namespace Vulkan::vk { | 38 | namespace Vulkan::vk { |
| 36 | 39 | ||
| 37 | /** | 40 | /** |
| @@ -616,6 +619,138 @@ public: | |||
| 616 | } | 619 | } |
| 617 | }; | 620 | }; |
| 618 | 621 | ||
| 622 | class Image { | ||
| 623 | public: | ||
| 624 | explicit Image(VkImage handle_, VkDevice owner_, VmaAllocator allocator_, | ||
| 625 | VmaAllocation allocation_, const DeviceDispatch& dld_) noexcept | ||
| 626 | : handle{handle_}, owner{owner_}, allocator{allocator_}, | ||
| 627 | allocation{allocation_}, dld{&dld_} {} | ||
| 628 | Image() = default; | ||
| 629 | |||
| 630 | Image(const Image&) = delete; | ||
| 631 | Image& operator=(const Image&) = delete; | ||
| 632 | |||
| 633 | Image(Image&& rhs) noexcept | ||
| 634 | : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator}, | ||
| 635 | allocation{rhs.allocation}, dld{rhs.dld} {} | ||
| 636 | |||
| 637 | Image& operator=(Image&& rhs) noexcept { | ||
| 638 | Release(); | ||
| 639 | handle = std::exchange(rhs.handle, nullptr); | ||
| 640 | owner = rhs.owner; | ||
| 641 | allocator = rhs.allocator; | ||
| 642 | allocation = rhs.allocation; | ||
| 643 | dld = rhs.dld; | ||
| 644 | return *this; | ||
| 645 | } | ||
| 646 | |||
| 647 | ~Image() noexcept { | ||
| 648 | Release(); | ||
| 649 | } | ||
| 650 | |||
| 651 | VkImage operator*() const noexcept { | ||
| 652 | return handle; | ||
| 653 | } | ||
| 654 | |||
| 655 | void reset() noexcept { | ||
| 656 | Release(); | ||
| 657 | handle = nullptr; | ||
| 658 | } | ||
| 659 | |||
| 660 | explicit operator bool() const noexcept { | ||
| 661 | return handle != nullptr; | ||
| 662 | } | ||
| 663 | |||
| 664 | void SetObjectNameEXT(const char* name) const; | ||
| 665 | |||
| 666 | private: | ||
| 667 | void Release() const noexcept; | ||
| 668 | |||
| 669 | VkImage handle = nullptr; | ||
| 670 | VkDevice owner = nullptr; | ||
| 671 | VmaAllocator allocator = nullptr; | ||
| 672 | VmaAllocation allocation = nullptr; | ||
| 673 | const DeviceDispatch* dld = nullptr; | ||
| 674 | }; | ||
| 675 | |||
| 676 | class Buffer { | ||
| 677 | public: | ||
| 678 | explicit Buffer(VkBuffer handle_, VkDevice owner_, VmaAllocator allocator_, | ||
| 679 | VmaAllocation allocation_, std::span<u8> mapped_, bool is_coherent_, | ||
| 680 | const DeviceDispatch& dld_) noexcept | ||
| 681 | : handle{handle_}, owner{owner_}, allocator{allocator_}, | ||
| 682 | allocation{allocation_}, mapped{mapped_}, is_coherent{is_coherent_}, dld{&dld_} {} | ||
| 683 | Buffer() = default; | ||
| 684 | |||
| 685 | Buffer(const Buffer&) = delete; | ||
| 686 | Buffer& operator=(const Buffer&) = delete; | ||
| 687 | |||
| 688 | Buffer(Buffer&& rhs) noexcept | ||
| 689 | : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator}, | ||
| 690 | allocation{rhs.allocation}, mapped{rhs.mapped}, | ||
| 691 | is_coherent{rhs.is_coherent}, dld{rhs.dld} {} | ||
| 692 | |||
| 693 | Buffer& operator=(Buffer&& rhs) noexcept { | ||
| 694 | Release(); | ||
| 695 | handle = std::exchange(rhs.handle, nullptr); | ||
| 696 | owner = rhs.owner; | ||
| 697 | allocator = rhs.allocator; | ||
| 698 | allocation = rhs.allocation; | ||
| 699 | mapped = rhs.mapped; | ||
| 700 | is_coherent = rhs.is_coherent; | ||
| 701 | dld = rhs.dld; | ||
| 702 | return *this; | ||
| 703 | } | ||
| 704 | |||
| 705 | ~Buffer() noexcept { | ||
| 706 | Release(); | ||
| 707 | } | ||
| 708 | |||
| 709 | VkBuffer operator*() const noexcept { | ||
| 710 | return handle; | ||
| 711 | } | ||
| 712 | |||
| 713 | void reset() noexcept { | ||
| 714 | Release(); | ||
| 715 | handle = nullptr; | ||
| 716 | } | ||
| 717 | |||
| 718 | explicit operator bool() const noexcept { | ||
| 719 | return handle != nullptr; | ||
| 720 | } | ||
| 721 | |||
| 722 | /// Returns the host mapped memory, an empty span otherwise. | ||
| 723 | std::span<u8> Mapped() noexcept { | ||
| 724 | return mapped; | ||
| 725 | } | ||
| 726 | |||
| 727 | std::span<const u8> Mapped() const noexcept { | ||
| 728 | return mapped; | ||
| 729 | } | ||
| 730 | |||
| 731 | /// Returns true if the buffer is mapped to the host. | ||
| 732 | bool IsHostVisible() const noexcept { | ||
| 733 | return !mapped.empty(); | ||
| 734 | } | ||
| 735 | |||
| 736 | void Flush() const; | ||
| 737 | |||
| 738 | void Invalidate() const; | ||
| 739 | |||
| 740 | void SetObjectNameEXT(const char* name) const; | ||
| 741 | |||
| 742 | private: | ||
| 743 | void Release() const noexcept; | ||
| 744 | |||
| 745 | VkBuffer handle = nullptr; | ||
| 746 | VkDevice owner = nullptr; | ||
| 747 | VmaAllocator allocator = nullptr; | ||
| 748 | VmaAllocation allocation = nullptr; | ||
| 749 | std::span<u8> mapped = {}; | ||
| 750 | bool is_coherent = false; | ||
| 751 | const DeviceDispatch* dld = nullptr; | ||
| 752 | }; | ||
| 753 | |||
| 619 | class Queue { | 754 | class Queue { |
| 620 | public: | 755 | public: |
| 621 | /// Construct an empty queue handle. | 756 | /// Construct an empty queue handle. |
| @@ -639,17 +774,6 @@ private: | |||
| 639 | const DeviceDispatch* dld = nullptr; | 774 | const DeviceDispatch* dld = nullptr; |
| 640 | }; | 775 | }; |
| 641 | 776 | ||
| 642 | class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> { | ||
| 643 | using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle; | ||
| 644 | |||
| 645 | public: | ||
| 646 | /// Attaches a memory allocation. | ||
| 647 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; | ||
| 648 | |||
| 649 | /// Set object name. | ||
| 650 | void SetObjectNameEXT(const char* name) const; | ||
| 651 | }; | ||
| 652 | |||
| 653 | class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> { | 777 | class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> { |
| 654 | using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle; | 778 | using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle; |
| 655 | 779 | ||
| @@ -658,17 +782,6 @@ public: | |||
| 658 | void SetObjectNameEXT(const char* name) const; | 782 | void SetObjectNameEXT(const char* name) const; |
| 659 | }; | 783 | }; |
| 660 | 784 | ||
| 661 | class Image : public Handle<VkImage, VkDevice, DeviceDispatch> { | ||
| 662 | using Handle<VkImage, VkDevice, DeviceDispatch>::Handle; | ||
| 663 | |||
| 664 | public: | ||
| 665 | /// Attaches a memory allocation. | ||
| 666 | void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; | ||
| 667 | |||
| 668 | /// Set object name. | ||
| 669 | void SetObjectNameEXT(const char* name) const; | ||
| 670 | }; | ||
| 671 | |||
| 672 | class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> { | 785 | class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> { |
| 673 | using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle; | 786 | using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle; |
| 674 | 787 | ||
| @@ -840,12 +953,8 @@ public: | |||
| 840 | 953 | ||
| 841 | Queue GetQueue(u32 family_index) const noexcept; | 954 | Queue GetQueue(u32 family_index) const noexcept; |
| 842 | 955 | ||
| 843 | Buffer CreateBuffer(const VkBufferCreateInfo& ci) const; | ||
| 844 | |||
| 845 | BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; | 956 | BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; |
| 846 | 957 | ||
| 847 | Image CreateImage(const VkImageCreateInfo& ci) const; | ||
| 848 | |||
| 849 | ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; | 958 | ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; |
| 850 | 959 | ||
| 851 | Semaphore CreateSemaphore() const; | 960 | Semaphore CreateSemaphore() const; |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 733c296e4..fe98e3605 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -98,6 +98,9 @@ add_executable(yuzu | |||
| 98 | configuration/configure_input_profile_dialog.cpp | 98 | configuration/configure_input_profile_dialog.cpp |
| 99 | configuration/configure_input_profile_dialog.h | 99 | configuration/configure_input_profile_dialog.h |
| 100 | configuration/configure_input_profile_dialog.ui | 100 | configuration/configure_input_profile_dialog.ui |
| 101 | configuration/configure_mouse_panning.cpp | ||
| 102 | configuration/configure_mouse_panning.h | ||
| 103 | configuration/configure_mouse_panning.ui | ||
| 101 | configuration/configure_motion_touch.cpp | 104 | configuration/configure_motion_touch.cpp |
| 102 | configuration/configure_motion_touch.h | 105 | configuration/configure_motion_touch.h |
| 103 | configuration/configure_motion_touch.ui | 106 | configuration/configure_motion_touch.ui |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index edc206a25..87ab88cfa 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -351,6 +351,10 @@ void Config::ReadPlayerValue(std::size_t player_index) { | |||
| 351 | player_motions = default_param; | 351 | player_motions = default_param; |
| 352 | } | 352 | } |
| 353 | } | 353 | } |
| 354 | |||
| 355 | if (player_index == 0) { | ||
| 356 | ReadMousePanningValues(); | ||
| 357 | } | ||
| 354 | } | 358 | } |
| 355 | 359 | ||
| 356 | void Config::ReadDebugValues() { | 360 | void Config::ReadDebugValues() { |
| @@ -471,6 +475,7 @@ void Config::ReadControlValues() { | |||
| 471 | ReadKeyboardValues(); | 475 | ReadKeyboardValues(); |
| 472 | ReadMouseValues(); | 476 | ReadMouseValues(); |
| 473 | ReadTouchscreenValues(); | 477 | ReadTouchscreenValues(); |
| 478 | ReadMousePanningValues(); | ||
| 474 | ReadMotionTouchValues(); | 479 | ReadMotionTouchValues(); |
| 475 | ReadHidbusValues(); | 480 | ReadHidbusValues(); |
| 476 | ReadIrCameraValues(); | 481 | ReadIrCameraValues(); |
| @@ -481,8 +486,6 @@ void Config::ReadControlValues() { | |||
| 481 | Settings::values.enable_raw_input = false; | 486 | Settings::values.enable_raw_input = false; |
| 482 | #endif | 487 | #endif |
| 483 | ReadBasicSetting(Settings::values.emulate_analog_keyboard); | 488 | ReadBasicSetting(Settings::values.emulate_analog_keyboard); |
| 484 | Settings::values.mouse_panning = false; | ||
| 485 | ReadBasicSetting(Settings::values.mouse_panning_sensitivity); | ||
| 486 | ReadBasicSetting(Settings::values.enable_joycon_driver); | 489 | ReadBasicSetting(Settings::values.enable_joycon_driver); |
| 487 | ReadBasicSetting(Settings::values.enable_procon_driver); | 490 | ReadBasicSetting(Settings::values.enable_procon_driver); |
| 488 | ReadBasicSetting(Settings::values.random_amiibo_id); | 491 | ReadBasicSetting(Settings::values.random_amiibo_id); |
| @@ -496,6 +499,16 @@ void Config::ReadControlValues() { | |||
| 496 | qt_config->endGroup(); | 499 | qt_config->endGroup(); |
| 497 | } | 500 | } |
| 498 | 501 | ||
| 502 | void Config::ReadMousePanningValues() { | ||
| 503 | ReadBasicSetting(Settings::values.mouse_panning); | ||
| 504 | ReadBasicSetting(Settings::values.mouse_panning_x_sensitivity); | ||
| 505 | ReadBasicSetting(Settings::values.mouse_panning_y_sensitivity); | ||
| 506 | ReadBasicSetting(Settings::values.mouse_panning_deadzone_x_counterweight); | ||
| 507 | ReadBasicSetting(Settings::values.mouse_panning_deadzone_y_counterweight); | ||
| 508 | ReadBasicSetting(Settings::values.mouse_panning_decay_strength); | ||
| 509 | ReadBasicSetting(Settings::values.mouse_panning_min_decay); | ||
| 510 | } | ||
| 511 | |||
| 499 | void Config::ReadMotionTouchValues() { | 512 | void Config::ReadMotionTouchValues() { |
| 500 | int num_touch_from_button_maps = | 513 | int num_touch_from_button_maps = |
| 501 | qt_config->beginReadArray(QStringLiteral("touch_from_button_maps")); | 514 | qt_config->beginReadArray(QStringLiteral("touch_from_button_maps")); |
| @@ -1064,6 +1077,10 @@ void Config::SavePlayerValue(std::size_t player_index) { | |||
| 1064 | QString::fromStdString(player.motions[i]), | 1077 | QString::fromStdString(player.motions[i]), |
| 1065 | QString::fromStdString(default_param)); | 1078 | QString::fromStdString(default_param)); |
| 1066 | } | 1079 | } |
| 1080 | |||
| 1081 | if (player_index == 0) { | ||
| 1082 | SaveMousePanningValues(); | ||
| 1083 | } | ||
| 1067 | } | 1084 | } |
| 1068 | 1085 | ||
| 1069 | void Config::SaveDebugValues() { | 1086 | void Config::SaveDebugValues() { |
| @@ -1100,6 +1117,16 @@ void Config::SaveTouchscreenValues() { | |||
| 1100 | WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); | 1117 | WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); |
| 1101 | } | 1118 | } |
| 1102 | 1119 | ||
| 1120 | void Config::SaveMousePanningValues() { | ||
| 1121 | // Don't overwrite values.mouse_panning | ||
| 1122 | WriteBasicSetting(Settings::values.mouse_panning_x_sensitivity); | ||
| 1123 | WriteBasicSetting(Settings::values.mouse_panning_y_sensitivity); | ||
| 1124 | WriteBasicSetting(Settings::values.mouse_panning_deadzone_x_counterweight); | ||
| 1125 | WriteBasicSetting(Settings::values.mouse_panning_deadzone_y_counterweight); | ||
| 1126 | WriteBasicSetting(Settings::values.mouse_panning_decay_strength); | ||
| 1127 | WriteBasicSetting(Settings::values.mouse_panning_min_decay); | ||
| 1128 | } | ||
| 1129 | |||
| 1103 | void Config::SaveMotionTouchValues() { | 1130 | void Config::SaveMotionTouchValues() { |
| 1104 | WriteBasicSetting(Settings::values.touch_device); | 1131 | WriteBasicSetting(Settings::values.touch_device); |
| 1105 | WriteBasicSetting(Settings::values.touch_from_button_map_index); | 1132 | WriteBasicSetting(Settings::values.touch_from_button_map_index); |
| @@ -1186,6 +1213,7 @@ void Config::SaveControlValues() { | |||
| 1186 | SaveDebugValues(); | 1213 | SaveDebugValues(); |
| 1187 | SaveMouseValues(); | 1214 | SaveMouseValues(); |
| 1188 | SaveTouchscreenValues(); | 1215 | SaveTouchscreenValues(); |
| 1216 | SaveMousePanningValues(); | ||
| 1189 | SaveMotionTouchValues(); | 1217 | SaveMotionTouchValues(); |
| 1190 | SaveHidbusValues(); | 1218 | SaveHidbusValues(); |
| 1191 | SaveIrCameraValues(); | 1219 | SaveIrCameraValues(); |
| @@ -1200,7 +1228,6 @@ void Config::SaveControlValues() { | |||
| 1200 | WriteBasicSetting(Settings::values.random_amiibo_id); | 1228 | WriteBasicSetting(Settings::values.random_amiibo_id); |
| 1201 | WriteBasicSetting(Settings::values.keyboard_enabled); | 1229 | WriteBasicSetting(Settings::values.keyboard_enabled); |
| 1202 | WriteBasicSetting(Settings::values.emulate_analog_keyboard); | 1230 | WriteBasicSetting(Settings::values.emulate_analog_keyboard); |
| 1203 | WriteBasicSetting(Settings::values.mouse_panning_sensitivity); | ||
| 1204 | WriteBasicSetting(Settings::values.controller_navigation); | 1231 | WriteBasicSetting(Settings::values.controller_navigation); |
| 1205 | 1232 | ||
| 1206 | WriteBasicSetting(Settings::values.tas_enable); | 1233 | WriteBasicSetting(Settings::values.tas_enable); |
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 0fd4baf6b..1211389d2 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h | |||
| @@ -74,6 +74,7 @@ private: | |||
| 74 | void ReadKeyboardValues(); | 74 | void ReadKeyboardValues(); |
| 75 | void ReadMouseValues(); | 75 | void ReadMouseValues(); |
| 76 | void ReadTouchscreenValues(); | 76 | void ReadTouchscreenValues(); |
| 77 | void ReadMousePanningValues(); | ||
| 77 | void ReadMotionTouchValues(); | 78 | void ReadMotionTouchValues(); |
| 78 | void ReadHidbusValues(); | 79 | void ReadHidbusValues(); |
| 79 | void ReadIrCameraValues(); | 80 | void ReadIrCameraValues(); |
| @@ -104,6 +105,7 @@ private: | |||
| 104 | void SaveDebugValues(); | 105 | void SaveDebugValues(); |
| 105 | void SaveMouseValues(); | 106 | void SaveMouseValues(); |
| 106 | void SaveTouchscreenValues(); | 107 | void SaveTouchscreenValues(); |
| 108 | void SaveMousePanningValues(); | ||
| 107 | void SaveMotionTouchValues(); | 109 | void SaveMotionTouchValues(); |
| 108 | void SaveHidbusValues(); | 110 | void SaveHidbusValues(); |
| 109 | void SaveIrCameraValues(); | 111 | void SaveIrCameraValues(); |
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index f13156434..3cfd5d439 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp | |||
| @@ -129,9 +129,6 @@ void ConfigureInputAdvanced::ApplyConfiguration() { | |||
| 129 | Settings::values.mouse_enabled = ui->mouse_enabled->isChecked(); | 129 | Settings::values.mouse_enabled = ui->mouse_enabled->isChecked(); |
| 130 | Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked(); | 130 | Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked(); |
| 131 | Settings::values.emulate_analog_keyboard = ui->emulate_analog_keyboard->isChecked(); | 131 | Settings::values.emulate_analog_keyboard = ui->emulate_analog_keyboard->isChecked(); |
| 132 | Settings::values.mouse_panning = ui->mouse_panning->isChecked(); | ||
| 133 | Settings::values.mouse_panning_sensitivity = | ||
| 134 | static_cast<float>(ui->mouse_panning_sensitivity->value()); | ||
| 135 | Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); | 132 | Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); |
| 136 | Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); | 133 | Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); |
| 137 | Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); | 134 | Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); |
| @@ -167,8 +164,6 @@ void ConfigureInputAdvanced::LoadConfiguration() { | |||
| 167 | ui->mouse_enabled->setChecked(Settings::values.mouse_enabled.GetValue()); | 164 | ui->mouse_enabled->setChecked(Settings::values.mouse_enabled.GetValue()); |
| 168 | ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled.GetValue()); | 165 | ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled.GetValue()); |
| 169 | ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue()); | 166 | ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue()); |
| 170 | ui->mouse_panning->setChecked(Settings::values.mouse_panning.GetValue()); | ||
| 171 | ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue()); | ||
| 172 | ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); | 167 | ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); |
| 173 | ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); | 168 | ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); |
| 174 | ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); | 169 | ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); |
| @@ -197,8 +192,6 @@ void ConfigureInputAdvanced::RetranslateUI() { | |||
| 197 | void ConfigureInputAdvanced::UpdateUIEnabled() { | 192 | void ConfigureInputAdvanced::UpdateUIEnabled() { |
| 198 | ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); | 193 | ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); |
| 199 | ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); | 194 | ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); |
| 200 | ui->mouse_panning->setEnabled(!ui->mouse_enabled->isChecked()); | ||
| 201 | ui->mouse_panning_sensitivity->setEnabled(!ui->mouse_enabled->isChecked()); | ||
| 202 | ui->ring_controller_configure->setEnabled(ui->enable_ring_controller->isChecked()); | 195 | ui->ring_controller_configure->setEnabled(ui->enable_ring_controller->isChecked()); |
| 203 | #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) || !defined(YUZU_USE_QT_MULTIMEDIA) | 196 | #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) || !defined(YUZU_USE_QT_MULTIMEDIA) |
| 204 | ui->enable_ir_sensor->setEnabled(false); | 197 | ui->enable_ir_sensor->setEnabled(false); |
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 2e8b13660..2994d0ab4 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui | |||
| @@ -2744,48 +2744,13 @@ | |||
| 2744 | </widget> | 2744 | </widget> |
| 2745 | </item> | 2745 | </item> |
| 2746 | <item row="8" column="0"> | 2746 | <item row="8" column="0"> |
| 2747 | <widget class="QCheckBox" name="mouse_panning"> | ||
| 2748 | <property name="minimumSize"> | ||
| 2749 | <size> | ||
| 2750 | <width>0</width> | ||
| 2751 | <height>23</height> | ||
| 2752 | </size> | ||
| 2753 | </property> | ||
| 2754 | <property name="text"> | ||
| 2755 | <string>Enable mouse panning</string> | ||
| 2756 | </property> | ||
| 2757 | </widget> | ||
| 2758 | </item> | ||
| 2759 | <item row="8" column="2"> | ||
| 2760 | <widget class="QSpinBox" name="mouse_panning_sensitivity"> | ||
| 2761 | <property name="toolTip"> | ||
| 2762 | <string>Mouse sensitivity</string> | ||
| 2763 | </property> | ||
| 2764 | <property name="alignment"> | ||
| 2765 | <set>Qt::AlignCenter</set> | ||
| 2766 | </property> | ||
| 2767 | <property name="suffix"> | ||
| 2768 | <string>%</string> | ||
| 2769 | </property> | ||
| 2770 | <property name="minimum"> | ||
| 2771 | <number>1</number> | ||
| 2772 | </property> | ||
| 2773 | <property name="maximum"> | ||
| 2774 | <number>100</number> | ||
| 2775 | </property> | ||
| 2776 | <property name="value"> | ||
| 2777 | <number>100</number> | ||
| 2778 | </property> | ||
| 2779 | </widget> | ||
| 2780 | </item> | ||
| 2781 | <item row="9" column="0"> | ||
| 2782 | <widget class="QLabel" name="motion_touch"> | 2747 | <widget class="QLabel" name="motion_touch"> |
| 2783 | <property name="text"> | 2748 | <property name="text"> |
| 2784 | <string>Motion / Touch</string> | 2749 | <string>Motion / Touch</string> |
| 2785 | </property> | 2750 | </property> |
| 2786 | </widget> | 2751 | </widget> |
| 2787 | </item> | 2752 | </item> |
| 2788 | <item row="9" column="2"> | 2753 | <item row="8" column="2"> |
| 2789 | <widget class="QPushButton" name="buttonMotionTouch"> | 2754 | <widget class="QPushButton" name="buttonMotionTouch"> |
| 2790 | <property name="text"> | 2755 | <property name="text"> |
| 2791 | <string>Configure</string> | 2756 | <string>Configure</string> |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 2c2e7e47b..576f5b571 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "yuzu/configuration/config.h" | 23 | #include "yuzu/configuration/config.h" |
| 24 | #include "yuzu/configuration/configure_input_player.h" | 24 | #include "yuzu/configuration/configure_input_player.h" |
| 25 | #include "yuzu/configuration/configure_input_player_widget.h" | 25 | #include "yuzu/configuration/configure_input_player_widget.h" |
| 26 | #include "yuzu/configuration/configure_mouse_panning.h" | ||
| 26 | #include "yuzu/configuration/input_profiles.h" | 27 | #include "yuzu/configuration/input_profiles.h" |
| 27 | #include "yuzu/util/limitable_input_dialog.h" | 28 | #include "yuzu/util/limitable_input_dialog.h" |
| 28 | 29 | ||
| @@ -711,6 +712,21 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 711 | }); | 712 | }); |
| 712 | } | 713 | } |
| 713 | 714 | ||
| 715 | if (player_index_ == 0) { | ||
| 716 | connect(ui->mousePanningButton, &QPushButton::clicked, [this, input_subsystem_] { | ||
| 717 | const auto right_stick_param = | ||
| 718 | emulated_controller->GetStickParam(Settings::NativeAnalog::RStick); | ||
| 719 | ConfigureMousePanning dialog(this, input_subsystem_, | ||
| 720 | right_stick_param.Get("deadzone", 0.0f), | ||
| 721 | right_stick_param.Get("range", 1.0f)); | ||
| 722 | if (dialog.exec() == QDialog::Accepted) { | ||
| 723 | dialog.ApplyConfiguration(); | ||
| 724 | } | ||
| 725 | }); | ||
| 726 | } else { | ||
| 727 | ui->mousePanningWidget->hide(); | ||
| 728 | } | ||
| 729 | |||
| 714 | // Player Connected checkbox | 730 | // Player Connected checkbox |
| 715 | connect(ui->groupConnectedController, &QGroupBox::toggled, | 731 | connect(ui->groupConnectedController, &QGroupBox::toggled, |
| 716 | [this](bool checked) { emit Connected(checked); }); | 732 | [this](bool checked) { emit Connected(checked); }); |
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index a9567c6ee..43f6c7b50 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui | |||
| @@ -3048,6 +3048,102 @@ | |||
| 3048 | </item> | 3048 | </item> |
| 3049 | </layout> | 3049 | </layout> |
| 3050 | </item> | 3050 | </item> |
| 3051 | <item> | ||
| 3052 | <widget class="QWidget" name="mousePanningWidget" native="true"> | ||
| 3053 | <layout class="QHBoxLayout" name="mousePanningHorizontalLayout"> | ||
| 3054 | <property name="spacing"> | ||
| 3055 | <number>0</number> | ||
| 3056 | </property> | ||
| 3057 | <property name="leftMargin"> | ||
| 3058 | <number>0</number> | ||
| 3059 | </property> | ||
| 3060 | <property name="topMargin"> | ||
| 3061 | <number>0</number> | ||
| 3062 | </property> | ||
| 3063 | <property name="rightMargin"> | ||
| 3064 | <number>0</number> | ||
| 3065 | </property> | ||
| 3066 | <property name="bottomMargin"> | ||
| 3067 | <number>3</number> | ||
| 3068 | </property> | ||
| 3069 | <item> | ||
| 3070 | <spacer name="mousePanningHorizontalSpacerLeft"> | ||
| 3071 | <property name="orientation"> | ||
| 3072 | <enum>Qt::Horizontal</enum> | ||
| 3073 | </property> | ||
| 3074 | <property name="sizeHint" stdset="0"> | ||
| 3075 | <size> | ||
| 3076 | <width>20</width> | ||
| 3077 | <height>20</height> | ||
| 3078 | </size> | ||
| 3079 | </property> | ||
| 3080 | </spacer> | ||
| 3081 | </item> | ||
| 3082 | <item> | ||
| 3083 | <widget class="QGroupBox" name="mousePanningGroup"> | ||
| 3084 | <property name="title"> | ||
| 3085 | <string>Mouse panning</string> | ||
| 3086 | </property> | ||
| 3087 | <property name="alignment"> | ||
| 3088 | <set>Qt::AlignCenter</set> | ||
| 3089 | </property> | ||
| 3090 | <layout class="QVBoxLayout" name="mousePanningVerticalLayout"> | ||
| 3091 | <property name="spacing"> | ||
| 3092 | <number>3</number> | ||
| 3093 | </property> | ||
| 3094 | <property name="leftMargin"> | ||
| 3095 | <number>3</number> | ||
| 3096 | </property> | ||
| 3097 | <property name="topMargin"> | ||
| 3098 | <number>3</number> | ||
| 3099 | </property> | ||
| 3100 | <property name="rightMargin"> | ||
| 3101 | <number>3</number> | ||
| 3102 | </property> | ||
| 3103 | <property name="bottomMargin"> | ||
| 3104 | <number>3</number> | ||
| 3105 | </property> | ||
| 3106 | <item> | ||
| 3107 | <widget class="QPushButton" name="mousePanningButton"> | ||
| 3108 | <property name="minimumSize"> | ||
| 3109 | <size> | ||
| 3110 | <width>68</width> | ||
| 3111 | <height>0</height> | ||
| 3112 | </size> | ||
| 3113 | </property> | ||
| 3114 | <property name="maximumSize"> | ||
| 3115 | <size> | ||
| 3116 | <width>68</width> | ||
| 3117 | <height>16777215</height> | ||
| 3118 | </size> | ||
| 3119 | </property> | ||
| 3120 | <property name="styleSheet"> | ||
| 3121 | <string notr="true">min-width: 68px;</string> | ||
| 3122 | </property> | ||
| 3123 | <property name="text"> | ||
| 3124 | <string>Configure</string> | ||
| 3125 | </property> | ||
| 3126 | </widget> | ||
| 3127 | </item> | ||
| 3128 | </layout> | ||
| 3129 | </widget> | ||
| 3130 | </item> | ||
| 3131 | <item> | ||
| 3132 | <spacer name="mousePanningHorizontalSpacerRight"> | ||
| 3133 | <property name="orientation"> | ||
| 3134 | <enum>Qt::Horizontal</enum> | ||
| 3135 | </property> | ||
| 3136 | <property name="sizeHint" stdset="0"> | ||
| 3137 | <size> | ||
| 3138 | <width>20</width> | ||
| 3139 | <height>20</height> | ||
| 3140 | </size> | ||
| 3141 | </property> | ||
| 3142 | </spacer> | ||
| 3143 | </item> | ||
| 3144 | </layout> | ||
| 3145 | </widget> | ||
| 3146 | </item> | ||
| 3051 | </layout> | 3147 | </layout> |
| 3052 | </widget> | 3148 | </widget> |
| 3053 | </item> | 3149 | </item> |
diff --git a/src/yuzu/configuration/configure_mouse_panning.cpp b/src/yuzu/configuration/configure_mouse_panning.cpp new file mode 100644 index 000000000..f183d2740 --- /dev/null +++ b/src/yuzu/configuration/configure_mouse_panning.cpp | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <QCloseEvent> | ||
| 5 | |||
| 6 | #include "common/settings.h" | ||
| 7 | #include "ui_configure_mouse_panning.h" | ||
| 8 | #include "yuzu/configuration/configure_mouse_panning.h" | ||
| 9 | |||
| 10 | ConfigureMousePanning::ConfigureMousePanning(QWidget* parent, | ||
| 11 | InputCommon::InputSubsystem* input_subsystem_, | ||
| 12 | float right_stick_deadzone, float right_stick_range) | ||
| 13 | : QDialog(parent), input_subsystem{input_subsystem_}, | ||
| 14 | ui(std::make_unique<Ui::ConfigureMousePanning>()) { | ||
| 15 | ui->setupUi(this); | ||
| 16 | SetConfiguration(right_stick_deadzone, right_stick_range); | ||
| 17 | ConnectEvents(); | ||
| 18 | } | ||
| 19 | |||
| 20 | ConfigureMousePanning::~ConfigureMousePanning() = default; | ||
| 21 | |||
| 22 | void ConfigureMousePanning::closeEvent(QCloseEvent* event) { | ||
| 23 | event->accept(); | ||
| 24 | } | ||
| 25 | |||
| 26 | void ConfigureMousePanning::SetConfiguration(float right_stick_deadzone, float right_stick_range) { | ||
| 27 | ui->enable->setChecked(Settings::values.mouse_panning.GetValue()); | ||
| 28 | ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetValue()); | ||
| 29 | ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetValue()); | ||
| 30 | ui->deadzone_x_counterweight->setValue( | ||
| 31 | Settings::values.mouse_panning_deadzone_x_counterweight.GetValue()); | ||
| 32 | ui->deadzone_y_counterweight->setValue( | ||
| 33 | Settings::values.mouse_panning_deadzone_y_counterweight.GetValue()); | ||
| 34 | ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetValue()); | ||
| 35 | ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetValue()); | ||
| 36 | |||
| 37 | if (right_stick_deadzone > 0.0f || right_stick_range != 1.0f) { | ||
| 38 | ui->warning_label->setText(QString::fromStdString( | ||
| 39 | "Mouse panning works better with a deadzone of 0% and a range of 100%.\n" | ||
| 40 | "Current values are " + | ||
| 41 | std::to_string(static_cast<int>(right_stick_deadzone * 100.0f)) + "% and " + | ||
| 42 | std::to_string(static_cast<int>(right_stick_range * 100.0f)) + "% respectively.")); | ||
| 43 | } else { | ||
| 44 | ui->warning_label->hide(); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | void ConfigureMousePanning::SetDefaultConfiguration() { | ||
| 49 | ui->x_sensitivity->setValue(Settings::values.mouse_panning_x_sensitivity.GetDefault()); | ||
| 50 | ui->y_sensitivity->setValue(Settings::values.mouse_panning_y_sensitivity.GetDefault()); | ||
| 51 | ui->deadzone_x_counterweight->setValue( | ||
| 52 | Settings::values.mouse_panning_deadzone_x_counterweight.GetDefault()); | ||
| 53 | ui->deadzone_y_counterweight->setValue( | ||
| 54 | Settings::values.mouse_panning_deadzone_y_counterweight.GetDefault()); | ||
| 55 | ui->decay_strength->setValue(Settings::values.mouse_panning_decay_strength.GetDefault()); | ||
| 56 | ui->min_decay->setValue(Settings::values.mouse_panning_min_decay.GetDefault()); | ||
| 57 | } | ||
| 58 | |||
| 59 | void ConfigureMousePanning::ConnectEvents() { | ||
| 60 | connect(ui->default_button, &QPushButton::clicked, this, | ||
| 61 | &ConfigureMousePanning::SetDefaultConfiguration); | ||
| 62 | connect(ui->button_box, &QDialogButtonBox::accepted, this, | ||
| 63 | &ConfigureMousePanning::ApplyConfiguration); | ||
| 64 | connect(ui->button_box, &QDialogButtonBox::rejected, this, [this] { reject(); }); | ||
| 65 | } | ||
| 66 | |||
| 67 | void ConfigureMousePanning::ApplyConfiguration() { | ||
| 68 | Settings::values.mouse_panning = ui->enable->isChecked(); | ||
| 69 | Settings::values.mouse_panning_x_sensitivity = static_cast<float>(ui->x_sensitivity->value()); | ||
| 70 | Settings::values.mouse_panning_y_sensitivity = static_cast<float>(ui->y_sensitivity->value()); | ||
| 71 | Settings::values.mouse_panning_deadzone_x_counterweight = | ||
| 72 | static_cast<float>(ui->deadzone_x_counterweight->value()); | ||
| 73 | Settings::values.mouse_panning_deadzone_y_counterweight = | ||
| 74 | static_cast<float>(ui->deadzone_y_counterweight->value()); | ||
| 75 | Settings::values.mouse_panning_decay_strength = static_cast<float>(ui->decay_strength->value()); | ||
| 76 | Settings::values.mouse_panning_min_decay = static_cast<float>(ui->min_decay->value()); | ||
| 77 | |||
| 78 | accept(); | ||
| 79 | } | ||
diff --git a/src/yuzu/configuration/configure_mouse_panning.h b/src/yuzu/configuration/configure_mouse_panning.h new file mode 100644 index 000000000..08c6e1f62 --- /dev/null +++ b/src/yuzu/configuration/configure_mouse_panning.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | #include <QDialog> | ||
| 8 | |||
| 9 | namespace InputCommon { | ||
| 10 | class InputSubsystem; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Ui { | ||
| 14 | class ConfigureMousePanning; | ||
| 15 | } | ||
| 16 | |||
| 17 | class ConfigureMousePanning : public QDialog { | ||
| 18 | Q_OBJECT | ||
| 19 | public: | ||
| 20 | explicit ConfigureMousePanning(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_, | ||
| 21 | float right_stick_deadzone, float right_stick_range); | ||
| 22 | ~ConfigureMousePanning() override; | ||
| 23 | |||
| 24 | public slots: | ||
| 25 | void ApplyConfiguration(); | ||
| 26 | |||
| 27 | private: | ||
| 28 | void closeEvent(QCloseEvent* event) override; | ||
| 29 | void SetConfiguration(float right_stick_deadzone, float right_stick_range); | ||
| 30 | void SetDefaultConfiguration(); | ||
| 31 | void ConnectEvents(); | ||
| 32 | |||
| 33 | InputCommon::InputSubsystem* input_subsystem; | ||
| 34 | std::unique_ptr<Ui::ConfigureMousePanning> ui; | ||
| 35 | }; | ||
diff --git a/src/yuzu/configuration/configure_mouse_panning.ui b/src/yuzu/configuration/configure_mouse_panning.ui new file mode 100644 index 000000000..75795b727 --- /dev/null +++ b/src/yuzu/configuration/configure_mouse_panning.ui | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ConfigureMousePanning</class> | ||
| 4 | <widget class="QDialog" name="configure_mouse_panning"> | ||
| 5 | <property name="windowTitle"> | ||
| 6 | <string>Configure mouse panning</string> | ||
| 7 | </property> | ||
| 8 | <layout class="QVBoxLayout"> | ||
| 9 | <item> | ||
| 10 | <widget class="QCheckBox" name="enable"> | ||
| 11 | <property name="text"> | ||
| 12 | <string>Enable</string> | ||
| 13 | </property> | ||
| 14 | <property name="toolTip"> | ||
| 15 | <string>Can be toggled via a hotkey</string> | ||
| 16 | </property> | ||
| 17 | </widget> | ||
| 18 | </item> | ||
| 19 | <item> | ||
| 20 | <layout class="QHBoxLayout"> | ||
| 21 | <item> | ||
| 22 | <widget class="QGroupBox" name="sensitivity_box"> | ||
| 23 | <property name="title"> | ||
| 24 | <string>Sensitivity</string> | ||
| 25 | </property> | ||
| 26 | <layout class="QGridLayout"> | ||
| 27 | <item row="0" column="0"> | ||
| 28 | <widget class="QLabel" name="x_sensitivity_label"> | ||
| 29 | <property name="text"> | ||
| 30 | <string>Horizontal</string> | ||
| 31 | </property> | ||
| 32 | </widget> | ||
| 33 | </item> | ||
| 34 | <item row="0" column="1"> | ||
| 35 | <widget class="QSpinBox" name="x_sensitivity"> | ||
| 36 | <property name="alignment"> | ||
| 37 | <set>Qt::AlignCenter</set> | ||
| 38 | </property> | ||
| 39 | <property name="suffix"> | ||
| 40 | <string>%</string> | ||
| 41 | </property> | ||
| 42 | <property name="minimum"> | ||
| 43 | <number>1</number> | ||
| 44 | </property> | ||
| 45 | <property name="maximum"> | ||
| 46 | <number>100</number> | ||
| 47 | </property> | ||
| 48 | <property name="value"> | ||
| 49 | <number>50</number> | ||
| 50 | </property> | ||
| 51 | </widget> | ||
| 52 | </item> | ||
| 53 | <item row="1" column="0"> | ||
| 54 | <widget class="QLabel" name="y_sensitivity_label"> | ||
| 55 | <property name="text"> | ||
| 56 | <string>Vertical</string> | ||
| 57 | </property> | ||
| 58 | </widget> | ||
| 59 | </item> | ||
| 60 | <item row="1" column="1"> | ||
| 61 | <widget class="QSpinBox" name="y_sensitivity"> | ||
| 62 | <property name="alignment"> | ||
| 63 | <set>Qt::AlignCenter</set> | ||
| 64 | </property> | ||
| 65 | <property name="suffix"> | ||
| 66 | <string>%</string> | ||
| 67 | </property> | ||
| 68 | <property name="minimum"> | ||
| 69 | <number>1</number> | ||
| 70 | </property> | ||
| 71 | <property name="maximum"> | ||
| 72 | <number>100</number> | ||
| 73 | </property> | ||
| 74 | <property name="value"> | ||
| 75 | <number>50</number> | ||
| 76 | </property> | ||
| 77 | </widget> | ||
| 78 | </item> | ||
| 79 | </layout> | ||
| 80 | </widget> | ||
| 81 | </item> | ||
| 82 | <item> | ||
| 83 | <widget class="QGroupBox" name="deadzone_counterweight_box"> | ||
| 84 | <property name="title"> | ||
| 85 | <string>Deadzone counterweight</string> | ||
| 86 | </property> | ||
| 87 | <property name="toolTip"> | ||
| 88 | <string>Counteracts a game's built-in deadzone</string> | ||
| 89 | </property> | ||
| 90 | <layout class="QGridLayout"> | ||
| 91 | <item row="0" column="0"> | ||
| 92 | <widget class="QLabel" name="deadzone_x_counterweight_label"> | ||
| 93 | <property name="text"> | ||
| 94 | <string>Horizontal</string> | ||
| 95 | </property> | ||
| 96 | </widget> | ||
| 97 | </item> | ||
| 98 | <item row="0" column="1"> | ||
| 99 | <widget class="QSpinBox" name="deadzone_x_counterweight"> | ||
| 100 | <property name="alignment"> | ||
| 101 | <set>Qt::AlignCenter</set> | ||
| 102 | </property> | ||
| 103 | <property name="suffix"> | ||
| 104 | <string>%</string> | ||
| 105 | </property> | ||
| 106 | <property name="minimum"> | ||
| 107 | <number>0</number> | ||
| 108 | </property> | ||
| 109 | <property name="maximum"> | ||
| 110 | <number>100</number> | ||
| 111 | </property> | ||
| 112 | <property name="value"> | ||
| 113 | <number>0</number> | ||
| 114 | </property> | ||
| 115 | </widget> | ||
| 116 | </item> | ||
| 117 | <item row="1" column="0"> | ||
| 118 | <widget class="QLabel" name="deadzone_y_counterweight_label"> | ||
| 119 | <property name="text"> | ||
| 120 | <string>Vertical</string> | ||
| 121 | </property> | ||
| 122 | </widget> | ||
| 123 | </item> | ||
| 124 | <item row="1" column="1"> | ||
| 125 | <widget class="QSpinBox" name="deadzone_y_counterweight"> | ||
| 126 | <property name="alignment"> | ||
| 127 | <set>Qt::AlignCenter</set> | ||
| 128 | </property> | ||
| 129 | <property name="suffix"> | ||
| 130 | <string>%</string> | ||
| 131 | </property> | ||
| 132 | <property name="minimum"> | ||
| 133 | <number>0</number> | ||
| 134 | </property> | ||
| 135 | <property name="maximum"> | ||
| 136 | <number>100</number> | ||
| 137 | </property> | ||
| 138 | <property name="value"> | ||
| 139 | <number>0</number> | ||
| 140 | </property> | ||
| 141 | </widget> | ||
| 142 | </item> | ||
| 143 | </layout> | ||
| 144 | </widget> | ||
| 145 | </item> | ||
| 146 | <item> | ||
| 147 | <widget class="QGroupBox" name="decay_box"> | ||
| 148 | <property name="title"> | ||
| 149 | <string>Stick decay</string> | ||
| 150 | </property> | ||
| 151 | <layout class="QGridLayout"> | ||
| 152 | <item row="0" column="0"> | ||
| 153 | <widget class="QLabel" name="decay_strength_label"> | ||
| 154 | <property name="text"> | ||
| 155 | <string>Strength</string> | ||
| 156 | </property> | ||
| 157 | </widget> | ||
| 158 | </item> | ||
| 159 | <item row="0" column="1"> | ||
| 160 | <widget class="QSpinBox" name="decay_strength"> | ||
| 161 | <property name="alignment"> | ||
| 162 | <set>Qt::AlignCenter</set> | ||
| 163 | </property> | ||
| 164 | <property name="suffix"> | ||
| 165 | <string>%</string> | ||
| 166 | </property> | ||
| 167 | <property name="minimum"> | ||
| 168 | <number>0</number> | ||
| 169 | </property> | ||
| 170 | <property name="maximum"> | ||
| 171 | <number>100</number> | ||
| 172 | </property> | ||
| 173 | <property name="value"> | ||
| 174 | <number>22</number> | ||
| 175 | </property> | ||
| 176 | </widget> | ||
| 177 | </item> | ||
| 178 | <item row="1" column="0"> | ||
| 179 | <widget class="QLabel" name="min_decay_label"> | ||
| 180 | <property name="text"> | ||
| 181 | <string>Minimum</string> | ||
| 182 | </property> | ||
| 183 | </widget> | ||
| 184 | </item> | ||
| 185 | <item row="1" column="1"> | ||
| 186 | <widget class="QSpinBox" name="min_decay"> | ||
| 187 | <property name="alignment"> | ||
| 188 | <set>Qt::AlignCenter</set> | ||
| 189 | </property> | ||
| 190 | <property name="suffix"> | ||
| 191 | <string>%</string> | ||
| 192 | </property> | ||
| 193 | <property name="minimum"> | ||
| 194 | <number>0</number> | ||
| 195 | </property> | ||
| 196 | <property name="maximum"> | ||
| 197 | <number>100</number> | ||
| 198 | </property> | ||
| 199 | <property name="value"> | ||
| 200 | <number>5</number> | ||
| 201 | </property> | ||
| 202 | </widget> | ||
| 203 | </item> | ||
| 204 | </layout> | ||
| 205 | </widget> | ||
| 206 | </item> | ||
| 207 | </layout> | ||
| 208 | </item> | ||
| 209 | <item> | ||
| 210 | <widget class="QLabel" name="warning_label"> | ||
| 211 | <property name="text"> | ||
| 212 | <string/> | ||
| 213 | </property> | ||
| 214 | </widget> | ||
| 215 | </item> | ||
| 216 | <item> | ||
| 217 | <layout class="QHBoxLayout"> | ||
| 218 | <item> | ||
| 219 | <widget class="QPushButton" name="default_button"> | ||
| 220 | <property name="text"> | ||
| 221 | <string>Default</string> | ||
| 222 | </property> | ||
| 223 | </widget> | ||
| 224 | </item> | ||
| 225 | <item> | ||
| 226 | <widget class="QDialogButtonBox" name="button_box"> | ||
| 227 | <property name="standardButtons"> | ||
| 228 | <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||
| 229 | </property> | ||
| 230 | </widget> | ||
| 231 | </item> | ||
| 232 | </layout> | ||
| 233 | </item> | ||
| 234 | </layout> | ||
| 235 | </widget> | ||
| 236 | <resources/> | ||
| 237 | <connections/> | ||
| 238 | </ui> | ||
diff --git a/src/yuzu/configuration/configure_ringcon.ui b/src/yuzu/configuration/configure_ringcon.ui index 514dff372..38ecccc3d 100644 --- a/src/yuzu/configuration/configure_ringcon.ui +++ b/src/yuzu/configuration/configure_ringcon.ui | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | </size> | 23 | </size> |
| 24 | </property> | 24 | </property> |
| 25 | <property name="text"> | 25 | <property name="text"> |
| 26 | <string>If you want to use this controller configure player 1 as right controller and player 2 as dual joycon before starting the game to allow this controller to be detected properly.</string> | 26 | <string>To use Ring-Con, configure player 1 as right Joy-Con (both physical and emulated), and player 2 as left Joy-Con (left physical and dual emulated) before starting the game.</string> |
| 27 | </property> | 27 | </property> |
| 28 | <property name="wordWrap"> | 28 | <property name="wordWrap"> |
| 29 | <bool>true</bool> | 29 | <bool>true</bool> |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 45a39451d..2133f7343 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -447,6 +447,14 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan | |||
| 447 | 447 | ||
| 448 | #if defined(HAVE_SDL2) && !defined(_WIN32) | 448 | #if defined(HAVE_SDL2) && !defined(_WIN32) |
| 449 | SDL_InitSubSystem(SDL_INIT_VIDEO); | 449 | SDL_InitSubSystem(SDL_INIT_VIDEO); |
| 450 | |||
| 451 | // Set a screensaver inhibition reason string. Currently passed to DBus by SDL and visible to | ||
| 452 | // the user through their desktop environment. | ||
| 453 | //: TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the | ||
| 454 | //: computer from sleeping | ||
| 455 | QByteArray wakelock_reason = tr("Running a game").toLatin1(); | ||
| 456 | SDL_SetHint(SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME, wakelock_reason.data()); | ||
| 457 | |||
| 450 | // SDL disables the screen saver by default, and setting the hint | 458 | // SDL disables the screen saver by default, and setting the hint |
| 451 | // SDL_HINT_VIDEO_ALLOW_SCREENSAVER doesn't seem to work, so we just enable the screen saver | 459 | // SDL_HINT_VIDEO_ALLOW_SCREENSAVER doesn't seem to work, so we just enable the screen saver |
| 452 | // for now. | 460 | // for now. |
| @@ -1623,45 +1631,6 @@ void GMainWindow::OnPrepareForSleep(bool prepare_sleep) { | |||
| 1623 | } | 1631 | } |
| 1624 | 1632 | ||
| 1625 | #ifdef __unix__ | 1633 | #ifdef __unix__ |
| 1626 | static std::optional<QDBusObjectPath> HoldWakeLockLinux(u32 window_id = 0) { | ||
| 1627 | if (!QDBusConnection::sessionBus().isConnected()) { | ||
| 1628 | return {}; | ||
| 1629 | } | ||
| 1630 | // reference: https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Inhibit | ||
| 1631 | QDBusInterface xdp(QString::fromLatin1("org.freedesktop.portal.Desktop"), | ||
| 1632 | QString::fromLatin1("/org/freedesktop/portal/desktop"), | ||
| 1633 | QString::fromLatin1("org.freedesktop.portal.Inhibit")); | ||
| 1634 | if (!xdp.isValid()) { | ||
| 1635 | LOG_WARNING(Frontend, "Couldn't connect to XDP D-Bus endpoint"); | ||
| 1636 | return {}; | ||
| 1637 | } | ||
| 1638 | QVariantMap options = {}; | ||
| 1639 | //: TRANSLATORS: This string is shown to the user to explain why yuzu needs to prevent the | ||
| 1640 | //: computer from sleeping | ||
| 1641 | options.insert(QString::fromLatin1("reason"), | ||
| 1642 | QCoreApplication::translate("GMainWindow", "yuzu is running a game")); | ||
| 1643 | // 0x4: Suspend lock; 0x8: Idle lock | ||
| 1644 | QDBusReply<QDBusObjectPath> reply = | ||
| 1645 | xdp.call(QString::fromLatin1("Inhibit"), | ||
| 1646 | QString::fromLatin1("x11:") + QString::number(window_id, 16), 12U, options); | ||
| 1647 | |||
| 1648 | if (reply.isValid()) { | ||
| 1649 | return reply.value(); | ||
| 1650 | } | ||
| 1651 | LOG_WARNING(Frontend, "Couldn't read Inhibit reply from XDP: {}", | ||
| 1652 | reply.error().message().toStdString()); | ||
| 1653 | return {}; | ||
| 1654 | } | ||
| 1655 | |||
| 1656 | static void ReleaseWakeLockLinux(QDBusObjectPath lock) { | ||
| 1657 | if (!QDBusConnection::sessionBus().isConnected()) { | ||
| 1658 | return; | ||
| 1659 | } | ||
| 1660 | QDBusInterface unlocker(QString::fromLatin1("org.freedesktop.portal.Desktop"), lock.path(), | ||
| 1661 | QString::fromLatin1("org.freedesktop.portal.Request")); | ||
| 1662 | unlocker.call(QString::fromLatin1("Close")); | ||
| 1663 | } | ||
| 1664 | |||
| 1665 | std::array<int, 3> GMainWindow::sig_interrupt_fds{0, 0, 0}; | 1634 | std::array<int, 3> GMainWindow::sig_interrupt_fds{0, 0, 0}; |
| 1666 | 1635 | ||
| 1667 | void GMainWindow::SetupSigInterrupts() { | 1636 | void GMainWindow::SetupSigInterrupts() { |
| @@ -1714,12 +1683,6 @@ void GMainWindow::PreventOSSleep() { | |||
| 1714 | SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); | 1683 | SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); |
| 1715 | #elif defined(HAVE_SDL2) | 1684 | #elif defined(HAVE_SDL2) |
| 1716 | SDL_DisableScreenSaver(); | 1685 | SDL_DisableScreenSaver(); |
| 1717 | #ifdef __unix__ | ||
| 1718 | auto reply = HoldWakeLockLinux(winId()); | ||
| 1719 | if (reply) { | ||
| 1720 | wake_lock = std::move(reply.value()); | ||
| 1721 | } | ||
| 1722 | #endif | ||
| 1723 | #endif | 1686 | #endif |
| 1724 | } | 1687 | } |
| 1725 | 1688 | ||
| @@ -1728,11 +1691,6 @@ void GMainWindow::AllowOSSleep() { | |||
| 1728 | SetThreadExecutionState(ES_CONTINUOUS); | 1691 | SetThreadExecutionState(ES_CONTINUOUS); |
| 1729 | #elif defined(HAVE_SDL2) | 1692 | #elif defined(HAVE_SDL2) |
| 1730 | SDL_EnableScreenSaver(); | 1693 | SDL_EnableScreenSaver(); |
| 1731 | #ifdef __unix__ | ||
| 1732 | if (!wake_lock.path().isEmpty()) { | ||
| 1733 | ReleaseWakeLockLinux(wake_lock); | ||
| 1734 | } | ||
| 1735 | #endif | ||
| 1736 | #endif | 1694 | #endif |
| 1737 | } | 1695 | } |
| 1738 | 1696 | ||
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index e0e775d87..2cfb96257 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -504,8 +504,6 @@ private: | |||
| 504 | #ifdef __unix__ | 504 | #ifdef __unix__ |
| 505 | QSocketNotifier* sig_interrupt_notifier; | 505 | QSocketNotifier* sig_interrupt_notifier; |
| 506 | static std::array<int, 3> sig_interrupt_fds; | 506 | static std::array<int, 3> sig_interrupt_fds; |
| 507 | |||
| 508 | QDBusObjectPath wake_lock{}; | ||
| 509 | #endif | 507 | #endif |
| 510 | 508 | ||
| 511 | protected: | 509 | protected: |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 911d461e4..119e22183 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -140,9 +140,29 @@ udp_input_servers = | |||
| 140 | # 0 (default): Off, 1: On | 140 | # 0 (default): Off, 1: On |
| 141 | mouse_panning = | 141 | mouse_panning = |
| 142 | 142 | ||
| 143 | # Set mouse sensitivity. | 143 | # Set mouse panning horizontal sensitivity. |
| 144 | # Default: 1.0 | 144 | # Default: 50.0 |
| 145 | mouse_panning_sensitivity = | 145 | mouse_panning_x_sensitivity = |
| 146 | |||
| 147 | # Set mouse panning vertical sensitivity. | ||
| 148 | # Default: 50.0 | ||
| 149 | mouse_panning_y_sensitivity = | ||
| 150 | |||
| 151 | # Set mouse panning deadzone horizontal counterweight. | ||
| 152 | # Default: 0.0 | ||
| 153 | mouse_panning_deadzone_x_counterweight = | ||
| 154 | |||
| 155 | # Set mouse panning deadzone vertical counterweight. | ||
| 156 | # Default: 0.0 | ||
| 157 | mouse_panning_deadzone_y_counterweight = | ||
| 158 | |||
| 159 | # Set mouse panning stick decay strength. | ||
| 160 | # Default: 22.0 | ||
| 161 | mouse_panning_decay_strength = | ||
| 162 | |||
| 163 | # Set mouse panning stick minimum decay. | ||
| 164 | # Default: 5.0 | ||
| 165 | mouse_panning_minimum_decay = | ||
| 146 | 166 | ||
| 147 | # Emulate an analog control stick from keyboard inputs. | 167 | # Emulate an analog control stick from keyboard inputs. |
| 148 | # 0 (default): Disabled, 1: Enabled | 168 | # 0 (default): Disabled, 1: Enabled |