summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/app/build.gradle.kts25
-rw-r--r--src/android/app/src/main/AndroidManifest.xml2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt28
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt24
-rw-r--r--src/android/app/src/main/jni/native.cpp20
-rw-r--r--src/android/app/src/main/res/values/strings.xml7
-rw-r--r--src/shader_recompiler/CMakeLists.txt1
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate_program.cpp3
-rw-r--r--src/shader_recompiler/host_translate_info.h1
-rw-r--r--src/shader_recompiler/ir_opt/lower_fp64_to_fp32.cpp185
-rw-r--r--src/shader_recompiler/ir_opt/passes.h1
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h82
-rw-r--r--src/video_core/buffer_cache/buffer_cache_base.h11
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp18
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h4
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp55
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp54
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h3
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp5
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h5
-rw-r--r--src/yuzu/main.cpp2
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
6import android.app.Activity 6import android.app.Activity
7import android.content.Context 7import android.content.Context
8import android.content.Intent 8import android.content.Intent
9import android.content.res.Configuration
10import android.graphics.Rect 9import android.graphics.Rect
11import android.hardware.Sensor 10import android.hardware.Sensor
12import android.hardware.SensorEvent 11import android.hardware.SensorEvent
13import android.hardware.SensorEventListener 12import android.hardware.SensorEventListener
14import android.hardware.SensorManager 13import android.hardware.SensorManager
15import android.hardware.display.DisplayManager
16import android.os.Bundle 14import android.os.Bundle
17import android.view.Display
18import android.view.InputDevice 15import android.view.InputDevice
19import android.view.KeyEvent 16import android.view.KeyEvent
20import android.view.MotionEvent 17import android.view.MotionEvent
@@ -23,7 +20,6 @@ import android.view.View
23import android.view.inputmethod.InputMethodManager 20import android.view.inputmethod.InputMethodManager
24import androidx.activity.viewModels 21import androidx.activity.viewModels
25import androidx.appcompat.app.AppCompatActivity 22import androidx.appcompat.app.AppCompatActivity
26import androidx.core.content.getSystemService
27import androidx.core.view.WindowCompat 23import androidx.core.view.WindowCompat
28import androidx.core.view.WindowInsetsCompat 24import androidx.core.view.WindowInsetsCompat
29import androidx.core.view.WindowInsetsControllerCompat 25import androidx.core.view.WindowInsetsControllerCompat
@@ -39,7 +35,6 @@ import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
39import org.yuzu.yuzu_emu.fragments.EmulationFragment 35import org.yuzu.yuzu_emu.fragments.EmulationFragment
40import org.yuzu.yuzu_emu.model.Game 36import org.yuzu.yuzu_emu.model.Game
41import org.yuzu.yuzu_emu.utils.ControllerMappingHelper 37import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
42import org.yuzu.yuzu_emu.utils.EmulationMenuSettings
43import org.yuzu.yuzu_emu.utils.ForegroundService 38import org.yuzu.yuzu_emu.utils.ForegroundService
44import org.yuzu.yuzu_emu.utils.InputHandler 39import org.yuzu.yuzu_emu.utils.InputHandler
45import org.yuzu.yuzu_emu.utils.NfcReader 40import 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
7import android.database.Cursor 7import android.database.Cursor
8import android.net.Uri 8import android.net.Uri
9import android.provider.DocumentsContract 9import android.provider.DocumentsContract
10import android.provider.OpenableColumns
10import androidx.documentfile.provider.DocumentFile 11import androidx.documentfile.provider.DocumentFile
12import org.yuzu.yuzu_emu.YuzuApplication
11import org.yuzu.yuzu_emu.model.MinimalDocumentFile 13import org.yuzu.yuzu_emu.model.MinimalDocumentFile
12import java.io.BufferedInputStream 14import java.io.BufferedInputStream
13import java.io.File 15import 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
429u32 GetAndroidScreenRotation() {
430 return EmulationSession::GetInstance().ScreenRotation();
431}
432
433static Core::SystemResultStatus RunEmulation(const std::string& filepath) { 420static 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
476void 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
483void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, 463void 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
12struct HostTranslateInfo { 12struct 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
9namespace Shader::Optimization {
10namespace {
11
12constexpr s32 F64ToF32Exp = +1023 - 127;
13constexpr s32 F32ToF64Exp = +127 - 1023;
14
15IR::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
34IR::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
52IR::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
157void 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
177void 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);
18void DeadCodeEliminationPass(IR::Program& program); 18void DeadCodeEliminationPass(IR::Program& program);
19void GlobalMemoryToStorageBufferPass(IR::Program& program); 19void GlobalMemoryToStorageBufferPass(IR::Program& program);
20void IdentityRemovalPass(IR::Program& program); 20void IdentityRemovalPass(IR::Program& program);
21void LowerFp64ToFp32(IR::Program& program);
21void LowerFp16ToFp32(IR::Program& program); 22void LowerFp16ToFp32(IR::Program& program);
22void LowerInt64ToInt32(IR::Program& program); 23void LowerInt64ToInt32(IR::Program& program);
23void RescalingPass(IR::Program& program); 24void 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
716template <class P> 716template <class P>
717void BufferCache<P>::BindHostVertexBuffers() { 717void 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
1617template <class P> 1645template <class P>
1618void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { 1646void 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
1648template <class P>
1649void 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
108struct 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
108class BufferCacheChannelInfo : public ChannelInfo { 117class BufferCacheChannelInfo : public ChannelInfo {
109public: 118public:
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
235void 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
235void BufferCacheRuntime::BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, 244void 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
332void 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
323void BufferCacheRuntime::BindTextureBuffer(Buffer& buffer, u32 offset, u32 size, 341void 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
41extern u32 GetAndroidScreenRotation();
42#endif
43
44namespace Vulkan { 40namespace Vulkan {
45 41
46namespace { 42namespace {
@@ -78,47 +74,6 @@ struct ScreenRectVertex {
78 } 74 }
79}; 75};
80 76
81#ifdef ANDROID
82
83std::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
122std::array<f32, 4 * 4> MakeOrthographicMatrix(f32 width, f32 height) { 77std::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
133u32 GetBytesPerPixel(const Tegra::FramebufferConfig& framebuffer) { 86u32 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
504void 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
505void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, 538void 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
559void 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
526void BufferCacheRuntime::ReserveNullBuffer() { 578void 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 {
18class Device; 18class Device;
19class DescriptorPool; 19class DescriptorPool;
20class Scheduler; 20class Scheduler;
21struct HostVertexBinding;
21 22
22class BufferCacheRuntime; 23class 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()) {