Compare commits

..

78 Commits

Author SHA1 Message Date
Morph
1a46823ec5 parcel: Optimize small_vector sizes 2023-06-30 22:05:28 -04:00
Morph
5a09fa5012 maxwell_dma: Specify dst_operand.pitch instead of a temp var 2023-06-30 21:49:59 -04:00
Morph
310b6cf4af general: Use ScratchBuffer where possible 2023-06-30 21:49:59 -04:00
Morph
fbd85417ff ring_buffer: Fix const usage on std::span 2023-06-30 13:33:14 -04:00
Morph
b8c906f9d1 scratch_buffer: Add member types to ScratchBuffer
Allows for implicit conversion to std::span<T>.
2023-06-30 13:33:13 -04:00
Fernando S
9252ad4e10 Merge pull request #10956 from FernandoS27/pikmin-another-game-ill-hate
AccelerateDMA: Don't accelerate 3D texture DMA operations
2023-06-30 09:37:07 +02:00
Fernando Sahmkow
596a6132b9 AccelerateDMA: Don't accelerate 3D texture DMA operations 2023-06-29 17:23:29 +02:00
Charles Lombardo
45be4c3214 Merge pull request #10955 from 8bitDream/gradle
android: Suppress a known incompatibility
2023-06-29 11:07:00 -04:00
liamwhite
5e70db0d43 Merge pull request #10935 from Morph1984/mwaitx
x64: Make use of monitorx instructions for power efficient sleeps (AMD)
2023-06-29 10:01:26 -04:00
liamwhite
4c705db73e Merge pull request #10937 from german77/ring
input_common: Remove duplicated enum and fix ring detection
2023-06-29 10:01:19 -04:00
liamwhite
7de778ad39 Merge pull request #10946 from goldenx86/amdBlending
Blacklist EDS3 blending from new AMD drivers
2023-06-29 10:01:11 -04:00
Abandoned Cart
13506e7782 android: Suppress a known incompatibility
Android Gradle plugin 8.0.2 is designed for API 33, but a newer plugin hasn't been released yet. The warning message is rather extravagant, but also suggests adding this property if you are aware of the risks.
2023-06-29 07:32:12 -04:00
german77
ac755476cd input_common: Allow timeouts to happen while scanning for a ring 2023-06-29 01:07:39 -06:00
bunnei
217e958a95 Merge pull request #10945 from t895/android-14
android: Android 14 support
2023-06-28 16:30:12 -07:00
Matías Locatti
ed93cbd462 Blacklist EDS3 blending from new AMD drivers 2023-06-28 20:10:27 -03:00
Charles Lombardo
b76b698c17 android: Android 14 support
Specifies the permissions needed for the changes to foreground services in Android 14.
2023-06-28 16:15:18 -04:00
liamwhite
b60b70e86d Merge pull request #10837 from liamwhite/mali-support
android: Mali support
2023-06-28 12:53:17 -04:00
german77
df9685a21c input_common: Remove duplicated DriverResult enum 2023-06-28 09:49:47 -06:00
Morph
295fc7d0f8 x64: cpu_wait: Implement MWAITX for non-MSVC compilers 2023-06-28 01:39:15 -04:00
Morph
2b68a3cbbf x64: cpu_wait: Remove magic values 2023-06-28 01:39:06 -04:00
Morph
3d868baaa4 x64: cpu_wait: Make use of MWAITX in MicroSleep
MWAITX is equivalent to UMWAIT on Intel's Alder Lake CPUs.
We can emulate TPAUSE by using MONITORX in conjunction with MWAITX to wait for 100K cycles.
2023-06-28 01:38:55 -04:00
Morph
4303ed614d x64: Add detection of monitorx instructions
monitorx introduces 2 instructions: MONITORX and MWAITX.
2023-06-28 01:36:06 -04:00
GPUCode
ddcc958336 renderer_vulkan: Prevent crashes when blitting depth stencil 2023-06-27 18:00:09 -07:00
GPUCode
eac46ad7ce video_core: Add BCn decoding support 2023-06-27 18:00:09 -07:00
GPUCode
b8c96cee5f renderer_vulkan: Add more feature checking 2023-06-27 18:00:09 -07:00
GPUCode
220a42896d renderer_vulkan: Don't assume debug tool with debug renderer
* Causes crashes because mali drivers don't support debug utils
2023-06-27 18:00:09 -07:00
GPUCode
1522b95658 renderer_vulkan: Bump minimum SPIRV version
* 1.3 is guaranteed on all 1.1 drivers
2023-06-27 18:00:09 -07:00
GPUCode
c339af37a7 renderer_vulkan: Respect viewport limit 2023-06-27 18:00:09 -07:00
GPUCode
a9b44d37e1 renderer_vulkan: Don't add transform feedback flag if unsupported 2023-06-27 18:00:09 -07:00
GPUCode
72e7f5b4dd renderer_vulkan: Add suport for debug report callback 2023-06-27 18:00:09 -07:00
liamwhite
0fe44071f8 Merge pull request #10933 from merryhime/dunno
arm_dynarmic_32: Remove disabling of block linking on arm64
2023-06-27 20:50:24 -04:00
liamwhite
e0d406042c Merge pull request #10932 from abouvier/git-indent
gitmodules: normalize indentation and url
2023-06-27 20:50:16 -04:00
liamwhite
0b2798be27 Merge pull request #10930 from lat9nq/msvc-inconsistent-time-zones
settings: Catch runtime_error, fallback time zone
2023-06-27 20:50:06 -04:00
lat9nq
21675c9b68 settings: Clean up includes
Adds <version> since we are looking at C++ implementation version
details. Also moves exception header includes into the if preprocessor
command since we only use it there.
2023-06-27 19:13:54 -04:00
Merry
e3c548d081 arm_dynarmic_32: Remove disabling of block linking on arm64 2023-06-27 23:51:49 +01:00
lat9nq
32475efbc4 settings: Catch runtime_error, fallback time zone
Windows will let you select time zones that  will fail in their
own C++ implementation library. Evidently from the stack trace, we get a
runtime error to work with, so catch it and use the fallback.
2023-06-27 18:12:26 -04:00
Morph
bd4fefe5e7 Merge pull request #10931 from german77/clang
yuzu: Fix clang format
2023-06-27 18:11:22 -04:00
german77
30544fbfa5 yuzu: Fix clang format 2023-06-27 15:55:23 -06:00
Alexandre Bouvier
33cd3a0db0 gitmodules: normalize indentation and url 2023-06-27 23:39:29 +02:00
Narr the Reg
112b660456 Merge pull request #9663 from EBADBEEF/disable-controller-applet
qt: add option to disable controller applet
2023-06-27 10:32:51 -06:00
liamwhite
2b3bfafb9e Merge pull request #10867 from Kelebek1/dma_safe
Use safe reads in DMA engine
2023-06-27 11:21:47 -04:00
liamwhite
c6959449d1 Merge pull request #10473 from GPUCode/vma
Use vulkan memory allocator
2023-06-27 11:21:36 -04:00
liamwhite
20111c86b6 Merge pull request #10495 from bm01/master
input_common: Redesign mouse panning
2023-06-27 11:21:28 -04:00
liamwhite
f254ce2c60 Merge pull request #10679 from zeltermann/wakelock-reason
Only use SDL wakelock on Linux
2023-06-27 11:21:20 -04:00
liamwhite
dafbc86366 Merge pull request #10916 from ameerj/lolmem
OpenGL: Add Local Memory warmup shader for Nvidia
2023-06-27 11:21:10 -04:00
liamwhite
02882d9251 Merge pull request #10925 from t895/fs-agony
android: Fix size check for content uris
2023-06-26 23:33:51 -04:00
Charles Lombardo
9074a70b01 android: Fix size check for content uris
Fix for checking file size for android content uris
2023-06-26 22:24:18 -04:00
liamwhite
2ed8b3cbb9 Merge pull request #10908 from kiri11/clarify-ring-ui
Clarify Ring-Con configuration message in UI
2023-06-26 14:31:30 -04:00
liamwhite
b82c649b0f Merge pull request #10903 from german77/nfc_state
input_common: Improve nfc state handling and 3rd party support
2023-06-26 14:31:23 -04:00
liamwhite
ce990adae5 Merge pull request #10901 from german77/sdl_fix
input_common: Make use of new SDL features
2023-06-26 14:31:14 -04:00
liamwhite
c280a2fe1c Merge pull request #10894 from lat9nq/bsd-tzdb
nx_tzdb: Update tzdb_to_nx
2023-06-26 14:31:07 -04:00
liamwhite
28df6ac0aa Merge pull request #10888 from 8bitDream/native
android: (native) Parameter types from Android Studio
2023-06-26 14:31:00 -04:00
liamwhite
0030fa9721 Merge pull request #10865 from t895/extension-meme
android: Clean up file extension checks
2023-06-26 14:30:49 -04:00
Charles Lombardo
0f31039831 android: Clean up file extension checks 2023-06-26 13:25:56 -04:00
GPUCode
b6c6dcc576 externals: Use cmake subdirectory 2023-06-26 18:59:24 +03:00
ameerj
4f160633d3 OpenGL: Limit lmem warmup to NVIDIA
🐸
2023-06-25 19:06:51 -04:00
ameerj
405eae3734 shaders: Track local memory usage 2023-06-25 18:59:33 -04:00
ameerj
b198339580 emit_glasm: Fix lmem size computation 2023-06-25 18:43:52 -04:00
ameerj
82107b33a2 OpenGL: Add Local Memory warmup shader 2023-06-25 18:43:23 -04:00
lat9nq
f5569bfed9 nx_tzdb: Update tzdb_to_nx to 212afa2
Moves build data to a separate directory so the build happens out of the source
tree.
2023-06-25 17:20:18 -04:00
Kirill Ignatev
b6e89bdf2c Hyphenate Joy-Con and clarify further 2023-06-25 12:51:16 -04:00
Kirill Ignatev
b6025cf62f Clarify Ring-Con configuration message in UI
Not obvious how left controller should be set up
Mention that it should be left physical dual emulated
2023-06-25 11:52:15 -04:00
german77
bf641e2964 core: hid: Allow to read bin files while switch controller is available 2023-06-24 18:59:55 -06:00
german77
5aa208e264 input_common: Dont try to read/write data from 3rd party controllers 2023-06-24 18:59:55 -06:00
german77
ec9a71b12a externals: Include player led fix on SDL 2023-06-24 17:43:08 -06:00
german77
474fa13a1a input_common: Make use of new SDL features 2023-06-24 17:42:56 -06:00
zeltermann
482fbded9b Only use SDL wakelock on Linux
SDL has internally fixed shenanigans related to wakelocking through DBus
from inside sandboxes from around August 2022, so we can now remove the
workaround we used since 2021.
2023-06-24 14:51:41 +07:00
lat9nq
e5769e9467 nx_tzdb: Update tzdb_to_nx
Includes fixes for other BSD's, and axes shell scripts for pure CMake.
2023-06-23 19:07:26 -04:00
Abandoned Cart
b53945a99f android: define [[maybe_unused]] (const) auto 2023-06-23 14:05:14 -04:00
Abandoned Cart
a58a1403ba android: Parameter types from Android Studio
Android Studio marked these parameters as errors because it is an instance, not a class, that is being passed from Java.
2023-06-23 10:36:30 -04:00
GPUCode
75fb29e08e vulkan_common: Remove required flags
* Allows VMA to fallback to system RAM instead of crashing
2023-06-22 20:03:12 +03:00
GPUCode
ee0d68300e renderer_vulkan: Add missing initializers 2023-06-18 14:14:03 +03:00
GPUCode
7b2f680468 renderer_vulkan: Use VMA for buffers 2023-06-18 12:45:18 +03:00
GPUCode
48e39756f1 renderer_vulkan: Use VMA for images 2023-06-18 12:45:18 +03:00
GPUCode
c60eed36b7 memory_allocator: Remove OpenGL interop
* Appears to be unused atm
2023-06-18 12:45:18 +03:00
lat9nq
6448eade2e externals: Add vma and initialize it
video_core: Move vma implementation to library
2023-06-18 12:45:12 +03:00
Baptiste Marie
8e3d4e3396 input_common: Redesign mouse panning 2023-06-12 00:47:52 +02:00
EBADBEEF
a84ad180e8 qt: add option to disable controller applet
- add checkbox to disable the controller applet UI
- when controller applet is disabled, use the yuzu-cmd fallback
  controller applet that applies controller config based on rules
- See https://github.com/yuzu-emu/yuzu/issues/8552 for some discussion
2023-01-22 23:36:40 -08:00
140 changed files with 3980 additions and 1448 deletions

43
.gitmodules vendored
View File

@@ -2,35 +2,35 @@
# SPDX-License-Identifier: GPL-2.0-or-later
[submodule "enet"]
path = externals/enet
url = https://github.com/lsalzman/enet.git
path = externals/enet
url = https://github.com/lsalzman/enet.git
[submodule "inih"]
path = externals/inih/inih
url = https://github.com/benhoyt/inih.git
path = externals/inih/inih
url = https://github.com/benhoyt/inih.git
[submodule "cubeb"]
path = externals/cubeb
url = https://github.com/mozilla/cubeb.git
path = externals/cubeb
url = https://github.com/mozilla/cubeb.git
[submodule "dynarmic"]
path = externals/dynarmic
url = https://github.com/MerryMage/dynarmic.git
path = externals/dynarmic
url = https://github.com/merryhime/dynarmic.git
[submodule "libusb"]
path = externals/libusb/libusb
url = https://github.com/libusb/libusb.git
[submodule "discord-rpc"]
path = externals/discord-rpc
url = https://github.com/yuzu-emu/discord-rpc.git
path = externals/discord-rpc
url = https://github.com/yuzu-emu/discord-rpc.git
[submodule "Vulkan-Headers"]
path = externals/Vulkan-Headers
url = https://github.com/KhronosGroup/Vulkan-Headers.git
path = externals/Vulkan-Headers
url = https://github.com/KhronosGroup/Vulkan-Headers.git
[submodule "sirit"]
path = externals/sirit
url = https://github.com/yuzu-emu/sirit
path = externals/sirit
url = https://github.com/yuzu-emu/sirit.git
[submodule "mbedtls"]
path = externals/mbedtls
url = https://github.com/yuzu-emu/mbedtls
path = externals/mbedtls
url = https://github.com/yuzu-emu/mbedtls.git
[submodule "xbyak"]
path = externals/xbyak
url = https://github.com/herumi/xbyak.git
path = externals/xbyak
url = https://github.com/herumi/xbyak.git
[submodule "opus"]
path = externals/opus/opus
url = https://github.com/xiph/opus.git
@@ -45,13 +45,16 @@
url = https://github.com/FFmpeg/FFmpeg.git
[submodule "vcpkg"]
path = externals/vcpkg
url = https://github.com/Microsoft/vcpkg.git
url = https://github.com/microsoft/vcpkg.git
[submodule "cpp-jwt"]
path = externals/cpp-jwt
url = https://github.com/arun11299/cpp-jwt.git
[submodule "libadrenotools"]
path = externals/libadrenotools
url = https://github.com/bylaws/libadrenotools
url = https://github.com/bylaws/libadrenotools.git
[submodule "tzdb_to_nx"]
path = externals/nx_tzdb/tzdb_to_nx
url = https://github.com/lat9nq/tzdb_to_nx.git
[submodule "VulkanMemoryAllocator"]
path = externals/vma/VulkanMemoryAllocator
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git

View File

@@ -143,6 +143,11 @@ endif()
# TZDB (Time Zone Database)
add_subdirectory(nx_tzdb)
# VMA
add_library(vma vma/vma.cpp)
target_include_directories(vma PUBLIC ./vma/VulkanMemoryAllocator/include)
target_link_libraries(vma PRIVATE Vulkan::Headers)
if (NOT TARGET LLVM::Demangle)
add_library(demangle demangle/ItaniumDemangle.cpp)
target_include_directories(demangle PUBLIC ./demangle)
@@ -152,6 +157,9 @@ endif()
add_library(stb stb/stb_dxt.cpp)
target_include_directories(stb PUBLIC ./stb)
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
target_include_directories(bc_decoder PUBLIC ./bc_decoder)
if (ANDROID)
if (ARCHITECTURE_arm64)
add_subdirectory(libadrenotools)

2
externals/SDL vendored

1522
externals/bc_decoder/bc_decoder.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

43
externals/bc_decoder/bc_decoder.h vendored Normal file
View File

