diff options
Diffstat (limited to 'src')
24 files changed, 395 insertions, 151 deletions
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 13bb227ff..d4698ae1c 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts | |||
| @@ -74,16 +74,7 @@ android { | |||
| 74 | 74 | ||
| 75 | // Signed by release key, allowing for upload to Play Store. | 75 | // Signed by release key, allowing for upload to Play Store. |
| 76 | release { | 76 | release { |
| 77 | signingConfig = signingConfigs.getByName("debug") | 77 | resValue("string", "app_name_suffixed", "yuzu") |
| 78 | isMinifyEnabled = true | ||
| 79 | isDebuggable = false | ||
| 80 | proguardFiles( | ||
| 81 | getDefaultProguardFile("proguard-android.txt"), | ||
| 82 | "proguard-rules.pro" | ||
| 83 | ) | ||
| 84 | } | ||
| 85 | |||
| 86 | register("relWithVersionCode") { | ||
| 87 | signingConfig = signingConfigs.getByName("debug") | 78 | signingConfig = signingConfigs.getByName("debug") |
| 88 | isMinifyEnabled = true | 79 | isMinifyEnabled = true |
| 89 | isDebuggable = false | 80 | isDebuggable = false |
| @@ -96,6 +87,7 @@ android { | |||
| 96 | // builds a release build that doesn't need signing | 87 | // builds a release build that doesn't need signing |
| 97 | // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. | 88 | // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. |
| 98 | register("relWithDebInfo") { | 89 | register("relWithDebInfo") { |
| 90 | resValue("string", "app_name_suffixed", "yuzu Debug Release") | ||
| 99 | signingConfig = signingConfigs.getByName("debug") | 91 | signingConfig = signingConfigs.getByName("debug") |
| 100 | isMinifyEnabled = true | 92 | isMinifyEnabled = true |
| 101 | isDebuggable = true | 93 | isDebuggable = true |
| @@ -103,16 +95,19 @@ android { | |||
| 103 | getDefaultProguardFile("proguard-android.txt"), | 95 | getDefaultProguardFile("proguard-android.txt"), |
| 104 | "proguard-rules.pro" | 96 | "proguard-rules.pro" |
| 105 | ) | 97 | ) |
| 106 | versionNameSuffix = "-debug" | 98 | versionNameSuffix = "-relWithDebInfo" |
| 99 | applicationIdSuffix = ".relWithDebInfo" | ||
| 107 | isJniDebuggable = true | 100 | isJniDebuggable = true |
| 108 | } | 101 | } |
| 109 | 102 | ||
| 110 | // Signed by debug key disallowing distribution on Play Store. | 103 | // Signed by debug key disallowing distribution on Play Store. |
| 111 | // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. | 104 | // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. |
| 112 | debug { | 105 | debug { |
| 106 | resValue("string", "app_name_suffixed", "yuzu Debug") | ||
| 113 | isDebuggable = true | 107 | isDebuggable = true |
| 114 | isJniDebuggable = true | 108 | isJniDebuggable = true |
| 115 | versionNameSuffix = "-debug" | 109 | versionNameSuffix = "-debug" |
| 110 | applicationIdSuffix = ".debug" | ||
| 116 | } | 111 | } |
| 117 | } | 112 | } |
| 118 | 113 | ||
| @@ -162,19 +157,19 @@ dependencies { | |||
| 162 | implementation("androidx.appcompat:appcompat:1.6.1") | 157 | implementation("androidx.appcompat:appcompat:1.6.1") |
| 163 | implementation("androidx.recyclerview:recyclerview:1.3.0") | 158 | implementation("androidx.recyclerview:recyclerview:1.3.0") |
| 164 | implementation("androidx.constraintlayout:constraintlayout:2.1.4") | 159 | implementation("androidx.constraintlayout:constraintlayout:2.1.4") |
| 165 | implementation("androidx.fragment:fragment-ktx:1.5.7") | 160 | implementation("androidx.fragment:fragment-ktx:1.6.0") |
| 166 | implementation("androidx.documentfile:documentfile:1.0.1") | 161 | implementation("androidx.documentfile:documentfile:1.0.1") |
| 167 | implementation("com.google.android.material:material:1.9.0") | 162 | implementation("com.google.android.material:material:1.9.0") |
| 168 | implementation("androidx.preference:preference:1.2.0") | 163 | implementation("androidx.preference:preference:1.2.0") |
| 169 | implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1") | 164 | implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1") |
| 170 | implementation("io.coil-kt:coil:2.2.2") | 165 | implementation("io.coil-kt:coil:2.2.2") |
| 171 | implementation("androidx.core:core-splashscreen:1.0.1") | 166 | implementation("androidx.core:core-splashscreen:1.0.1") |
| 172 | implementation("androidx.window:window:1.0.0") | 167 | implementation("androidx.window:window:1.1.0") |
| 173 | implementation("org.ini4j:ini4j:0.5.4") | 168 | implementation("org.ini4j:ini4j:0.5.4") |
| 174 | implementation("androidx.constraintlayout:constraintlayout:2.1.4") | 169 | implementation("androidx.constraintlayout:constraintlayout:2.1.4") |
| 175 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") | 170 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") |
| 176 | implementation("androidx.navigation:navigation-fragment-ktx:2.5.3") | 171 | implementation("androidx.navigation:navigation-fragment-ktx:2.6.0") |
| 177 | implementation("androidx.navigation:navigation-ui-ktx:2.5.3") | 172 | implementation("androidx.navigation:navigation-ui-ktx:2.6.0") |
| 178 | implementation("info.debatty:java-string-similarity:2.0.0") | 173 | implementation("info.debatty:java-string-similarity:2.0.0") |
| 179 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") | 174 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") |
| 180 | } | 175 | } |
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index eef566042..1e92098ec 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml | |||
| @@ -18,7 +18,7 @@ SPDX-License-Identifier: GPL-3.0-or-later | |||
| 18 | 18 | ||
| 19 | <application | 19 | <application |
| 20 | android:name="org.yuzu.yuzu_emu.YuzuApplication" | 20 | android:name="org.yuzu.yuzu_emu.YuzuApplication" |
| 21 | android:label="@string/app_name" | 21 | android:label="@string/app_name_suffixed" |
| 22 | android:icon="@drawable/ic_launcher" | 22 | android:icon="@drawable/ic_launcher" |
| 23 | android:allowBackup="true" | 23 | android:allowBackup="true" |
| 24 | android:hasFragileUserData="true" | 24 | android:hasFragileUserData="true" |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index f4db61cb3..20a0394f5 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt | |||
| @@ -6,15 +6,12 @@ package org.yuzu.yuzu_emu.activities | |||
| 6 | import android.app.Activity | 6 | import android.app.Activity |
| 7 | import android.content.Context | 7 | import android.content.Context |
| 8 | import android.content.Intent | 8 | import android.content.Intent |
| 9 | import android.content.res.Configuration | ||
| 10 | import android.graphics.Rect | 9 | import android.graphics.Rect |
| 11 | import android.hardware.Sensor | 10 | import android.hardware.Sensor |
| 12 | import android.hardware.SensorEvent | 11 | import android.hardware.SensorEvent |
| 13 | import android.hardware.SensorEventListener | 12 | import android.hardware.SensorEventListener |
| 14 | import android.hardware.SensorManager | 13 | import android.hardware.SensorManager |
| 15 | import android.hardware.display.DisplayManager | ||
| 16 | import android.os.Bundle | 14 | import android.os.Bundle |
| 17 | import android.view.Display | ||
| 18 | import android.view.InputDevice | 15 | import android.view.InputDevice |
| 19 | import android.view.KeyEvent | 16 | import android.view.KeyEvent |
| 20 | import android.view.MotionEvent | 17 | import android.view.MotionEvent |
| @@ -23,7 +20,6 @@ import android.view.View | |||
| 23 | import android.view.inputmethod.InputMethodManager | 20 | import android.view.inputmethod.InputMethodManager |
| 24 | import androidx.activity.viewModels | 21 | import androidx.activity.viewModels |
| 25 | import androidx.appcompat.app.AppCompatActivity | 22 | import androidx.appcompat.app.AppCompatActivity |
| 26 | import androidx.core.content.getSystemService | ||
| 27 | import androidx.core.view.WindowCompat | 23 | import androidx.core.view.WindowCompat |
| 28 | import androidx.core.view.WindowInsetsCompat | 24 | import androidx.core.view.WindowInsetsCompat |
| 29 | import androidx.core.view.WindowInsetsControllerCompat | 25 | import androidx.core.view.WindowInsetsControllerCompat |
| @@ -39,7 +35,6 @@ import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel | |||
| 39 | import org.yuzu.yuzu_emu.fragments.EmulationFragment | 35 | import org.yuzu.yuzu_emu.fragments.EmulationFragment |
| 40 | import org.yuzu.yuzu_emu.model.Game | 36 | import org.yuzu.yuzu_emu.model.Game |
| 41 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper | 37 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper |
| 42 | import org.yuzu.yuzu_emu.utils.EmulationMenuSettings | ||
| 43 | import org.yuzu.yuzu_emu.utils.ForegroundService | 38 | import org.yuzu.yuzu_emu.utils.ForegroundService |
| 44 | import org.yuzu.yuzu_emu.utils.InputHandler | 39 | import org.yuzu.yuzu_emu.utils.InputHandler |
| 45 | import org.yuzu.yuzu_emu.utils.NfcReader | 40 | import org.yuzu.yuzu_emu.utils.NfcReader |
| @@ -148,11 +143,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 148 | super.onResume() | 143 | super.onResume() |
| 149 | nfcReader.startScanning() | 144 | nfcReader.startScanning() |
| 150 | startMotionSensorListener() | 145 | startMotionSensorListener() |
| 151 | |||
| 152 | NativeLibrary.notifyOrientationChange( | ||
| 153 | EmulationMenuSettings.landscapeScreenLayout, | ||
| 154 | getAdjustedRotation() | ||
| 155 | ) | ||
| 156 | } | 146 | } |
| 157 | 147 | ||
| 158 | override fun onPause() { | 148 | override fun onPause() { |
| @@ -258,24 +248,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 258 | 248 | ||
| 259 | override fun onAccuracyChanged(sensor: Sensor, i: Int) {} | 249 | override fun onAccuracyChanged(sensor: Sensor, i: Int) {} |
| 260 | 250 | ||
| 261 | private fun getAdjustedRotation():Int { | ||
| 262 | val rotation = getSystemService<DisplayManager>()!!.getDisplay(Display.DEFAULT_DISPLAY).rotation | ||
| 263 | val config: Configuration = resources.configuration | ||
| 264 | |||
| 265 | if ((config.screenLayout and Configuration.SCREENLAYOUT_LONG_YES) != 0 || | ||
| 266 | (config.screenLayout and Configuration.SCREENLAYOUT_LONG_NO) == 0 || | ||
| 267 | (config.screenLayout and Configuration.SCREENLAYOUT_SIZE_SMALL) != 0) { | ||
| 268 | return rotation | ||
| 269 | } | ||
| 270 | when (rotation) { | ||
| 271 | Surface.ROTATION_0 -> return Surface.ROTATION_90 | ||
| 272 | Surface.ROTATION_90 -> return Surface.ROTATION_0 | ||
| 273 | Surface.ROTATION_180 -> return Surface.ROTATION_270 | ||
| 274 | Surface.ROTATION_270 -> return Surface.ROTATION_180 | ||
| 275 | } | ||
| 276 | return rotation | ||
| 277 | } | ||
| 278 | |||
| 279 | private fun restoreState(savedInstanceState: Bundle) { | 251 | private fun restoreState(savedInstanceState: Bundle) { |
| 280 | game = savedInstanceState.parcelable(EXTRA_SELECTED_GAME)!! | 252 | game = savedInstanceState.parcelable(EXTRA_SELECTED_GAME)!! |
| 281 | } | 253 | } |
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 124f62f08..3fca0a7e6 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 | |||
| @@ -284,10 +284,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 284 | if (result == null) | 284 | if (result == null) |
| 285 | return@registerForActivityResult | 285 | return@registerForActivityResult |
| 286 | 286 | ||
| 287 | if (!FileUtil.hasExtension(result.toString(), "keys")) { | 287 | if (!FileUtil.hasExtension(result, "keys")) { |
| 288 | MessageDialogFragment.newInstance( | 288 | MessageDialogFragment.newInstance( |
| 289 | R.string.reading_keys_failure, | 289 | R.string.reading_keys_failure, |
| 290 | R.string.install_keys_failure_extension_description | 290 | R.string.install_prod_keys_failure_extension_description |
| 291 | ).show(supportFragmentManager, MessageDialogFragment.TAG) | 291 | ).show(supportFragmentManager, MessageDialogFragment.TAG) |
| 292 | return@registerForActivityResult | 292 | return@registerForActivityResult |
| 293 | } | 293 | } |
| @@ -379,10 +379,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 379 | if (result == null) | 379 | if (result == null) |
| 380 | return@registerForActivityResult | 380 | return@registerForActivityResult |
| 381 | 381 | ||
| 382 | if (!FileUtil.hasExtension(result.toString(), "bin")) { | 382 | if (!FileUtil.hasExtension(result, "bin")) { |
| 383 | MessageDialogFragment.newInstance( | 383 | MessageDialogFragment.newInstance( |
| 384 | R.string.reading_keys_failure, | 384 | R.string.reading_keys_failure, |
| 385 | R.string.install_keys_failure_extension_description | 385 | R.string.install_amiibo_keys_failure_extension_description |
| 386 | ).show(supportFragmentManager, MessageDialogFragment.TAG) | 386 | ).show(supportFragmentManager, MessageDialogFragment.TAG) |
| 387 | return@registerForActivityResult | 387 | return@registerForActivityResult |
| 388 | } | 388 | } |
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 593dad8d3..492b1ad91 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,9 @@ 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 | ||
| 10 | import androidx.documentfile.provider.DocumentFile | 11 | import androidx.documentfile.provider.DocumentFile |
| 12 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 11 | import org.yuzu.yuzu_emu.model.MinimalDocumentFile | 13 | import org.yuzu.yuzu_emu.model.MinimalDocumentFile |
| 12 | import java.io.BufferedInputStream | 14 | import java.io.BufferedInputStream |
| 13 | import java.io.File | 15 | import java.io.File |
| @@ -324,7 +326,25 @@ object FileUtil { | |||
| 324 | } | 326 | } |
| 325 | } | 327 | } |
| 326 | 328 | ||
| 327 | fun hasExtension(path: String, extension: String): Boolean { | 329 | fun hasExtension(path: String, extension: String): Boolean = |
| 328 | return path.substring(path.lastIndexOf(".") + 1).contains(extension) | 330 | path.substring(path.lastIndexOf(".") + 1).contains(extension) |
| 331 | |||
| 332 | fun hasExtension(uri: Uri, extension: String): Boolean { | ||
| 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) | ||
| 329 | } | 349 | } |
| 330 | } | 350 | } |
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 03cb0b74b..7ebed5e6a 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -94,14 +94,6 @@ public: | |||
| 94 | m_native_window = native_window; | 94 | m_native_window = native_window; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | u32 ScreenRotation() const { | ||
| 98 | return m_screen_rotation; | ||
| 99 | } | ||
| 100 | |||
| 101 | void SetScreenRotation(u32 screen_rotation) { | ||
| 102 | m_screen_rotation = screen_rotation; | ||
| 103 | } | ||
| 104 | |||
| 105 | void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir, | 97 | void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir, |
| 106 | const std::string& custom_driver_name, | 98 | const std::string& custom_driver_name, |
| 107 | const std::string& file_redirect_dir) { | 99 | const std::string& file_redirect_dir) { |
| @@ -400,7 +392,6 @@ private: | |||
| 400 | // Window management | 392 | // Window management |
| 401 | std::unique_ptr<EmuWindow_Android> m_window; | 393 | std::unique_ptr<EmuWindow_Android> m_window; |
| 402 | ANativeWindow* m_native_window{}; | 394 | ANativeWindow* m_native_window{}; |
| 403 | u32 m_screen_rotation{}; | ||
| 404 | 395 | ||
| 405 | // Core emulation | 396 | // Core emulation |
| 406 | Core::System m_system; | 397 | Core::System m_system; |
| @@ -426,10 +417,6 @@ private: | |||
| 426 | 417 | ||
| 427 | } // Anonymous namespace | 418 | } // Anonymous namespace |
| 428 | 419 | ||
| 429 | u32 GetAndroidScreenRotation() { | ||
| 430 | return EmulationSession::GetInstance().ScreenRotation(); | ||
| 431 | } | ||
| 432 | |||
| 433 | static Core::SystemResultStatus RunEmulation(const std::string& filepath) { | 420 | static Core::SystemResultStatus RunEmulation(const std::string& filepath) { |
| 434 | Common::Log::Initialize(); | 421 | Common::Log::Initialize(); |
| 435 | Common::Log::SetColorConsoleBackendEnabled(true); | 422 | Common::Log::SetColorConsoleBackendEnabled(true); |
| @@ -473,13 +460,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, | |||
| 473 | EmulationSession::GetInstance().SurfaceChanged(); | 460 | EmulationSession::GetInstance().SurfaceChanged(); |
| 474 | } | 461 | } |
| 475 | 462 | ||
| 476 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_notifyOrientationChange(JNIEnv* env, | ||
| 477 | [[maybe_unused]] jclass clazz, | ||
| 478 | jint layout_option, | ||
| 479 | jint rotation) { | ||
| 480 | return EmulationSession::GetInstance().SetScreenRotation(static_cast<u32>(rotation)); | ||
| 481 | } | ||
| 482 | |||
| 483 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, | 463 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, |
| 484 | [[maybe_unused]] jclass clazz, | 464 | [[maybe_unused]] jclass clazz, |
| 485 | jstring j_directory) { | 465 | jstring j_directory) { |
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 0ae69afb4..6e9d47557 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -65,11 +65,8 @@ | |||
| 65 | <string name="invalid_keys_file">Invalid keys file selected</string> | 65 | <string name="invalid_keys_file">Invalid keys file selected</string> |
| 66 | <string name="install_keys_success">Keys successfully installed</string> | 66 | <string name="install_keys_success">Keys successfully installed</string> |
| 67 | <string name="reading_keys_failure">Error reading encryption keys</string> | 67 | <string name="reading_keys_failure">Error reading encryption keys</string> |
| 68 | <string name="install_keys_failure_extension_description"> | 68 | <string name="install_prod_keys_failure_extension_description">Verify your keys file has a .keys extension and try again.</string> |
| 69 | 1. Verify your keys have the .keys extension.\n\n | 69 | <string name="install_amiibo_keys_failure_extension_description">Verify your keys file has a .bin extension and try again.</string> |
| 70 | 2. Keys must not be stored in the Downloads folder.\n\n | ||
| 71 | Resolve the issue(s) and try again. | ||
| 72 | </string> | ||
| 73 | <string name="invalid_keys_error">Invalid encryption keys</string> | 70 | <string name="invalid_keys_error">Invalid encryption keys</string> |
| 74 | <string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string> | 71 | <string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string> |
| 75 | <string name="install_keys_failure_description">The selected file is incorrect or corrupt. Please redump your keys.</string> | 72 | <string name="install_keys_failure_description">The selected file is incorrect or corrupt. Please redump your keys.</string> |
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 2baa64322..07e75f9d8 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -224,6 +224,7 @@ add_library(shader_recompiler STATIC | |||
| 224 | ir_opt/identity_removal_pass.cpp | 224 | ir_opt/identity_removal_pass.cpp |
| 225 | ir_opt/layer_pass.cpp | 225 | ir_opt/layer_pass.cpp |
| 226 | ir_opt/lower_fp16_to_fp32.cpp | 226 | ir_opt/lower_fp16_to_fp32.cpp |
| 227 | ir_opt/lower_fp64_to_fp32.cpp | ||
| 227 | ir_opt/lower_int64_to_int32.cpp | 228 | ir_opt/lower_int64_to_int32.cpp |
| 228 | ir_opt/passes.h | 229 | ir_opt/passes.h |
| 229 | ir_opt/position_pass.cpp | 230 | ir_opt/position_pass.cpp |
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 529382355..928b35561 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp | |||
| @@ -280,6 +280,9 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 280 | RemoveUnreachableBlocks(program); | 280 | RemoveUnreachableBlocks(program); |
| 281 | 281 | ||
| 282 | // Replace instructions before the SSA rewrite | 282 | // Replace instructions before the SSA rewrite |
| 283 | if (!host_info.support_float64) { | ||
| 284 | Optimization::LowerFp64ToFp32(program); | ||
| 285 | } | ||
| 283 | if (!host_info.support_float16) { | 286 | if (!host_info.support_float16) { |
| 284 | Optimization::LowerFp16ToFp32(program); | 287 | Optimization::LowerFp16ToFp32(program); |
| 285 | } | 288 | } |
diff --git a/src/shader_recompiler/host_translate_info.h b/src/shader_recompiler/host_translate_info.h index d4e4f4d28..7d2ded907 100644 --- a/src/shader_recompiler/host_translate_info.h +++ b/src/shader_recompiler/host_translate_info.h | |||
| @@ -10,6 +10,7 @@ namespace Shader { | |||
| 10 | 10 | ||
| 11 | /// Misc information about the host | 11 | /// Misc information about the host |
| 12 | struct HostTranslateInfo { | 12 | struct HostTranslateInfo { |
| 13 | bool support_float64{}; ///< True when the device supports 64-bit floats | ||
| 13 | bool support_float16{}; ///< True when the device supports 16-bit floats | 14 | bool support_float16{}; ///< True when the device supports 16-bit floats |
| 14 | bool support_int64{}; ///< True when the device supports 64-bit integers | 15 | bool support_int64{}; ///< True when the device supports 64-bit integers |
| 15 | bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered | 16 | bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered |
diff --git a/src/shader_recompiler/ir_opt/lower_fp64_to_fp32.cpp b/src/shader_recompiler/ir_opt/lower_fp64_to_fp32.cpp new file mode 100644 index 000000000..5db7a38ad --- /dev/null +++ b/src/shader_recompiler/ir_opt/lower_fp64_to_fp32.cpp | |||
| @@ -0,0 +1,185 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "shader_recompiler/frontend/ir/ir_emitter.h" | ||
| 5 | #include "shader_recompiler/frontend/ir/opcodes.h" | ||
| 6 | #include "shader_recompiler/frontend/ir/value.h" | ||
| 7 | #include "shader_recompiler/ir_opt/passes.h" | ||
| 8 | |||
| 9 | namespace Shader::Optimization { | ||
| 10 | namespace { | ||
| 11 | |||
| 12 | constexpr s32 F64ToF32Exp = +1023 - 127; | ||
| 13 | constexpr s32 F32ToF64Exp = +127 - 1023; | ||
| 14 | |||
| 15 | IR::F32 PackedF64ToF32(IR::IREmitter& ir, const IR::Value& packed) { | ||
| 16 | const IR::U32 lo{ir.CompositeExtract(packed, 0)}; | ||
| 17 | const IR::U32 hi{ir.CompositeExtract(packed, 1)}; | ||
| 18 | const IR::U32 sign{ir.BitFieldExtract(hi, ir.Imm32(31), ir.Imm32(1))}; | ||
| 19 | const IR::U32 exp{ir.BitFieldExtract(hi, ir.Imm32(20), ir.Imm32(11))}; | ||
| 20 | const IR::U32 mantissa_hi{ir.BitFieldExtract(hi, ir.Imm32(0), ir.Imm32(20))}; | ||
| 21 | const IR::U32 mantissa_lo{ir.BitFieldExtract(lo, ir.Imm32(29), ir.Imm32(3))}; | ||
| 22 | const IR::U32 mantissa{ | ||
| 23 | ir.BitwiseOr(ir.ShiftLeftLogical(mantissa_hi, ir.Imm32(3)), mantissa_lo)}; | ||
| 24 | const IR::U32 exp_if_subnorm{ | ||
| 25 | ir.Select(ir.IEqual(exp, ir.Imm32(0)), ir.Imm32(0), ir.IAdd(exp, ir.Imm32(F64ToF32Exp)))}; | ||
| 26 | const IR::U32 exp_if_infnan{ | ||
| 27 | ir.Select(ir.IEqual(exp, ir.Imm32(0x7ff)), ir.Imm32(0xff), exp_if_subnorm)}; | ||
| 28 | const IR::U32 result{ | ||
| 29 | ir.BitwiseOr(ir.ShiftLeftLogical(sign, ir.Imm32(31)), | ||
| 30 | ir.BitwiseOr(ir.ShiftLeftLogical(exp_if_infnan, ir.Imm32(23)), mantissa))}; | ||
| 31 | return ir.BitCast<IR::F32>(result); | ||
| 32 | } | ||
| 33 | |||
| 34 | IR::Value F32ToPackedF64(IR::IREmitter& ir, const IR::Value& raw) { | ||
| 35 | const IR::U32 value{ir.BitCast<IR::U32>(IR::F32(raw))}; | ||
| 36 | const IR::U32 sign{ir.BitFieldExtract(value, ir.Imm32(31), ir.Imm32(1))}; | ||
| 37 | const IR::U32 exp{ir.BitFieldExtract(value, ir.Imm32(23), ir.Imm32(8))}; | ||
| 38 | const IR::U32 mantissa{ir.BitFieldExtract(value, ir.Imm32(0), ir.Imm32(23))}; | ||
| 39 | const IR::U32 mantissa_hi{ir.BitFieldExtract(mantissa, ir.Imm32(3), ir.Imm32(20))}; | ||
| 40 | const IR::U32 mantissa_lo{ir.BitFieldExtract(mantissa, ir.Imm32(0), ir.Imm32(3))}; | ||
| 41 | const IR::U32 exp_if_subnorm{ | ||
| 42 | ir.Select(ir.IEqual(exp, ir.Imm32(0)), ir.Imm32(0), ir.IAdd(exp, ir.Imm32(F32ToF64Exp)))}; | ||
| 43 | const IR::U32 exp_if_infnan{ | ||
| 44 | ir.Select(ir.IEqual(exp, ir.Imm32(0xff)), ir.Imm32(0x7ff), exp_if_subnorm)}; | ||
| 45 | const IR::U32 lo{ir.ShiftLeftLogical(mantissa_lo, ir.Imm32(29))}; | ||
| 46 | const IR::U32 hi{ | ||
| 47 | ir.BitwiseOr(ir.ShiftLeftLogical(sign, ir.Imm32(31)), | ||
| 48 | ir.BitwiseOr(ir.ShiftLeftLogical(exp_if_infnan, ir.Imm32(20)), mantissa_hi))}; | ||
| 49 | return ir.CompositeConstruct(lo, hi); | ||
| 50 | } | ||
| 51 | |||
| 52 | IR::Opcode Replace(IR::Opcode op) { | ||
| 53 | switch (op) { | ||
| 54 | case IR::Opcode::FPAbs64: | ||
| 55 | return IR::Opcode::FPAbs32; | ||
| 56 | case IR::Opcode::FPAdd64: | ||
| 57 | return IR::Opcode::FPAdd32; | ||
| 58 | case IR::Opcode::FPCeil64: | ||
| 59 | return IR::Opcode::FPCeil32; | ||
| 60 | case IR::Opcode::FPFloor64: | ||
| 61 | return IR::Opcode::FPFloor32; | ||
| 62 | case IR::Opcode::FPFma64: | ||
| 63 | return IR::Opcode::FPFma32; | ||
| 64 | case IR::Opcode::FPMul64: | ||
| 65 | return IR::Opcode::FPMul32; | ||
| 66 | case IR::Opcode::FPNeg64: | ||
| 67 | return IR::Opcode::FPNeg32; | ||
| 68 | case IR::Opcode::FPRoundEven64: | ||
| 69 | return IR::Opcode::FPRoundEven32; | ||
| 70 | case IR::Opcode::FPSaturate64: | ||
| 71 | return IR::Opcode::FPSaturate32; | ||
| 72 | case IR::Opcode::FPClamp64: | ||
| 73 | return IR::Opcode::FPClamp32; | ||
| 74 | case IR::Opcode::FPTrunc64: | ||
| 75 | return IR::Opcode::FPTrunc32; | ||
| 76 | case IR::Opcode::CompositeConstructF64x2: | ||
| 77 | return IR::Opcode::CompositeConstructF32x2; | ||
| 78 | case IR::Opcode::CompositeConstructF64x3: | ||
| 79 | return IR::Opcode::CompositeConstructF32x3; | ||
| 80 | case IR::Opcode::CompositeConstructF64x4: | ||
| 81 | return IR::Opcode::CompositeConstructF32x4; | ||
| 82 | case IR::Opcode::CompositeExtractF64x2: | ||
| 83 | return IR::Opcode::CompositeExtractF32x2; | ||
| 84 | case IR::Opcode::CompositeExtractF64x3: | ||
| 85 | return IR::Opcode::CompositeExtractF32x3; | ||
| 86 | case IR::Opcode::CompositeExtractF64x4: | ||
| 87 | return IR::Opcode::CompositeExtractF32x4; | ||
| 88 | case IR::Opcode::CompositeInsertF64x2: | ||
| 89 | return IR::Opcode::CompositeInsertF32x2; | ||
| 90 | case IR::Opcode::CompositeInsertF64x3: | ||
| 91 | return IR::Opcode::CompositeInsertF32x3; | ||
| 92 | case IR::Opcode::CompositeInsertF64x4: | ||
| 93 | return IR::Opcode::CompositeInsertF32x4; | ||
| 94 | case IR::Opcode::FPOrdEqual64: | ||
| 95 | return IR::Opcode::FPOrdEqual32; | ||
| 96 | case IR::Opcode::FPUnordEqual64: | ||
| 97 | return IR::Opcode::FPUnordEqual32; | ||
| 98 | case IR::Opcode::FPOrdNotEqual64: | ||
| 99 | return IR::Opcode::FPOrdNotEqual32; | ||
| 100 | case IR::Opcode::FPUnordNotEqual64: | ||
| 101 | return IR::Opcode::FPUnordNotEqual32; | ||
| 102 | case IR::Opcode::FPOrdLessThan64: | ||
| 103 | return IR::Opcode::FPOrdLessThan32; | ||
| 104 | case IR::Opcode::FPUnordLessThan64: | ||
| 105 | return IR::Opcode::FPUnordLessThan32; | ||
| 106 | case IR::Opcode::FPOrdGreaterThan64: | ||
| 107 | return IR::Opcode::FPOrdGreaterThan32; | ||
| 108 | case IR::Opcode::FPUnordGreaterThan64: | ||
| 109 | return IR::Opcode::FPUnordGreaterThan32; | ||
| 110 | case IR::Opcode::FPOrdLessThanEqual64: | ||
| 111 | return IR::Opcode::FPOrdLessThanEqual32; | ||
| 112 | case IR::Opcode::FPUnordLessThanEqual64: | ||
| 113 | return IR::Opcode::FPUnordLessThanEqual32; | ||
| 114 | case IR::Opcode::FPOrdGreaterThanEqual64: | ||
| 115 | return IR::Opcode::FPOrdGreaterThanEqual32; | ||
| 116 | case IR::Opcode::FPUnordGreaterThanEqual64: | ||
| 117 | return IR::Opcode::FPUnordGreaterThanEqual32; | ||
| 118 | case IR::Opcode::FPIsNan64: | ||
| 119 | return IR::Opcode::FPIsNan32; | ||
| 120 | case IR::Opcode::ConvertS16F64: | ||
| 121 | return IR::Opcode::ConvertS16F32; | ||
| 122 | case IR::Opcode::ConvertS32F64: | ||
| 123 | return IR::Opcode::ConvertS32F32; | ||
| 124 | case IR::Opcode::ConvertS64F64: | ||
| 125 | return IR::Opcode::ConvertS64F32; | ||
| 126 | case IR::Opcode::ConvertU16F64: | ||
| 127 | return IR::Opcode::ConvertU16F32; | ||
| 128 | case IR::Opcode::ConvertU32F64: | ||
| 129 | return IR::Opcode::ConvertU32F32; | ||
| 130 | case IR::Opcode::ConvertU64F64: | ||
| 131 | return IR::Opcode::ConvertU64F32; | ||
| 132 | case IR::Opcode::ConvertF32F64: | ||
| 133 | return IR::Opcode::Identity; | ||
| 134 | case IR::Opcode::ConvertF64F32: | ||
| 135 | return IR::Opcode::Identity; | ||
| 136 | case IR::Opcode::ConvertF64S8: | ||
| 137 | return IR::Opcode::ConvertF32S8; | ||
| 138 | case IR::Opcode::ConvertF64S16: | ||
| 139 | return IR::Opcode::ConvertF32S16; | ||
| 140 | case IR::Opcode::ConvertF64S32: | ||
| 141 | return IR::Opcode::ConvertF32S32; | ||
| 142 | case IR::Opcode::ConvertF64S64: | ||
| 143 | return IR::Opcode::ConvertF32S64; | ||
| 144 | case IR::Opcode::ConvertF64U8: | ||
| 145 | return IR::Opcode::ConvertF32U8; | ||
| 146 | case IR::Opcode::ConvertF64U16: | ||
| 147 | return IR::Opcode::ConvertF32U16; | ||
| 148 | case IR::Opcode::ConvertF64U32: | ||
| 149 | return IR::Opcode::ConvertF32U32; | ||
| 150 | case IR::Opcode::ConvertF64U64: | ||
| 151 | return IR::Opcode::ConvertF32U64; | ||
| 152 | default: | ||
| 153 | return op; | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | void Lower(IR::Block& block, IR::Inst& inst) { | ||
| 158 | switch (inst.GetOpcode()) { | ||
| 159 | case IR::Opcode::PackDouble2x32: { | ||
| 160 | IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst)); | ||
| 161 | inst.ReplaceUsesWith(PackedF64ToF32(ir, inst.Arg(0))); | ||
| 162 | break; | ||
| 163 | } | ||
| 164 | case IR::Opcode::UnpackDouble2x32: { | ||
| 165 | IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst)); | ||
| 166 | inst.ReplaceUsesWith(F32ToPackedF64(ir, inst.Arg(0))); | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | default: | ||
| 170 | inst.ReplaceOpcode(Replace(inst.GetOpcode())); | ||
| 171 | break; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | } // Anonymous namespace | ||
| 176 | |||
| 177 | void LowerFp64ToFp32(IR::Program& program) { | ||
| 178 | for (IR::Block* const block : program.blocks) { | ||
| 179 | for (IR::Inst& inst : block->Instructions()) { | ||
| 180 | Lower(*block, inst); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | } // namespace Shader::Optimization | ||
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index a677bfc65..629d18fa1 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h | |||
| @@ -18,6 +18,7 @@ void ConstantPropagationPass(Environment& env, IR::Program& program); | |||
| 18 | void DeadCodeEliminationPass(IR::Program& program); | 18 | void DeadCodeEliminationPass(IR::Program& program); |
| 19 | void GlobalMemoryToStorageBufferPass(IR::Program& program); | 19 | void GlobalMemoryToStorageBufferPass(IR::Program& program); |
| 20 | void IdentityRemovalPass(IR::Program& program); | 20 | void IdentityRemovalPass(IR::Program& program); |
| 21 | void LowerFp64ToFp32(IR::Program& program); | ||
| 21 | void LowerFp16ToFp32(IR::Program& program); | 22 | void LowerFp16ToFp32(IR::Program& program); |
| 22 | void LowerInt64ToInt32(IR::Program& program); | 23 | void LowerInt64ToInt32(IR::Program& program); |
| 23 | void RescalingPass(IR::Program& program); | 24 | void RescalingPass(IR::Program& program); |
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 2f281b370..251a4a880 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -715,20 +715,38 @@ void BufferCache<P>::BindHostIndexBuffer() { | |||
| 715 | 715 | ||
| 716 | template <class P> | 716 | template <class P> |
| 717 | void BufferCache<P>::BindHostVertexBuffers() { | 717 | void BufferCache<P>::BindHostVertexBuffers() { |
| 718 | HostBindings host_bindings; | ||
| 719 | bool any_valid{false}; | ||
| 718 | auto& flags = maxwell3d->dirty.flags; | 720 | auto& flags = maxwell3d->dirty.flags; |
| 719 | for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) { | 721 | for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) { |
| 720 | const Binding& binding = channel_state->vertex_buffers[index]; | ||
| 721 | Buffer& buffer = slot_buffers[binding.buffer_id]; | ||
| 722 | TouchBuffer(buffer, binding.buffer_id); | ||
| 723 | SynchronizeBuffer(buffer, binding.cpu_addr, binding.size); | ||
| 724 | if (!flags[Dirty::VertexBuffer0 + index]) { | 722 | if (!flags[Dirty::VertexBuffer0 + index]) { |
| 725 | continue; | 723 | continue; |
| 726 | } | 724 | } |
| 727 | flags[Dirty::VertexBuffer0 + index] = false; | 725 | host_bindings.min_index = std::min(host_bindings.min_index, index); |
| 726 | host_bindings.max_index = std::max(host_bindings.max_index, index); | ||
| 727 | any_valid = true; | ||
| 728 | } | ||
| 728 | 729 | ||
| 729 | const u32 stride = maxwell3d->regs.vertex_streams[index].stride; | 730 | if (any_valid) { |
| 730 | const u32 offset = buffer.Offset(binding.cpu_addr); | 731 | host_bindings.max_index++; |
| 731 | runtime.BindVertexBuffer(index, buffer, offset, binding.size, stride); | 732 | for (u32 index = host_bindings.min_index; index < host_bindings.max_index; index++) { |
| 733 | flags[Dirty::VertexBuffer0 + index] = false; | ||
| 734 | |||
| 735 | const Binding& binding = channel_state->vertex_buffers[index]; | ||
| 736 | Buffer& buffer = slot_buffers[binding.buffer_id]; | ||
| 737 | |||
| 738 | TouchBuffer(buffer, binding.buffer_id); | ||
| 739 | SynchronizeBuffer(buffer, binding.cpu_addr, binding.size); | ||
| 740 | |||
| 741 | const u32 stride = maxwell3d->regs.vertex_streams[index].stride; | ||
| 742 | const u32 offset = buffer.Offset(binding.cpu_addr); | ||
| 743 | |||
| 744 | host_bindings.buffers.push_back(reinterpret_cast<void*>(&buffer)); | ||
| 745 | host_bindings.offsets.push_back(offset); | ||
| 746 | host_bindings.sizes.push_back(binding.size); | ||
| 747 | host_bindings.strides.push_back(stride); | ||
| 748 | } | ||
| 749 | runtime.BindVertexBuffers(host_bindings); | ||
| 732 | } | 750 | } |
| 733 | } | 751 | } |
| 734 | 752 | ||
| @@ -882,15 +900,25 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() { | |||
| 882 | if (maxwell3d->regs.transform_feedback_enabled == 0) { | 900 | if (maxwell3d->regs.transform_feedback_enabled == 0) { |
| 883 | return; | 901 | return; |
| 884 | } | 902 | } |
| 903 | HostBindings host_bindings; | ||
| 885 | for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) { | 904 | for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) { |
| 886 | const Binding& binding = channel_state->transform_feedback_buffers[index]; | 905 | const Binding& binding = channel_state->transform_feedback_buffers[index]; |
| 906 | if (maxwell3d->regs.transform_feedback.controls[index].varying_count == 0 && | ||
| 907 | maxwell3d->regs.transform_feedback.controls[index].stride == 0) { | ||
| 908 | break; | ||
| 909 | } | ||
| 887 | Buffer& buffer = slot_buffers[binding.buffer_id]; | 910 | Buffer& buffer = slot_buffers[binding.buffer_id]; |
| 888 | TouchBuffer(buffer, binding.buffer_id); | 911 | TouchBuffer(buffer, binding.buffer_id); |
| 889 | const u32 size = binding.size; | 912 | const u32 size = binding.size; |
| 890 | SynchronizeBuffer(buffer, binding.cpu_addr, size); | 913 | SynchronizeBuffer(buffer, binding.cpu_addr, size); |
| 891 | 914 | ||
| 892 | const u32 offset = buffer.Offset(binding.cpu_addr); | 915 | const u32 offset = buffer.Offset(binding.cpu_addr); |
| 893 | runtime.BindTransformFeedbackBuffer(index, buffer, offset, size); | 916 | host_bindings.buffers.push_back(reinterpret_cast<void*>(&buffer)); |
| 917 | host_bindings.offsets.push_back(offset); | ||
| 918 | host_bindings.sizes.push_back(binding.size); | ||
| 919 | } | ||
| 920 | if (host_bindings.buffers.size() > 0) { | ||
| 921 | runtime.BindTransformFeedbackBuffers(host_bindings); | ||
| 894 | } | 922 | } |
| 895 | } | 923 | } |
| 896 | 924 | ||
| @@ -1616,6 +1644,8 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si | |||
| 1616 | 1644 | ||
| 1617 | template <class P> | 1645 | template <class P> |
| 1618 | void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { | 1646 | void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { |
| 1647 | bool dirty_index{false}; | ||
| 1648 | boost::container::small_vector<u64, NUM_VERTEX_BUFFERS> dirty_vertex_buffers; | ||
| 1619 | const auto scalar_replace = [buffer_id](Binding& binding) { | 1649 | const auto scalar_replace = [buffer_id](Binding& binding) { |
| 1620 | if (binding.buffer_id == buffer_id) { | 1650 | if (binding.buffer_id == buffer_id) { |
| 1621 | binding.buffer_id = BufferId{}; | 1651 | binding.buffer_id = BufferId{}; |
| @@ -1624,8 +1654,19 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { | |||
| 1624 | const auto replace = [scalar_replace](std::span<Binding> bindings) { | 1654 | const auto replace = [scalar_replace](std::span<Binding> bindings) { |
| 1625 | std::ranges::for_each(bindings, scalar_replace); | 1655 | std::ranges::for_each(bindings, scalar_replace); |
| 1626 | }; | 1656 | }; |
| 1627 | scalar_replace(channel_state->index_buffer); | 1657 | |
| 1628 | replace(channel_state->vertex_buffers); | 1658 | if (channel_state->index_buffer.buffer_id == buffer_id) { |
| 1659 | channel_state->index_buffer.buffer_id = BufferId{}; | ||
| 1660 | dirty_index = true; | ||
| 1661 | } | ||
| 1662 | |||
| 1663 | for (u32 index = 0; index < channel_state->vertex_buffers.size(); index++) { | ||
| 1664 | auto& binding = channel_state->vertex_buffers[index]; | ||
| 1665 | if (binding.buffer_id == buffer_id) { | ||
| 1666 | binding.buffer_id = BufferId{}; | ||
| 1667 | dirty_vertex_buffers.push_back(index); | ||
| 1668 | } | ||
| 1669 | } | ||
| 1629 | std::ranges::for_each(channel_state->uniform_buffers, replace); | 1670 | std::ranges::for_each(channel_state->uniform_buffers, replace); |
| 1630 | std::ranges::for_each(channel_state->storage_buffers, replace); | 1671 | std::ranges::for_each(channel_state->storage_buffers, replace); |
| 1631 | replace(channel_state->transform_feedback_buffers); | 1672 | replace(channel_state->transform_feedback_buffers); |
| @@ -1642,20 +1683,21 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { | |||
| 1642 | delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id])); | 1683 | delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id])); |
| 1643 | slot_buffers.erase(buffer_id); | 1684 | slot_buffers.erase(buffer_id); |
| 1644 | 1685 | ||
| 1645 | NotifyBufferDeletion(); | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | template <class P> | ||
| 1649 | void BufferCache<P>::NotifyBufferDeletion() { | ||
| 1650 | if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { | 1686 | if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { |
| 1651 | channel_state->dirty_uniform_buffers.fill(~u32{0}); | 1687 | channel_state->dirty_uniform_buffers.fill(~u32{0}); |
| 1652 | channel_state->uniform_buffer_binding_sizes.fill({}); | 1688 | channel_state->uniform_buffer_binding_sizes.fill({}); |
| 1653 | } | 1689 | } |
| 1690 | |||
| 1654 | auto& flags = maxwell3d->dirty.flags; | 1691 | auto& flags = maxwell3d->dirty.flags; |
| 1655 | flags[Dirty::IndexBuffer] = true; | 1692 | if (dirty_index) { |
| 1656 | flags[Dirty::VertexBuffers] = true; | 1693 | flags[Dirty::IndexBuffer] = true; |
| 1657 | for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) { | 1694 | } |
| 1658 | flags[Dirty::VertexBuffer0 + index] = true; | 1695 | |
| 1696 | if (dirty_vertex_buffers.size() > 0) { | ||
| 1697 | flags[Dirty::VertexBuffers] = true; | ||
| 1698 | for (auto index : dirty_vertex_buffers) { | ||
| 1699 | flags[Dirty::VertexBuffer0 + index] = true; | ||
| 1700 | } | ||
| 1659 | } | 1701 | } |
| 1660 | channel_state->has_deleted_buffers = true; | 1702 | channel_state->has_deleted_buffers = true; |
| 1661 | } | 1703 | } |
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 60a1f285e..cf359e241 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h | |||
| @@ -105,6 +105,15 @@ static constexpr Binding NULL_BINDING{ | |||
| 105 | .buffer_id = NULL_BUFFER_ID, | 105 | .buffer_id = NULL_BUFFER_ID, |
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| 108 | struct HostBindings { | ||
| 109 | boost::container::small_vector<void*, NUM_VERTEX_BUFFERS> buffers; | ||
| 110 | boost::container::small_vector<u64, NUM_VERTEX_BUFFERS> offsets; | ||
| 111 | boost::container::small_vector<u64, NUM_VERTEX_BUFFERS> sizes; | ||
| 112 | boost::container::small_vector<u64, NUM_VERTEX_BUFFERS> strides; | ||
| 113 | u32 min_index{NUM_VERTEX_BUFFERS}; | ||
| 114 | u32 max_index{0}; | ||
| 115 | }; | ||
| 116 | |||
| 108 | class BufferCacheChannelInfo : public ChannelInfo { | 117 | class BufferCacheChannelInfo : public ChannelInfo { |
| 109 | public: | 118 | public: |
| 110 | BufferCacheChannelInfo() = delete; | 119 | BufferCacheChannelInfo() = delete; |
| @@ -519,8 +528,6 @@ private: | |||
| 519 | 528 | ||
| 520 | void DeleteBuffer(BufferId buffer_id, bool do_not_mark = false); | 529 | void DeleteBuffer(BufferId buffer_id, bool do_not_mark = false); |
| 521 | 530 | ||
| 522 | void NotifyBufferDeletion(); | ||
| 523 | |||
| 524 | [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index, | 531 | [[nodiscard]] Binding StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index, |
| 525 | bool is_written) const; | 532 | bool is_written) const; |
| 526 | 533 | ||
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index c419714d4..0cc546a3a 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp | |||
| @@ -232,6 +232,15 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, | |||
| 232 | } | 232 | } |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings& bindings) { | ||
| 236 | for (u32 index = 0; index < bindings.buffers.size(); index++) { | ||
| 237 | BindVertexBuffer( | ||
| 238 | bindings.min_index + index, *reinterpret_cast<Buffer*>(bindings.buffers[index]), | ||
| 239 | static_cast<u32>(bindings.offsets[index]), static_cast<u32>(bindings.sizes[index]), | ||
| 240 | static_cast<u32>(bindings.strides[index])); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 235 | void BufferCacheRuntime::BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, | 244 | void BufferCacheRuntime::BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, |
| 236 | u32 offset, u32 size) { | 245 | u32 offset, u32 size) { |
| 237 | if (use_assembly_shaders) { | 246 | if (use_assembly_shaders) { |
| @@ -320,6 +329,15 @@ void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, Buffer& buffer, | |||
| 320 | static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size)); | 329 | static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size)); |
| 321 | } | 330 | } |
| 322 | 331 | ||
| 332 | void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings& bindings) { | ||
| 333 | for (u32 index = 0; index < bindings.buffers.size(); index++) { | ||
| 334 | glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, index, | ||
| 335 | reinterpret_cast<Buffer*>(bindings.buffers[index])->Handle(), | ||
| 336 | static_cast<GLintptr>(bindings.offsets[index]), | ||
| 337 | static_cast<GLsizeiptr>(bindings.sizes[index])); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 323 | void BufferCacheRuntime::BindTextureBuffer(Buffer& buffer, u32 offset, u32 size, | 341 | void BufferCacheRuntime::BindTextureBuffer(Buffer& buffer, u32 offset, u32 size, |
| 324 | PixelFormat format) { | 342 | PixelFormat format) { |
| 325 | *texture_handles++ = buffer.View(offset, size, format); | 343 | *texture_handles++ = buffer.View(offset, size, format); |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index a24991585..e4e000284 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #include <span> | 7 | #include <span> |
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "video_core/buffer_cache/buffer_cache.h" | 10 | #include "video_core/buffer_cache/buffer_cache_base.h" |
| 11 | #include "video_core/buffer_cache/memory_tracker_base.h" | 11 | #include "video_core/buffer_cache/memory_tracker_base.h" |
| 12 | #include "video_core/rasterizer_interface.h" | 12 | #include "video_core/rasterizer_interface.h" |
| 13 | #include "video_core/renderer_opengl/gl_device.h" | 13 | #include "video_core/renderer_opengl/gl_device.h" |
| @@ -87,6 +87,7 @@ public: | |||
| 87 | void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size); | 87 | void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size); |
| 88 | 88 | ||
| 89 | void BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride); | 89 | void BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride); |
| 90 | void BindVertexBuffers(VideoCommon::HostBindings& bindings); | ||
| 90 | 91 | ||
| 91 | void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size); | 92 | void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size); |
| 92 | 93 | ||
| @@ -99,6 +100,7 @@ public: | |||
| 99 | bool is_written); | 100 | bool is_written); |
| 100 | 101 | ||
| 101 | void BindTransformFeedbackBuffer(u32 index, Buffer& buffer, u32 offset, u32 size); | 102 | void BindTransformFeedbackBuffer(u32 index, Buffer& buffer, u32 offset, u32 size); |
| 103 | void BindTransformFeedbackBuffers(VideoCommon::HostBindings& bindings); | ||
| 102 | 104 | ||
| 103 | void BindTextureBuffer(Buffer& buffer, u32 offset, u32 size, | 105 | void BindTextureBuffer(Buffer& buffer, u32 offset, u32 size, |
| 104 | VideoCore::Surface::PixelFormat format); | 106 | VideoCore::Surface::PixelFormat format); |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 183c1a7ea..3f077311e 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -232,6 +232,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | |||
| 232 | .gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(), | 232 | .gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(), |
| 233 | }, | 233 | }, |
| 234 | host_info{ | 234 | host_info{ |
| 235 | .support_float64 = true, | ||
| 235 | .support_float16 = false, | 236 | .support_float16 = false, |
| 236 | .support_int64 = device.HasShaderInt64(), | 237 | .support_int64 = device.HasShaderInt64(), |
| 237 | .needs_demote_reorder = device.IsAmd(), | 238 | .needs_demote_reorder = device.IsAmd(), |
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 7cdde992b..acb143fc7 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp | |||
| @@ -37,10 +37,6 @@ | |||
| 37 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" | 37 | #include "video_core/vulkan_common/vulkan_memory_allocator.h" |
| 38 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 38 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 39 | 39 | ||
| 40 | #ifdef ANDROID | ||
| 41 | extern u32 GetAndroidScreenRotation(); | ||
| 42 | #endif | ||
| 43 | |||
| 44 | namespace Vulkan { | 40 | namespace Vulkan { |
| 45 | 41 | ||
| 46 | namespace { | 42 | namespace { |
| @@ -78,47 +74,6 @@ struct ScreenRectVertex { | |||
| 78 | } | 74 | } |
| 79 | }; | 75 | }; |
| 80 | 76 | ||
| 81 | #ifdef ANDROID | ||
| 82 | |||
| 83 | std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { | ||
| 84 | constexpr u32 ROTATION_0 = 0; | ||
| 85 | constexpr u32 ROTATION_90 = 1; | ||
| 86 | constexpr u32 ROTATION_180 = 2; | ||
| 87 | constexpr u32 ROTATION_270 = 3; | ||
| 88 | |||
| 89 | // clang-format off | ||
| 90 | switch (GetAndroidScreenRotation()) { | ||
| 91 | case ROTATION_0: | ||
| 92 | // Desktop | ||
| 93 | return { 2.f / width, 0.f, 0.f, 0.f, | ||
| 94 | 0.f, 2.f / height, 0.f, 0.f, | ||
| 95 | 0.f, 0.f, 1.f, 0.f, | ||
| 96 | -1.f, -1.f, 0.f, 1.f}; | ||
| 97 | case ROTATION_180: | ||
| 98 | // Reverse desktop | ||
| 99 | return {-2.f / width, 0.f, 0.f, 0.f, | ||
| 100 | 0.f, -2.f / height, 0.f, 0.f, | ||
| 101 | 0.f, 0.f, 1.f, 0.f, | ||
| 102 | 1.f, 1.f, 0.f, 1.f}; | ||
| 103 | case ROTATION_270: | ||
| 104 | // Reverse landscape | ||
| 105 | return { 0.f, -2.f / width, 0.f, 0.f, | ||
| 106 | 2.f / height, 0.f, 0.f, 0.f, | ||
| 107 | 0.f, 0.f, 1.f, 0.f, | ||
| 108 | -1.f, 1.f, 0.f, 1.f}; | ||
| 109 | case ROTATION_90: | ||
| 110 | default: | ||
| 111 | // Landscape | ||
| 112 | return { 0.f, 2.f / width, 0.f, 0.f, | ||
| 113 | -2.f / height, 0.f, 0.f, 0.f, | ||
| 114 | 0.f, 0.f, 1.f, 0.f, | ||
| 115 | 1.f, -1.f, 0.f, 1.f}; | ||
| 116 | } | ||
| 117 | // clang-format on | ||
| 118 | } | ||
| 119 | |||
| 120 | #else | ||
| 121 | |||
| 122 | std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { | 77 | std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { |
| 123 | // clang-format off | 78 | // clang-format off |
| 124 | return { 2.f / width, 0.f, 0.f, 0.f, | 79 | return { 2.f / width, 0.f, 0.f, 0.f, |
| @@ -128,8 +83,6 @@ std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { | |||
| 128 | // clang-format on | 83 | // clang-format on |
| 129 | } | 84 | } |
| 130 | 85 | ||
| 131 | #endif | ||
| 132 | |||
| 133 | u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { | 86 | u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { |
| 134 | using namespace VideoCore::Surface; | 87 | using namespace VideoCore::Surface; |
| 135 | return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); | 88 | return BytesPerBlock(PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)); |
| @@ -1159,7 +1112,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1159 | .pNext = nullptr, | 1112 | .pNext = nullptr, |
| 1160 | .flags = 0, | 1113 | .flags = 0, |
| 1161 | .imageType = VK_IMAGE_TYPE_2D, | 1114 | .imageType = VK_IMAGE_TYPE_2D, |
| 1162 | .format = GetFormat(framebuffer), | 1115 | .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer), |
| 1163 | .extent = | 1116 | .extent = |
| 1164 | { | 1117 | { |
| 1165 | .width = (up_scale * framebuffer.width) >> down_shift, | 1118 | .width = (up_scale * framebuffer.width) >> down_shift, |
| @@ -1180,14 +1133,14 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1180 | const auto create_commit = [&](vk::Image& image) { | 1133 | const auto create_commit = [&](vk::Image& image) { |
| 1181 | return memory_allocator.Commit(image, MemoryUsage::DeviceLocal); | 1134 | return memory_allocator.Commit(image, MemoryUsage::DeviceLocal); |
| 1182 | }; | 1135 | }; |
| 1183 | const auto create_image_view = [&](vk::Image& image) { | 1136 | const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) { |
| 1184 | return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ | 1137 | return device.GetLogical().CreateImageView(VkImageViewCreateInfo{ |
| 1185 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 1138 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| 1186 | .pNext = nullptr, | 1139 | .pNext = nullptr, |
| 1187 | .flags = 0, | 1140 | .flags = 0, |
| 1188 | .image = *image, | 1141 | .image = *image, |
| 1189 | .viewType = VK_IMAGE_VIEW_TYPE_2D, | 1142 | .viewType = VK_IMAGE_VIEW_TYPE_2D, |
| 1190 | .format = GetFormat(framebuffer), | 1143 | .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer), |
| 1191 | .components = | 1144 | .components = |
| 1192 | { | 1145 | { |
| 1193 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, | 1146 | .r = VK_COMPONENT_SWIZZLE_IDENTITY, |
| @@ -1217,7 +1170,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { | |||
| 1217 | const u32 down_shift = Settings::values.resolution_info.down_shift; | 1170 | const u32 down_shift = Settings::values.resolution_info.down_shift; |
| 1218 | aa_image = create_image(true, up_scale, down_shift); | 1171 | aa_image = create_image(true, up_scale, down_shift); |
| 1219 | aa_commit = create_commit(aa_image); | 1172 | aa_commit = create_commit(aa_image); |
| 1220 | aa_image_view = create_image_view(aa_image); | 1173 | aa_image_view = create_image_view(aa_image, true); |
| 1221 | VkExtent2D size{ | 1174 | VkExtent2D size{ |
| 1222 | .width = (up_scale * framebuffer.width) >> down_shift, | 1175 | .width = (up_scale * framebuffer.width) >> down_shift, |
| 1223 | .height = (up_scale * framebuffer.height) >> down_shift, | 1176 | .height = (up_scale * framebuffer.height) >> down_shift, |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index daa128399..d72d99899 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include <span> | 7 | #include <span> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include "video_core/buffer_cache/buffer_cache.h" | ||
| 11 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 10 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 12 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" | 11 | #include "video_core/renderer_vulkan/vk_buffer_cache.h" |
| 13 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 12 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| @@ -502,6 +501,40 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset | |||
| 502 | } | 501 | } |
| 503 | } | 502 | } |
| 504 | 503 | ||
| 504 | void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings& bindings) { | ||
| 505 | boost::container::small_vector<VkBuffer, 32> buffer_handles; | ||
| 506 | for (u32 index = 0; index < bindings.buffers.size(); index++) { | ||
| 507 | auto& buffer = *reinterpret_cast<Buffer*>(bindings.buffers[index]); | ||
| 508 | auto handle = buffer.Handle(); | ||
| 509 | if (handle == VK_NULL_HANDLE) { | ||
| 510 | bindings.offsets[index] = 0; | ||
| 511 | bindings.sizes[index] = VK_WHOLE_SIZE; | ||
| 512 | if (!device.HasNullDescriptor()) { | ||
| 513 | ReserveNullBuffer(); | ||
| 514 | handle = *null_buffer; | ||
| 515 | } | ||
| 516 | } | ||
| 517 | buffer_handles.push_back(handle); | ||
| 518 | } | ||
| 519 | if (device.IsExtExtendedDynamicStateSupported()) { | ||
| 520 | scheduler.Record([bindings = bindings, | ||
| 521 | buffer_handles = buffer_handles](vk::CommandBuffer cmdbuf) { | ||
| 522 | cmdbuf.BindVertexBuffers2EXT( | ||
| 523 | bindings.min_index, bindings.max_index - bindings.min_index, buffer_handles.data(), | ||
| 524 | reinterpret_cast<const VkDeviceSize*>(bindings.offsets.data()), | ||
| 525 | reinterpret_cast<const VkDeviceSize*>(bindings.sizes.data()), | ||
| 526 | reinterpret_cast<const VkDeviceSize*>(bindings.strides.data())); | ||
| 527 | }); | ||
| 528 | } else { | ||
| 529 | scheduler.Record([bindings = bindings, | ||
| 530 | buffer_handles = buffer_handles](vk::CommandBuffer cmdbuf) { | ||
| 531 | cmdbuf.BindVertexBuffers( | ||
| 532 | bindings.min_index, bindings.max_index - bindings.min_index, buffer_handles.data(), | ||
| 533 | reinterpret_cast<const VkDeviceSize*>(bindings.offsets.data())); | ||
| 534 | }); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 505 | void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, | 538 | void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, |
| 506 | u32 size) { | 539 | u32 size) { |
| 507 | if (!device.IsExtTransformFeedbackSupported()) { | 540 | if (!device.IsExtTransformFeedbackSupported()) { |
| @@ -523,6 +556,25 @@ void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, | |||
| 523 | }); | 556 | }); |
| 524 | } | 557 | } |
| 525 | 558 | ||
| 559 | void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings& bindings) { | ||
| 560 | if (!device.IsExtTransformFeedbackSupported()) { | ||
| 561 | // Already logged in the rasterizer | ||
| 562 | return; | ||
| 563 | } | ||
| 564 | boost::container::small_vector<VkBuffer, 4> buffer_handles; | ||
| 565 | for (u32 index = 0; index < bindings.buffers.size(); index++) { | ||
| 566 | auto& buffer = *reinterpret_cast<Buffer*>(bindings.buffers[index]); | ||
| 567 | buffer_handles.push_back(buffer.Handle()); | ||
| 568 | } | ||
| 569 | scheduler.Record( | ||
| 570 | [bindings = bindings, buffer_handles = buffer_handles](vk::CommandBuffer cmdbuf) { | ||
| 571 | cmdbuf.BindTransformFeedbackBuffersEXT( | ||
| 572 | 0, static_cast<u32>(buffer_handles.size()), buffer_handles.data(), | ||
| 573 | reinterpret_cast<const VkDeviceSize*>(bindings.offsets.data()), | ||
| 574 | reinterpret_cast<const VkDeviceSize*>(bindings.sizes.data())); | ||
| 575 | }); | ||
| 576 | } | ||
| 577 | |||
| 526 | void BufferCacheRuntime::ReserveNullBuffer() { | 578 | void BufferCacheRuntime::ReserveNullBuffer() { |
| 527 | if (null_buffer) { | 579 | if (null_buffer) { |
| 528 | return; | 580 | return; |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 92b4f7859..92d3e9f32 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -18,6 +18,7 @@ namespace Vulkan { | |||
| 18 | class Device; | 18 | class Device; |
| 19 | class DescriptorPool; | 19 | class DescriptorPool; |
| 20 | class Scheduler; | 20 | class Scheduler; |
| 21 | struct HostVertexBinding; | ||
| 21 | 22 | ||
| 22 | class BufferCacheRuntime; | 23 | class BufferCacheRuntime; |
| 23 | 24 | ||
| @@ -96,8 +97,10 @@ public: | |||
| 96 | void BindQuadIndexBuffer(PrimitiveTopology topology, u32 first, u32 count); | 97 | void BindQuadIndexBuffer(PrimitiveTopology topology, u32 first, u32 count); |
| 97 | 98 | ||
| 98 | void BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, u32 stride); | 99 | void BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, u32 stride); |
| 100 | void BindVertexBuffers(VideoCommon::HostBindings& bindings); | ||
| 99 | 101 | ||
| 100 | void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size); | 102 | void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size); |
| 103 | void BindTransformFeedbackBuffers(VideoCommon::HostBindings& bindings); | ||
| 101 | 104 | ||
| 102 | std::span<u8> BindMappedUniformBuffer([[maybe_unused]] size_t stage, | 105 | std::span<u8> BindMappedUniformBuffer([[maybe_unused]] size_t stage, |
| 103 | [[maybe_unused]] u32 binding_index, u32 size) { | 106 | [[maybe_unused]] u32 binding_index, u32 size) { |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 9482e91b0..5734f51e5 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -350,6 +350,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | |||
| 350 | .has_broken_spirv_subgroup_mask_vector_extract_dynamic = | 350 | .has_broken_spirv_subgroup_mask_vector_extract_dynamic = |
| 351 | driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY}; | 351 | driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY}; |
| 352 | host_info = Shader::HostTranslateInfo{ | 352 | host_info = Shader::HostTranslateInfo{ |
| 353 | .support_float64 = device.IsFloat64Supported(), | ||
| 353 | .support_float16 = device.IsFloat16Supported(), | 354 | .support_float16 = device.IsFloat16Supported(), |
| 354 | .support_int64 = device.IsShaderInt64Supported(), | 355 | .support_int64 = device.IsShaderInt64Supported(), |
| 355 | .needs_demote_reorder = | 356 | .needs_demote_reorder = |
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index afcf34fba..d3cddac69 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp | |||
| @@ -231,7 +231,12 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo | |||
| 231 | .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, | 231 | .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 232 | .queueFamilyIndexCount = 0, | 232 | .queueFamilyIndexCount = 0, |
| 233 | .pQueueFamilyIndices = nullptr, | 233 | .pQueueFamilyIndices = nullptr, |
| 234 | #ifdef ANDROID | ||
| 235 | // On Android, do not allow surface rotation to deviate from the frontend. | ||
| 236 | .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, | ||
| 237 | #else | ||
| 234 | .preTransform = capabilities.currentTransform, | 238 | .preTransform = capabilities.currentTransform, |
| 239 | #endif | ||
| 235 | .compositeAlpha = alpha_flags, | 240 | .compositeAlpha = alpha_flags, |
| 236 | .presentMode = present_mode, | 241 | .presentMode = present_mode, |
| 237 | .clipped = VK_FALSE, | 242 | .clipped = VK_FALSE, |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index ccce9429a..f314d0ffe 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -300,6 +300,11 @@ public: | |||
| 300 | return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY; | 300 | return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY; |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | /// Returns true if the device suppors float64 natively. | ||
| 304 | bool IsFloat64Supported() const { | ||
| 305 | return features.features.shaderFloat64; | ||
| 306 | } | ||
| 307 | |||
| 303 | /// Returns true if the device supports float16 natively. | 308 | /// Returns true if the device supports float16 natively. |
| 304 | bool IsFloat16Supported() const { | 309 | bool IsFloat16Supported() const { |
| 305 | return features.shader_float16_int8.shaderFloat16; | 310 | return features.shader_float16_int8.shaderFloat16; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9d06b21b6..013715b44 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -3067,7 +3067,7 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename) { | |||
| 3067 | return false; | 3067 | return false; |
| 3068 | } | 3068 | } |
| 3069 | 3069 | ||
| 3070 | std::array<u8, 0x1000> buffer{}; | 3070 | std::vector<u8> buffer(1_MiB); |
| 3071 | 3071 | ||
| 3072 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { | 3072 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { |
| 3073 | if (install_progress->wasCanceled()) { | 3073 | if (install_progress->wasCanceled()) { |