@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <cstdint>
namespace bcn {
/**
* @brief Decodes a BC1 encoded image to R8G8B8A8
*/
void DecodeBc1(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC2 encoded image to R8G8B8A8
*/
void DecodeBc2(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC3 encoded image to R8G8B8A8
*/
void DecodeBc3(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC4 encoded image to R8
*/
void DecodeBc4(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC5 encoded image to R8G8
*/
void DecodeBc5(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC6 encoded image to R16G16B16A16
*/
void DecodeBc6(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC7 encoded image to R8G8B8A8
*/
void DecodeBc7(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
}

8
externals/vma/vma.cpp vendored Normal file
View File

@@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#define VMA_IMPLEMENTATION
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
#include <vk_mem_alloc.h>

View File

@@ -26,7 +26,7 @@ val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toIn
android {
namespace = "org.yuzu.yuzu_emu"
compileSdkVersion = "android-33"
compileSdkVersion = "android-34"
ndkVersion = "25.2.9519653"
buildFeatures {
@@ -51,7 +51,7 @@ android {
// TODO If this is ever modified, change application_id in strings.xml
applicationId = "org.yuzu.yuzu_emu"
minSdk = 30
targetSdk = 33
targetSdk = 34
versionName = getGitVersion()
// If you want to use autoVersion for the versionCode, create a property in local.properties

View File

@@ -13,6 +13,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
@@ -69,7 +70,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:resource="@xml/nfc_tech_filter" />
</activity>
<service android:name="org.yuzu.yuzu_emu.utils.ForegroundService"/>
<service android:name="org.yuzu.yuzu_emu.utils.ForegroundService" android:foregroundServiceType="specialUse">
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="Keep emulation running in background"/>
</service>
<provider
android:name=".features.DocumentProvider"

View File

@@ -29,7 +29,6 @@ import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.FileUtil
class SearchFragment : Fragment() {
private var _binding: FragmentSearchBinding? = null
@@ -128,10 +127,7 @@ class SearchFragment : Fragment() {
R.id.chip_homebrew -> baseList.filter { it.isHomebrew }
R.id.chip_retail -> baseList.filter {
FileUtil.hasExtension(it.path, "xci") ||
FileUtil.hasExtension(it.path, "nsp")
}
R.id.chip_retail -> baseList.filter { !it.isHomebrew }
else -> baseList
}

View File

@@ -43,7 +43,7 @@ class Game(
companion object {
val extensions: Set<String> = HashSet(
listOf(".xci", ".nsp", ".nca", ".nro")
listOf("xci", "nsp", "nca", "nro")
)
}
}

View File

@@ -296,7 +296,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
return@registerForActivityResult
}
if (!FileUtil.hasExtension(result, "keys")) {
if (FileUtil.getExtension(result) != "keys") {
MessageDialogFragment.newInstance(
R.string.reading_keys_failure,
R.string.install_prod_keys_failure_extension_description
@@ -393,7 +393,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
return@registerForActivityResult
}
if (!FileUtil.hasExtension(result, "bin")) {
if (FileUtil.getExtension(result) != "bin") {
MessageDialogFragment.newInstance(
R.string.reading_keys_failure,
R.string.install_amiibo_keys_failure_extension_description

View File

@@ -7,7 +7,6 @@ import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.provider.DocumentsContract
import android.provider.OpenableColumns
import androidx.documentfile.provider.DocumentFile
import java.io.BufferedInputStream
import java.io.File
@@ -185,19 +184,18 @@ object FileUtil {
/**
* Get file display name from given path
* @param path content uri path
* @param uri content uri
* @return String display name
*/
fun getFilename(context: Context, path: String): String {
val resolver = context.contentResolver
fun getFilename(uri: Uri): String {
val resolver = YuzuApplication.appContext.contentResolver
val columns = arrayOf(
DocumentsContract.Document.COLUMN_DISPLAY_NAME
)
var filename = ""
var c: Cursor? = null
try {
val mUri = Uri.parse(path)
c = resolver.query(mUri, columns, null, null, null)
c = resolver.query(uri, columns, null, null, null)
c!!.moveToNext()
filename = c.getString(0)
} catch (e: Exception) {
@@ -326,25 +324,9 @@ object FileUtil {
}
}
fun hasExtension(path: String, extension: String): Boolean =
path.substring(path.lastIndexOf(".") + 1).contains(extension)
fun hasExtension(uri: Uri, extension: String): Boolean {
val fileName: String?
val cursor = YuzuApplication.appContext.contentResolver.query(uri, null, null, null, null)
val nameIndex = cursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME)
cursor?.moveToFirst()
if (nameIndex == null) {
return false
}
fileName = cursor.getString(nameIndex)
cursor.close()
if (fileName == null) {
return false
}
return fileName.substring(fileName.lastIndexOf(".") + 1).contains(extension)
fun getExtension(uri: Uri): String {
val fileName = getFilename(uri)
return fileName.substring(fileName.lastIndexOf(".") + 1)
.lowercase()
}
}

View File

@@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.utils
import android.content.SharedPreferences
import android.net.Uri
import androidx.preference.PreferenceManager
import java.util.*
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.yuzu.yuzu_emu.NativeLibrary
@@ -33,15 +32,9 @@ object GameHelper {
val children = FileUtil.listFiles(context, gamesUri)
for (file in children) {
if (!file.isDirectory) {
val filename = file.uri.toString()
val extensionStart = filename.lastIndexOf('.')
if (extensionStart > 0) {
val fileExtension = filename.substring(extensionStart)
// Check that the file has an extension we care about before trying to read out of it.
if (Game.extensions.contains(fileExtension.lowercase(Locale.getDefault()))) {
games.add(getGame(filename))
}
// Check that the file has an extension we care about before trying to read out of it.
if (Game.extensions.contains(FileUtil.getExtension(file.uri))) {
games.add(getGame(file.uri))
}
}
}
@@ -59,21 +52,19 @@ object GameHelper {
return games.toList()
}
private fun getGame(filePath: String): Game {
private fun getGame(uri: Uri): Game {
val filePath = uri.toString()
var name = NativeLibrary.getTitle(filePath)
// If the game's title field is empty, use the filename.
if (name.isEmpty()) {
name = filePath.substring(filePath.lastIndexOf("/") + 1)
name = FileUtil.getFilename(uri)
}
var gameId = NativeLibrary.getGameId(filePath)
// If the game's ID field is empty, use the filename without extension.
if (gameId.isEmpty()) {
gameId = filePath.substring(
filePath.lastIndexOf("/") + 1,
filePath.lastIndexOf(".")
)
gameId = name.substring(0, name.lastIndexOf("."))
}
val newGame = Game(

View File

@@ -60,6 +60,9 @@
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
#define jconst [[maybe_unused]] const auto
#define jauto [[maybe_unused]] auto
namespace {
class EmulationSession final {
@@ -99,8 +102,8 @@ public:
}
int InstallFileToNand(std::string filename) {
const auto copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
std::size_t block_size) {
jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
std::size_t block_size) {
if (src == nullptr || dest == nullptr) {
return false;
}
@@ -109,10 +112,10 @@ public:
}
using namespace Common::Literals;
std::vector<u8> buffer(1_MiB);
[[maybe_unused]] std::vector<u8> buffer(1_MiB);
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
const auto read = src->Read(buffer.data(), buffer.size(), i);
jconst read = src->Read(buffer.data(), buffer.size(), i);
dest->Write(buffer.data(), read, i);
}
return true;
@@ -129,14 +132,14 @@ public:
m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
m_system.GetFileSystemController().CreateFactories(*m_vfs);
std::shared_ptr<FileSys::NSP> nsp;
[[maybe_unused]] std::shared_ptr<FileSys::NSP> nsp;
if (filename.ends_with("nsp")) {
nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
if (nsp->IsExtractedType()) {
return InstallError;
}
} else if (filename.ends_with("xci")) {
const auto xci =
jconst xci =
std::make_shared<FileSys::XCI>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
nsp = xci->GetSecurePartitionNSP();
} else {
@@ -151,7 +154,7 @@ public:
return InstallError;
}
const auto res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(
jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(
*nsp, true, copy_func);
switch (res) {
@@ -234,7 +237,7 @@ public:
m_system.SetFilesystem(m_vfs);
// Initialize system.
auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
jauto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
m_software_keyboard = android_keyboard.get();
m_system.SetShuttingDown(false);
m_system.ApplySettings();
@@ -332,7 +335,7 @@ public:
while (true) {
{
std::unique_lock lock(m_mutex);
[[maybe_unused]] std::unique_lock lock(m_mutex);
if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
[&]() { return !m_is_running; })) {
// Emulation halted.
@@ -364,7 +367,7 @@ public:
}
bool IsHandheldOnly() {
const auto npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
if (npad_style_set.fullkey == 1) {
return false;
@@ -377,17 +380,17 @@ public:
return !Settings::values.use_docked_mode.GetValue();
}
void SetDeviceType(int index, int type) {
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
void SetDeviceType([[maybe_unused]] int index, int type) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type));
}
void OnGamepadConnectEvent(int index) {
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
void OnGamepadConnectEvent([[maybe_unused]] int index) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
// Ensure that player1 is configured correctly and handheld disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) {
auto handheld =
jauto handheld =
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
@@ -399,7 +402,8 @@ public:
// Ensure that handheld is configured correctly and player 1 disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) {
auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
jauto player1 =
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) {
player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
@@ -413,8 +417,8 @@ public:
}
}
void OnGamepadDisconnectEvent(int index) {
auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
void OnGamepadDisconnectEvent([[maybe_unused]] int index) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
controller->Disconnect();
}
@@ -430,7 +434,7 @@ private:
};
RomMetadata GetRomMetadata(const std::string& path) {
if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
if (jauto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
return search->second;
}
@@ -438,14 +442,14 @@ private:
}
RomMetadata CacheRomMetadata(const std::string& path) {
const auto file = Core::GetGameFileFromPath(m_vfs, path);
auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
jconst file = Core::GetGameFileFromPath(m_vfs, path);
jauto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
RomMetadata entry;
loader->ReadTitle(entry.title);
loader->ReadIcon(entry.icon);
if (loader->GetFileType() == Loader::FileType::NRO) {
auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
jauto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
entry.isHomebrew = loader_nro->IsHomebrew();
} else {
entry.isHomebrew = false;
@@ -516,7 +520,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
const auto result = EmulationSession::GetInstance().InitializeEmulation(filepath);
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath);
if (result != Core::SystemResultStatus::Success) {
return result;
}
@@ -528,24 +532,25 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
extern "C" {
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jclass clazz, jobject surf) {
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject instance,
[[maybe_unused]] jobject surf) {
EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf));
EmulationSession::GetInstance().SurfaceChanged();
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jclass clazz) {
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jobject instance) {
ANativeWindow_release(EmulationSession::GetInstance().NativeWindow());
EmulationSession::GetInstance().SetNativeWindow(nullptr);
EmulationSession::GetInstance().SurfaceChanged();
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jclass clazz,
jstring j_directory) {
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance,
[[maybe_unused]] jstring j_directory) {
Common::FS::SetAppDirectory(GetJString(env, j_directory));
}
int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jclass clazz,
jstring j_file) {
int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance,
[[maybe_unused]] jstring j_file) {
return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file));
}
@@ -570,7 +575,7 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* e
}
jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading(
JNIEnv* env, [[maybe_unused]] jobject instance) {
JNIEnv* env, jobject instance) {
#ifdef ARCHITECTURE_arm64
// If the KGSL device exists custom drivers can be loaded using adrenotools
return SupportsCustomDriver();
@@ -648,8 +653,8 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(JNIEnv*
return static_cast<jboolean>(true);
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent(JNIEnv* env, jclass clazz,
[[maybe_unused]] jint j_device,
jint j_button, jint action) {
jint j_device, jint j_button,
jint action) {
if (EmulationSession::GetInstance().IsRunning()) {
// Ensure gamepad is connected
EmulationSession::GetInstance().OnGamepadConnectEvent(j_device);
@@ -718,8 +723,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c
}
jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass clazz,
[[maybe_unused]] jstring j_filename) {
auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
jstring j_filename) {
jauto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
reinterpret_cast<jbyte*>(icon_data.data()));
@@ -727,8 +732,8 @@ jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass cla
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle(JNIEnv* env, jclass clazz,
[[maybe_unused]] jstring j_filename) {
auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
jstring j_filename) {
jauto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
return env->NewStringUTF(title.c_str());
}
@@ -743,22 +748,21 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId(JNIEnv* env, jclass claz
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions(JNIEnv* env, jclass clazz,
[[maybe_unused]] jstring j_filename) {
jstring j_filename) {
return env->NewStringUTF("");
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany(JNIEnv* env, jclass clazz,
[[maybe_unused]] jstring j_filename) {
jstring j_filename) {
return env->NewStringUTF("");
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew(JNIEnv* env, jclass clazz,
[[maybe_unused]] jstring j_filename) {
jstring j_filename) {
return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename));
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation
[[maybe_unused]] (JNIEnv* env, jclass clazz) {
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation(JNIEnv* env, jclass clazz) {
// Create the default config.ini.
Config{};
// Initialize the emulated system.
@@ -770,8 +774,7 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass cl
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z(
JNIEnv* env, jclass clazz, [[maybe_unused]] jstring j_file,
[[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) {
Config{};
@@ -816,7 +819,7 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jcl
jdoubleArray j_stats = env->NewDoubleArray(4);
if (EmulationSession::GetInstance().IsRunning()) {
const auto results = EmulationSession::GetInstance().PerfStats();
jconst results = EmulationSession::GetInstance().PerfStats();
// Converting the structure into an array makes it easier to pass it to the frontend
double stats[4] = {results.system_fps, results.average_game_fps, results.frametime,

View File

@@ -15,3 +15,6 @@ android.useAndroidX=true
kotlin.code.style=official
kotlin.parallel.tasks.in.project=true
android.defaults.buildfeatures.buildconfig=true
# Android Gradle plugin 8.0.2
android.suppressUnsupportedCompileSdk=34

View File

@@ -605,6 +605,12 @@ fs::file_type GetEntryType(const fs::path& path) {
}
u64 GetSize(const fs::path& path) {
#ifdef ANDROID
if (Android::IsContentUri(path)) {
return Android::GetSize(path);
}
#endif
std::error_code ec;
const auto file_size = fs::file_size(path, ec);

View File

@@ -75,8 +75,10 @@ enum class DriverResult {
ErrorWritingData,
NoDeviceDetected,
InvalidHandle,
InvalidParameters,
NotSupported,
Disabled,
Delayed,
Unknown,
};

View File

@@ -54,7 +54,7 @@ public:
return push_count;
}
std::size_t Push(const std::span<T> input) {
std::size_t Push(std::span<const T> input) {
return Push(input.data(), input.size());
}

View File

@@ -5,7 +5,6 @@
#include <iterator>
#include "common/concepts.h"
#include "common/make_unique_for_overwrite.h"
namespace Common {
@@ -19,15 +18,22 @@ namespace Common {
template <typename T>
class ScratchBuffer {
public:
using iterator = T*;
using const_iterator = const T*;
using value_type = T;
using element_type = T;
using iterator_category = std::contiguous_iterator_tag;
using value_type = T;
using size_type = size_t;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = pointer;
using const_iterator = const_pointer;
using iterator_category = std::random_access_iterator_tag;
using iterator_concept = std::contiguous_iterator_tag;
ScratchBuffer() = default;
explicit ScratchBuffer(size_t initial_capacity)
explicit ScratchBuffer(size_type initial_capacity)
: last_requested_size{initial_capacity}, buffer_capacity{initial_capacity},
buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {}
@@ -39,7 +45,7 @@ public:
/// This will only grow the buffer's capacity if size is greater than the current capacity.
/// The previously held data will remain intact.
void resize(size_t size) {
void resize(size_type size) {
if (size > buffer_capacity) {
auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
std::move(buffer.get(), buffer.get() + buffer_capacity, new_buffer.get());
@@ -51,7 +57,7 @@ public:
/// This will only grow the buffer's capacity if size is greater than the current capacity.
/// The previously held data will be destroyed if a reallocation occurs.
void resize_destructive(size_t size) {
void resize_destructive(size_type size) {
if (size > buffer_capacity) {
buffer_capacity = size;
buffer = Common::make_unique_for_overwrite<T[]>(buffer_capacity);
@@ -59,43 +65,43 @@ public:
last_requested_size = size;
}
[[nodiscard]] T* data() noexcept {
[[nodiscard]] pointer data() noexcept {
return buffer.get();
}
[[nodiscard]] const T* data() const noexcept {
[[nodiscard]] const_pointer data() const noexcept {
return buffer.get();
}
[[nodiscard]] T* begin() noexcept {
[[nodiscard]] iterator begin() noexcept {
return data();
}
[[nodiscard]] const T* begin() const noexcept {
[[nodiscard]] const_iterator begin() const noexcept {
return data();
}
[[nodiscard]] T* end() noexcept {
[[nodiscard]] iterator end() noexcept {
return data() + last_requested_size;
}
[[nodiscard]] const T* end() const noexcept {
[[nodiscard]] const_iterator end() const noexcept {
return data() + last_requested_size;
}
[[nodiscard]] T& operator[](size_t i) {
[[nodiscard]] reference operator[](size_type i) {
return buffer[i];
}
[[nodiscard]] const T& operator[](size_t i) const {
[[nodiscard]] const_reference operator[](size_type i) const {
return buffer[i];
}
[[nodiscard]] size_t size() const noexcept {
[[nodiscard]] size_type size() const noexcept {
return last_requested_size;
}
[[nodiscard]] size_t capacity() const noexcept {
[[nodiscard]] size_type capacity() const noexcept {
return buffer_capacity;
}
@@ -106,8 +112,8 @@ public:
}
private:
size_t last_requested_size{};
size_t buffer_capacity{};
size_type last_requested_size{};
size_type buffer_capacity{};
std::unique_ptr<T[]> buffer{};
};

View File

@@ -1,8 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <version>
#if __cpp_lib_chrono >= 201907L
#include <chrono>
#include <exception>
#include <stdexcept>
#endif
#include <string_view>
@@ -25,9 +28,19 @@ std::string GetTimeZoneString() {
if (time_zone_index == 0) { // Auto
#if __cpp_lib_chrono >= 201907L
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
std::string_view current_zone_name = current_zone->name();
location_name = current_zone_name;
try {
const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
std::string_view current_zone_name = current_zone->name();
location_name = current_zone_name;
} catch (std::runtime_error& runtime_error) {
// VCRUNTIME will throw a runtime_error if the operating system's selected time zone
// cannot be found
location_name = Common::TimeZone::FindSystemTimeZone();
LOG_WARNING(Common,
"Error occurred when trying to determine system time zone:\n{}\nFalling "
"back to hour offset \"{}\"",
runtime_error.what(), location_name);
}
#else
location_name = Common::TimeZone::FindSystemTimeZone();
#endif

View File

@@ -525,9 +525,16 @@ struct Values {
Setting<bool> tas_loop{false, "tas_loop"};
Setting<bool> mouse_panning{false, "mouse_panning"};
Setting<u8, true> mouse_panning_sensitivity{50, 1, 100, "mouse_panning_sensitivity"};
Setting<bool> mouse_enabled{false, "mouse_enabled"};
Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"};
Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"};
Setting<u8, true> mouse_panning_deadzone_x_counterweight{
0, 0, 100, "mouse_panning_deadzone_x_counterweight"};
Setting<u8, true> mouse_panning_deadzone_y_counterweight{
0, 0, 100, "mouse_panning_deadzone_y_counterweight"};
Setting<u8, true> mouse_panning_decay_strength{22, 0, 100, "mouse_panning_decay_strength"};
Setting<u8, true> mouse_panning_min_decay{5, 0, 100, "mouse_panning_min_decay"};
Setting<bool> mouse_enabled{false, "mouse_enabled"};
Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
Setting<bool> keyboard_enabled{false, "keyboard_enabled"};

View File

@@ -93,6 +93,7 @@ void AppendCPUInfo(FieldCollection& fc) {
add_field("CPU_Extension_x64_GFNI", caps.gfni);
add_field("CPU_Extension_x64_INVARIANT_TSC", caps.invariant_tsc);
add_field("CPU_Extension_x64_LZCNT", caps.lzcnt);
add_field("CPU_Extension_x64_MONITORX", caps.monitorx);
add_field("CPU_Extension_x64_MOVBE", caps.movbe);
add_field("CPU_Extension_x64_PCLMULQDQ", caps.pclmulqdq);
add_field("CPU_Extension_x64_POPCNT", caps.popcnt);

View File

@@ -168,6 +168,7 @@ static CPUCaps Detect() {
__cpuid(cpu_id, 0x80000001);
caps.lzcnt = Common::Bit<5>(cpu_id[2]);
caps.fma4 = Common::Bit<16>(cpu_id[2]);
caps.monitorx = Common::Bit<29>(cpu_id[2]);
}
if (max_ex_fn >= 0x80000007) {

View File

@@ -63,6 +63,7 @@ struct CPUCaps {
bool gfni : 1;
bool invariant_tsc : 1;
bool lzcnt : 1;
bool monitorx : 1;
bool movbe : 1;
bool pclmulqdq : 1;
bool popcnt : 1;

View File

@@ -13,36 +13,60 @@
namespace Common::X64 {
namespace {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
constexpr auto PauseCycles = 100'000U;
} // Anonymous namespace
#ifdef _MSC_VER
__forceinline static void TPAUSE() {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
static constexpr auto PauseCycles = 100'000;
_tpause(0, FencedRDTSC() + PauseCycles);
static constexpr auto RequestC02State = 0U;
_tpause(RequestC02State, FencedRDTSC() + PauseCycles);
}
__forceinline static void MWAITX() {
static constexpr auto EnableWaitTimeFlag = 1U << 1;
static constexpr auto RequestC1State = 0U;
// monitor_var should be aligned to a cache line.
alignas(64) u64 monitor_var{};
_mm_monitorx(&monitor_var, 0, 0);
_mm_mwaitx(EnableWaitTimeFlag, RequestC1State, PauseCycles);
}
#else
static void TPAUSE() {
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
// For reference:
// At 1 GHz, 100K cycles is 100us
// At 2 GHz, 100K cycles is 50us
// At 4 GHz, 100K cycles is 25us
static constexpr auto PauseCycles = 100'000;
static constexpr auto RequestC02State = 0U;
const auto tsc = FencedRDTSC() + PauseCycles;
const auto eax = static_cast<u32>(tsc & 0xFFFFFFFF);
const auto edx = static_cast<u32>(tsc >> 32);
asm volatile("tpause %0" : : "r"(0), "d"(edx), "a"(eax));
asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax));
}
static void MWAITX() {
static constexpr auto EnableWaitTimeFlag = 1U << 1;
static constexpr auto RequestC1State = 0U;
// monitor_var should be aligned to a cache line.
alignas(64) u64 monitor_var{};
asm volatile("monitorx" : : "a"(&monitor_var), "c"(0), "d"(0));
asm volatile("mwaitx" : : "a"(RequestC1State), "b"(PauseCycles), "c"(EnableWaitTimeFlag));
}
#endif
void MicroSleep() {
static const bool has_waitpkg = GetCPUCaps().waitpkg;
static const bool has_monitorx = GetCPUCaps().monitorx;
if (has_waitpkg) {
TPAUSE();
} else if (has_monitorx) {
MWAITX();
} else {
std::this_thread::yield();
}

View File

@@ -322,11 +322,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
}
}
#ifdef ARCHITECTURE_arm64
// TODO: remove when fixed in dynarmic
config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking;
#endif
return std::make_unique<Dynarmic::A32::Jit>(config);
}

View File

@@ -1250,6 +1250,11 @@ Common::Input::DriverResult EmulatedController::SetPollingMode(
const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode);
const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode);
// Restore previous state
if (mapped_nfc_result != Common::Input::DriverResult::Success) {
right_output_device->SetPollingMode(Common::Input::PollingMode::Active);
}
if (virtual_nfc_result == Common::Input::DriverResult::Success) {
return virtual_nfc_result;
}
@@ -1329,16 +1334,22 @@ bool EmulatedController::StartNfcPolling() {
auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
auto& nfc_virtual_output_device = output_devices[3];
return nfc_output_device->StartNfcPolling() == Common::Input::NfcState::Success ||
nfc_virtual_output_device->StartNfcPolling() == Common::Input::NfcState::Success;
const auto device_result = nfc_output_device->StartNfcPolling();
const auto virtual_device_result = nfc_virtual_output_device->StartNfcPolling();
return device_result == Common::Input::NfcState::Success ||
virtual_device_result == Common::Input::NfcState::Success;
}
bool EmulatedController::StopNfcPolling() {
auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
auto& nfc_virtual_output_device = output_devices[3];
return nfc_output_device->StopNfcPolling() == Common::Input::NfcState::Success ||
nfc_virtual_output_device->StopNfcPolling() == Common::Input::NfcState::Success;
const auto device_result = nfc_output_device->StopNfcPolling();
const auto virtual_device_result = nfc_virtual_output_device->StopNfcPolling();
return device_result == Common::Input::NfcState::Success ||
virtual_device_result == Common::Input::NfcState::Success;
}
bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) {

View File

@@ -5,7 +5,7 @@
#include "audio_core/renderer/audio_device.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/scratch_buffer.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
@@ -124,12 +124,15 @@ private:
void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
tmp_buffer.resize_destructive(write_buffer_size);
tmp_buffer[0] = 0;
released_buffer.resize_destructive(write_buffer_size);
released_buffer[0] = 0;
const auto count = impl->GetReleasedBuffers(tmp_buffer);
const auto count = impl->GetReleasedBuffers(released_buffer);
ctx.WriteBuffer(tmp_buffer);
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
impl->GetSystem().GetSessionId(), count);
ctx.WriteBuffer(released_buffer);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
@@ -155,7 +158,6 @@ private:
LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(buffer_count);
}
@@ -195,7 +197,7 @@ private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* event;
std::shared_ptr<AudioCore::AudioIn::In> impl;
Common::ScratchBuffer<u64> tmp_buffer;
Common::ScratchBuffer<u64> released_buffer;
};
AudInU::AudInU(Core::System& system_)

View File

@@ -9,6 +9,7 @@
#include "audio_core/renderer/audio_device.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "common/scratch_buffer.h"
#include "common/string_util.h"
#include "common/swap.h"
#include "core/core.h"
@@ -102,8 +103,8 @@ private:
AudioOutBuffer buffer{};
std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer));
[[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag);
LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
impl->GetSystem().GetSessionId(), tag);
auto result = impl->AppendBuffer(buffer, tag);
@@ -123,12 +124,15 @@ private:
void GetReleasedAudioOutBuffers(HLERequestContext& ctx) {
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
tmp_buffer.resize_destructive(write_buffer_size);
tmp_buffer[0] = 0;
released_buffer.resize_destructive(write_buffer_size);
released_buffer[0] = 0;
const auto count = impl->GetReleasedBuffers(tmp_buffer);
const auto count = impl->GetReleasedBuffers(released_buffer);
ctx.WriteBuffer(tmp_buffer);
ctx.WriteBuffer(released_buffer);
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
impl->GetSystem().GetSessionId(), count);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
@@ -154,7 +158,6 @@ private:
LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(buffer_count);
}
@@ -165,7 +168,6 @@ private:
LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(samples_played);
}
@@ -205,7 +207,7 @@ private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* event;
std::shared_ptr<AudioCore::AudioOut::Out> impl;
Common::ScratchBuffer<u64> tmp_buffer;
Common::ScratchBuffer<u64> released_buffer;
};
AudOutU::AudOutU(Core::System& system_)

View File

@@ -15,6 +15,7 @@
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "common/polyfill_ranges.h"
#include "common/scratch_buffer.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
@@ -119,23 +120,23 @@ private:
auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
if (is_buffer_b) {
const auto buffersB{ctx.BufferDescriptorB()};
tmp_output.resize_destructive(buffersB[0].Size());
tmp_performance.resize_destructive(buffersB[1].Size());
output_buffer.resize_destructive(buffersB[0].Size());
performance_buffer.resize_destructive(buffersB[1].Size());
} else {
const auto buffersC{ctx.BufferDescriptorC()};
tmp_output.resize_destructive(buffersC[0].Size());
tmp_performance.resize_destructive(buffersC[1].Size());
output_buffer.resize_destructive(buffersC[0].Size());
performance_buffer.resize_destructive(buffersC[1].Size());
}
auto result = impl->RequestUpdate(input, tmp_performance, tmp_output);
auto result = impl->RequestUpdate(input, performance_buffer, output_buffer);
if (result.IsSuccess()) {
if (is_buffer_b) {
ctx.WriteBufferB(tmp_output.data(), tmp_output.size(), 0);
ctx.WriteBufferB(tmp_performance.data(), tmp_performance.size(), 1);
ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0);
ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1);
} else {
ctx.WriteBufferC(tmp_output.data(), tmp_output.size(), 0);
ctx.WriteBufferC(tmp_performance.data(), tmp_performance.size(), 1);
ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0);
ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
}
} else {
LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description);
@@ -233,8 +234,8 @@ private:
Kernel::KEvent* rendered_event;
Manager& manager;
std::unique_ptr<Renderer> impl;
Common::ScratchBuffer<u8> tmp_output;
Common::ScratchBuffer<u8> tmp_performance;
Common::ScratchBuffer<u8> output_buffer;
Common::ScratchBuffer<u8> performance_buffer;
};
class IAudioDevice final : public ServiceFramework<IAudioDevice> {

View File

@@ -11,6 +11,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/scratch_buffer.h"
#include "core/hle/service/audio/hwopus.h"
#include "core/hle/service/ipc_helpers.h"
@@ -68,13 +69,13 @@ private:
ExtraBehavior extra_behavior) {
u32 consumed = 0;
u32 sample_count = 0;
tmp_samples.resize_destructive(ctx.GetWriteBufferNumElements<opus_int16>());
samples.resize_destructive(ctx.GetWriteBufferNumElements<opus_int16>());
if (extra_behavior == ExtraBehavior::ResetContext) {
ResetDecoderContext();
}
if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), tmp_samples, performance)) {
if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), samples, performance)) {
LOG_ERROR(Audio, "Failed to decode opus data");
IPC::ResponseBuilder rb{ctx, 2};
// TODO(ogniK): Use correct error code
@@ -90,7 +91,7 @@ private:
if (performance) {
rb.Push<u64>(*performance);
}
ctx.WriteBuffer(tmp_samples);
ctx.WriteBuffer(samples);
}
bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input,
@@ -154,7 +155,7 @@ private:
OpusDecoderPtr decoder;
u32 sample_rate;
u32 channel_count;
Common::ScratchBuffer<opus_int16> tmp_samples;
Common::ScratchBuffer<opus_int16> samples;
};
class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {

View File

@@ -2,7 +2,6 @@
// SPDX-FileCopyrightText: 2021 Skyline Team and Contributors
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cinttypes>
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
@@ -63,12 +62,12 @@ void NVDRV::Ioctl1(HLERequestContext& ctx) {
}
// Check device
tmp_output.resize_destructive(ctx.GetWriteBufferSize(0));
output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
const auto input_buffer = ctx.ReadBuffer(0);
const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, tmp_output);
const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
if (command.is_out != 0) {
ctx.WriteBuffer(tmp_output);
ctx.WriteBuffer(output_buffer);
}
IPC::ResponseBuilder rb{ctx, 3};
@@ -90,12 +89,12 @@ void NVDRV::Ioctl2(HLERequestContext& ctx) {
const auto input_buffer = ctx.ReadBuffer(0);
const auto input_inlined_buffer = ctx.ReadBuffer(1);
tmp_output.resize_destructive(ctx.GetWriteBufferSize(0));
output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
const auto nv_result =
nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, tmp_output);
nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
if (command.is_out != 0) {
ctx.WriteBuffer(tmp_output);
ctx.WriteBuffer(output_buffer);
}
IPC::ResponseBuilder rb{ctx, 3};
@@ -116,12 +115,14 @@ void NVDRV::Ioctl3(HLERequestContext& ctx) {
}
const auto input_buffer = ctx.ReadBuffer(0);
tmp_output.resize_destructive(ctx.GetWriteBufferSize(0));
tmp_output_inline.resize_destructive(ctx.GetWriteBufferSize(1));
const auto nv_result = nvdrv->Ioctl3(fd, command, input_buffer, tmp_output, tmp_output_inline);
output_buffer.resize_destructive(ctx.GetWriteBufferSize(0));
inline_output_buffer.resize_destructive(ctx.GetWriteBufferSize(1));
const auto nv_result =
nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, inline_output_buffer);
if (command.is_out != 0) {
ctx.WriteBuffer(tmp_output, 0);
ctx.WriteBuffer(tmp_output_inline, 1);
ctx.WriteBuffer(output_buffer, 0);
ctx.WriteBuffer(inline_output_buffer, 1);
}
IPC::ResponseBuilder rb{ctx, 3};

View File

@@ -4,6 +4,7 @@
#pragma once
#include <memory>
#include "common/scratch_buffer.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/service.h"
@@ -34,8 +35,8 @@ private:
u64 pid{};
bool is_initialized{};
Common::ScratchBuffer<u8> tmp_output;
Common::ScratchBuffer<u8> tmp_output_inline;
Common::ScratchBuffer<u8> output_buffer;
Common::ScratchBuffer<u8> inline_output_buffer;
};
} // namespace Service::Nvidia

View File

@@ -6,6 +6,7 @@
#include <memory>
#include <span>
#include <vector>
#include <boost/container/small_vector.hpp>
#include "common/alignment.h"
@@ -148,9 +149,9 @@ public:
this->WriteImpl(0U, m_object_buffer);
}
std::vector<u8> Serialize() const {
std::vector<u8> output_buffer(sizeof(ParcelHeader) + m_data_buffer.size() +
m_object_buffer.size());
std::span<u8> Serialize() {
m_output_buffer.resize(sizeof(ParcelHeader) + m_data_buffer.size() +
m_object_buffer.size());
ParcelHeader header{};
header.data_size = static_cast<u32>(m_data_buffer.size());
@@ -158,17 +159,17 @@ public:
header.objects_size = static_cast<u32>(m_object_buffer.size());
header.objects_offset = header.data_offset + header.data_size;
std::memcpy(output_buffer.data(), &header, sizeof(header));
std::ranges::copy(m_data_buffer, output_buffer.data() + header.data_offset);
std::ranges::copy(m_object_buffer, output_buffer.data() + header.objects_offset);
std::memcpy(m_output_buffer.data(), &header, sizeof(ParcelHeader));
std::ranges::copy(m_data_buffer, m_output_buffer.data() + header.data_offset);
std::ranges::copy(m_object_buffer, m_output_buffer.data() + header.objects_offset);
return output_buffer;
return m_output_buffer;
}
private:
template <typename T>
template <typename T, size_t BufferSize>
requires(std::is_trivially_copyable_v<T>)
void WriteImpl(const T& val, boost::container::small_vector<u8, 0x200>& buffer) {
void WriteImpl(const T& val, boost::container::small_vector<u8, BufferSize>& buffer) {
const size_t aligned_size = Common::AlignUp(sizeof(T), 4);
const size_t old_size = buffer.size();
buffer.resize(old_size + aligned_size);
@@ -177,8 +178,9 @@ private:
}
private:
boost::container::small_vector<u8, 0x200> m_data_buffer;
boost::container::small_vector<u8, 0x200> m_object_buffer;
boost::container::small_vector<u8, 0x1B0> m_data_buffer;
boost::container::small_vector<u8, 0x40> m_object_buffer;
boost::container::small_vector<u8, 0x200> m_output_buffer;
};
} // namespace Service::android

View File

@@ -102,12 +102,12 @@ bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const {
Joycon::SerialNumber serial_number{};
const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type);
if (result != Joycon::DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return false;
}
const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number);
if (result2 != Joycon::DriverResult::Success) {
if (result2 != Common::Input::DriverResult::Success) {
return false;
}
@@ -171,10 +171,10 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) {
LOG_WARNING(Input, "No free handles available");
return;
}
if (result == Joycon::DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = handle->RequestDeviceAccess(device_info);
}
if (result == Joycon::DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
LOG_WARNING(Input, "Initialize device");
const std::size_t port = handle->GetDevicePort();
@@ -273,8 +273,7 @@ Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier,
led_config += led_status.led_3 ? 4 : 0;
led_config += led_status.led_4 ? 8 : 0;
return static_cast<Common::Input::DriverResult>(
handle->SetLedConfig(static_cast<u8>(led_config)));
return handle->SetLedConfig(static_cast<u8>(led_config));
}
Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier,
@@ -283,8 +282,8 @@ Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identi
if (handle == nullptr) {
return Common::Input::DriverResult::InvalidHandle;
}
return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig(
Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format)));
return handle->SetIrsConfig(Joycon::IrsMode::ImageTransfer,
static_cast<Joycon::IrsResolution>(camera_format));
};
Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const {
@@ -351,7 +350,7 @@ Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier,
std::vector<Joycon::MifareReadData> read_data(read_request.size());
const auto result = handle->ReadMifareData(read_request, read_data);
if (result == Joycon::DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
for (std::size_t i = 0; i < read_request.size(); i++) {
data.data[i] = {
.command = static_cast<u8>(command),
@@ -402,15 +401,15 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif
switch (polling_mode) {
case Common::Input::PollingMode::Active:
return static_cast<Common::Input::DriverResult>(handle->SetActiveMode());
return handle->SetActiveMode();
case Common::Input::PollingMode::Passive:
return static_cast<Common::Input::DriverResult>(handle->SetPassiveMode());
return handle->SetPassiveMode();
case Common::Input::PollingMode::IR:
return static_cast<Common::Input::DriverResult>(handle->SetIrMode());
return handle->SetIrMode();
case Common::Input::PollingMode::NFC:
return static_cast<Common::Input::DriverResult>(handle->SetNfcMode());
return handle->SetNfcMode();
case Common::Input::PollingMode::Ring:
return static_cast<Common::Input::DriverResult>(handle->SetRingConMode());
return handle->SetRingConMode();
default:
return Common::Input::DriverResult::NotSupported;
}
@@ -828,13 +827,13 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const {
}
}
Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const {
Common::Input::NfcState Joycons::TranslateDriverResult(Common::Input::DriverResult result) const {
switch (result) {
case Joycon::DriverResult::Success:
case Common::Input::DriverResult::Success:
return Common::Input::NfcState::Success;
case Joycon::DriverResult::Disabled:
case Common::Input::DriverResult::Disabled:
return Common::Input::NfcState::WrongDeviceState;
case Joycon::DriverResult::NotSupported:
case Common::Input::DriverResult::NotSupported:
return Common::Input::NfcState::NotSupported;
default:
return Common::Input::NfcState::Unknown;

View File

@@ -17,7 +17,6 @@ struct Color;
struct MotionData;
struct TagInfo;
enum class ControllerType : u8;
enum class DriverResult;
enum class IrsResolution;
class JoyconDriver;
} // namespace InputCommon::Joycon
@@ -112,7 +111,7 @@ private:
/// Returns the name of the device in text format
std::string JoyconName(Joycon::ControllerType type) const;
Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const;
Common::Input::NfcState TranslateDriverResult(Common::Input::DriverResult result) const;
std::jthread scan_thread;

View File

@@ -76,9 +76,6 @@ void Mouse::UpdateThread(std::stop_token stop_token) {
UpdateStickInput();
UpdateMotionInput();
if (mouse_panning_timeout++ > 20) {
StopPanning();
}
std::this_thread::sleep_for(std::chrono::milliseconds(update_time));
}
}
@@ -88,18 +85,45 @@ void Mouse::UpdateStickInput() {
return;
}
const float sensitivity =
Settings::values.mouse_panning_sensitivity.GetValue() * default_stick_sensitivity;
const float length = last_mouse_change.Length();
// Slow movement by 4%
last_mouse_change *= 0.96f;
SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity);
SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity);
// Prevent input from exceeding the max range (1.0f) too much,
// but allow some room to make it easier to sustain
if (length > 1.2f) {
last_mouse_change /= length;
last_mouse_change *= 1.2f;
}
auto mouse_change = last_mouse_change;
// Bind the mouse change to [0 <= deadzone_counterweight <= 1,1]
if (length < 1.0f) {
const float deadzone_h_counterweight =
Settings::values.mouse_panning_deadzone_x_counterweight.GetValue();
const float deadzone_v_counterweight =
Settings::values.mouse_panning_deadzone_y_counterweight.GetValue();
mouse_change /= length;
mouse_change.x *= length + (1 - length) * deadzone_h_counterweight * 0.01f;
mouse_change.y *= length + (1 - length) * deadzone_v_counterweight * 0.01f;
}
SetAxis(identifier, mouse_axis_x, mouse_change.x);
SetAxis(identifier, mouse_axis_y, -mouse_change.y);
// Decay input over time
const float clamped_length = std::min(1.0f, length);
const float decay_strength = Settings::values.mouse_panning_decay_strength.GetValue();
const float decay = 1 - clamped_length * clamped_length * decay_strength * 0.01f;
const float min_decay = Settings::values.mouse_panning_min_decay.GetValue();
const float clamped_decay = std::min(1 - min_decay / 100.0f, decay);
last_mouse_change *= clamped_decay;
}
void Mouse::UpdateMotionInput() {
const float sensitivity =
Settings::values.mouse_panning_sensitivity.GetValue() * default_motion_sensitivity;
// This may need its own sensitivity instead of using the average
const float sensitivity = (Settings::values.mouse_panning_x_sensitivity.GetValue() +
Settings::values.mouse_panning_y_sensitivity.GetValue()) /
2.0f * default_motion_sensitivity;
const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x +
last_motion_change.y * last_motion_change.y);
@@ -131,49 +155,28 @@ void Mouse::UpdateMotionInput() {
void Mouse::Move(int x, int y, int center_x, int center_y) {
if (Settings::values.mouse_panning) {
mouse_panning_timeout = 0;
auto mouse_change =
const auto mouse_change =
(Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>();
const float x_sensitivity =
Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity;
const float y_sensitivity =
Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity;
last_motion_change += {-mouse_change.y, -mouse_change.x, 0};
const auto move_distance = mouse_change.Length();
if (move_distance == 0) {
return;
}
// Make slow movements at least 3 units on length
if (move_distance < 3.0f) {
// Normalize value
mouse_change /= move_distance;
mouse_change *= 3.0f;
}
// Average mouse movements
last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f);
const auto last_move_distance = last_mouse_change.Length();
// Make fast movements clamp to 8 units on length
if (last_move_distance > 8.0f) {
// Normalize value
last_mouse_change /= last_move_distance;
last_mouse_change *= 8.0f;
}
// Ignore average if it's less than 1 unit and use current movement value
if (last_move_distance < 1.0f) {
last_mouse_change = mouse_change / mouse_change.Length();
}
last_mouse_change.x += mouse_change.x * x_sensitivity * 0.09f;
last_mouse_change.y += mouse_change.y * y_sensitivity * 0.09f;
return;
}
if (button_pressed) {
const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin;
const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f;
SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * sensitivity);
SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * sensitivity);
const float x_sensitivity = Settings::values.mouse_panning_x_sensitivity.GetValue();
const float y_sensitivity = Settings::values.mouse_panning_y_sensitivity.GetValue();
SetAxis(identifier, mouse_axis_x,
static_cast<float>(mouse_move.x) * x_sensitivity * 0.0012f);
SetAxis(identifier, mouse_axis_y,
static_cast<float>(-mouse_move.y) * y_sensitivity * 0.0012f);
last_motion_change = {
static_cast<float>(-mouse_move.y) / 50.0f,
@@ -241,10 +244,6 @@ void Mouse::ReleaseAllButtons() {
button_pressed = false;
}
void Mouse::StopPanning() {
last_mouse_change = {};
}
std::vector<Common::ParamPackage> Mouse::GetInputDevices() const {
std::vector<Common::ParamPackage> devices;
devices.emplace_back(Common::ParamPackage{

View File

@@ -98,7 +98,6 @@ private:
void UpdateThread(std::stop_token stop_token);
void UpdateStickInput();
void UpdateMotionInput();
void StopPanning();
Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const;
@@ -108,7 +107,6 @@ private:
Common::Vec3<float> last_motion_change;
Common::Vec2<int> wheel_position;
bool button_pressed;
int mouse_panning_timeout{};
std::jthread update_thread;
};

View File

@@ -150,6 +150,8 @@ public:
if (sdl_controller) {
const auto type = SDL_GameControllerGetType(sdl_controller.get());
return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ||
(type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) ||
(type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) ||
(type == SDL_CONTROLLER_TYPE_PS5);
}
return false;
@@ -228,9 +230,8 @@ public:
return false;
}
Common::Input::BatteryLevel GetBatteryLevel() {
const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get());
switch (level) {
Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) {
switch (battery_level) {
case SDL_JOYSTICK_POWER_EMPTY:
return Common::Input::BatteryLevel::Empty;
case SDL_JOYSTICK_POWER_LOW:
@@ -378,7 +379,6 @@ void SDLDriver::InitJoystick(int joystick_index) {
if (joystick_map.find(guid) == joystick_map.end()) {
auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
PreSetController(joystick->GetPadIdentifier());
SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
joystick->EnableMotion();
joystick_map[guid].emplace_back(std::move(joystick));
return;
@@ -398,7 +398,6 @@ void SDLDriver::InitJoystick(int joystick_index) {
const int port = static_cast<int>(joystick_guid_list.size());
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
PreSetController(joystick->GetPadIdentifier());
SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel());
joystick->EnableMotion();
joystick_guid_list.emplace_back(std::move(joystick));
}
@@ -438,8 +437,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
const PadIdentifier identifier = joystick->GetPadIdentifier();
SetButton(identifier, event.jbutton.button, true);
// Battery doesn't trigger an event so just update every button press
SetBattery(identifier, joystick->GetBatteryLevel());
}
break;
}
@@ -466,6 +463,13 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
}
break;
}
case SDL_JOYBATTERYUPDATED: {
if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) {
const PadIdentifier identifier = joystick->GetPadIdentifier();
SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level));
}
break;
}
case SDL_JOYDEVICEREMOVED:
LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
@@ -483,6 +487,10 @@ void SDLDriver::CloseJoysticks() {
}
SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
// Set our application name. Currently passed to DBus by SDL and visible to the user through
// their desktop environment.
SDL_SetHint(SDL_HINT_APP_NAME, "yuzu");
if (!Settings::values.enable_raw_input) {
// Disable raw input. When enabled this setting causes SDL to die when a web applet opens
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
@@ -501,6 +509,9 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0");
} else {
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED, "0");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1");
}
// Disable hidapi drivers for pro controllers when the custom joycon driver is enabled
@@ -508,8 +519,11 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0");
} else {
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
}
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1");
// Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
// driver on Linux.
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
@@ -789,7 +803,9 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
// This list also excludes Screenshot since there's not really a mapping for that
ButtonBindings switch_to_sdl_button;
if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) {
if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO ||
SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT ||
SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) {
switch_to_sdl_button = GetNintendoButtonBinding(joystick);
} else {
switch_to_sdl_button = GetDefaultButtonBinding();

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "common/swap.h"
@@ -28,13 +29,13 @@ void JoyconDriver::Stop() {
input_thread = {};
}
DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) {
std::scoped_lock lock{mutex};
handle_device_type = ControllerType::None;
GetDeviceType(device_info, handle_device_type);
if (handle_device_type == ControllerType::None) {
return DriverResult::UnsupportedControllerType;
return Common::Input::DriverResult::UnsupportedControllerType;
}
hidapi_handle->handle =
@@ -43,15 +44,15 @@ DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info)
if (!hidapi_handle->handle) {
LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
device_info->vendor_id, device_info->product_id);
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconDriver::InitializeDevice() {
Common::Input::DriverResult JoyconDriver::InitializeDevice() {
if (!hidapi_handle->handle) {
return DriverResult::InvalidHandle;
return Common::Input::DriverResult::InvalidHandle;
}
std::scoped_lock lock{mutex};
disable_input_thread = true;
@@ -72,6 +73,7 @@ DriverResult JoyconDriver::InitializeDevice() {
nfc_enabled = false;
passive_enabled = false;
irs_enabled = false;
input_only_device = false;
gyro_sensitivity = Joycon::GyroSensitivity::DPS2000;
gyro_performance = Joycon::GyroPerformance::HZ833;
accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8;
@@ -86,16 +88,23 @@ DriverResult JoyconDriver::InitializeDevice() {
rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle);
// Get fixed joycon info
generic_protocol->GetVersionNumber(version);
generic_protocol->SetLowPowerMode(false);
generic_protocol->GetColor(color);
if (handle_device_type == ControllerType::Pro) {
// Some 3rd party controllers aren't pro controllers
generic_protocol->GetControllerType(device_type);
} else {
device_type = handle_device_type;
if (generic_protocol->GetVersionNumber(version) != Common::Input::DriverResult::Success) {
// If this command fails the device doesn't accept configuration commands
input_only_device = true;
}
generic_protocol->GetSerialNumber(serial_number);
if (!input_only_device) {
generic_protocol->SetLowPowerMode(false);
generic_protocol->GetColor(color);
if (handle_device_type == ControllerType::Pro) {
// Some 3rd party controllers aren't pro controllers
generic_protocol->GetControllerType(device_type);
} else {
device_type = handle_device_type;
}
generic_protocol->GetSerialNumber(serial_number);
}
supported_features = GetSupportedFeatures();
// Get Calibration data
@@ -121,7 +130,7 @@ DriverResult JoyconDriver::InitializeDevice() {
}
disable_input_thread = false;
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
void JoyconDriver::InputThread(std::stop_token stop_token) {
@@ -221,7 +230,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
if (!amiibo_detected) {
Joycon::TagInfo tag_info;
const auto result = nfc_protocol->GetTagInfo(tag_info);
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
joycon_poller->UpdateAmiibo(tag_info);
amiibo_detected = true;
}
@@ -247,7 +256,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
}
}
DriverResult JoyconDriver::SetPollingMode() {
Common::Input::DriverResult JoyconDriver::SetPollingMode() {
SCOPE_EXIT({ disable_input_thread = false; });
disable_input_thread = true;
@@ -261,6 +270,10 @@ DriverResult JoyconDriver::SetPollingMode() {
generic_protocol->EnableImu(false);
}
if (input_only_device) {
return Common::Input::DriverResult::NotSupported;
}
if (irs_protocol->IsEnabled()) {
irs_protocol->DisableIrs();
}
@@ -277,39 +290,42 @@ DriverResult JoyconDriver::SetPollingMode() {
if (irs_enabled && supported_features.irs) {
auto result = irs_protocol->EnableIrs();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
return result;
}
irs_protocol->DisableIrs();
LOG_ERROR(Input, "Error enabling IRS");
return result;
}
if (nfc_enabled && supported_features.nfc) {
auto result = nfc_protocol->EnableNfc();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
return result;
}
nfc_protocol->DisableNfc();
LOG_ERROR(Input, "Error enabling NFC");
return result;
}
if (hidbus_enabled && supported_features.hidbus) {
auto result = ring_protocol->EnableRingCon();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = ring_protocol->StartRingconPolling();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
ring_connected = true;
return result;
}
ring_connected = false;
ring_protocol->DisableRingCon();
LOG_ERROR(Input, "Error enabling Ringcon");
return result;
}
if (passive_enabled && supported_features.passive) {
const auto result = generic_protocol->EnablePassiveMode();
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
return result;
}
LOG_ERROR(Input, "Error enabling passive mode");
@@ -317,7 +333,7 @@ DriverResult JoyconDriver::SetPollingMode() {
// Default Mode
const auto result = generic_protocol->EnableActiveMode();
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
LOG_ERROR(Input, "Error enabling active mode");
}
// Switch calls this function after enabling active mode
@@ -333,6 +349,10 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() {
.vibration = true,
};
if (input_only_device) {
return features;
}
if (device_type == ControllerType::Right) {
features.nfc = true;
features.irs = true;
@@ -377,26 +397,26 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) {
return true;
}
DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) {
std::scoped_lock lock{mutex};
if (disable_input_thread) {
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
return rumble_protocol->SendVibration(vibration);
}
DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) {
std::scoped_lock lock{mutex};
if (disable_input_thread) {
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
return generic_protocol->SetLedPattern(led_pattern);
}
DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
std::scoped_lock lock{mutex};
if (disable_input_thread) {
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
disable_input_thread = true;
const auto result = irs_protocol->SetIrsConfig(mode_, format_);
@@ -404,7 +424,7 @@ DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) {
return result;
}
DriverResult JoyconDriver::SetPassiveMode() {
Common::Input::DriverResult JoyconDriver::SetPassiveMode() {
std::scoped_lock lock{mutex};
motion_enabled = false;
hidbus_enabled = false;
@@ -414,7 +434,7 @@ DriverResult JoyconDriver::SetPassiveMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetActiveMode() {
Common::Input::DriverResult JoyconDriver::SetActiveMode() {
if (is_ring_disabled_by_irs) {
is_ring_disabled_by_irs = false;
SetActiveMode();
@@ -430,11 +450,11 @@ DriverResult JoyconDriver::SetActiveMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetIrMode() {
Common::Input::DriverResult JoyconDriver::SetIrMode() {
std::scoped_lock lock{mutex};
if (!supported_features.irs) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (ring_connected) {
@@ -449,11 +469,11 @@ DriverResult JoyconDriver::SetIrMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetNfcMode() {
Common::Input::DriverResult JoyconDriver::SetNfcMode() {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
motion_enabled = true;
@@ -464,11 +484,11 @@ DriverResult JoyconDriver::SetNfcMode() {
return SetPollingMode();
}
DriverResult JoyconDriver::SetRingConMode() {
Common::Input::DriverResult JoyconDriver::SetRingConMode() {
std::scoped_lock lock{mutex};
if (!supported_features.hidbus) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
motion_enabled = true;
@@ -480,20 +500,20 @@ DriverResult JoyconDriver::SetRingConMode() {
const auto result = SetPollingMode();
if (!ring_connected) {
return DriverResult::NoDeviceDetected;
return Common::Input::DriverResult::NoDeviceDetected;
}
return result;
}
DriverResult JoyconDriver::StartNfcPolling() {
Common::Input::DriverResult JoyconDriver::StartNfcPolling() {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
disable_input_thread = true;
@@ -503,34 +523,39 @@ DriverResult JoyconDriver::StartNfcPolling() {
return result;
}
DriverResult JoyconDriver::StopNfcPolling() {
Common::Input::DriverResult JoyconDriver::StopNfcPolling() {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
disable_input_thread = true;
const auto result = nfc_protocol->StopNFCPollingMode();
disable_input_thread = false;
if (amiibo_detected) {
amiibo_detected = false;
joycon_poller->UpdateAmiibo({});
}
return result;
}
DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
out_data.resize(0x21C);
@@ -541,17 +566,17 @@ DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) {
return result;
}
DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
disable_input_thread = true;
@@ -561,18 +586,18 @@ DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) {
return result;
}
DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
std::span<MifareReadData> out_data) {
Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
std::span<MifareReadData> out_data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
disable_input_thread = true;
@@ -582,17 +607,17 @@ DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data,
return result;
}
DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) {
std::scoped_lock lock{mutex};
if (!supported_features.nfc) {
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
if (!nfc_protocol->IsEnabled()) {
return DriverResult::Disabled;
return Common::Input::DriverResult::Disabled;
}
if (!amiibo_detected) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
disable_input_thread = true;
@@ -651,8 +676,8 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) {
joycon_poller->SetCallbacks(callbacks);
}
DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type) {
Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type) {
static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{
std::pair<u32, ControllerType>{0x2006, ControllerType::Left},
{0x2007, ControllerType::Right},
@@ -662,25 +687,25 @@ DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info,
controller_type = ControllerType::None;
if (device_info->vendor_id != nintendo_vendor_id) {
return DriverResult::UnsupportedControllerType;
return Common::Input::DriverResult::UnsupportedControllerType;
}
for (const auto& [product_id, type] : supported_devices) {
if (device_info->product_id == static_cast<u16>(product_id)) {
controller_type = type;
return Joycon::DriverResult::Success;
return Common::Input::DriverResult::Success;
}
}
return Joycon::DriverResult::UnsupportedControllerType;
return Common::Input::DriverResult::UnsupportedControllerType;
}
DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number) {
Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number) {
if (device_info->serial_number == nullptr) {
return DriverResult::Unknown;
return Common::Input::DriverResult::Unknown;
}
std::memcpy(&serial_number, device_info->serial_number, 15);
return Joycon::DriverResult::Success;
return Common::Input::DriverResult::Success;
}
} // namespace InputCommon::Joycon

View File

@@ -11,6 +11,10 @@
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class CalibrationProtocol;
class GenericProtocol;
@@ -26,8 +30,8 @@ public:
~JoyconDriver();
DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info);
DriverResult InitializeDevice();
Common::Input::DriverResult RequestDeviceAccess(SDL_hid_device_info* device_info);
Common::Input::DriverResult InitializeDevice();
void Stop();
bool IsConnected() const;
@@ -41,31 +45,31 @@ public:
SerialNumber GetSerialNumber() const;
SerialNumber GetHandleSerialNumber() const;
DriverResult SetVibration(const VibrationValue& vibration);
DriverResult SetLedConfig(u8 led_pattern);
DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_);
DriverResult SetPassiveMode();
DriverResult SetActiveMode();
DriverResult SetIrMode();
DriverResult SetNfcMode();
DriverResult SetRingConMode();
DriverResult StartNfcPolling();
DriverResult StopNfcPolling();
DriverResult ReadAmiiboData(std::vector<u8>& out_data);
DriverResult WriteNfcData(std::span<const u8> data);
DriverResult ReadMifareData(std::span<const MifareReadChunk> request,
std::span<MifareReadData> out_data);
DriverResult WriteMifareData(std::span<const MifareWriteChunk> request);
Common::Input::DriverResult SetVibration(const VibrationValue& vibration);
Common::Input::DriverResult SetLedConfig(u8 led_pattern);
Common::Input::DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_);
Common::Input::DriverResult SetPassiveMode();
Common::Input::DriverResult SetActiveMode();
Common::Input::DriverResult SetIrMode();
Common::Input::DriverResult SetNfcMode();
Common::Input::DriverResult SetRingConMode();
Common::Input::DriverResult StartNfcPolling();
Common::Input::DriverResult StopNfcPolling();
Common::Input::DriverResult ReadAmiiboData(std::vector<u8>& out_data);
Common::Input::DriverResult WriteNfcData(std::span<const u8> data);
Common::Input::DriverResult ReadMifareData(std::span<const MifareReadChunk> request,
std::span<MifareReadData> out_data);
Common::Input::DriverResult WriteMifareData(std::span<const MifareWriteChunk> request);
void SetCallbacks(const JoyconCallbacks& callbacks);
// Returns device type from hidapi handle
static DriverResult GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type);
static Common::Input::DriverResult GetDeviceType(SDL_hid_device_info* device_info,
ControllerType& controller_type);
// Returns serial number from hidapi handle
static DriverResult GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number);
static Common::Input::DriverResult GetSerialNumber(SDL_hid_device_info* device_info,
SerialNumber& serial_number);
private:
struct SupportedFeatures {
@@ -84,7 +88,7 @@ private:
void OnNewData(std::span<u8> buffer);
/// Updates device configuration to enable or disable features
DriverResult SetPollingMode();
Common::Input::DriverResult SetPollingMode();
/// Returns true if input thread is valid and doesn't need to be stopped
bool IsInputThreadValid() const;
@@ -120,6 +124,7 @@ private:
// Hardware configuration
u8 leds{};
ReportMode mode{};
bool input_only_device{};
bool passive_enabled{}; // Low power mode, Ideal for multiple controllers at the same time
bool hidbus_enabled{}; // External device support
bool irs_enabled{}; // Infrared camera input

View File

@@ -3,6 +3,7 @@
#include <cstring>
#include "common/input.h"
#include "input_common/helpers/joycon_protocol/calibration.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
@@ -11,28 +12,29 @@ namespace InputCommon::Joycon {
CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) {
Common::Input::DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(
JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
JoystickLeftSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
if (result == Common::Input::DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -47,28 +49,29 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
return result;
}
DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) {
Common::Input::DriverResult CalibrationProtocol::GetRightJoyStickCalibration(
JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
JoystickRightSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
if (result == Common::Input::DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
@@ -83,28 +86,28 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
return result;
}
DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
Common::Input::DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
ImuSpiCalibration spi_calibration{};
bool has_user_calibration = false;
calibration = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
}
// Read User defined calibration
if (result == DriverResult::Success && has_user_calibration) {
if (result == Common::Input::DriverResult::Success && has_user_calibration) {
result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
}
// Read Factory calibration
if (result == DriverResult::Success && !has_user_calibration) {
if (result == Common::Input::DriverResult::Success && !has_user_calibration) {
result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0];
calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1];
calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2];
@@ -127,8 +130,8 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
return result;
}
DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
s16 current_value) {
Common::Input::DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
s16 current_value) {
constexpr s16 DefaultRingRange{800};
// TODO: Get default calibration form ring itself
@@ -144,15 +147,15 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
.max_value = ring_data_max,
.min_value = ring_data_min,
};
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
bool& has_user_calibration) {
Common::Input::DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
bool& has_user_calibration) {
MagicSpiCalibration spi_magic{};
const DriverResult result{ReadSPI(address, spi_magic)};
const Common::Input::DriverResult result{ReadSPI(address, spi_magic)};
has_user_calibration = false;
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
spi_magic.second == CalibrationMagic::USR_MAGIC_1;
}

View File

@@ -12,8 +12,11 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
namespace InputCommon::Joycon {
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
struct JoyStickCalibration;
struct IMUCalibration;
struct JoyconHandle;
@@ -31,30 +34,30 @@ public:
* @param is_factory_calibration if true factory values will be returned
* @returns JoyStickCalibration of the left joystick
*/
DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration);
Common::Input::DriverResult GetLeftJoyStickCalibration(JoyStickCalibration& calibration);
/**
* Sends a request to obtain the right stick calibration from memory
* @param is_factory_calibration if true factory values will be returned
* @returns JoyStickCalibration of the right joystick
*/
DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration);
Common::Input::DriverResult GetRightJoyStickCalibration(JoyStickCalibration& calibration);
/**
* Sends a request to obtain the motion calibration from memory
* @returns ImuCalibration of the motion sensor
*/
DriverResult GetImuCalibration(MotionCalibration& calibration);
Common::Input::DriverResult GetImuCalibration(MotionCalibration& calibration);
/**
* Calculates on run time the proper calibration of the ring controller
* @returns RingCalibration of the ring sensor
*/
DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
Common::Input::DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
private:
/// Returns true if the specified address corresponds to the magic value of user calibration
DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
Common::Input::DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
/// Converts a raw calibration block to an u16 value containing the x axis value
u16 GetXAxisCalibrationValue(std::span<u8> block) const;

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/common_protocol.h"
@@ -21,10 +22,10 @@ void JoyconCommonProtocol::SetNonBlocking() {
SDL_hid_set_nonblocking(hidapi_handle->handle, 1);
}
DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
const auto result = ReadSPI(SpiAddress::DEVICE_TYPE, controller_type);
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
// Fallback to 3rd party pro controllers
if (controller_type == ControllerType::None) {
controller_type = ControllerType::Pro;
@@ -34,12 +35,13 @@ DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type
return result;
}
DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) {
Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess(
SDL_hid_device_info* device_info) {
ControllerType controller_type{ControllerType::None};
const auto result = GetDeviceType(controller_type);
if (result != DriverResult::Success || controller_type == ControllerType::None) {
return DriverResult::UnsupportedControllerType;
if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) {
return Common::Input::DriverResult::UnsupportedControllerType;
}
hidapi_handle->handle =
@@ -48,32 +50,32 @@ DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device
if (!hidapi_handle->handle) {
LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
device_info->vendor_id, device_info->product_id);
return DriverResult::HandleInUse;
return Common::Input::DriverResult::HandleInUse;
}
SetNonBlocking();
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) {
const std::array<u8, 1> buffer{static_cast<u8>(report_mode)};
return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer);
}
DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> buffer) {
const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size());
if (result == -1) {
return DriverResult::ErrorWritingData;
return Common::Input::DriverResult::ErrorWritingData;
}
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
SubCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse(
SubCommand sc, SubCommandResponse& output) {
constexpr int timeout_mili = 66;
constexpr int MaxTries = 15;
constexpr int MaxTries = 10;
int tries = 0;
do {
@@ -84,16 +86,17 @@ DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc,
LOG_ERROR(Input, "No response from joycon");
}
if (tries++ > MaxTries) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY &&
output.sub_command != sc);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer,
SubCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
std::span<const u8> buffer,
SubCommandResponse& output) {
SubCommandPacket packet{
.output_report = OutputReport::RUMBLE_AND_SUBCMD,
.packet_counter = GetCounter(),
@@ -102,28 +105,28 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const
};
if (buffer.size() > packet.command_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.command_data.data(), buffer.data(), buffer.size());
auto result = SendData(packet);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
result = GetSubCommandResponse(sc, output);
return DriverResult::Success;
return GetSubCommandResponse(sc, output);
}
DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc,
std::span<const u8> buffer) {
SubCommandResponse output{};
return SendSubCommand(sc, buffer, output);
}
DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc,
std::span<const u8> buffer) {
SubCommandPacket packet{
.output_report = OutputReport::MCU_DATA,
.packet_counter = GetCounter(),
@@ -132,7 +135,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
};
if (buffer.size() > packet.command_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.command_data.data(), buffer.data(), buffer.size());
@@ -140,7 +143,7 @@ DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const
return SendData(packet);
}
DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
Common::Input::DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) {
VibrationPacket packet{
.output_report = OutputReport::RUMBLE_ONLY,
.packet_counter = GetCounter(),
@@ -148,7 +151,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
};
if (buffer.size() > packet.vibration_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.vibration_data.data(), buffer.data(), buffer.size());
@@ -156,9 +159,10 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
return SendData(packet);
}
DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) {
Common::Input::DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr,
std::span<u8> output) {
constexpr std::size_t HeaderSize = 5;
constexpr std::size_t MaxTries = 10;
constexpr std::size_t MaxTries = 5;
std::size_t tries = 0;
SubCommandResponse response{};
std::array<u8, sizeof(ReadSpiPacket)> buffer{};
@@ -170,36 +174,36 @@ DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> out
memcpy(buffer.data(), &packet_data, sizeof(ReadSpiPacket));
do {
const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, response);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > MaxTries) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (response.spi_address != addr);
if (response.command_data.size() < packet_data.size + HeaderSize) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
// Remove header from output
memcpy(output.data(), response.command_data.data() + HeaderSize, packet_data.size);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
Common::Input::DriverResult JoyconCommonProtocol::EnableMCU(bool enable) {
const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)};
const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
LOG_ERROR(Input, "Failed with error {}", result);
}
return result;
}
DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
LOG_DEBUG(Input, "ConfigureMCU");
std::array<u8, sizeof(MCUConfig)> config_buffer;
memcpy(config_buffer.data(), &config, sizeof(MCUConfig));
@@ -207,15 +211,15 @@ DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) {
const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
LOG_ERROR(Input, "Failed with error {}", result);
}
return result;
}
DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
MCUCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
MCUCommandResponse& output) {
constexpr int TimeoutMili = 200;
constexpr int MaxTries = 9;
int tries = 0;
@@ -228,17 +232,18 @@ DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode,
LOG_ERROR(Input, "No response from joycon attempt {}", tries);
}
if (tries++ > MaxTries) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.input_report.report_mode != report_mode ||
output.mcu_report == MCUReport::EmptyAwaitingCmd);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCommand sc,
std::span<const u8> buffer,
MCUCommandResponse& output) {
Common::Input::DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode,
MCUSubCommand sc,
std::span<const u8> buffer,
MCUCommandResponse& output) {
SubCommandPacket packet{
.output_report = OutputReport::MCU_DATA,
.packet_counter = GetCounter(),
@@ -247,23 +252,24 @@ DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, MCUSubCom
};
if (buffer.size() > packet.command_data.size()) {
return DriverResult::InvalidParameters;
return Common::Input::DriverResult::InvalidParameters;
}
memcpy(packet.command_data.data(), buffer.data(), buffer.size());
auto result = SendData(packet);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
result = GetMCUDataResponse(report_mode, output);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) {
Common::Input::DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode,
MCUMode mode) {
MCUCommandResponse output{};
constexpr std::size_t MaxTries{16};
std::size_t tries{};
@@ -271,17 +277,17 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod
do {
const auto result = SendMCUData(report_mode, MCUSubCommand::SetDeviceMode, {}, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > MaxTries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (output.mcu_report != MCUReport::StateReport ||
output.mcu_data[6] != static_cast<u8>(mode));
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
// crc-8-ccitt / polynomial 0x07 look up table

View File

@@ -38,30 +38,30 @@ public:
* Sends a request to obtain the joycon type from device
* @returns controller type of the joycon
*/
DriverResult GetDeviceType(ControllerType& controller_type);
Common::Input::DriverResult GetDeviceType(ControllerType& controller_type);
/**
* Verifies and sets the joycon_handle if device is valid
* @param device info from the driver
* @returns success if the device is valid
*/
DriverResult CheckDeviceAccess(SDL_hid_device_info* device);
Common::Input::DriverResult CheckDeviceAccess(SDL_hid_device_info* device);
/**
* Sends a request to set the polling mode of the joycon
* @param report_mode polling mode to be set
*/
DriverResult SetReportMode(Joycon::ReportMode report_mode);
Common::Input::DriverResult SetReportMode(Joycon::ReportMode report_mode);
/**
* Sends data to the joycon device
* @param buffer data to be send
*/
DriverResult SendRawData(std::span<const u8> buffer);
Common::Input::DriverResult SendRawData(std::span<const u8> buffer);
template <typename Output>
requires std::is_trivially_copyable_v<Output>
DriverResult SendData(const Output& output) {
Common::Input::DriverResult SendData(const Output& output) {
std::array<u8, sizeof(Output)> buffer;
std::memcpy(buffer.data(), &output, sizeof(Output));
return SendRawData(buffer);
@@ -72,7 +72,8 @@ public:
* @param sub_command type of data to be returned
* @returns a buffer containing the response
*/
DriverResult GetSubCommandResponse(SubCommand sub_command, SubCommandResponse& output);
Common::Input::DriverResult GetSubCommandResponse(SubCommand sub_command,
SubCommandResponse& output);
/**
* Sends a sub command to the device and waits for it's reply
@@ -80,35 +81,35 @@ public:
* @param buffer data to be send
* @returns output buffer containing the response
*/
DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
SubCommandResponse& output);
Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer,
SubCommandResponse& output);
/**
* Sends a sub command to the device and waits for it's reply and ignores the output
* @param sc sub command to be send
* @param buffer data to be send
*/
DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer);
Common::Input::DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer);
/**
* Sends a mcu command to the device
* @param sc sub command to be send
* @param buffer data to be send
*/
DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer);
Common::Input::DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer);
/**
* Sends vibration data to the joycon
* @param buffer data to be send
*/
DriverResult SendVibrationReport(std::span<const u8> buffer);
Common::Input::DriverResult SendVibrationReport(std::span<const u8> buffer);
/**
* Reads the SPI memory stored on the joycon
* @param Initial address location
* @returns output buffer containing the response
*/
DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
Common::Input::DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
/**
* Reads the SPI memory stored on the joycon
@@ -117,37 +118,38 @@ public:
*/
template <typename Output>
requires std::is_trivially_copyable_v<Output>
DriverResult ReadSPI(SpiAddress addr, Output& output) {
Common::Input::DriverResult ReadSPI(SpiAddress addr, Output& output) {
std::array<u8, sizeof(Output)> buffer;
output = {};
const auto result = ReadRawSPI(addr, buffer);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
std::memcpy(&output, buffer.data(), sizeof(Output));
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
/**
* Enables MCU chip on the joycon
* @param enable if true the chip will be enabled
*/
DriverResult EnableMCU(bool enable);
Common::Input::DriverResult EnableMCU(bool enable);
/**
* Configures the MCU to the corresponding mode
* @param MCUConfig configuration
*/
DriverResult ConfigureMCU(const MCUConfig& config);
Common::Input::DriverResult ConfigureMCU(const MCUConfig& config);
/**
* Waits until there's MCU data available. On timeout returns error
* @param report mode of the expected reply
* @returns a buffer containing the response
*/
DriverResult GetMCUDataResponse(ReportMode report_mode_, MCUCommandResponse& output);
Common::Input::DriverResult GetMCUDataResponse(ReportMode report_mode_,
MCUCommandResponse& output);
/**
* Sends data to the MCU chip and waits for it's reply
@@ -156,15 +158,15 @@ public:
* @param buffer data to be send
* @returns output buffer containing the response
*/
DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc, std::span<const u8> buffer,
MCUCommandResponse& output);
Common::Input::DriverResult SendMCUData(ReportMode report_mode, MCUSubCommand sc,
std::span<const u8> buffer, MCUCommandResponse& output);
/**
* Wait's until the MCU chip is on the specified mode
* @param report mode of the expected reply
* @param MCUMode configuration
*/
DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode);
Common::Input::DriverResult WaitSetMCUMode(ReportMode report_mode, MCUMode mode);
/**
* Calculates the checksum from the MCU data

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/generic_functions.h"
@@ -9,73 +10,74 @@ namespace InputCommon::Joycon {
GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult GenericProtocol::EnablePassiveMode() {
Common::Input::DriverResult GenericProtocol::EnablePassiveMode() {
ScopedSetBlocking sb(this);
return SetReportMode(ReportMode::SIMPLE_HID_MODE);
}
DriverResult GenericProtocol::EnableActiveMode() {
Common::Input::DriverResult GenericProtocol::EnableActiveMode() {
ScopedSetBlocking sb(this);
return SetReportMode(ReportMode::STANDARD_FULL_60HZ);
}
DriverResult GenericProtocol::SetLowPowerMode(bool enable) {
Common::Input::DriverResult GenericProtocol::SetLowPowerMode(bool enable) {
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
return SendSubCommand(SubCommand::LOW_POWER_MODE, buffer);
}
DriverResult GenericProtocol::TriggersElapsed() {
Common::Input::DriverResult GenericProtocol::TriggersElapsed() {
ScopedSetBlocking sb(this);
return SendSubCommand(SubCommand::TRIGGERS_ELAPSED, {});
}
DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
Common::Input::DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) {
ScopedSetBlocking sb(this);
SubCommandResponse output{};
const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output);
device_info = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
device_info = output.device_info;
}
return result;
}
DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) {
Common::Input::DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) {
return GetDeviceType(controller_type);
}
DriverResult GenericProtocol::EnableImu(bool enable) {
Common::Input::DriverResult GenericProtocol::EnableImu(bool enable) {
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)};
return SendSubCommand(SubCommand::ENABLE_IMU, buffer);
}
DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen,
AccelerometerPerformance afrec) {
Common::Input::DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen,
GyroPerformance gfrec,
AccelerometerSensitivity asen,
AccelerometerPerformance afrec) {
ScopedSetBlocking sb(this);
const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen),
static_cast<u8>(gfrec), static_cast<u8>(afrec)};
return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer);
}
DriverResult GenericProtocol::GetBattery(u32& battery_level) {
Common::Input::DriverResult GenericProtocol::GetBattery(u32& battery_level) {
// This function is meant to request the high resolution battery status
battery_level = 0;
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
DriverResult GenericProtocol::GetColor(Color& color) {
Common::Input::DriverResult GenericProtocol::GetColor(Color& color) {
ScopedSetBlocking sb(this);
std::array<u8, 12> buffer{};
const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
color = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
color.body = static_cast<u32>((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]);
color.buttons = static_cast<u32>((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]);
color.left_grip = static_cast<u32>((buffer[6] << 16) | (buffer[7] << 8) | buffer[8]);
@@ -85,26 +87,26 @@ DriverResult GenericProtocol::GetColor(Color& color) {
return result;
}
DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
Common::Input::DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
ScopedSetBlocking sb(this);
std::array<u8, 16> buffer{};
const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
serial_number = {};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
memcpy(serial_number.data(), buffer.data() + 1, sizeof(SerialNumber));
}
return result;
}
DriverResult GenericProtocol::GetTemperature(u32& temperature) {
Common::Input::DriverResult GenericProtocol::GetTemperature(u32& temperature) {
// Not all devices have temperature sensor
temperature = 25;
return DriverResult::NotSupported;
return Common::Input::DriverResult::NotSupported;
}
DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
Common::Input::DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
DeviceInfo device_info{};
const auto result = GetDeviceInfo(device_info);
@@ -113,23 +115,23 @@ DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) {
return result;
}
DriverResult GenericProtocol::SetHomeLight() {
Common::Input::DriverResult GenericProtocol::SetHomeLight() {
ScopedSetBlocking sb(this);
static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00};
return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer);
}
DriverResult GenericProtocol::SetLedBusy() {
return DriverResult::NotSupported;
Common::Input::DriverResult GenericProtocol::SetLedBusy() {
return Common::Input::DriverResult::NotSupported;
}
DriverResult GenericProtocol::SetLedPattern(u8 leds) {
Common::Input::DriverResult GenericProtocol::SetLedPattern(u8 leds) {
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{leds};
return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer);
}
DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) {
Common::Input::DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) {
return SetLedPattern(static_cast<u8>(leds << 4));
}

View File

@@ -11,6 +11,10 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
/// Joycon driver functions that easily implemented
@@ -20,34 +24,34 @@ public:
/// Enables passive mode. This mode only sends button data on change. Sticks will return digital
/// data instead of analog. Motion will be disabled
DriverResult EnablePassiveMode();
Common::Input::DriverResult EnablePassiveMode();
/// Enables active mode. This mode will return the current status every 5-15ms
DriverResult EnableActiveMode();
Common::Input::DriverResult EnableActiveMode();
/// Enables or disables the low power mode
DriverResult SetLowPowerMode(bool enable);
Common::Input::DriverResult SetLowPowerMode(bool enable);
/// Unknown function used by the switch
DriverResult TriggersElapsed();
Common::Input::DriverResult TriggersElapsed();
/**
* Sends a request to obtain the joycon firmware and mac from handle
* @returns controller device info
*/
DriverResult GetDeviceInfo(DeviceInfo& controller_type);
Common::Input::DriverResult GetDeviceInfo(DeviceInfo& controller_type);
/**
* Sends a request to obtain the joycon type from handle
* @returns controller type of the joycon
*/
DriverResult GetControllerType(ControllerType& controller_type);
Common::Input::DriverResult GetControllerType(ControllerType& controller_type);
/**
* Enables motion input
* @param enable if true motion data will be enabled
*/
DriverResult EnableImu(bool enable);
Common::Input::DriverResult EnableImu(bool enable);
/**
* Configures the motion sensor with the specified parameters
@@ -56,59 +60,60 @@ public:
* @param asen accelerometer sensitivity in G force
* @param afrec accelerometer frequency in hertz
*/
DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen, AccelerometerPerformance afrec);
Common::Input::DriverResult SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen,
AccelerometerPerformance afrec);
/**
* Request battery level from the device
* @returns battery level
*/
DriverResult GetBattery(u32& battery_level);
Common::Input::DriverResult GetBattery(u32& battery_level);
/**
* Request joycon colors from the device
* @returns colors of the body and buttons
*/
DriverResult GetColor(Color& color);
Common::Input::DriverResult GetColor(Color& color);
/**
* Request joycon serial number from the device
* @returns 16 byte serial number
*/
DriverResult GetSerialNumber(SerialNumber& serial_number);
Common::Input::DriverResult GetSerialNumber(SerialNumber& serial_number);
/**
* Request joycon serial number from the device
* @returns 16 byte serial number
*/
DriverResult GetTemperature(u32& temperature);
Common::Input::DriverResult GetTemperature(u32& temperature);
/**
* Request joycon serial number from the device
* @returns 16 byte serial number
*/
DriverResult GetVersionNumber(FirmwareVersion& version);
Common::Input::DriverResult GetVersionNumber(FirmwareVersion& version);
/**
* Sets home led behaviour
*/
DriverResult SetHomeLight();
Common::Input::DriverResult SetHomeLight();
/**
* Sets home led into a slow breathing state
*/
DriverResult SetLedBusy();
Common::Input::DriverResult SetLedBusy();
/**
* Sets the 4 player leds on the joycon on a solid state
* @params bit flag containing the led state
*/
DriverResult SetLedPattern(u8 leds);
Common::Input::DriverResult SetLedPattern(u8 leds);
/**
* Sets the 4 player leds on the joycon on a blinking state
* @returns bit flag containing the led state
*/
DriverResult SetLedBlinkPattern(u8 leds);
Common::Input::DriverResult SetLedBlinkPattern(u8 leds);
};
} // namespace InputCommon::Joycon

View File

@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/irs.h"
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult IrsProtocol::EnableIrs() {
Common::Input::DriverResult IrsProtocol::EnableIrs() {
LOG_INFO(Input, "Enable IRS");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
const MCUConfig config{
.command = MCUCommand::ConfigureMCU,
.sub_command = MCUSubCommand::SetMCUMode,
@@ -34,16 +34,16 @@ DriverResult IrsProtocol::EnableIrs() {
result = ConfigureMCU(config);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = ConfigureIrs();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WriteRegistersStep1();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WriteRegistersStep2();
}
@@ -52,12 +52,12 @@ DriverResult IrsProtocol::EnableIrs() {
return result;
}
DriverResult IrsProtocol::DisableIrs() {
Common::Input::DriverResult IrsProtocol::DisableIrs() {
LOG_DEBUG(Input, "Disable IRS");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(false);
}
@@ -66,7 +66,7 @@ DriverResult IrsProtocol::DisableIrs() {
return result;
}
DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
Common::Input::DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
irs_mode = mode;
switch (format) {
case IrsResolution::Size320x240:
@@ -103,10 +103,10 @@ DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) {
return EnableIrs();
}
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
Common::Input::DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
const u8 next_packet_fragment =
static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1));
@@ -129,7 +129,7 @@ DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) {
return RequestFrame(packet_fragment);
}
DriverResult IrsProtocol::ConfigureIrs() {
Common::Input::DriverResult IrsProtocol::ConfigureIrs() {
LOG_DEBUG(Input, "Configure IRS");
constexpr std::size_t max_tries = 28;
SubCommandResponse output{};
@@ -152,20 +152,20 @@ DriverResult IrsProtocol::ConfigureIrs() {
do {
const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (output.command_data[0] != 0x0b);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::WriteRegistersStep1() {
Common::Input::DriverResult IrsProtocol::WriteRegistersStep1() {
LOG_DEBUG(Input, "WriteRegistersStep1");
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
constexpr std::size_t max_tries = 28;
SubCommandResponse output{};
std::size_t tries = 0;
@@ -197,7 +197,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
mcu_request[37] = 0xFF;
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -205,26 +205,26 @@ DriverResult IrsProtocol::WriteRegistersStep1() {
result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
// First time we need to set the report mode
if (result == DriverResult::Success && tries == 0) {
if (result == Common::Input::DriverResult::Success && tries == 0) {
result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
}
if (result == DriverResult::Success && tries == 0) {
if (result == Common::Input::DriverResult::Success && tries == 0) {
GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output);
}
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (!(output.command_data[0] == 0x13 && output.command_data[2] == 0x07) &&
output.command_data[0] != 0x23);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::WriteRegistersStep2() {
Common::Input::DriverResult IrsProtocol::WriteRegistersStep2() {
LOG_DEBUG(Input, "WriteRegistersStep2");
constexpr std::size_t max_tries = 28;
SubCommandResponse output{};
@@ -255,18 +255,18 @@ DriverResult IrsProtocol::WriteRegistersStep2() {
do {
const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::WrongReply;
return Common::Input::DriverResult::WrongReply;
}
} while (output.command_data[0] != 0x13 && output.command_data[0] != 0x23);
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult IrsProtocol::RequestFrame(u8 frame) {
Common::Input::DriverResult IrsProtocol::RequestFrame(u8 frame) {
std::array<u8, 38> mcu_request{};
mcu_request[3] = frame;
mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36);
@@ -274,7 +274,7 @@ DriverResult IrsProtocol::RequestFrame(u8 frame) {
return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request);
}
DriverResult IrsProtocol::ResendFrame(u8 frame) {
Common::Input::DriverResult IrsProtocol::ResendFrame(u8 frame) {
std::array<u8, 38> mcu_request{};
mcu_request[1] = 0x1;
mcu_request[2] = frame;

View File

@@ -13,19 +13,23 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class IrsProtocol final : private JoyconCommonProtocol {
public:
explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableIrs();
Common::Input::DriverResult EnableIrs();
DriverResult DisableIrs();
Common::Input::DriverResult DisableIrs();
DriverResult SetIrsConfig(IrsMode mode, IrsResolution format);
Common::Input::DriverResult SetIrsConfig(IrsMode mode, IrsResolution format);
DriverResult RequestImage(std::span<u8> buffer);
Common::Input::DriverResult RequestImage(std::span<u8> buffer);
std::vector<u8> GetImage() const;
@@ -34,13 +38,13 @@ public:
bool IsEnabled() const;
private:
DriverResult ConfigureIrs();
Common::Input::DriverResult ConfigureIrs();
DriverResult WriteRegistersStep1();
DriverResult WriteRegistersStep2();
Common::Input::DriverResult WriteRegistersStep1();
Common::Input::DriverResult WriteRegistersStep2();
DriverResult RequestFrame(u8 frame);
DriverResult ResendFrame(u8 frame);
Common::Input::DriverResult RequestFrame(u8 frame);
Common::Input::DriverResult ResendFrame(u8 frame);
IrsMode irs_mode{IrsMode::ImageTransfer};
IrsResolution resolution{IrsResolution::Size40x30};

View File

@@ -402,23 +402,6 @@ enum class ExternalDeviceId : u16 {
Starlink = 0x2800,
};
enum class DriverResult {
Success,
WrongReply,
Timeout,
InvalidParameters,
UnsupportedControllerType,
HandleInUse,
ErrorReadingData,
ErrorWritingData,
NoDeviceDetected,
InvalidHandle,
NotSupported,
Disabled,
Delayed,
Unknown,
};
struct MotionSensorCalibration {
s16 offset;
s16 scale;

View File

@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/nfc.h"
@@ -10,21 +10,21 @@ namespace InputCommon::Joycon {
NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult NfcProtocol::EnableNfc() {
Common::Input::DriverResult NfcProtocol::EnableNfc() {
LOG_INFO(Input, "Enable NFC");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
const MCUConfig config{
.command = MCUCommand::ConfigureMCU,
.sub_command = MCUSubCommand::SetMCUMode,
@@ -34,32 +34,32 @@ DriverResult NfcProtocol::EnableNfc() {
result = ConfigureMCU(config);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_enabled = true;
}
return result;
}
DriverResult NfcProtocol::DisableNfc() {
Common::Input::DriverResult NfcProtocol::DisableNfc() {
LOG_DEBUG(Input, "Disable NFC");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(false);
}
@@ -69,60 +69,60 @@ DriverResult NfcProtocol::DisableNfc() {
return result;
}
DriverResult NfcProtocol::StartNFCPollingMode() {
Common::Input::DriverResult NfcProtocol::StartNFCPollingMode() {
LOG_DEBUG(Input, "Start NFC polling Mode");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Polling);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_polling = true;
}
return result;
}
DriverResult NfcProtocol::StopNFCPollingMode() {
Common::Input::DriverResult NfcProtocol::StopNFCPollingMode() {
LOG_DEBUG(Input, "Stop NFC polling Mode");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_polling = false;
}
return result;
}
DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
Common::Input::DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
if (update_counter++ < AMIIBO_UPDATE_DELAY) {
return DriverResult::Delayed;
return Common::Input::DriverResult::Delayed;
}
update_counter = 0;
LOG_DEBUG(Input, "Scan for amiibos");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
tag_info = {
.uuid_length = tag_data.uuid_size,
.protocol = 1,
@@ -147,59 +147,59 @@ DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) {
return result;
}
DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) {
Common::Input::DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) {
LOG_DEBUG(Input, "Scan for amiibos");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = GetAmiiboData(data);
}
return result;
}
DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
LOG_DEBUG(Input, "Write amiibo");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagUUID tag_uuid = GetTagUUID(data);
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
if (tag_data.uuid != tag_uuid) {
result = DriverResult::InvalidParameters;
result = Common::Input::DriverResult::InvalidParameters;
}
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output, true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WriteAmiiboData(tag_uuid, data);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteDone);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
@@ -207,64 +207,65 @@ DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) {
return result;
}
DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
Common::Input::DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
LOG_DEBUG(Input, "Read mifare");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
MifareUUID tag_uuid{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
result = GetMifareData(tag_uuid, read_request, out_data);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output, true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
return result;
}
DriverResult NfcProtocol::WriteMifare(std::span<const MifareWriteChunk> write_request) {
Common::Input::DriverResult NfcProtocol::WriteMifare(
std::span<const MifareWriteChunk> write_request) {
LOG_DEBUG(Input, "Write mifare");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
MifareUUID tag_uuid{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID));
result = WriteMifareData(tag_uuid, write_request);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStopPollingRequest(output);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::Ready);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
MCUCommandResponse output{};
result = SendStartPollingRequest(output, true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = WaitUntilNfcIs(NFCStatus::WriteReady);
}
return result;
@@ -277,17 +278,17 @@ bool NfcProtocol::HasAmiibo() {
update_counter = 0;
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
TagFoundData tag_data{};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsTagInRange(tag_data, 7);
}
return result == DriverResult::Success;
return result == Common::Input::DriverResult::Success;
}
DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
Common::Input::DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
constexpr std::size_t timeout_limit = 10;
MCUCommandResponse output{};
std::size_t tries = 0;
@@ -295,30 +296,31 @@ DriverResult NfcProtocol::WaitUntilNfcIs(NFCStatus status) {
do {
auto result = SendNextPackageRequest(output, {});
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > timeout_limit) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.mcu_report != MCUReport::NFCState ||
(output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
output.mcu_data[5] != 0x31 || output.mcu_data[6] != static_cast<u8>(status));
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_limit) {
Common::Input::DriverResult NfcProtocol::IsTagInRange(TagFoundData& data,
std::size_t timeout_limit) {
MCUCommandResponse output{};
std::size_t tries = 0;
do {
const auto result = SendNextPackageRequest(output, {});
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (tries++ > timeout_limit) {
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
} while (output.mcu_report != MCUReport::NFCState ||
(output.mcu_data[1] << 8) + output.mcu_data[0] != 0x0500 ||
@@ -328,10 +330,10 @@ DriverResult NfcProtocol::IsTagInRange(TagFoundData& data, std::size_t timeout_l
data.uuid_size = std::min(output.mcu_data[14], static_cast<u8>(sizeof(TagUUID)));
memcpy(data.uuid.data(), output.mcu_data.data() + 15, data.uuid.size());
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
Common::Input::DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
constexpr std::size_t timeout_limit = 60;
MCUCommandResponse output{};
std::size_t tries = 0;
@@ -340,7 +342,7 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
std::size_t ntag_buffer_pos = 0;
auto result = SendReadAmiiboRequest(output, NFCPages::Block135);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -349,14 +351,14 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if ((output.mcu_report == MCUReport::NFCReadData ||
output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -375,14 +377,15 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) {
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) {
LOG_INFO(Input, "Finished reading amiibo");
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
}
return DriverResult::Timeout;
return Common::Input::DriverResult::Timeout;
}
DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid,
std::span<const u8> data) {
constexpr std::size_t timeout_limit = 60;
const auto nfc_data = MakeAmiiboWritePackage(tag_uuid, data);
const std::vector<u8> nfc_buffer_data = SerializeWritePackage(nfc_data);
@@ -397,7 +400,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
auto result = SendWriteAmiiboRequest(output, tag_uuid);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -406,14 +409,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if ((output.mcu_report == MCUReport::NFCReadData ||
output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCReadData && output.mcu_data[1] == 0x07) {
@@ -442,7 +445,7 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
if ((output.mcu_report == MCUReport::NFCReadData ||
output.mcu_report == MCUReport::NFCState) &&
nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
// Increase position when data is confirmed by the joycon
@@ -457,14 +460,14 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con
return result;
}
DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
Common::Input::DriverResult NfcProtocol::GetMifareData(
const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data) {
constexpr std::size_t timeout_limit = 60;
const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request);
const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data);
std::span<const u8> buffer(nfc_buffer_data);
DriverResult result = DriverResult::Success;
Common::Input::DriverResult result = Common::Input::DriverResult::Success;
MCUCommandResponse output{};
u8 block_id = 1;
u8 package_index = 0;
@@ -486,7 +489,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
// Increase position when data is confirmed by the joycon
@@ -498,7 +501,7 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
}
}
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -507,12 +510,12 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
@@ -538,13 +541,13 @@ DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid,
return result;
}
DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
std::span<const MifareWriteChunk> write_request) {
Common::Input::DriverResult NfcProtocol::WriteMifareData(
const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> write_request) {
constexpr std::size_t timeout_limit = 60;
const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request);
const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data);
std::span<const u8> buffer(nfc_buffer_data);
DriverResult result = DriverResult::Success;
Common::Input::DriverResult result = Common::Input::DriverResult::Success;
MCUCommandResponse output{};
u8 block_id = 1;
u8 package_index = 0;
@@ -566,7 +569,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
// Increase position when data is confirmed by the joycon
@@ -578,7 +581,7 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
}
}
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
@@ -587,12 +590,12 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
result = SendNextPackageRequest(output, package_index);
const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}
if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) {
return DriverResult::ErrorReadingData;
return Common::Input::DriverResult::ErrorReadingData;
}
if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) {
@@ -609,8 +612,8 @@ DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid,
return result;
}
DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt) {
Common::Input::DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt) {
NFCRequestState request{
.command_argument = NFCCommand::StartPolling,
.block_id = {},
@@ -635,7 +638,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output,
output);
}
DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
Common::Input::DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
NFCRequestState request{
.command_argument = NFCCommand::StopPolling,
.block_id = {},
@@ -653,7 +656,8 @@ DriverResult NfcProtocol::SendStopPollingRequest(MCUCommandResponse& output) {
output);
}
DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id) {
Common::Input::DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output,
u8 packet_id) {
NFCRequestState request{
.command_argument = NFCCommand::StartWaitingRecieve,
.block_id = {},
@@ -671,7 +675,8 @@ DriverResult NfcProtocol::SendNextPackageRequest(MCUCommandResponse& output, u8
output);
}
DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages) {
Common::Input::DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output,
NFCPages ntag_pages) {
NFCRequestState request{
.command_argument = NFCCommand::ReadNtag,
.block_id = {},
@@ -696,8 +701,8 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(MCUCommandResponse& output, NFCP
output);
}
DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
const TagUUID& tag_uuid) {
Common::Input::DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
const TagUUID& tag_uuid) {
NFCRequestState request{
.command_argument = NFCCommand::ReadNtag,
.block_id = {},
@@ -722,9 +727,10 @@ DriverResult NfcProtocol::SendWriteAmiiboRequest(MCUCommandResponse& output,
output);
}
DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet,
std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
u8 block_id,
bool is_last_packet,
std::span<const u8> data) {
const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
NFCRequestState request{
.command_argument = NFCCommand::WriteNtag,
@@ -745,8 +751,9 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output,
output);
}
DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet, std::span<const u8> data) {
Common::Input::DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output,
u8 block_id, bool is_last_packet,
std::span<const u8> data) {
const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data));
NFCRequestState request{
.command_argument = NFCCommand::Mifare,

View File

@@ -13,30 +13,34 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class NfcProtocol final : private JoyconCommonProtocol {
public:
explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableNfc();
Common::Input::DriverResult EnableNfc();
DriverResult DisableNfc();
Common::Input::DriverResult DisableNfc();
DriverResult StartNFCPollingMode();
Common::Input::DriverResult StartNFCPollingMode();
DriverResult StopNFCPollingMode();
Common::Input::DriverResult StopNFCPollingMode();
DriverResult GetTagInfo(Joycon::TagInfo& tag_info);
Common::Input::DriverResult GetTagInfo(Joycon::TagInfo& tag_info);
DriverResult ReadAmiibo(std::vector<u8>& data);
Common::Input::DriverResult ReadAmiibo(std::vector<u8>& data);
DriverResult WriteAmiibo(std::span<const u8> data);
Common::Input::DriverResult WriteAmiibo(std::span<const u8> data);
DriverResult ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
Common::Input::DriverResult ReadMifare(std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request);
Common::Input::DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request);
bool HasAmiibo();
@@ -54,37 +58,41 @@ private:
TagUUID uuid;
};
DriverResult WaitUntilNfcIs(NFCStatus status);
Common::Input::DriverResult WaitUntilNfcIs(NFCStatus status);
DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1);
Common::Input::DriverResult IsTagInRange(TagFoundData& data, std::size_t timeout_limit = 1);
DriverResult GetAmiiboData(std::vector<u8>& data);
Common::Input::DriverResult GetAmiiboData(std::vector<u8>& data);
DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data);
Common::Input::DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data);
DriverResult GetMifareData(const MifareUUID& tag_uuid,
std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
Common::Input::DriverResult GetMifareData(const MifareUUID& tag_uuid,
std::span<const MifareReadChunk> read_request,
std::span<MifareReadData> out_data);
DriverResult WriteMifareData(const MifareUUID& tag_uuid,
std::span<const MifareWriteChunk> write_request);
Common::Input::DriverResult WriteMifareData(const MifareUUID& tag_uuid,
std::span<const MifareWriteChunk> write_request);
DriverResult SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt = false);
Common::Input::DriverResult SendStartPollingRequest(MCUCommandResponse& output,
bool is_second_attempt = false);
DriverResult SendStopPollingRequest(MCUCommandResponse& output);
Common::Input::DriverResult SendStopPollingRequest(MCUCommandResponse& output);
DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id);
Common::Input::DriverResult SendNextPackageRequest(MCUCommandResponse& output, u8 packet_id);
DriverResult SendReadAmiiboRequest(MCUCommandResponse& output, NFCPages ntag_pages);
Common::Input::DriverResult SendReadAmiiboRequest(MCUCommandResponse& output,
NFCPages ntag_pages);
DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output, const TagUUID& tag_uuid);
Common::Input::DriverResult SendWriteAmiiboRequest(MCUCommandResponse& output,
const TagUUID& tag_uuid);
DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet, std::span<const u8> data);
Common::Input::DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet,
std::span<const u8> data);
DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet, std::span<const u8> data);
Common::Input::DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id,
bool is_last_packet,
std::span<const u8> data);
std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const;

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/ringcon.h"
@@ -9,18 +10,18 @@ namespace InputCommon::Joycon {
RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult RingConProtocol::EnableRingCon() {
Common::Input::DriverResult RingConProtocol::EnableRingCon() {
LOG_DEBUG(Input, "Enable Ringcon");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = SetReportMode(ReportMode::STANDARD_FULL_60HZ);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(true);
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
const MCUConfig config{
.command = MCUCommand::ConfigureMCU,
.sub_command = MCUSubCommand::SetDeviceMode,
@@ -33,12 +34,12 @@ DriverResult RingConProtocol::EnableRingCon() {
return result;
}
DriverResult RingConProtocol::DisableRingCon() {
Common::Input::DriverResult RingConProtocol::DisableRingCon() {
LOG_DEBUG(Input, "Disable RingCon");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = EnableMCU(false);
}
@@ -47,29 +48,29 @@ DriverResult RingConProtocol::DisableRingCon() {
return result;
}
DriverResult RingConProtocol::StartRingconPolling() {
Common::Input::DriverResult RingConProtocol::StartRingconPolling() {
LOG_DEBUG(Input, "Enable Ringcon");
ScopedSetBlocking sb(this);
DriverResult result{DriverResult::Success};
Common::Input::DriverResult result{Common::Input::DriverResult::Success};
bool is_connected = false;
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
result = IsRingConnected(is_connected);
}
if (result == DriverResult::Success && is_connected) {
if (result == Common::Input::DriverResult::Success && is_connected) {
LOG_INFO(Input, "Ringcon detected");
result = ConfigureRing();
}
if (result == DriverResult::Success) {
if (result == Common::Input::DriverResult::Success) {
is_enabled = true;
}
return result;
}
DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
Common::Input::DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
LOG_DEBUG(Input, "IsRingConnected");
constexpr std::size_t max_tries = 28;
constexpr std::size_t max_tries = 42;
SubCommandResponse output{};
std::size_t tries = 0;
is_connected = false;
@@ -77,20 +78,21 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) {
do {
const auto result = SendSubCommand(SubCommand::GET_EXTERNAL_DEVICE_INFO, {}, output);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success &&
result != Common::Input::DriverResult::Timeout) {
return result;
}
if (tries++ >= max_tries) {
return DriverResult::NoDeviceDetected;
return Common::Input::DriverResult::NoDeviceDetected;
}
} while (output.external_device_id != ExternalDeviceId::RingController);
is_connected = true;
return DriverResult::Success;
return Common::Input::DriverResult::Success;
}
DriverResult RingConProtocol::ConfigureRing() {
Common::Input::DriverResult RingConProtocol::ConfigureRing() {
LOG_DEBUG(Input, "ConfigureRing");
static constexpr std::array<u8, 37> ring_config{
@@ -98,9 +100,10 @@ DriverResult RingConProtocol::ConfigureRing() {
0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36};
const DriverResult result = SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
const Common::Input::DriverResult result =
SendSubCommand(SubCommand::SET_EXTERNAL_FORMAT_CONFIG, ring_config);
if (result != DriverResult::Success) {
if (result != Common::Input::DriverResult::Success) {
return result;
}

View File

@@ -13,24 +13,28 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class RingConProtocol final : private JoyconCommonProtocol {
public:
explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableRingCon();
Common::Input::DriverResult EnableRingCon();
DriverResult DisableRingCon();
Common::Input::DriverResult DisableRingCon();
DriverResult StartRingconPolling();
Common::Input::DriverResult StartRingconPolling();
bool IsEnabled() const;
private:
DriverResult IsRingConnected(bool& is_connected);
Common::Input::DriverResult IsRingConnected(bool& is_connected);
DriverResult ConfigureRing();
Common::Input::DriverResult ConfigureRing();
bool is_enabled{};
};

View File

@@ -4,6 +4,7 @@
#include <algorithm>
#include <cmath>
#include "common/input.h"
#include "common/logging/log.h"
#include "input_common/helpers/joycon_protocol/rumble.h"
@@ -12,14 +13,14 @@ namespace InputCommon::Joycon {
RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle)
: JoyconCommonProtocol(std::move(handle)) {}
DriverResult RumbleProtocol::EnableRumble(bool is_enabled) {
Common::Input::DriverResult RumbleProtocol::EnableRumble(bool is_enabled) {
LOG_DEBUG(Input, "Enable Rumble");
ScopedSetBlocking sb(this);
const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)};
return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer);
}
DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) {
Common::Input::DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) {
std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{};
if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) {

View File

@@ -13,15 +13,19 @@
#include "input_common/helpers/joycon_protocol/common_protocol.h"
#include "input_common/helpers/joycon_protocol/joycon_types.h"
namespace Common::Input {
enum class DriverResult;
}
namespace InputCommon::Joycon {
class RumbleProtocol final : private JoyconCommonProtocol {
public:
explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle);
DriverResult EnableRumble(bool is_enabled);
Common::Input::DriverResult EnableRumble(bool is_enabled);
DriverResult SendVibration(const VibrationValue& vibration);
Common::Input::DriverResult SendVibration(const VibrationValue& vibration);
private:
u16 EncodeHighFrequency(f32 frequency) const;

View File

@@ -461,7 +461,7 @@ std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, I
header += fmt::format("R{},", index);
}
if (program.local_memory_size > 0) {
header += fmt::format("lmem[{}],", program.local_memory_size);
header += fmt::format("lmem[{}],", Common::DivCeil(program.local_memory_size, 4U));
}
if (program.info.uses_fswzadd) {
header += "FSWZA[4],FSWZB[4],";

View File

@@ -424,6 +424,10 @@ void VisitUsages(Info& info, IR::Inst& inst) {
info.used_constant_buffer_types |= IR::Type::U32 | IR::Type::U32x2;
info.used_storage_buffer_types |= IR::Type::U32 | IR::Type::U32x2 | IR::Type::U32x4;
break;
case IR::Opcode::LoadLocal:
case IR::Opcode::WriteLocal:
info.uses_local_memory = true;
break;
default:
break;
}

View File

@@ -172,6 +172,7 @@ struct Info {
bool stores_indexed_attributes{};
bool stores_global_memory{};
bool uses_local_memory{};
bool uses_fp16{};
bool uses_fp64{};

View File

@@ -220,8 +220,8 @@ add_library(video_core STATIC
surface.h
texture_cache/accelerated_swizzle.cpp
texture_cache/accelerated_swizzle.h
texture_cache/decode_bc4.cpp
texture_cache/decode_bc4.h
texture_cache/decode_bc.cpp
texture_cache/decode_bc.h
texture_cache/descriptor_table.h
texture_cache/formatter.cpp
texture_cache/formatter.h
@@ -279,7 +279,7 @@ add_library(video_core STATIC
create_target_directory_groups(video_core)
target_link_libraries(video_core PUBLIC common core)
target_link_libraries(video_core PUBLIC glad shader_recompiler stb)
target_link_libraries(video_core PUBLIC glad shader_recompiler stb bc_decoder)
if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID))
add_dependencies(video_core ffmpeg-build)
@@ -291,7 +291,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})
add_dependencies(video_core host_shaders)
target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
target_link_libraries(video_core PRIVATE sirit Vulkan::Headers)
target_link_libraries(video_core PRIVATE sirit Vulkan::Headers vma)
if (ENABLE_NSIGHT_AFTERMATH)
if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})

View File

@@ -174,8 +174,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
src_operand.address = regs.offset_in;
DMA::BufferOperand dst_operand;
u32 abs_pitch_out = std::abs(static_cast<s32>(regs.pitch_out));
dst_operand.pitch = abs_pitch_out;
dst_operand.pitch = static_cast<u32>(std::abs(regs.pitch_out));
dst_operand.width = regs.line_length_in;
dst_operand.height = regs.line_count;
dst_operand.address = regs.offset_out;
@@ -222,7 +221,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
const size_t src_size =
CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth);
const size_t dst_size = static_cast<size_t>(abs_pitch_out) * regs.line_count;
const size_t dst_size = dst_operand.pitch * regs.line_count;
read_buffer.resize_destructive(src_size);
write_buffer.resize_destructive(dst_size);
@@ -231,7 +230,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset,
src_params.origin.y, x_elements, regs.line_count, block_height, block_depth,
abs_pitch_out);
dst_operand.pitch);
memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size);
}

View File

@@ -290,7 +290,7 @@ void Codec::Decode() {
return vp9_decoder->GetFrameBytes();
default:
ASSERT(false);
return std::vector<u8>{};
return std::span<const u8>{};
}
}();
AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter};

View File

@@ -29,15 +29,15 @@ H264::H264(Host1x::Host1x& host1x_) : host1x{host1x_} {}
H264::~H264() = default;
const std::vector<u8>& H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
bool is_first_frame) {
std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
bool is_first_frame) {
H264DecoderContext context;
host1x.MemoryManager().ReadBlock(state.picture_info_offset, &context,
sizeof(H264DecoderContext));
const s64 frame_number = context.h264_parameter_set.frame_number.Value();
if (!is_first_frame && frame_number != 0) {
frame.resize(context.stream_len);
frame.resize_destructive(context.stream_len);
host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size());
return frame;
}
@@ -135,14 +135,14 @@ const std::vector<u8>& H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegist
for (s32 index = 0; index < 6; index++) {
writer.WriteBit(true);
std::span<const u8> matrix{context.weight_scale};
writer.WriteScalingList(matrix, index * 16, 16);
writer.WriteScalingList(scan, matrix, index * 16, 16);
}
if (context.h264_parameter_set.transform_8x8_mode_flag) {
for (s32 index = 0; index < 2; index++) {
writer.WriteBit(true);
std::span<const u8> matrix{context.weight_scale_8x8};
writer.WriteScalingList(matrix, index * 64, 64);
writer.WriteScalingList(scan, matrix, index * 64, 64);
}
}
@@ -188,8 +188,8 @@ void H264BitWriter::WriteBit(bool state) {
WriteBits(state ? 1 : 0, 1);
}
void H264BitWriter::WriteScalingList(std::span<const u8> list, s32 start, s32 count) {
static Common::ScratchBuffer<u8> scan{};
void H264BitWriter::WriteScalingList(Common::ScratchBuffer<u8>& scan, std::span<const u8> list,
s32 start, s32 count) {
scan.resize_destructive(count);
if (count == 16) {
std::memcpy(scan.data(), zig_zag_scan.data(), scan.size());

View File

@@ -5,9 +5,11 @@
#include <span>
#include <vector>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/scratch_buffer.h"
#include "video_core/host1x/nvdec_common.h"
namespace Tegra {
@@ -37,7 +39,8 @@ public:
/// Based on section 7.3.2.1.1.1 and Table 7-4 in the H.264 specification
/// Writes the scaling matrices of the sream
void WriteScalingList(std::span<const u8> list, s32 start, s32 count);
void WriteScalingList(Common::ScratchBuffer<u8>& scan, std::span<const u8> list, s32 start,
s32 count);
/// Return the bitstream as a vector.
[[nodiscard]] std::vector<u8>& GetByteArray();
@@ -63,11 +66,12 @@ public:
~H264();
/// Compose the H264 frame for FFmpeg decoding
[[nodiscard]] const std::vector<u8>& ComposeFrame(
const Host1x::NvdecCommon::NvdecRegisters& state, bool is_first_frame = false);
[[nodiscard]] std::span<const u8> ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
bool is_first_frame = false);
private:
std::vector<u8> frame;
Common::ScratchBuffer<u8> frame;
Common::ScratchBuffer<u8> scan;
Host1x::Host1x& host1x;
struct H264ParameterSet {

View File

@@ -12,7 +12,7 @@ VP8::VP8(Host1x::Host1x& host1x_) : host1x{host1x_} {}
VP8::~VP8() = default;
const std::vector<u8>& VP8::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state) {
std::span<const u8> VP8::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state) {
VP8PictureInfo info;
host1x.MemoryManager().ReadBlock(state.picture_info_offset, &info, sizeof(VP8PictureInfo));

View File

@@ -4,10 +4,11 @@
#pragma once
#include <array>
#include <vector>
#include <span>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/scratch_buffer.h"
#include "video_core/host1x/nvdec_common.h"
namespace Tegra {
@@ -24,11 +25,11 @@ public:
~VP8();
/// Compose the VP8 frame for FFmpeg decoding
[[nodiscard]] const std::vector<u8>& ComposeFrame(
[[nodiscard]] std::span<const u8> ComposeFrame(
const Host1x::NvdecCommon::NvdecRegisters& state);
private:
std::vector<u8> frame;
Common::ScratchBuffer<u8> frame;
Host1x::Host1x& host1x;
struct VP8PictureInfo {

View File

@@ -3,6 +3,7 @@
#include <algorithm> // for std::copy
#include <numeric>
#include "common/assert.h"
#include "video_core/host1x/codecs/vp9.h"
#include "video_core/host1x/host1x.h"

View File

@@ -4,9 +4,11 @@
#pragma once
#include <array>
#include <span>
#include <vector>
#include "common/common_types.h"
#include "common/scratch_buffer.h"
#include "common/stream.h"
#include "video_core/host1x/codecs/vp9_types.h"
#include "video_core/host1x/nvdec_common.h"
@@ -128,8 +130,8 @@ public:
return !current_frame_info.show_frame;
}
/// Returns a const reference to the composed frame data.
[[nodiscard]] const std::vector<u8>& GetFrameBytes() const {
/// Returns a const span to the composed frame data.
[[nodiscard]] std::span<const u8> GetFrameBytes() const {
return frame;
}
@@ -181,7 +183,7 @@ private:
[[nodiscard]] VpxBitStreamWriter ComposeUncompressedHeader();
Host1x::Host1x& host1x;
std::vector<u8> frame;
Common::ScratchBuffer<u8> frame;
std::array<s8, 4> loop_filter_ref_deltas{};
std::array<s8, 2> loop_filter_mode_deltas{};

View File

@@ -5,6 +5,7 @@
#include <array>
#include <vector>
#include "common/common_funcs.h"
#include "common/common_types.h"

View File

@@ -33,6 +33,7 @@ set(SHADER_FILES
opengl_fidelityfx_fsr.frag
opengl_fidelityfx_fsr_easu.frag
opengl_fidelityfx_fsr_rcas.frag
opengl_lmem_warmup.comp
opengl_present.frag
opengl_present.vert
opengl_present_scaleforce.frag

View File

@@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// This shader is a workaround for a quirk in NVIDIA OpenGL drivers
// Shaders using local memory see a great performance benefit if a shader that was dispatched
// before it had more local memory allocated.
// This shader allocates the maximum local memory allowed on NVIDIA drivers to ensure that
// subsequent shaders see the performance boost.
// NOTE: This shader does no actual meaningful work and returns immediately,
// it is simply a means to have the driver expect a shader using lots of local memory.
#version 450
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(location = 0) uniform uint uniform_data;
layout(binding = 0, rgba8) uniform writeonly restrict image2DArray dest_image;
#define MAX_LMEM_SIZE 4080 // Size chosen to avoid errors in Nvidia's GLSL compiler
#define NUM_LMEM_CONSTANTS 1
#define ARRAY_SIZE MAX_LMEM_SIZE - NUM_LMEM_CONSTANTS
uint lmem_0[ARRAY_SIZE];
const uvec4 constant_values[NUM_LMEM_CONSTANTS] = uvec4[](uvec4(0));
void main() {
const uint global_id = gl_GlobalInvocationID.x;
if (global_id <= 128) {
// Since the shader is called with a dispatch of 1x1x1
// This should always be the case, and this shader will not actually execute
return;
}
for (uint t = 0; t < uniform_data; t++) {
const uint offset = (t * uniform_data);
lmem_0[offset] = t;
}
const uint offset = (gl_GlobalInvocationID.y * uniform_data + gl_GlobalInvocationID.x);
const uint value = lmem_0[offset];
const uint const_value = constant_values[offset / 4][offset % 4];
const uvec4 color = uvec4(value + const_value);
// A "side-effect" is needed so the variables don't get optimized out,
// but this should never execute so there should be no clobbering of previously bound state.
imageStore(dest_image, ivec3(gl_GlobalInvocationID), color);
}

View File

@@ -63,6 +63,7 @@ ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cac
writes_global_memory = !use_storage_buffers &&
std::ranges::any_of(info.storage_buffers_descriptors,
[](const auto& desc) { return desc.is_written; });
uses_local_memory = info.uses_local_memory;
if (force_context_flush) {
std::scoped_lock lock{built_mutex};
built_fence.Create();

View File

@@ -59,6 +59,10 @@ public:
return writes_global_memory;
}
[[nodiscard]] bool UsesLocalMemory() const noexcept {
return uses_local_memory;
}
void SetEngine(Tegra::Engines::KeplerCompute* kepler_compute_,
Tegra::MemoryManager* gpu_memory_) {
kepler_compute = kepler_compute_;
@@ -84,6 +88,7 @@ private:
bool use_storage_buffers{};
bool writes_global_memory{};
bool uses_local_memory{};
std::mutex built_mutex;
std::condition_variable built_condvar;

View File

@@ -194,6 +194,7 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
has_bool_ref_bug = true;
}
}
has_lmem_perf_bug = is_nvidia;
strict_context_required = emu_window.StrictContextRequired();
// Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation.

View File

@@ -192,6 +192,10 @@ public:
return supports_conditional_barriers;
}
bool HasLmemPerfBug() const {
return has_lmem_perf_bug;
}
private:
static bool TestVariableAoffi();
static bool TestPreciseBug();
@@ -238,6 +242,7 @@ private:
bool can_report_memory{};
bool strict_context_required{};
bool supports_conditional_barriers{};
bool has_lmem_perf_bug{};
std::string vendor_name;
};

View File

@@ -215,6 +215,7 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
writes_global_memory |= std::ranges::any_of(
info.storage_buffers_descriptors, [](const auto& desc) { return desc.is_written; });
uses_local_memory |= info.uses_local_memory;
}
ASSERT(num_textures <= MAX_TEXTURES);
ASSERT(num_images <= MAX_IMAGES);

View File

@@ -98,6 +98,10 @@ public:
return writes_global_memory;
}
[[nodiscard]] bool UsesLocalMemory() const noexcept {
return uses_local_memory;
}
[[nodiscard]] bool IsBuilt() noexcept;
template <typename Spec>
@@ -146,6 +150,7 @@ private:
bool use_storage_buffers{};
bool writes_global_memory{};
bool uses_local_memory{};
static constexpr std::size_t XFB_ENTRY_STRIDE = 3;
GLsizei num_xfb_attribs{};

View File

@@ -222,6 +222,9 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
gpu.TickWork();
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
if (pipeline->UsesLocalMemory()) {
program_manager.LocalMemoryWarmup();
}
pipeline->SetEngine(maxwell3d, gpu_memory);
pipeline->Configure(is_indexed);
@@ -371,6 +374,9 @@ void RasterizerOpenGL::DispatchCompute() {
if (!pipeline) {
return;
}
if (pipeline->UsesLocalMemory()) {
program_manager.LocalMemoryWarmup();
}
pipeline->SetEngine(kepler_compute, gpu_memory);
pipeline->Configure();
const auto& qmd{kepler_compute->launch_description};

View File

@@ -3,7 +3,9 @@
#include <glad/glad.h>
#include "video_core/host_shaders/opengl_lmem_warmup_comp.h"
#include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
namespace OpenGL {
@@ -17,6 +19,10 @@ ProgramManager::ProgramManager(const Device& device) {
if (device.UseAssemblyShaders()) {
glEnable(GL_COMPUTE_PROGRAM_NV);
}
if (device.HasLmemPerfBug()) {
lmem_warmup_program =
CreateProgram(HostShaders::OPENGL_LMEM_WARMUP_COMP, GL_COMPUTE_SHADER);
}
}
void ProgramManager::BindComputeProgram(GLuint program) {
@@ -98,6 +104,13 @@ void ProgramManager::BindAssemblyPrograms(std::span<const OGLAssemblyProgram, NU
void ProgramManager::RestoreGuestCompute() {}
void ProgramManager::LocalMemoryWarmup() {
if (lmem_warmup_program.handle != 0) {
BindComputeProgram(lmem_warmup_program.handle);
glDispatchCompute(1, 1, 1);
}
}
void ProgramManager::BindPipeline() {
if (!is_pipeline_bound) {
is_pipeline_bound = true;

View File

@@ -30,6 +30,8 @@ public:
void RestoreGuestCompute();
void LocalMemoryWarmup();
private:
void BindPipeline();
@@ -44,6 +46,7 @@ private:
u32 current_stage_mask = 0;
std::array<GLuint, NUM_STAGES> current_programs{};
GLuint current_assembly_compute_program = 0;
OGLProgram lmem_warmup_program;
};
} // namespace OpenGL

View File

@@ -495,6 +495,9 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation) {
if (!device.IsExtShaderStencilExportSupported()) {
return;
}
ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy);
const BlitImagePipelineKey key{

View File

@@ -259,6 +259,26 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with
break;
}
}
// Transcode on hardware that doesn't support BCn natively
if (!device.IsOptimalBcnSupported() && VideoCore::Surface::IsPixelFormatBCn(pixel_format)) {
const bool is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format);
if (pixel_format == PixelFormat::BC4_SNORM) {
tuple.format = VK_FORMAT_R8_SNORM;
} else if (pixel_format == PixelFormat::BC4_UNORM) {
tuple.format = VK_FORMAT_R8_UNORM;
} else if (pixel_format == PixelFormat::BC5_SNORM) {
tuple.format = VK_FORMAT_R8G8_SNORM;
} else if (pixel_format == PixelFormat::BC5_UNORM) {
tuple.format = VK_FORMAT_R8G8_UNORM;
} else if (pixel_format == PixelFormat::BC6H_SFLOAT ||
pixel_format == PixelFormat::BC6H_UFLOAT) {
tuple.format = VK_FORMAT_R16G16B16A16_SFLOAT;
} else if (is_srgb) {
tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32;
} else {
tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
}
}
const bool attachable = (tuple.usage & Attachable) != 0;
const bool storage = (tuple.usage & Storage) != 0;

View File

@@ -12,6 +12,7 @@
#include <fmt/format.h>
#include "common/logging/log.h"
#include "common/polyfill_ranges.h"
#include "common/scope_exit.h"
#include "common/settings.h"
#include "common/telemetry.h"
@@ -65,6 +66,21 @@ std::string BuildCommaSeparatedExtensions(
return fmt::format("{}", fmt::join(available_extensions, ","));
}
DebugCallback MakeDebugCallback(const vk::Instance& instance, const vk::InstanceDispatch& dld) {
if (!Settings::values.renderer_debug) {
return DebugCallback{};
}
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
const auto it = std::ranges::find_if(*properties, [](const auto& prop) {
return std::strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, prop.extensionName) == 0;
});
if (it != properties->end()) {
return CreateDebugUtilsCallback(instance);
} else {
return CreateDebugReportCallback(instance);
}
}
} // Anonymous namespace
Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
@@ -87,10 +103,10 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())),
instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
Settings::values.renderer_debug.GetValue())),
debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
debug_callback(MakeDebugCallback(instance, dld)),
surface(CreateSurface(instance, render_window.GetWindowInfo())),
device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false),
state_tracker(), scheduler(device, state_tracker),
device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(),
scheduler(device, state_tracker),
swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
render_window.GetFramebufferLayout().height, false),
present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
@@ -173,7 +189,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
return;
}
const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
vk::Image staging_image = device.GetLogical().CreateImage(VkImageCreateInfo{
vk::Image staging_image = memory_allocator.CreateImage(VkImageCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
@@ -196,7 +212,6 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
});
const auto image_commit = memory_allocator.Commit(staging_image, MemoryUsage::DeviceLocal);
const vk::ImageView dst_view = device.GetLogical().CreateImageView(VkImageViewCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@@ -234,8 +249,8 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
};
const vk::Buffer dst_buffer = device.GetLogical().CreateBuffer(dst_buffer_info);
MemoryCommit dst_buffer_memory = memory_allocator.Commit(dst_buffer, MemoryUsage::Download);
const vk::Buffer dst_buffer =
memory_allocator.CreateBuffer(dst_buffer_info, MemoryUsage::Download);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
@@ -309,8 +324,9 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
scheduler.Finish();
// Copy backing image data to the QImage screenshot buffer
const auto dst_memory_map = dst_buffer_memory.Map();
std::memcpy(renderer_settings.screenshot_bits, dst_memory_map.data(), dst_memory_map.size());
dst_buffer.Invalidate();
std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(),
dst_buffer.Mapped().size());
renderer_settings.screenshot_complete_callback(false);
renderer_settings.screenshot_requested = false;
}

View File

@@ -5,6 +5,7 @@
#include <memory>
#include <string>
#include <variant>
#include "common/dynamic_library.h"
#include "video_core/renderer_base.h"
@@ -33,6 +34,8 @@ class GPU;
namespace Vulkan {
using DebugCallback = std::variant<vk::DebugUtilsMessenger, vk::DebugReportCallback>;
Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
VkSurfaceKHR surface);
@@ -71,7 +74,7 @@ private:
vk::InstanceDispatch dld;
vk::Instance instance;
vk::DebugUtilsMessenger debug_callback;
DebugCallback debug_callback;
vk::SurfaceKHR surface;
ScreenInfo screen_info;

View File

@@ -162,7 +162,7 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
SetUniformData(data, layout);
SetVertexData(data, framebuffer, layout);
const std::span<u8> mapped_span = buffer_commit.Map();
const std::span<u8> mapped_span = buffer.Mapped();
std::memcpy(mapped_span.data(), &data, sizeof(data));
if (!use_accelerated) {
@@ -1071,14 +1071,9 @@ void BlitScreen::ReleaseRawImages() {
scheduler.Wait(tick);
}
raw_images.clear();
raw_buffer_commits.clear();
aa_image_view.reset();
aa_image.reset();
aa_commit = MemoryCommit{};
buffer.reset();
buffer_commit = MemoryCommit{};
}
void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) {
@@ -1094,20 +1089,18 @@ void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer
.pQueueFamilyIndices = nullptr,
};
buffer = device.GetLogical().CreateBuffer(ci);
buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload);
buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload);
}
void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
raw_images.resize(image_count);
raw_image_views.resize(image_count);
raw_buffer_commits.resize(image_count);
const auto create_image = [&](bool used_on_framebuffer = false, u32 up_scale = 1,
u32 down_shift = 0) {
u32 extra_usages = used_on_framebuffer ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
: VK_IMAGE_USAGE_TRANSFER_DST_BIT;
return device.GetLogical().CreateImage(VkImageCreateInfo{
return memory_allocator.CreateImage(VkImageCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -1130,9 +1123,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
});
};
const auto create_commit = [&](vk::Image& image) {
return memory_allocator.Commit(image, MemoryUsage::DeviceLocal);
};
const auto create_image_view = [&](vk::Image& image, bool used_on_framebuffer = false) {
return device.GetLogical().CreateImageView(VkImageViewCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@@ -1161,7 +1151,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
for (size_t i = 0; i < image_count; ++i) {
raw_images[i] = create_image();
raw_buffer_commits[i] = create_commit(raw_images[i]);
raw_image_views[i] = create_image_view(raw_images[i]);
}
@@ -1169,7 +1158,6 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
const u32 up_scale = Settings::values.resolution_info.up_scale;
const u32 down_shift = Settings::values.resolution_info.down_shift;
aa_image = create_image(true, up_scale, down_shift);
aa_commit = create_commit(aa_image);
aa_image_view = create_image_view(aa_image, true);
VkExtent2D size{
.width = (up_scale * framebuffer.width) >> down_shift,

View File

@@ -142,13 +142,11 @@ private:
vk::Sampler sampler;
vk::Buffer buffer;
MemoryCommit buffer_commit;
std::vector<u64> resource_ticks;
std::vector<vk::Image> raw_images;
std::vector<vk::ImageView> raw_image_views;
std::vector<MemoryCommit> raw_buffer_commits;
vk::DescriptorPool aa_descriptor_pool;
vk::DescriptorSetLayout aa_descriptor_set_layout;
@@ -159,7 +157,6 @@ private:
vk::DescriptorSets aa_descriptor_sets;
vk::Image aa_image;
vk::ImageView aa_image_view;
MemoryCommit aa_commit;
u32 raw_width = 0;
u32 raw_height = 0;

View File

@@ -50,7 +50,7 @@ size_t BytesPerIndex(VkIndexType index_type) {
}
}
vk::Buffer CreateBuffer(const Device& device, u64 size) {
vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allocator, u64 size) {
VkBufferUsageFlags flags =
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
@@ -60,7 +60,7 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) {
if (device.IsExtTransformFeedbackSupported()) {
flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
return device.GetLogical().CreateBuffer({
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -69,7 +69,8 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) {
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
});
};
return memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
}
} // Anonymous namespace
@@ -79,8 +80,8 @@ Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params)
Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_,
VAddr cpu_addr_, u64 size_bytes_)
: VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_),
device{&runtime.device}, buffer{CreateBuffer(*device, SizeBytes())},
commit{runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal)} {
device{&runtime.device}, buffer{
CreateBuffer(*device, runtime.memory_allocator, SizeBytes())} {
if (runtime.device.HasDebuggingToolAttached()) {
buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str());
}
@@ -138,7 +139,7 @@ public:
const u32 num_first_offset_copies = 4;
const size_t bytes_per_index = BytesPerIndex(index_type);
const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies;
buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -147,14 +148,21 @@ public:
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
});
};
buffer = memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
if (device.HasDebuggingToolAttached()) {
buffer.SetObjectNameEXT("Quad LUT");
}
memory_commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
const StagingBufferRef staging = staging_pool.Request(size_bytes, MemoryUsage::Upload);
u8* staging_data = staging.mapped_span.data();
const bool host_visible = buffer.IsHostVisible();
const StagingBufferRef staging = [&] {
if (host_visible) {
return StagingBufferRef{};
}
return staging_pool.Request(size_bytes, MemoryUsage::Upload);
}();
u8* staging_data = host_visible ? buffer.Mapped().data() : staging.mapped_span.data();
const size_t quad_size = bytes_per_index * 6;
for (u32 first = 0; first < num_first_offset_copies; ++first) {
@@ -164,29 +172,33 @@ public:
}
}
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset,
dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) {
const VkBufferCopy copy{
.srcOffset = src_offset,
.dstOffset = 0,
.size = size_bytes,
};
const VkBufferMemoryBarrier write_barrier{
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_INDEX_READ_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = dst_buffer,
.offset = 0,
.size = size_bytes,
};
cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier);
});
if (!host_visible) {
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset,
dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) {
const VkBufferCopy copy{
.srcOffset = src_offset,
.dstOffset = 0,
.size = size_bytes,
};
const VkBufferMemoryBarrier write_barrier{
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_INDEX_READ_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = dst_buffer,
.offset = 0,
.size = size_bytes,
};
cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier);
});
} else {
buffer.Flush();
}
}
void BindBuffer(u32 first) {
@@ -578,7 +590,8 @@ void BufferCacheRuntime::ReserveNullBuffer() {
.pNext = nullptr,
.flags = 0,
.size = 4,
.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
@@ -587,11 +600,10 @@ void BufferCacheRuntime::ReserveNullBuffer() {
create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
null_buffer = device.GetLogical().CreateBuffer(create_info);
null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal);
if (device.HasDebuggingToolAttached()) {
null_buffer.SetObjectNameEXT("Null buffer");
}
null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) {

View File

@@ -48,7 +48,6 @@ private:
const Device* device{};
vk::Buffer buffer;
MemoryCommit commit;
std::vector<BufferView> views;
};
@@ -142,7 +141,6 @@ private:
std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer;
vk::Buffer null_buffer;
MemoryCommit null_buffer_commit;
std::unique_ptr<Uint8Pass> uint8_pass;
QuadIndexedPass quad_index_pass;

View File

@@ -205,10 +205,9 @@ void FSR::CreateDescriptorSets() {
void FSR::CreateImages() {
images.resize(image_count * 2);
image_views.resize(image_count * 2);
buffer_commits.resize(image_count * 2);
for (size_t i = 0; i < image_count * 2; ++i) {
images[i] = device.GetLogical().CreateImage(VkImageCreateInfo{
images[i] = memory_allocator.CreateImage(VkImageCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -231,7 +230,6 @@ void FSR::CreateImages() {
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
});
buffer_commits[i] = memory_allocator.Commit(images[i], MemoryUsage::DeviceLocal);
image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr,

View File

@@ -47,7 +47,6 @@ private:
vk::Sampler sampler;
std::vector<vk::Image> images;
std::vector<vk::ImageView> image_views;
std::vector<MemoryCommit> buffer_commits;
};
} // namespace Vulkan

View File

@@ -652,13 +652,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.pNext = nullptr,
.negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE,
};
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
VkPipelineViewportStateCreateInfo viewport_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.viewportCount = Maxwell::NumViewports,
.viewportCount = num_viewports,
.pViewports = nullptr,
.scissorCount = Maxwell::NumViewports,
.scissorCount = num_viewports,
.pScissors = nullptr,
};
if (device.IsNvViewportSwizzleSupported()) {

View File

@@ -309,7 +309,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.support_int16 = device.IsShaderInt16Supported(),
.support_int64 = device.IsShaderInt64Supported(),
.support_vertex_instance_id = false,
.support_float_controls = true,
.support_float_controls = device.IsKhrShaderFloatControlsSupported(),
.support_separate_denorm_behavior =
float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
.support_separate_rounding_mode =
@@ -325,12 +325,13 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.support_fp64_signed_zero_nan_preserve =
float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
.support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
.support_vote = true,
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
.support_viewport_index_layer_non_geometry =
device.IsExtShaderViewportIndexLayerSupported(),
.support_viewport_mask = device.IsNvViewportArray2Supported(),
.support_typeless_image_loads = device.IsFormatlessImageLoadSupported(),
.support_demote_to_helper_invocation = true,
.support_demote_to_helper_invocation =
device.IsExtShaderDemoteToHelperInvocationSupported(),
.support_int64_atomics = device.IsExtShaderAtomicInt64Supported(),
.support_derivative_control = true,
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),

View File

@@ -181,7 +181,7 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_
frame->height = height;
frame->is_srgb = is_srgb;
frame->image = dld.CreateImage({
frame->image = memory_allocator.CreateImage({
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
@@ -204,8 +204,6 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
});
frame->image_commit = memory_allocator.Commit(frame->image, MemoryUsage::DeviceLocal);
frame->image_view = dld.CreateImageView({
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr,

View File

@@ -29,7 +29,6 @@ struct Frame {
vk::Image image;
vk::ImageView image_view;
vk::Framebuffer framebuffer;
MemoryCommit image_commit;
vk::CommandBuffer cmdbuf;
vk::Semaphore render_ready;
vk::Fence present_done;

View File

@@ -315,7 +315,14 @@ void RasterizerVulkan::Clear(u32 layer_count) {
FlushWork();
gpu_memory->FlushCaching();
#if ANDROID
if (Settings::IsGPULevelHigh()) {
// This is problematic on Android, disable on GPU Normal.
query_cache.UpdateCounters();
}
#else
query_cache.UpdateCounters();
#endif
auto& regs = maxwell3d->regs;
const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B ||
@@ -925,7 +932,7 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
}
const bool is_rescaling{texture_cache.IsRescaling()};
const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f;
const std::array viewports{
const std::array viewport_list{
GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale),
GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale),
GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale),
@@ -935,7 +942,11 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale),
GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale),
};
scheduler.Record([viewports](vk::CommandBuffer cmdbuf) { cmdbuf.SetViewport(0, viewports); });
scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
cmdbuf.SetViewport(0, viewports);
});
}
void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) {
@@ -948,7 +959,7 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
up_scale = Settings::values.resolution_info.up_scale;
down_shift = Settings::values.resolution_info.down_shift;
}
const std::array scissors{
const std::array scissor_list{
GetScissorState(regs, 0, up_scale, down_shift),
GetScissorState(regs, 1, up_scale, down_shift),
GetScissorState(regs, 2, up_scale, down_shift),
@@ -966,7 +977,11 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
GetScissorState(regs, 14, up_scale, down_shift),
GetScissorState(regs, 15, up_scale, down_shift),
};
scheduler.Record([scissors](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissors); });
scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) {
const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
cmdbuf.SetScissor(0, scissors);
});
}
void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {

View File

@@ -25,9 +25,7 @@ namespace {
#define ARRAY_TO_SPAN(a) std::span(a, (sizeof(a) / sizeof(a[0])))
std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device,
MemoryAllocator& allocator,
VkExtent2D dimensions, VkFormat format) {
vk::Image CreateWrappedImage(MemoryAllocator& allocator, VkExtent2D dimensions, VkFormat format) {
const VkImageCreateInfo image_ci{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = nullptr,
@@ -46,11 +44,7 @@ std::pair<vk::Image, MemoryCommit> CreateWrappedImage(const Device& device,
.pQueueFamilyIndices = nullptr,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
};
auto image = device.GetLogical().CreateImage(image_ci);
auto commit = allocator.Commit(image, Vulkan::MemoryUsage::DeviceLocal);
return std::make_pair(std::move(image), std::move(commit));
return allocator.CreateImage(image_ci);
}
void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayout target_layout,
@@ -82,7 +76,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler,
vk::Image& image, VkExtent2D dimensions, VkFormat format,
std::span<const u8> initial_contents = {}) {
auto upload_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
const VkBufferCreateInfo upload_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -91,9 +85,10 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
});
auto upload_commit = allocator.Commit(upload_buffer, MemoryUsage::Upload);
std::ranges::copy(initial_contents, upload_commit.Map().begin());
};
auto upload_buffer = allocator.CreateBuffer(upload_ci, MemoryUsage::Upload);
std::ranges::copy(initial_contents, upload_buffer.Mapped().begin());
upload_buffer.Flush();
const std::array<VkBufferImageCopy, 1> regions{{{
.bufferOffset = 0,
@@ -117,9 +112,6 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
});
scheduler.Finish();
// This should go out of scope before the commit
auto upload_buffer2 = std::move(upload_buffer);
}
vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) {
@@ -531,10 +523,8 @@ void SMAA::CreateImages() {
static constexpr VkExtent2D area_extent{AREATEX_WIDTH, AREATEX_HEIGHT};
static constexpr VkExtent2D search_extent{SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT};
std::tie(m_static_images[Area], m_static_buffer_commits[Area]) =
CreateWrappedImage(m_device, m_allocator, area_extent, VK_FORMAT_R8G8_UNORM);
std::tie(m_static_images[Search], m_static_buffer_commits[Search]) =
CreateWrappedImage(m_device, m_allocator, search_extent, VK_FORMAT_R8_UNORM);
m_static_images[Area] = CreateWrappedImage(m_allocator, area_extent, VK_FORMAT_R8G8_UNORM);
m_static_images[Search] = CreateWrappedImage(m_allocator, search_extent, VK_FORMAT_R8_UNORM);
m_static_image_views[Area] =
CreateWrappedImageView(m_device, m_static_images[Area], VK_FORMAT_R8G8_UNORM);
@@ -544,12 +534,11 @@ void SMAA::CreateImages() {
for (u32 i = 0; i < m_image_count; i++) {
Images& images = m_dynamic_images.emplace_back();
std::tie(images.images[Blend], images.buffer_commits[Blend]) =
CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
std::tie(images.images[Edges], images.buffer_commits[Edges]) =
CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT);
std::tie(images.images[Output], images.buffer_commits[Output]) =
CreateWrappedImage(m_device, m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
images.images[Blend] =
CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
images.images[Edges] = CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16_SFLOAT);
images.images[Output] =
CreateWrappedImage(m_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
images.image_views[Blend] =
CreateWrappedImageView(m_device, images.images[Blend], VK_FORMAT_R16G16B16A16_SFLOAT);

View File

@@ -66,13 +66,11 @@ private:
std::array<vk::Pipeline, MaxSMAAStage> m_pipelines{};
std::array<vk::RenderPass, MaxSMAAStage> m_renderpasses{};
std::array<MemoryCommit, MaxStaticImage> m_static_buffer_commits;
std::array<vk::Image, MaxStaticImage> m_static_images{};
std::array<vk::ImageView, MaxStaticImage> m_static_image_views{};
struct Images {
vk::DescriptorSets descriptor_sets{};
std::array<MemoryCommit, MaxDynamicImage> buffer_commits;
std::array<vk::Image, MaxDynamicImage> images{};
std::array<vk::ImageView, MaxDynamicImage> image_views{};
std::array<vk::Framebuffer, MaxSMAAStage> framebuffers{};

View File

@@ -30,55 +30,6 @@ constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB;
constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB;
constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS;
constexpr VkMemoryPropertyFlags HOST_FLAGS =
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
constexpr VkMemoryPropertyFlags STREAM_FLAGS = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | HOST_FLAGS;
bool IsStreamHeap(VkMemoryHeap heap) noexcept {
return STREAM_BUFFER_SIZE < (heap.size * 2) / 3;
}
std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask,
VkMemoryPropertyFlags flags) noexcept {
for (u32 type_index = 0; type_index < props.memoryTypeCount; ++type_index) {
if (((type_mask >> type_index) & 1) == 0) {
// Memory type is incompatible
continue;
}
const VkMemoryType& memory_type = props.memoryTypes[type_index];
if ((memory_type.propertyFlags & flags) != flags) {
// Memory type doesn't have the flags we want
continue;
}
if (!IsStreamHeap(props.memoryHeaps[memory_type.heapIndex])) {
// Memory heap is not suitable for streaming
continue;
}
// Success!
return type_index;
}
return std::nullopt;
}
u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask,
bool try_device_local) {
std::optional<u32> type;
if (try_device_local) {
// Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this
type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS);
if (type) {
return *type;
}
}
// Otherwise try without the DEVICE_LOCAL_BIT
type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS);
if (type) {
return *type;
}
// This should never happen, and in case it does, signal it as an out of memory situation
throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY);
}
size_t Region(size_t iterator) noexcept {
return iterator / REGION_SIZE;
}
@@ -87,58 +38,26 @@ size_t Region(size_t iterator) noexcept {
StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
Scheduler& scheduler_)
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {
const vk::Device& dev = device.GetLogical();
stream_buffer = dev.CreateBuffer(VkBufferCreateInfo{
VkBufferCreateInfo stream_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = STREAM_BUFFER_SIZE,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
});
};
if (device.IsExtTransformFeedbackSupported()) {
stream_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream);
if (device.HasDebuggingToolAttached()) {
stream_buffer.SetObjectNameEXT("Stream Buffer");
}
VkMemoryDedicatedRequirements dedicated_reqs{
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
.pNext = nullptr,
.prefersDedicatedAllocation = VK_FALSE,
.requiresDedicatedAllocation = VK_FALSE,
};
const auto requirements = dev.GetBufferMemoryRequirements(*stream_buffer, &dedicated_reqs);
const bool make_dedicated = dedicated_reqs.prefersDedicatedAllocation == VK_TRUE ||
dedicated_reqs.requiresDedicatedAllocation == VK_TRUE;
const VkMemoryDedicatedAllocateInfo dedicated_info{
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
.pNext = nullptr,
.image = nullptr,
.buffer = *stream_buffer,
};
const auto memory_properties = device.GetPhysical().GetMemoryProperties().memoryProperties;
VkMemoryAllocateInfo stream_memory_info{
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = make_dedicated ? &dedicated_info : nullptr,
.allocationSize = requirements.size,
.memoryTypeIndex =
FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true),
};
stream_memory = dev.TryAllocateMemory(stream_memory_info);
if (!stream_memory) {
LOG_INFO(Render_Vulkan, "Dynamic memory allocation failed, trying with system memory");
stream_memory_info.memoryTypeIndex =
FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, false);
stream_memory = dev.AllocateMemory(stream_memory_info);
}
if (device.HasDebuggingToolAttached()) {
stream_memory.SetObjectNameEXT("Stream Buffer Memory");
}
stream_buffer.BindMemory(*stream_memory, 0);
stream_pointer = stream_memory.Map(0, STREAM_BUFFER_SIZE);
stream_pointer = stream_buffer.Mapped();
ASSERT_MSG(!stream_pointer.empty(), "Stream buffer must be host visible!");
}
StagingBufferPool::~StagingBufferPool() = default;
@@ -199,7 +118,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
return StagingBufferRef{
.buffer = *stream_buffer,
.offset = static_cast<VkDeviceSize>(offset),
.mapped_span = std::span<u8>(stream_pointer + offset, size),
.mapped_span = stream_pointer.subspan(offset, size),
.usage{},
.log2_level{},
.index{},
@@ -247,29 +166,29 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s
StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage,
bool deferred) {
const u32 log2 = Common::Log2Ceil64(size);
vk::Buffer buffer = device.GetLogical().CreateBuffer({
VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = 1ULL << log2,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
});
};
if (device.IsExtTransformFeedbackSupported()) {
buffer_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage);
if (device.HasDebuggingToolAttached()) {
++buffer_index;
buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str());
}
MemoryCommit commit = memory_allocator.Commit(buffer, usage);
const std::span<u8> mapped_span = IsHostVisible(usage) ? commit.Map() : std::span<u8>{};
const std::span<u8> mapped_span = buffer.Mapped();
StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{
.buffer = std::move(buffer),
.commit = std::move(commit),
.mapped_span = mapped_span,
.usage = usage,
.log2_level = log2,

Some files were not shown because too many files have changed in this diff Show More